ffi M1.2 A.0: objc_defined_class_cache + scan-pass registration

Adds an insertion-ordered cache on Module for sx-defined Obj-C
classes — every '#objc_class("Cls") { ... }' declaration WITHOUT
'#foreign'. registerForeignClassDecl appends the entry alongside
its existing foreign_class_map insert; lookup helper available
via Module.lookupObjcDefinedClass.

  ObjcDefinedClassEntry { name, *const ast.ForeignClassDecl }

The pointer back into the AST lets later passes (M1.2 A.1+) walk
'members' for fields / methods / '#extends' / '#implements'
without duplicating that data on the entry. Insertion order
matters because class-pair init constructors (A.4) must register
parent classes before children — 'objc_allocateClassPair(super,
...)' resolves super by lookup.

Infrastructure only — no observable behavior change. The cache
is populated but not yet read; A.1+ start pulling from it. 170
example tests + zig build test green.
This commit is contained in:
agra
2026-05-25 21:37:36 +03:00
parent d9dbdad3f5
commit 61a2593020
2 changed files with 37 additions and 0 deletions

View File

@@ -9413,8 +9413,17 @@ pub const Lowering = struct {
/// type (e.g. `*Activity`) is resolved via the existing struct
/// fallback in `type_bridge.resolveTypeName` (which interns unknown
/// named types as 0-field structs).
///
/// sx-defined Obj-C classes (no `#foreign`, runtime == .objc_class)
/// also land in `module.objc_defined_class_cache` in declaration
/// order — that cache drives M1.2 class-synthesis emission (A.4+).
fn registerForeignClassDecl(self: *Lowering, fcd: *const ast.ForeignClassDecl) void {
self.foreign_class_map.put(fcd.name, fcd) catch {};
if (!fcd.is_foreign and fcd.runtime == .objc_class) {
if (self.module.lookupObjcDefinedClass(fcd.name) == null) {
self.module.appendObjcDefinedClass(fcd.name, fcd);
}
}
}
/// Lazily declare the `sx_jni_env_tl_get` / `sx_jni_env_tl_set`