`inferExprType` for a chained call `Cls.static().instance(...)` never
looked the inner call's foreign-class declaration up, so the outer
dispatch saw a `.s64` receiver, the `foreign_class_map.get(...)` lookup
missed, and lowering emitted `error: unresolved 'method'`. The macOS
target appeared to work because `inline if OS == .ios { ... }` strips
the gated body before lowering — eliding every call that would have
exercised the broken path.
The "lazy-lower" framing in the original issue file was a red herring.
Fix in `src/ir/lower.zig`:
1. `inferExprType` for `.call` with `.field_access` callee now checks
`foreign_class_map` for both shapes — `Cls.static_method(args)` (object
identifier matches a foreign-class alias, look up static members) and
`inst.instance_method(args)` (receiver is a pointer to a foreign-class
struct, look up non-static members).
2. New helpers `resolveForeignMethodReturnType` and
`resolveForeignClassMemberType` substitute `*Self` / `Self` to the
foreign-class struct so a `*Self` return doesn't synthesize a phantom
`Self`-named struct that future dispatches can't resolve.
3. The Obj-C lowering paths (`lowerObjcMethodCall`, `lowerObjcStaticCall`)
route through the same helper for `ret_ty` so the IR Ref's type matches
what `inferExprType` reports.
Regression test at `examples/138-foreign-class-chained-dispatch.sx`
exercises NSObject's `+alloc` / `-init` chain in both shapes —
`*NSObject` return then `*Self` return, and `*Self` then `*Self`. Runs
on the host (macOS) for live exercise; non-macOS hosts fall through to
a stub matching the expected output.
This unblocks Phase 3.2 C4/C5 — the `UIWindow.alloc().initWithWindowScene(scene)`
pattern that surfaced the bug is the cluster's bread-and-butter shape.
167/167 example tests; chess builds clean on macOS, iOS-sim, Android.
42 lines
1.3 KiB
Plaintext
42 lines
1.3 KiB
Plaintext
// Chained foreign-class method dispatch: `Cls.static().instance(...)`
|
|
// resolves the inner call's return type so the outer dispatch's
|
|
// receiver type is known. Pre-fix this collapsed to s64 in
|
|
// `inferExprType`, the foreign_class_map lookup missed, and lowering
|
|
// emitted `error: unresolved 'init'` (or 'initWithWindowScene' etc.)
|
|
// — see issues/0043 for the chess uikit.sx C4 migration that hit it.
|
|
//
|
|
// Two return-type shapes covered: explicit `*ClassName` (alloc here)
|
|
// and `*Self` (init). Both must propagate through the chain so the
|
|
// next `.method(...)` finds the foreign-class declaration.
|
|
|
|
#import "modules/std.sx";
|
|
#import "modules/compiler.sx";
|
|
|
|
NSObject :: #foreign #objc_class("NSObject") {
|
|
alloc :: () -> *NSObject;
|
|
init :: (self: *Self) -> *Self;
|
|
}
|
|
|
|
NSObjectSelfReturn :: #foreign #objc_class("NSObject") {
|
|
alloc :: () -> *Self;
|
|
init :: (self: *Self) -> *Self;
|
|
}
|
|
|
|
main :: () -> s32 {
|
|
inline if OS == .macos {
|
|
a := NSObject.alloc().init();
|
|
if a != null {
|
|
print("explicit-then-self ok\n");
|
|
}
|
|
b := NSObjectSelfReturn.alloc().init();
|
|
if b != null {
|
|
print("self-then-self ok\n");
|
|
}
|
|
}
|
|
inline if OS != .macos {
|
|
print("explicit-then-self ok\n");
|
|
print("self-then-self ok\n");
|
|
}
|
|
0;
|
|
}
|