fix: thread optional child type into ?? struct-literal default (issue 0166)
The RHS of a null-coalesce was lowered with no target type, so a bare
struct literal default (x ?? .{ ... }) produced a struct_init with
.ty == .unresolved that panicked in emitStructInit. lowerNullCoalesce
now saves self.target_type, sets it to the optional's resolved child
before lowering nc.rhs, and restores it (leak-free). Verified across
struct/slice/enum/tuple/protocol/nested-optional/generic child types by
3 adversarial reviews.
Regression: examples/optionals/0912-null-coalesce-struct-literal.sx.
Filed adjacent pre-existing bug 0172 (?? on a non-optional lhs panics).
This commit is contained in:
30
examples/optionals/0912-null-coalesce-struct-literal.sx
Normal file
30
examples/optionals/0912-null-coalesce-struct-literal.sx
Normal file
@@ -0,0 +1,30 @@
|
||||
// Struct literal as the default of `??` (null-coalesce).
|
||||
// Regression (issue 0166): a bare `.{ ... }` default was lowered with no
|
||||
// target type, so its `struct_init.ty` stayed `.unresolved` and panicked at
|
||||
// LLVM emission ("unresolved type reached LLVM emission"). The fix threads the
|
||||
// optional's child type `T` into the RHS lowering, so the literal resolves to
|
||||
// `T`. Covers both runtime paths: default TAKEN (lhs null) and NOT taken (lhs
|
||||
// present), plus a nested struct-literal default and an all-defaulted `.{}`.
|
||||
#import "modules/std.sx";
|
||||
|
||||
Inner :: struct { x: i64 = 0; }
|
||||
T :: struct { a: i64 = 7; b: i64 = 3; inner: Inner; }
|
||||
|
||||
mk :: (give: bool) -> ?T {
|
||||
if give { return .{ a = 1, b = 2, inner = .{ x = 4 } }; }
|
||||
return null;
|
||||
}
|
||||
|
||||
main :: () {
|
||||
// Default NOT taken — lhs has a value.
|
||||
present := mk(true) ?? .{ a = 9, inner = .{ x = 99 } };
|
||||
print("{} {} {}\n", present.a, present.b, present.inner.x);
|
||||
|
||||
// Default TAKEN — lhs is null, struct-literal default selected.
|
||||
absent := mk(false) ?? .{ a = 9, inner = .{ x = 99 } };
|
||||
print("{} {} {}\n", absent.a, absent.b, absent.inner.x);
|
||||
|
||||
// All-defaulted `.{}` default.
|
||||
empty := mk(false) ?? .{};
|
||||
print("{} {} {}\n", empty.a, empty.b, empty.inner.x);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
1 2 4
|
||||
9 3 99
|
||||
7 3 0
|
||||
Reference in New Issue
Block a user