Files
sx/issues/0166-null-coalesce-struct-literal-default-unresolved.md
agra 2637ae98a5 docs: file issues 0164-0167 (optional/comptime bugs found during 0162 review)
0164 if <optional> no-binding folds has_value to true (silent miscompile)
0165 parenthesized nested optional ?(?T) malformed double-wrap (crash)
0166 ?? .{ } struct-literal default unresolved type (crash)
0167 comptime regToValue array-in-aggregate gap + unclean recovery
2026-06-22 19:43:55 +03:00

43 lines
1.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 0166 — `?? .{ ... }` struct-literal default panics with "unresolved type reached LLVM emission"
## Symptom
Using a struct literal as the default of a `??` (null-coalesce) operator panics:
```
panic: unresolved type reached LLVM emission
```
in `emitStructInit` (exit 134 / SIGABRT). The coalesce result type is inferred
correctly (the optional's child `T`), but that target type is NOT threaded into
the RHS struct-literal lowering, so the `struct_init` instruction's `.ty` stays
`.unresolved` and reaches codegen.
## Reproduction
```sx
#import "modules/std.sx";
T :: struct { a: i64 = 0; }
mk :: () -> ?T { return null; }
main :: () { t := mk() ?? .{ a = 9 }; print("{}\n", t.a); }
```
Expected: `9` (null lhs → take the struct-literal default, typed as `T`).
Observed: `panic: unresolved type reached LLVM emission`, exit 134.
## Investigation prompt
The result type IS inferred correctly — `src/ir/expr_typer.zig` (~lines 413425)
returns the optional's child `T` for the coalesce expression. The gap is in
lowering: the `??` RHS struct literal is lowered without a target type. Suspected
area: `src/ir/lower/expr.zig` `lowerNullCoalesce` (dispatched ~expr.zig:2417)
must set the lowering target type to the lhs optional's child (`T`) before
lowering `nc.rhs`, so an untyped `.{ ... }` literal on the RHS resolves to `T`
the same way an assignment/return target would. Mirror however other contexts
push an expected type into an untyped struct-literal lowering.
Verify: the repro prints `9`; also test a present lhs (`mk` returns a value →
prints the value's field, default not taken) and a nested-field struct literal
default. Add an `examples/optionals/09xx-null-coalesce-struct-literal.sx`
regression.