fix: union struct-literal init (issue 0158)
A plain union initialized with a struct literal (b : Overlay = .{ f = 3.14 })
silently miscompiled — it fell through the generic struct-literal path
(getStructFields returns empty for a union), building a malformed structInit
whose overlapping zero-fill clobbered the named member, so it read back 0.0
(and a type-pun read segfaulted).
lowerStructLiteral now detects a plain-union target and dispatches to a new
lowerUnionLiteral, which writes each named member into a union-sized slot via
the same lvalue resolver the u.member = v assignment path uses, then loads the
union value back. Validity: the named members must share one arm — a single
direct member, or several promoted members of the same anonymous-struct variant.
Overlapping members, members from different arms, and positional union literals
are rejected with a diagnostic (no silent last-wins); an empty .{} yields an
undefined union (matching the --- form).
specs.md updated. Regressions: examples/types/0194 (valid forms) +
examples/diagnostics/1191 (overlap rejection).
This commit is contained in:
20
specs.md
20
specs.md
@@ -452,12 +452,26 @@ Vec2 :: union {
|
||||
Access promoted members directly: `v.x`, `v.y` — these are zero-cost GEPs into the same underlying memory as `v.data[0]`, `v.data[1]`.
|
||||
|
||||
#### Initialization
|
||||
Unions must be initialized with `---` (undefined) and then assigned per-field:
|
||||
A union may be initialized either with `---` (undefined) then assigned
|
||||
per-field, or with a struct literal that sets a **single arm**:
|
||||
```sx
|
||||
o :Overlay = ---;
|
||||
o :Overlay = ---; // undefined, then set a member
|
||||
o.f = 3.14;
|
||||
print("{}\n", o.i); // reinterpret bits as i32
|
||||
print("{}\n", o.i); // reinterpret bits as i32
|
||||
|
||||
p :Overlay = .{ f = 3.14 }; // equivalent single-member literal
|
||||
```
|
||||
Because a union's members overlay the same storage, a literal may name **only
|
||||
one member** — or, for a union with an anonymous-struct arm, several members of
|
||||
the *same* arm (they do not overlap each other):
|
||||
```sx
|
||||
v :Vec2 = .{ x = 1.0, y = 2.0 }; // OK — both belong to the { x, y } arm
|
||||
```
|
||||
Naming two overlapping members (`.{ f = 3.14, i = 7 }`) or members from
|
||||
different arms (`.{ data = ..., x = ... }`) is a compile error — the literal
|
||||
would otherwise silently let a later store clobber an earlier one. An empty
|
||||
`.{}` yields an undefined union (same as `---`). A positional union literal
|
||||
(`.{ 3.14 }`) is rejected as ambiguous.
|
||||
|
||||
#### Restrictions
|
||||
- Pattern matching (`if x == { case ... }`) is not supported on unions.
|
||||
|
||||
Reference in New Issue
Block a user