fix(ir): open a fresh defer window when lowering a lambda body (issue 0073)

A closure literal declared inside a `defer` body segfaulted the compiler.
Root cause: lowerLambda never opened its own `func_defer_base` window. Every
other function-lowering entry (lowerFunction / monomorphizeFunction /
monomorphizePackFn) saves func_defer_base, sets it to defer_stack.items.len, and
restores it — lowerLambda didn't. So a lambda's `return` drained the ENCLOSING
function's defers; when the defer body itself declared the lambda, draining
re-lowered the lambda, which returned, which drained again → infinite recursion
→ stack-overflow SIGSEGV (the failable variant surfaced one frame out, in
expandCallDefaults→lookupFn reading a clobbered scope).

Fix: lowerLambda now saves func_defer_base + the defer_stack length, sets the
base to the current length (a fresh window), and restores both on exit — so a
lambda's `return` drains only its own defers.

Regression: examples/0310-closures-closure-literal-in-defer.sx — a closure
declared and called inside a `defer`; verifies `body` then `defer closure: 42`
at scope exit (exit 0). Issue 0073 marked RESOLVED; repro promoted from
issues/0073-*.sx.

zig build, zig build test, tests/run_examples.sh (358/0) all green.
This commit is contained in:
agra
2026-06-02 23:29:49 +03:00
parent eb20b2ddb5
commit 08f263c6e4
7 changed files with 52 additions and 17 deletions

View File

@@ -1,5 +1,18 @@
# issue 0073 — closure literal inside a `defer` body segfaults the compiler
> **✅ RESOLVED (2026-06-02).** Root cause: `lowerLambda` never opened its own
> `defer` window. Every other function-lowering entry (`lowerFunction`,
> `monomorphizeFunction`, `monomorphizePackFn`) saves `func_defer_base`, sets it
> to `defer_stack.items.len`, and restores it — but `lowerLambda` didn't, so a
> lambda's `return` drained the *enclosing* function's defers. When the defer
> body itself declared the lambda, draining re-lowered the lambda, which `return`ed,
> which drained again → infinite recursion → stack-overflow SIGSEGV.
> Fix: `lowerLambda` now opens a fresh defer window (save `func_defer_base` +
> `defer_stack` length, set base to the current length, restore both on exit) —
> `src/ir/lower.zig`. Regression test: `examples/0310-closures-closure-literal-in-defer.sx`
> (a closure declared + called inside a `defer`; verifies `body` then
> `defer closure: 42` at scope exit). Suite 358/0.
## Symptom
One-line: declaring a **closure literal inside a `defer` body** crashes the