// A closure literal inside a `defer` / `onfail` body is its OWN function // boundary (ERR step E1.7). The cleanup-absorption check stops at the lambda: // the E1.7 "no bare failable in cleanup" rule and the parser's `try`/`raise` // ban both apply only to the cleanup block itself, not to a closure declared // inside it. Within the closure, normal failable rules resume — `try` // propagates through the closure's own `!E` channel, and value-slot liveness // (E1.8) is analysed per-boundary, so `v` is live under its `if !err` guard. // // Locks the closure-boundary arms of the error-flow pass (`checkCleanupNode`'s // `.lambda` stop + `flowExpr`'s `.lambda` recursion) before A5.2 extracts the // pass into its own module. Constructible since issue 0073 (closure literal in // a `defer` body no longer segfaults lowering — see 0310). #import "modules/std.sx"; E :: error { Bad } failing :: () -> !E { raise error.Bad; } recover :: () -> (s32, !E) { return 21; } work :: () { defer { // Own boundary: `try` is legal here (it would be parser-banned in the // defer body directly), and the bare failable is governed by the // closure's `!E` signature, not the cleanup rule. emit := () -> !E { v, err := recover(); if !err { print("defer closure: v={}\n", v); } // E1.8: live under guard try failing(); }; emit() catch e print("defer closure: raised\n"); } print("body\n"); } main :: () -> s32 { work(); return 0; }