fix: diagnose ?? with a non-optional lhs instead of codegen panic (issue 0172)
lowerNullCoalesce fed resolveOptionalInner's .unresolved (returned for a non-optional lhs) into the merge-block params / optionalUnwrap / RHS target type, reaching codegen and panicking 'unresolved type reached LLVM emission'. Guard: when inferExprType(nc.lhs) is a resolved non-optional type, emit a located diagnostic and bail; an .unresolved lhs (prior error) is excluded to avoid double-report. ?? is optional-only per specs.md (error unions use or/catch), so rejecting a failable lhs is correct; comptime panic closed too. Regression: examples/diagnostics/1200-diagnostics-null-coalesce-non-optional.sx. Verified by 3 adversarial reviews, suite 790/0. Filed adjacent bug 0180 (?? lowering defects for generic/alias/tuple optional lhs).
This commit is contained in:
@@ -1952,7 +1952,24 @@ pub fn lowerForceUnwrap(self: *Lowering, fu: *const ast.ForceUnwrap) Ref {
|
||||
|
||||
pub fn lowerNullCoalesce(self: *Lowering, nc: *const ast.NullCoalesce) Ref {
|
||||
const lhs = self.lowerExpr(nc.lhs);
|
||||
const inner_ty = self.resolveOptionalInner(self.inferExprType(nc.lhs));
|
||||
const lhs_ty = self.inferExprType(nc.lhs);
|
||||
|
||||
// `??` requires an optional left operand. A resolved non-optional lhs is
|
||||
// malformed user input: diagnose it here instead of letting the
|
||||
// `.unresolved` inner type (from `resolveOptionalInner`) flow into the
|
||||
// merge-block params / `optionalUnwrap` / the RHS target type and reach
|
||||
// emit_llvm's "unresolved type reached LLVM emission" panic with no source
|
||||
// location (issue 0172). Skip an already-`.unresolved` lhs: that comes
|
||||
// from a PRIOR error (e.g. an undefined name) which has already been
|
||||
// diagnosed — re-reporting would be a confusing second message.
|
||||
const lhs_is_optional = !lhs_ty.isBuiltin() and self.module.types.get(lhs_ty) == .optional;
|
||||
if (lhs_ty != .unresolved and !lhs_is_optional) {
|
||||
if (self.diagnostics) |d|
|
||||
d.addFmt(.err, nc.lhs.span, "left operand of '??' must be an optional, but has type '{s}'", .{self.formatTypeName(lhs_ty)});
|
||||
return lhs; // placeholder — hasErrors() aborts before codegen
|
||||
}
|
||||
|
||||
const inner_ty = self.resolveOptionalInner(lhs_ty);
|
||||
|
||||
// Short-circuit: only evaluate RHS if LHS is null.
|
||||
// IMPORTANT: optional_unwrap must be in the "has value" branch,
|
||||
|
||||
Reference in New Issue
Block a user