A `defer`/`onfail` body runs while the block is already exiting, so a
failable call there has nowhere to propagate its error. The parser
already bans `try`/`raise`/`return`/`break`/`continue` in cleanup bodies
(f9dd965); this adds the remaining sema rule — a bare (un-absorbed)
failable call must be absorbed locally with `catch` or `or <value>`.
Implemented in the shared error-flow pass (`checkCleanupBody` /
`checkCleanupNode` / `cleanupReject` in ir/lower.zig): when the walk hits
a `defer`/`onfail`, it scans the body transitively (through blocks, `if`,
loops, match arms, `catch` handlers; stopping at nested closures) and
flags any still-failable expression. `catch` / `or value` strip the
error channel, so `exprIsFailable` is false for them — only an unhandled
failable trips the check. This completes ERR PLAN E0–E5 plus the two
deferred E1 follow-ups (E1.7 + E1.8).
New regressions: 1048 (catch/or-value absorbed forms compile + run) and
1049 (bare failable in defer and onfail rejected, exit 1).
Filed issue 0065: a braced `defer { … }` / value-block body routes
through `parseExpr` (not `parseBlock` like `onfail`), so it can't parse a
destructure or `catch`-statement inside. Orthogonal to E1.7 — the spec'd
cleanup absorbers (`catch` / `or value`) parse fine in a `defer` body.
Gates: zig build, zig build test, run_examples.sh -> 340 passed, 0 failed.
24 lines
732 B
Plaintext
24 lines
732 B
Plaintext
// Rejection counterpart to 1048 (ERR step E1.7). A bare (un-absorbed) failable
|
|
// call in a `defer` / `onfail` body is a compile error — the block is already
|
|
// exiting, so the error has nowhere to propagate. It must be absorbed locally
|
|
// with `catch` or `or <value>`. Both a `defer` and an `onfail` bare call are
|
|
// flagged; the program never runs (exit 1).
|
|
|
|
#import "modules/std.sx";
|
|
|
|
E :: error { Bad }
|
|
|
|
failing :: () -> !E { raise error.Bad; }
|
|
|
|
work :: (n: s32) -> !E {
|
|
defer failing(); // REJECTED: bare failable in a defer body
|
|
onfail { failing(); } // REJECTED: bare failable in an onfail body
|
|
if n < 0 { raise error.Bad; }
|
|
return;
|
|
}
|
|
|
|
main :: () -> s32 {
|
|
a := work(-1);
|
|
return 0;
|
|
}
|