ERR/E1.8: path-sensitive value-slot liveness check
A `v, err := failable()` destructure now binds the value slot(s) "live
only where `err` is proven absent". Reading `v` where the compiler cannot
prove `err == null` is a compile error.
New diagnostic-only Pass 1e (`checkErrorFlow` in ir/lower.zig): a
structured, path-sensitive walk over each main-file function body. A
proven-null set is threaded across branches and joined by intersection
at each `if`'s merge. Proof shapes recognized:
- `if !err { … v … }` (proven inside the guard)
- `if err { return/raise } … v` (proven on the fall-through)
- `if err { … } else { … v … }` (proven in the else branch)
- `!err and <reads v>` (short-circuit refinement)
Error-set tag compares (`if err == error.X`) prove nothing about
absence — they narrow the tag only. Nested lambdas are analyzed as their
own boundaries. Library modules are trusted (skipped).
Migrated the canon value-failable examples (1011/1012/1018/1044) to read
their value slots under `if !err` guards — output unchanged. New
regressions: 1046 (every proof shape compiles + runs, exit 210) and 1047
(unproven reads rejected, exit 1).
Gates: zig build, zig build test, run_examples.sh -> 338 passed, 0 failed.
This commit is contained in:
@@ -15,10 +15,10 @@ main :: () -> s32 {
|
||||
// success, consumed by catch
|
||||
print("catch={}\n", wrap(s32, closure(() -> (s32, !E) { return 7; })) catch e -1); // 7
|
||||
|
||||
// success, consumed by destructure (binds value + error slot)
|
||||
// success, consumed by destructure (binds value + error slot); the value
|
||||
// slot is read only under an `if !err` guard (ERR E1.8 path-sensitivity)
|
||||
r, err := wrap(s32, closure(() -> (s32, !E) { return 9; }));
|
||||
no_err := if err == error.Bad then false else true;
|
||||
print("destr={} ok={}\n", r, no_err); // destr=9 ok=true
|
||||
if !err { print("destr={} ok=true\n", r); } // destr=9 ok=true
|
||||
|
||||
// failure path: the raised tag propagates through the generic `try`
|
||||
print("fail={}\n", wrap(s32, closure(() -> (s32, !E) { raise error.Bad; }) ) catch e -1); // -1
|
||||
|
||||
Reference in New Issue
Block a user