fix: bindingless if/while/and/or over optional reads has_value (issue 0164)
lowerIfExpr emitted optional_has_value only for the binding form; a bare
'if opt' passed the raw {T,i1} aggregate to condBr, where emitCondBr's
catch-all struct arm silently folded it to 'i1 true' (structs always
truthy) — a silent miscompile that took the present-branch for null
optionals. while / and / or shared the same defect.
Reduce bindingless optional conditions to optional_has_value in
lowerIfExpr/lowerWhile and via a new lowerBoolCondition helper for and/or
operands. Replace the silent-true emitCondBr arm with a lowering-time
diagnostic (checkConditionType/isValidConditionType) rejecting conditions
whose type isn't bool/integer/pointer/optional; the backend @panic is now
an unreachable tripwire.
Regressions: examples/optionals/0908..0910 + diagnostics/1194 (negative).
Verified by 3+3 adversarial reviews.
Filed adjacent bugs found during review: 0168 (array-of-optionals element
load), 0169 (optional->bool coercion), 0170 (closure-optional layout).
This commit is contained in:
@@ -1,5 +1,23 @@
|
||||
# 0164 — `if <optional>` with no binding silently folds the has_value test to `true`
|
||||
|
||||
> **RESOLVED.** Two colluding sites: `lowerIfExpr` emitted `optional_has_value`
|
||||
> only for the binding form, and `emitCondBr`'s catch-all struct arm silently
|
||||
> folded any non-i1 condition to `i1 true` ("structs always truthy"). Fix: reduce
|
||||
> a bindingless optional condition to `optional_has_value` in `lowerIfExpr`/
|
||||
> `lowerWhile`, add a shared `lowerBoolCondition` helper for `and`/`or` operands
|
||||
> (the same defect affected `while`/`and`/`or`), and add a lowering-time
|
||||
> diagnostic (`checkConditionType`/`isValidConditionType` in `lower/expr.zig`)
|
||||
> rejecting conditions whose type isn't bool/integer/pointer/optional — turning
|
||||
> the `emitCondBr` silent-true into a real type error and leaving the backend
|
||||
> `@panic` as an unreachable tripwire. Regressions:
|
||||
> `examples/optionals/0908-if-optional-no-binding.sx`,
|
||||
> `0909-optionals-while-no-binding.sx`,
|
||||
> `0910-optionals-and-or-optional-operands.sx`,
|
||||
> `examples/diagnostics/1194-diagnostics-condition-non-bool-type.sx` (negative).
|
||||
> Verified by 3 + 3 adversarial reviews. (Adjacent bugs found during review and
|
||||
> filed separately: 0168 array-of-optionals element load, 0169 optional→bool
|
||||
> coercion, 0170 closure-optional layout.)
|
||||
|
||||
## Symptom
|
||||
|
||||
Branching on an optional **without a binding** (`if opt { ... }`) takes the
|
||||
|
||||
Reference in New Issue
Block a user