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:
@@ -1871,7 +1871,16 @@ pub fn lowerNullCoalesce(self: *Lowering, nc: *const ast.NullCoalesce) Ref {
|
||||
|
||||
// RHS block: evaluate fallback and branch to merge
|
||||
self.builder.switchToBlock(rhs_bb);
|
||||
// Thread the optional's child type as the expected/target type so an
|
||||
// untyped struct literal default (`?? .{ ... }`) resolves to `T` rather
|
||||
// than staying `.unresolved` and reaching codegen as a malformed
|
||||
// struct_init (issue 0166). Scalar/pointer/typed defaults are unaffected:
|
||||
// they ignore `target_type` or coerce identically. Restore afterwards so
|
||||
// a `??` nested inside a larger expression doesn't leak this target type.
|
||||
const saved_tt = self.target_type;
|
||||
self.target_type = inner_ty;
|
||||
var rhs = self.lowerExpr(nc.rhs);
|
||||
self.target_type = saved_tt;
|
||||
const rhs_ty = self.builder.getRefType(rhs);
|
||||
if (rhs_ty != inner_ty and rhs_ty != .void and inner_ty != .void) {
|
||||
rhs = self.coerceToType(rhs, rhs_ty, inner_ty);
|
||||
|
||||
Reference in New Issue
Block a user