Files
sx/examples/optionals/0922-optionals-binop-no-implicit-unwrap.sx
agra 468461becc fix: gate implicit optional unwrap on flow narrowing (issue 0179)
Optional (?T) operands were implicitly unwrapped without proof of
presence, silently miscompiling a NULL ?T to garbage. Unwraps in
binary ops and other expression positions are now gated on flow
narrowing: a ?T value is only auto-unwrapped where control flow has
established it is non-null (the narrowed_refs set). Outside a narrowed
region, an implicit unwrap is rejected rather than producing garbage.

Touches the lowering pipeline (lower.zig + lower/{call,closure,coerce,
comptime,control_flow,expr,ffi,generic,pack,stmt}.zig). Adds optionals
examples 0919-0923 and closures example 0312 covering flow narrowing,
binop narrowing, no-implicit-unwrap rejection, and no closure leak of
narrowed state. Updates specs.md and readme.md.
2026-06-25 13:57:48 +03:00

15 lines
526 B
Plaintext

// An un-narrowed `?T` used directly as a binary-op operand is a compile error
// — it does not implicitly unwrap.
//
// Regression (issue 0185): `null + 10` used to compile and unconditionally
// extract the payload, silently yielding `10` (0 + 10) with no diagnostic.
// The legal forms are `!` / `??` / a `!= null` guard (see 0921).
#import "modules/std.sx";
main :: () {
a : ?i64 = null;
b : i64 = 10;
c := a + b; // error: optional operand does not implicitly unwrap
print("c = {}\n", c);
}