fix: dispatch unwrapped optional-closure call g!() through call_closure (issue 0170)
Calling through an unwrapped optional closure (g!()) crashed with LLVM
'Called function must be a pointer!': the indirect-call catch-all else
arm emitted call_indirect on the whole {fn,env} closure struct with a
hardcoded .i64 return. The else arm now inspects inferExprType(callee):
a .closure callee dispatches through call_closure (threads env + ctx via
the [ctx, env, user_args] ABI, returns closure.ret); a plain fn pointer
uses call_indirect with the callee's real function.ret instead of i64.
The filed repro's ?(() -> void) spelling is a tuple-optional (now
diagnosed by the 0165 fix); the real ?Closure(...) layout was already
correct. Verified load-bearing (HEAD crashes) by 3 adversarial reviews,
suite 785/0. Regression: examples/closures/0311-closures-optional-closure.sx.
Filed adjacent bug 0177 (array-element closure direct call crashes).
This commit is contained in:
@@ -1,5 +1,22 @@
|
||||
# 0170 — closure optional `?(() -> ...)` alloca is sized one word, truncating the `{fn,env}` closure value
|
||||
|
||||
> **RESOLVED** (root cause differs from the title's hypothesis). Two findings:
|
||||
> (1) the filed repro's `?(() -> void)` spelling is a TUPLE-optional (the `(T)`
|
||||
> 1-tuple rule), now correctly diagnosed by the issue-0165 fix — not a closure
|
||||
> bug. (2) The REAL closure-optional `?Closure(args) -> R` layout was already
|
||||
> correct (sentinel form: the value IS the closure `{fn,env}`, has_value =
|
||||
> `fn_ptr != null`); `if g` / `== null` / `!= null` already worked. The genuine
|
||||
> bug was calling through an unwrapped optional closure `g!()` — the indirect-call
|
||||
> catch-all `else` arm (`src/ir/lower/call.zig`) emitted `call_indirect` on the
|
||||
> whole `{fn,env}` struct (LLVM "Called function must be a pointer!") with a
|
||||
> hardcoded `.i64` return. Fix: the `else` arm inspects `inferExprType(callee)` —
|
||||
> `.closure` → `call_closure` (threads env+ctx, returns `closure.ret`); else →
|
||||
> `call_indirect` with the callee's real `function.ret`. Verified load-bearing
|
||||
> (HEAD crashes) by 3 adversarial reviews; suite 785/0. Regression:
|
||||
> `examples/closures/0311-closures-optional-closure.sx`. (Adjacent pre-existing
|
||||
> bug found + filed: 0177 — array-element closure direct call `fns[i](args)`
|
||||
> crashes.)
|
||||
|
||||
## Symptom
|
||||
|
||||
An optional of a closure (`?(() -> void)`, `?Fn`) is mis-laid-out: the optional
|
||||
|
||||
Reference in New Issue
Block a user