fix: body-local #run of an unbridged shape fails loudly instead of silent garbage (issue 0182)
The body-local #run fold in emitCall was effectively dead (gated on args.len==0, but the __ct comptime wrapper always carries the implicit *Context arg), so every body-local #run fell through to a RUNTIME call: bridgeable shapes lucked into the right value; an unbridgeable shape (e.g. [2][]i64) ran over --- storage -> garbage, exit 0, no diagnostic. Fold any is_comptime callee (gated !enclosing.is_comptime so nested metatype calls in a comptime wrapper's dead body aren't folded). On a tryEval bail, distinguish a BRIDGE bail (result can't regToValue- materialize -> error: comptime init of 'X' failed: <reason> + comptime_failed, build fails, symmetric with the global #run path) from an EXECUTION bail (VM can't run the body, e.g. NaN/extern -> runtime fallthrough, preserving types/0150), via comptime_vm.last_bail_was_bridge (reset at tryEval entry, set only at regToValue). The const name is threaded onto the wrapper (comptime_display_name) so the diagnostic reads the source name, not __ct_N. Regressions: diagnostics/1204 (negative), comptime/0645 (positive). Verified by 3 adversarial reviews, suite 801/0.
This commit is contained in:
@@ -1,5 +1,26 @@
|
||||
# 0182 — a body-local `#run` of an unbridged-shape return silently miscompiles (no abort, exit 0 garbage)
|
||||
|
||||
> **RESOLVED.** Root cause was deeper than "doesn't set comptime_failed": the
|
||||
> body-local `#run` fold in `emitCall` (`src/backend/llvm/ops.zig`) was effectively
|
||||
> DEAD — gated on `args.len==0`, but the `__ct` comptime wrapper always carries
|
||||
> the implicit `*Context` arg — so EVERY body-local `#run` fell through to a
|
||||
> RUNTIME call (bridgeable shapes lucked into the right value; unbridgeable ones
|
||||
> ran over `---` storage → garbage). Fix: fold any `is_comptime` callee (gated
|
||||
> `!enclosing.is_comptime` so nested metatype calls in a comptime wrapper's dead
|
||||
> body aren't folded). On a `tryEval` bail, distinguish a BRIDGE bail (body ran,
|
||||
> result shape can't `regToValue`-materialize → `error: comptime init of '<name>'
|
||||
> failed: <reason>` + `comptime_failed`, build fails — symmetric with the global
|
||||
> `#run` path) from an EXECUTION bail (VM can't run the body, e.g. NaN/extern →
|
||||
> runtime fallthrough, preserving `examples/types/0150`), via a new
|
||||
> `comptime_vm.last_bail_was_bridge` flag (reset at `tryEval` entry, set only at
|
||||
> the `regToValue` step). The binding const's name is threaded onto the wrapper
|
||||
> (`comptime_display_name`) so the diagnostic reads `'L'` not `__ct_N`.
|
||||
> Regressions: `examples/diagnostics/1204-diagnostics-comptime-run-unbridged-shape.sx`
|
||||
> (negative), `examples/comptime/0645-comptime-body-local-run-bridgeable.sx`
|
||||
> (positive). Verified by 3 adversarial reviews; suite 801/0. (Note: a BARE
|
||||
> inline `#run` of an unbridgeable shape correctly fails but names the internal
|
||||
> `__ct_N` — a cosmetic diagnostic-name follow-up, build behavior is correct.)
|
||||
|
||||
## Symptom
|
||||
|
||||
A `#run` const declared INSIDE a function body, whose comptime function returns a
|
||||
|
||||
Reference in New Issue
Block a user