fix(stdlib/E4): source-pin sx-defined objc-class IMP trampolines + finish non-transitive bare-TYPE gate
Final E4 piece: the IMP trampolines emitted for an sx-defined #objc_class resolved their method-signature types (e.g. -> BOOL) at whatever lowering site triggered emission, not the class's defining module — so under the single-hop bare-TYPE gate a 2-flat-hop objc type (BOOL via uikit->objc) leaked as 'not visible' when m3te's main triggered emission. - ast.ForeignClassDecl gains source_file (stamped by resolveImports, like ProtocolDecl/StructTemplate); stampFnBodySource stamps the decl + each bodied method body. - emitObjcDefinedClassImps pins current_source_file to fcd.source_file for the whole per-class emission (alloc/dealloc/method/property IMPs). - Removes the BOOLLEAF debug probe. Completes E4: bare-TYPE visibility is single-hop non-transitive across all member kinds; every instantiation kind (generic struct/fn, pack fn, param protocol, type fn, objc-block, objc-class IMP) is source-pinned to its defining module. Full gate green; m3te ios-sim builds + launches (exit 0).
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user