@@ -513,30 +513,49 @@ LLVMValueRef codegen_expr_call(CodeGenContext *ctx, AstNode *node) {
513513 // Check if this is a method call (obj.method())
514514 if (callee -> type == AST_EXPR_MEMBER && !callee -> expr .member .is_compiletime ) {
515515 // Method call: obj.method(arg1, arg2)
516- // The typechecker has already injected 'self' as the first argument
517- // So we just need to codegen all arguments as-is
518-
519- // Get the method function
520516 const char * member_name = callee -> expr .member .member ;
517+
518+ // **FIX: The typechecker already injected self into args[0]!**
519+ // Just look up the method and use args as-is
520+
521+ LLVMValueRef method_func = NULL ;
521522
522- // Look up the method in the current module
523+ // First try current module
523524 LLVMModuleRef current_llvm_module =
524525 ctx -> current_module ? ctx -> current_module -> module : ctx -> module ;
525- LLVMValueRef method_func =
526- LLVMGetNamedFunction (current_llvm_module , member_name );
526+ method_func = LLVMGetNamedFunction (current_llvm_module , member_name );
527527
528+ // If not found in current module, search all other modules
528529 if (!method_func ) {
529- fprintf (stderr , "Error: Method '%s' not found\n" , member_name );
530+ for (ModuleCompilationUnit * unit = ctx -> modules ; unit ;
531+ unit = unit -> next ) {
532+ if (unit == ctx -> current_module )
533+ continue ;
534+
535+ LLVMValueRef found_func = LLVMGetNamedFunction (unit -> module , member_name );
536+ if (found_func ) {
537+ // CRITICAL FIX: Create external declaration in current module
538+ LLVMTypeRef func_type = LLVMGlobalGetValueType (found_func );
539+ method_func = LLVMAddFunction (current_llvm_module , member_name , func_type );
540+ LLVMSetLinkage (method_func , LLVMExternalLinkage );
541+ break ;
542+ }
543+ }
544+ }
545+
546+ if (!method_func ) {
547+ fprintf (stderr , "Error: Method '%s' not found in any module\n" ,
548+ member_name );
530549 return NULL ;
531550 }
532551
533552 callee_value = method_func ;
534553
535- // Allocate space for all arguments (including injected self)
554+ // Allocate space for arguments (typechecker already added self! )
536555 args = (LLVMValueRef * )arena_alloc (
537556 ctx -> arena , sizeof (LLVMValueRef ) * arg_count , alignof(LLVMValueRef ));
538557
539- // Codegen all arguments (self is already in args[0] from typechecker )
558+ // Generate all arguments (including self at index 0 )
540559 for (size_t i = 0 ; i < arg_count ; i ++ ) {
541560 args [i ] = codegen_expr (ctx , node -> expr .call .args [i ]);
542561 if (!args [i ]) {
@@ -545,8 +564,7 @@ LLVMValueRef codegen_expr_call(CodeGenContext *ctx, AstNode *node) {
545564 member_name );
546565 return NULL ;
547566 }
548- }
549-
567+ }
550568 } else {
551569 // Regular function call or compile-time member access (module::func)
552570 callee_value = codegen_expr (ctx , callee );
@@ -572,14 +590,10 @@ LLVMValueRef codegen_expr_call(CodeGenContext *ctx, AstNode *node) {
572590
573591 // Check if return type is void
574592 if (LLVMGetTypeKind (return_type ) == LLVMVoidTypeKind ) {
575- // For void functions, don't assign a name to the call
576593 LLVMBuildCall2 (ctx -> builder , func_type , callee_value , args , arg_count , "" );
577- // Return a void constant since we can't return NULL
578594 return LLVMConstNull (LLVMVoidTypeInContext (ctx -> context ));
579595 } else {
580- // For non-void functions, assign a name as usual
581- return LLVMBuildCall2 (ctx -> builder , func_type , callee_value , args ,
582- arg_count , "call" );
596+ return LLVMBuildCall2 (ctx -> builder , func_type , callee_value , args , arg_count , "call" );
583597 }
584598}
585599
0 commit comments