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.
This commit is contained in:
8
specs.md
8
specs.md
@@ -1122,6 +1122,14 @@ wrap :: (n: i32) -> ?i32 {
|
||||
}
|
||||
```
|
||||
|
||||
The reverse is **not** implicit: a `?T` never silently unwraps to its payload
|
||||
`T` in a value position (call argument, field initializer, `return`, assignment).
|
||||
Such a use is a compile error — extract the payload explicitly with `!` / `??` /
|
||||
a binding (`if v := opt`) / a `case` match, or rely on flow-sensitive narrowing
|
||||
after a `!= null` guard (below). Unwrapping a null optional implicitly would
|
||||
yield its zero payload with no diagnostic, so the conversion is rejected rather
|
||||
than allowed.
|
||||
|
||||
#### Force Unwrap (`!`)
|
||||
Extracts the payload, traps at runtime if null:
|
||||
```sx
|
||||
|
||||
Reference in New Issue
Block a user