ffi M1.2 A.7: open the dispatch gate — sx-defined class methods callable
Delete the bail at lower.zig:4407 that diagnosed sx-defined Obj-C
class dispatch as 'not yet supported'. Both foreign and
sx-defined '#objc_class' decls now flow through the same
'lowerObjcMethodCall' path — instance methods on sx-defined
classes dispatch via objc_msgSend, and the registered IMP
trampolines (M1.2 A.4b.iii) route to the sx bodies.
The runtime non-Obj-C branch (.swift_class / .swift_struct /
.swift_protocol) keeps its 'not yet supported' diagnostic;
M1.2 only addresses the Obj-C runtimes.
Constructor reorder in emit_llvm: emitObjcDefinedClassInit
runs BEFORE emitObjcClassInit. Otherwise the Phase 3.1
class-cache populator calls objc_getClass("SxFoo") before our
constructor registers the class — cache slot stored null and
'SxFoo.method()' dispatched against a null class pointer.
ffi-objc-defined-class-01-instance.sx (the integration test
from the plan) now runs the full lifecycle on macOS:
f := SxFoo.alloc() // synthesized +alloc IMP fires
f.bump() // dispatch → IMP trampoline → sx body
f.bump() // state persists across calls
f.bump()
f.get() // → 3
release_fn(f, sel_release) // synthesized -dealloc fires
The user declares 'alloc :: () -> *SxFoo;' bodyless to give the
synthesized +alloc IMP a typed contract at sx call sites —
same convention as foreign classes today.
M1.2 complete: A.0 A.1 A.2 A.3 A.4 A.4b.i A.4b.ii A.4b.iii
A.5 A.6 A.7. End-to-end class-synthesis foundation works.
177 example tests pass (+1 from the integration test). zig
build test green.
This commit is contained in:
@@ -4431,22 +4431,24 @@ pub const Lowering = struct {
|
||||
return Ref.none;
|
||||
};
|
||||
|
||||
if (!fcd.is_foreign) {
|
||||
if (self.diagnostics) |d| {
|
||||
d.addFmt(.err, span, "sx-defined foreign classes can't yet be dispatched into (class '{s}' missing '#foreign' modifier? — runtime synthesis is a follow-up)", .{fcd.name});
|
||||
}
|
||||
return Ref.none;
|
||||
}
|
||||
|
||||
// Obj-C instance dispatch (Phase 3 step 3.0). `inst.method(args)` on
|
||||
// an `#objc_class` / `#objc_protocol` receiver derives a selector
|
||||
// from the sx method name (default mangling: split on `_`, each
|
||||
// piece becomes a keyword with a trailing `:`; niladic stays
|
||||
// verbatim) and lowers to `objc_msg_send`. The Swift runtimes
|
||||
// still bail — Phase 4.
|
||||
// Obj-C instance dispatch (Phase 3 step 3.0 + M1.2 A.7).
|
||||
// `inst.method(args)` on an `#objc_class` / `#objc_protocol`
|
||||
// receiver derives a selector from the sx method name (default
|
||||
// mangling: split on `_`, each piece becomes a keyword with a
|
||||
// trailing `:`; niladic stays verbatim) and lowers to
|
||||
// `objc_msg_send`. Both foreign and sx-defined classes flow
|
||||
// through the same path — sx-defined classes have their IMPs
|
||||
// registered at module-init (M1.2 A.4b.iii) so `objc_msgSend`
|
||||
// finds them. The Swift runtimes still bail — Phase 4.
|
||||
if (fcd.runtime == .objc_class or fcd.runtime == .objc_protocol) {
|
||||
return self.lowerObjcMethodCall(fcd, method, target, method_args, span);
|
||||
}
|
||||
if (!fcd.is_foreign) {
|
||||
if (self.diagnostics) |d| {
|
||||
d.addFmt(.err, span, "sx-defined classes on non-Obj-C runtimes can't yet be dispatched into (class '{s}', runtime '{s}')", .{ fcd.name, @tagName(fcd.runtime) });
|
||||
}
|
||||
return Ref.none;
|
||||
}
|
||||
if (fcd.runtime != .jni_class and fcd.runtime != .jni_interface) {
|
||||
if (self.diagnostics) |d| {
|
||||
d.addFmt(.err, span, "method calls on '{s}' runtime not yet supported (Phase 3/4)", .{@tagName(fcd.runtime)});
|
||||
|
||||
Reference in New Issue
Block a user