issue-0038 fixed: closure capture through FfiIntrinsicCall args

`collectCaptures` in `src/ir/lower.zig` was the closure free-variable
analyzer that decides which names from a closure body need to be
boxed into the env struct at lambda-build time. Its switch on AST
node kind enumerated every other shape (`.call`, `.if_expr`,
`.match_expr`, `.for_expr`, etc.) but no arm for `.ffi_intrinsic_call`,
so the trailing `else => {}` quietly dropped its `args[]` and
`return_type` walks. Names referenced inside `#objc_call(T)(recv,
"sel:", ...)` from a closure body never made it into the captures
list, so when lowering bound the closure scope from env, those names
came back as "unresolved".

The fix adds the missing arm — walk `return_type` and every `args[i]`
the same way `.call` walks `callee` + `args`.

Companion changes:
- `examples/issue-0038.sx` → `examples/103-ffi-closure-capture.sx`
  (out of the open-issue namespace; comment header tightened to
  describe the feature, not the historical bug).
- `examples/ffi-objc-call-09-in-construct.sx` drops the
  `g_hasher_recv` module-global workaround that was added for this
  bug — the closure now captures `recv` from `make_hasher`'s arg
  list normally.
This commit is contained in:
agra
2026-05-19 21:14:31 +03:00
parent 35359b88f8
commit df2ccf77bd
8 changed files with 55 additions and 62 deletions

View File

@@ -5073,6 +5073,12 @@ pub const Lowering = struct {
.defer_stmt => |ds| {
self.collectCaptures(ds.expr, param_names, captures);
},
.ffi_intrinsic_call => |fic| {
self.collectCaptures(fic.return_type, param_names, captures);
for (fic.args) |arg| {
self.collectCaptures(arg, param_names, captures);
}
},
else => {},
}
}