diff --git a/src/ast.zig b/src/ast.zig index f1945590..8a4f287a 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -847,6 +847,11 @@ pub const ForeignClassDecl = struct { /// True when the sx-side alias NAME was a backtick raw identifier — exempt /// from the reserved-type-name decl check (issue 0089). is_raw: bool = false, + /// Defining module path (stamped by `resolveImports`), so the IMP trampolines + /// emitted for an sx-defined class resolve their method-signature types in the + /// module that declares the class — not the (cross-module) lowering site that + /// happens to trigger emission (E4). Null for a synthesized/sourceless decl. + source_file: ?[]const u8 = null, }; pub const JniEnvBlock = struct { diff --git a/src/imports.zig b/src/imports.zig index dc5c177f..af535cdb 100644 --- a/src/imports.zig +++ b/src/imports.zig @@ -666,6 +666,13 @@ fn stampFnBodySource(decl: *Node, file_path: []const u8) void { // defining path so the instantiation resolves method-signature types in // this module (E4). .protocol_decl => decl.data.protocol_decl.source_file = file_path, + // An sx-defined `#objc_class` / `#jni_class`: its IMP trampolines are + // emitted at lowering time (possibly from another module's context), so + // record the defining path AND stamp each method body (E4). + .foreign_class_decl => { + decl.data.foreign_class_decl.source_file = file_path; + stampForeignClassMethodSources(decl.data.foreign_class_decl, file_path); + }, .const_decl => |cd| switch (cd.value.data) { .fn_decl => |fd| fd.body.source_file = file_path, // `List :: struct { … append :: (…) { … } }` — the methods of a @@ -674,6 +681,10 @@ fn stampFnBodySource(decl: *Node, file_path: []const u8) void { // bodies need the defining path stamped just like a top-level fn. .struct_decl => |sd| stampStructMethodSources(sd, file_path), .protocol_decl => cd.value.data.protocol_decl.source_file = file_path, + .foreign_class_decl => { + cd.value.data.foreign_class_decl.source_file = file_path; + stampForeignClassMethodSources(cd.value.data.foreign_class_decl, file_path); + }, else => {}, }, else => {}, @@ -694,6 +705,16 @@ fn stampStructMethodSources(sd: ast.StructDecl, file_path: []const u8) void { } } +/// Stamp the defining module path onto every bodied method of an sx-defined +/// foreign class, so the method's sx body lowers in the class's own module. +fn stampForeignClassMethodSources(fcd: ast.ForeignClassDecl, file_path: []const u8) void { + for (fcd.members) |m| { + if (m == .method) { + if (m.method.body) |b| b.source_file = file_path; + } + } +} + /// `reportDuplicateName` keyed off a node whose `declName()` carries the name /// (the regular authored-decl sites; an `import_decl` has no `declName`, so a /// namespace alias must use `reportDuplicateName` with the alias directly). diff --git a/src/ir/lower.zig b/src/ir/lower.zig index 545c24ff..b4c9890a 100644 --- a/src/ir/lower.zig +++ b/src/ir/lower.zig @@ -2231,9 +2231,6 @@ pub const Lowering = struct { fn resolveNominalLeaf(self: *Lowering, name: []const u8, raw: bool, span: ?ast.Span) TypeId { const from = self.current_source_file orelse return self.typeResolver().resolveName(name, raw); - if (std.mem.eql(u8, name, "BOOL")) { - std.debug.print("[BOOLLEAF] from={s} -> {s}\n", .{ from, @tagName(self.selectNominalLeaf(name, from, raw)) }); - } return switch (self.selectNominalLeaf(name, from, raw)) { .resolved => |t| t, // A forward alias (`.pending`) or a forward / not-yet-interned named @@ -18042,6 +18039,12 @@ pub const Lowering = struct { fn emitObjcDefinedClassImps(self: *Lowering) void { for (self.module.objc_defined_class_cache.items) |entry| { const fcd = entry.decl; + // Pin to the class's defining module (E4) so the IMP trampolines' + // method-signature types (`-> BOOL`, param types) resolve where they + // are visible, not at whatever lowering site triggered emission. + const saved_src = self.current_source_file; + defer self.setCurrentSourceFile(saved_src); + if (fcd.source_file) |src| self.setCurrentSourceFile(src); // Synthesize +alloc (M1.2 A.5) and -dealloc (M1.2 A.6). emit_llvm // registers +alloc on the metaclass and -dealloc on the class // itself after objc_registerClassPair.