fix(0140): surface comptime type-construction bail as a diagnostic
evalComptimeType did `interp.call(...) catch return null`, dropping the
interp's last_bail_detail; callers poisoned to .unresolved with no
diagnostic, so the sentinel reached LLVM emission and panicked
("unresolved type reached LLVM emission"), or hid behind a downstream
cascade.
Clear last_bail_detail before the call; on the catch emit a build-gating
.err at the construction expr's span ("comptime type construction
failed: {detail}", mirroring the #run surfacing in emit_llvm.zig), then
return null to keep the .unresolved poison — now gated by a real message
so no unresolved type reaches emission unannounced.
Empty-variant define now prints 'comptime define(): enum has no
variants' and exits 1 (no panic); make_enum-style computed-slice
failures show their root reason at the construction site.
This commit is contained in:
@@ -1,5 +1,21 @@
|
|||||||
# 0140 — a failing comptime type construction panics ("unresolved type reached LLVM emission") instead of diagnosing the bail
|
# 0140 — a failing comptime type construction panics ("unresolved type reached LLVM emission") instead of diagnosing the bail
|
||||||
|
|
||||||
|
> **RESOLVED (2026-06-17).** Root cause exactly as the investigation prompt
|
||||||
|
> hypothesized: `evalComptimeType` (`src/ir/lower/comptime.zig`) did
|
||||||
|
> `interp.call(...) catch return null`, dropping the interpreter's
|
||||||
|
> `last_bail_detail`; callers poisoned to `.unresolved` with no diagnostic, so the
|
||||||
|
> sentinel reached LLVM emission and tripped the codegen panic (or hid behind a
|
||||||
|
> downstream cascade). Fix: clear `Interpreter.last_bail_detail` before the call,
|
||||||
|
> and on the `catch` emit a build-gating `.err` at the construction expression's
|
||||||
|
> span — `"comptime type construction failed: {detail}"` (mirroring the `#run`
|
||||||
|
> surfacing at `emit_llvm.zig:856`) — then return null (keeping the `.unresolved`
|
||||||
|
> poison, now gated by a real message). The empty-variants repro now prints
|
||||||
|
> `comptime type construction failed: comptime define(): enum has no variants`
|
||||||
|
> and exits 1 (no panic); make_enum-style computed-slice failures surface their
|
||||||
|
> root reason at the construction site instead of only the `.green` cascade.
|
||||||
|
> Regression test:
|
||||||
|
> [examples/1179-diagnostics-comptime-type-construction-bail.sx](../examples/1179-diagnostics-comptime-type-construction-bail.sx).
|
||||||
|
|
||||||
## Symptom
|
## Symptom
|
||||||
|
|
||||||
One-line: when a comptime type construction (`declare`/`define`) bails in the
|
One-line: when a comptime type construction (`declare`/`define`) bails in the
|
||||||
|
|||||||
@@ -454,7 +454,25 @@ pub fn evalComptimeType(self: *Lowering, expr: *const Node) ?TypeId {
|
|||||||
if (self.diagnostics) |d| if (d.import_sources) |sm| interp.setSourceMap(sm);
|
if (self.diagnostics) |d| if (d.import_sources) |sm| interp.setSourceMap(sm);
|
||||||
interp.setMintTable(&self.module.types);
|
interp.setMintTable(&self.module.types);
|
||||||
|
|
||||||
const result = interp.call(func_id, &.{}) catch return null;
|
// Clear the interp's last-bail channel so a bail HERE is attributable to
|
||||||
|
// THIS construction (not a stale message from an earlier comptime eval).
|
||||||
|
interp_mod.Interpreter.last_bail_detail = null;
|
||||||
|
const result = interp.call(func_id, &.{}) catch |err| {
|
||||||
|
// A comptime type construction (declare/define, reflection) that bails
|
||||||
|
// must surface a build-gating diagnostic naming the reason — NOT poison
|
||||||
|
// to `.unresolved` silently and let that crash at LLVM emission
|
||||||
|
// ("unresolved type reached LLVM emission") or hide behind a downstream
|
||||||
|
// cascade (issue 0140). The interp's `bailDetail` already set the precise
|
||||||
|
// reason; mirror the `#run` path (emit_llvm.zig) and render it. Returning
|
||||||
|
// null keeps the `.unresolved` poison for the caller, but now the build
|
||||||
|
// is gated by a real message, so no unresolved type reaches emission
|
||||||
|
// unannounced.
|
||||||
|
if (self.diagnostics) |d| {
|
||||||
|
const detail = interp_mod.Interpreter.last_bail_detail orelse @errorName(err);
|
||||||
|
d.addFmt(.err, expr.span, "comptime type construction failed: {s}", .{detail});
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
return result.asTypeId();
|
return result.asTypeId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user