diff --git a/examples/issue-0038.sx b/examples/issue-0038.sx new file mode 100644 index 0000000..bd613bf --- /dev/null +++ b/examples/issue-0038.sx @@ -0,0 +1,41 @@ +// Closure capture analysis doesn't trace into the `FfiIntrinsicCall` +// AST node — identifiers used inside `#objc_call` / `#jni_call` / +// `#jni_static_call` from a closure body aren't recognized as +// captured variables. Surfaced when writing `ffi-objc-call-09-in- +// construct.sx`. +// +// Reduced repro: capture in a closure body works fine for +// "normal" expressions (see `passthrough_works`), but the same +// capture inside `#objc_call`'s arg list trips +// "unresolved: 'recv'" (see `passthrough_via_objc_call` — would +// fail at parse time, so it's commented out). +// +// Likely fix: in the closure free-variable analyzer (sema.zig / +// lower.zig), add a recursive arm for `ffi_intrinsic_call` that +// visits `return_type` + every `args[i]` the same way the `.call` +// arm walks `callee` + `args`. + +#import "modules/std.sx"; +#import "modules/compiler.sx"; + +passthrough_works :: (recv: *void) -> Closure(s32) -> *void { + closure((d: s32) -> *void => recv); // captures `recv` — fine +} + +// passthrough_via_objc_call :: (recv: *void) -> Closure(s32) -> s64 { +// // Same `recv` capture, but inside `#objc_call(...)`: +// // error: unresolved: 'recv' +// closure((d: s32) -> s64 => #objc_call(s64)(recv, "hash")); +// } + +main :: () -> s32 { + inline if OS == .macos { + f := passthrough_works(null); + p := f(0); + print("ok (passthrough works) = {}\n", p == null); + } + inline if OS != .macos { + print("skipped (not macos)\n"); + } + 0; +} diff --git a/tests/expected/issue-0038.exit b/tests/expected/issue-0038.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/expected/issue-0038.exit @@ -0,0 +1 @@ +0 diff --git a/tests/expected/issue-0038.txt b/tests/expected/issue-0038.txt new file mode 100644 index 0000000..6d77b8c --- /dev/null +++ b/tests/expected/issue-0038.txt @@ -0,0 +1 @@ +ok (passthrough works) = true