fix: coerce array/vector literal elements to element type (issue 0168)
[N]?T arrays were corrupted: a positional literal .{ null, 7 } stored
bare T/null elements into {T,i1} optional slots because array elements
were never coerced (getStructFields is empty for an array, so the
i<struct_fields.len field-coercion gate never fired). A present element
then read back as absent and direct indexing segfaulted.
lowerStructLiteral's positional branch now computes array_elem_ty for
array/vector targets and coerces each element to it; lowerArrayLiteral
generalizes its slice-only coercion to coerce every element via
coerceToType (layout-aware: scalar->{T,i1}, pointer-sentinel->one-word,
array->slice, concrete->protocol). Verified by 3 adversarial reviews,
suite 780/0.
Regression: examples/optionals/0913-optionals-array-of-optionals.sx.
Filed adjacent pre-existing bugs: 0173 (typed .[null,..] element), 0174
(tuple positional-element coercion), 0175 (positional struct literal
variable element zeroed).
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
# 0175 — positional struct literal with a VARIABLE element silently zeroes the field
|
||||
|
||||
## Symptom
|
||||
|
||||
A positional struct literal `S.{ x, ... }` whose element is a VARIABLE reference
|
||||
(not a literal constant) silently stores `0` instead of the variable's value. The
|
||||
NAMED form `S.{ a = x, ... }` works correctly. Silent miscompile. Pre-existing
|
||||
(reproduces on clean master; surfaced while fixing issue 0168).
|
||||
|
||||
## Reproduction
|
||||
|
||||
```sx
|
||||
#import "modules/std.sx";
|
||||
P :: struct { a: i64 = 0; b: i64 = 0; }
|
||||
main :: () {
|
||||
x := 5;
|
||||
p : P = .{ x, 2 }; // positional, variable first element
|
||||
print("{} {}\n", p.a, p.b); // prints "0 0" — WRONG, expected "5 2"
|
||||
}
|
||||
```
|
||||
|
||||
Expected: `5 2`. Observed: `0 0` (the variable element zeroed; note even the
|
||||
`2` literal field is wrong here — the whole positional path mis-coerces once a
|
||||
variable element is present). The named form `P.{ a = x, b = 2 }` prints `5 2`.
|
||||
|
||||
A related crash: `[2]P = .{ .{ x, 2 }, .{ 3, 4 } }` with an i32 variable `x`
|
||||
aborted the LLVM verifier on master (`Invalid InsertValueInst operands`); after
|
||||
the issue 0168 fix it no longer crashes but still prints the residual `0 …` for
|
||||
the variable element — confirming the root cause is the positional-element
|
||||
coercion, independent of 0168.
|
||||
|
||||
## Investigation prompt
|
||||
|
||||
`src/ir/lower/expr.zig` `lowerStructLiteral` positional branch, the field
|
||||
coercion at the `i < struct_fields.len` path (~expr.zig:235-237): it computes
|
||||
`src_ty = self.inferExprType(fi.value)` then `coerceToType(val, src_ty,
|
||||
struct_fields[i].ty)`. For a variable reference element, `inferExprType` appears
|
||||
to return a wrong/narrower type, causing `coerceToType` to mis-narrow/zero the
|
||||
value. Investigate why `inferExprType(variable_ref)` disagrees with the value's
|
||||
actual `getRefType`, and prefer coercing from the lowered value's real type
|
||||
(`self.builder.getRefType(val)`) rather than a re-inferred source type — or fix
|
||||
the inference for a bare variable element. Verify: the repro prints `5 2`; a
|
||||
positional literal mixing variable + literal + expression elements; with field
|
||||
types needing real coercion (i32 var → i64 field, concrete var → protocol field).
|
||||
Add an `examples/types/01xx-positional-struct-literal-variable-element.sx`
|
||||
regression.
|
||||
Reference in New Issue
Block a user