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:
@@ -8313,6 +8313,19 @@ pub const Lowering = struct {
|
||||
defer self.current_ctx_ref = saved_ctx_ref_lam;
|
||||
if (lambda_wants_ctx) self.current_ctx_ref = Ref.fromIndex(0);
|
||||
|
||||
// A lambda is its own function: its `return` must drain only ITS OWN
|
||||
// `defer`s, not the enclosing function's. Open a fresh defer window
|
||||
// (like `lowerFunction`/`monomorphizeFunction`) and restore on exit —
|
||||
// otherwise lowering a closure literal inside a `defer` body re-enters
|
||||
// the enclosing function's defer drain (infinite recursion — issue 0073).
|
||||
const saved_func_defer_base = self.func_defer_base;
|
||||
const saved_defer_len = self.defer_stack.items.len;
|
||||
defer {
|
||||
self.func_defer_base = saved_func_defer_base;
|
||||
self.defer_stack.shrinkRetainingCapacity(saved_defer_len);
|
||||
}
|
||||
self.func_defer_base = saved_defer_len;
|
||||
|
||||
// Create entry block
|
||||
const entry_name = self.module.types.internString("entry");
|
||||
const entry = self.builder.appendBlock(entry_name, &.{});
|
||||
|
||||
Reference in New Issue
Block a user