docs: file issue 0190 (void-failable fall-through leaves error slot uninitialized)

This commit is contained in:
agra
2026-06-25 18:41:22 +03:00
parent 40b5fb5f7e
commit f52e16a3fc

View File

@@ -0,0 +1,71 @@
# 0190 — void failable (`-> !`) implicit fall-through leaves the error slot uninitialized
**Status:** OPEN
## Symptom
A `-> !` (void failable) function that exits by **implicit fall-through**
(no explicit `return;`) does not initialize its error-channel slot, so a
caller (or `main`) reads a non-zero garbage tag and reports a phantom
unhandled error.
- Observed: `main :: () -> ! { print("ok\n"); }` prints `ok` then
`error: unhandled error reached main: error.` and exits **1**.
- Expected: exit **0** (specs.md §11: "the exit code is `0` for void /
`-> !` success"). Adding an explicit trailing `return;` makes it exit 0.
This is the silent-uninitialized-slot failure mode: the success path
should write "no error" into the channel just like an explicit `return;`
does, but the fall-through path skips it.
## Reproduction
```sx
#import "modules/std.sx";
main :: () -> ! {
print("ok\n");
}
```
Run: `./zig-out/bin/sx run repro.sx` → prints `ok`, then
`error: unhandled error reached main: error.`, exit 1 (should be 0).
A non-`main` void failable shows the same uninitialized slot downstream:
```sx
#import "modules/std.sx";
noop :: () -> ! { } // falls through, no `return;`
main :: () {
noop() catch (e) { print("phantom: {}\n", e); } // fires spuriously
}
```
Workaround (confirms root cause): an explicit `return;` at the end of the
`-> !` body initializes the slot and the phantom error disappears.
## Investigation prompt
The error channel for a `-> !` function is the last slot of the return
aggregate (specs.md §12 ABI). An explicit `return;` lowers to a write of
the "no error" sentinel into that slot; the **implicit fall-through** exit
path (end of body with no `return`) apparently omits that write, leaving
the slot whatever was on the stack.
Likely area: the function-epilogue / failable-return lowering in
`src/ir/lower/` (the path that synthesizes the implicit return for a
body that falls off the end — search for where a void/`-> !` function's
trailing fall-through is lowered, and where the error slot's "no error"
sentinel is written on the explicit-`return;` path). The fix: the
implicit fall-through of a failable function must initialize the error
slot to "no error" exactly like `return;` does.
Verification: the two repros above must exit 0 / not fire the catch;
`examples/errors/1026-errors-failable-main.sx` (which currently passes
only because it ends in `return;`) must keep passing. Add a regression
example: a `-> !` function (and a `main :: () -> !`) that succeeds by
fall-through with no explicit `return;`.
(Found by adversarial review during the tuple-syntax-cutover docs pass,
commit `989e18b7`. Pre-existing — independent of the tuple change.)