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:
@@ -795,6 +795,12 @@ pub fn monomorphizePackFn(
|
||||
const owned_name = self.alloc.dupe(u8, mangled_name) catch return;
|
||||
self.lowered_functions.put(owned_name, {}) catch {};
|
||||
|
||||
// Flow narrowing (issue 0179) is per-function: this monomorphized pack body
|
||||
// has its own `Ref` space (overlapping the caller's), so isolate it from the
|
||||
// caller's `narrowed`/`narrowed_refs` to avoid a false-positive unwrap gate.
|
||||
var narrow_guard = Lowering.NarrowGuard.enter(self);
|
||||
defer narrow_guard.restore();
|
||||
|
||||
// Find the pack param's name and position in fd.params, plus its
|
||||
// constraint protocol (`..xs: Box` ⇒ "Box"; comptime `..$args` has none).
|
||||
var pack_name: []const u8 = "";
|
||||
|
||||
Reference in New Issue
Block a user