Problem
Nested untagged template substitutions still recurse through native Zig frames even though flat expression chains use an iterative spine. The parser lowers each substitution to a chain whose right operand is an internal ToString unary; nesting templates alternates evalChain -> evalUnary(.to_string) -> evalChain and bypasses the left-spine iteration.
On current main 8794ccc5, a 300-level nested template evaluates to "7" in a normal build but reaches the production source-nesting guard and escapes as RangeError: Maximum call stack size exceeded. under TSan. The backtrace repeats evalChain, foldChainLink, evalUnary, and eval for more than 1,300 frames.
Reproducer:
function nest(open, core, close, n) {
return open.repeat(n) + core + close.repeat(n);
}
(0, eval)(nest("`${", "7", "}`", 300)) === "7";Baseline evidence:
zig build test-runtime -Dtest-filter='nested template substitutions evaluate without native recursion': passeszig build test-runtime -Dtsan=true -Dtest-filter='nested template substitutions evaluate without native recursion': fails with an uncaught productionRangeError- no ThreadSanitizer race diagnostic
Scope
- Evaluate nested template substitutions with bounded native stack.
- Preserve left-to-right evaluation, logical short-circuiting, private-brand checks, debugger/step checkpoints, and GC rooting.
- Preserve the compact pointer-spine path and allocation profile for ordinary flat chains.
- Add normal and TSan regression coverage at depth 300.
- Run focused runtime, semantic unit, and sharded full-unit gates.
No-workaround rule
Do not lower the source depth, change the sanitizer-only expectation, enlarge the native-stack redzone, or weaken the production RangeError boundary. Remove the avoidable native recursion.