Summary
Nested synchronous concise arrows lose proper-tail-call lowering when compiled as function templates. The standalone plain-function path calls compileTailExpr, but Compiler.compileFunction currently lowers an expression body with compileExpr followed by ret. A strict recursive concise arrow therefore grows the native call stack in required-VM mode.
Parent roadmap: #491 Related bytecode eligibility work: #465 Related expression tier-agreement tranche: #1099
Reproduction
"use strict";
var recurse;
recurse = (n) => n === 0 ? 42 : recurse(n - 1);
recurse(20000);Current zig-js:
- tree walker:
42 - required VM:
RangeError: Maximum call stack size exceeded.
Oracles on the same machine:
- JavaScriptCore:
42 - Node:
RangeError(Node does not implement optional proper tail calls)
Root cause
compilePlainFunctionInner lowers concise bodies through compileTailExpr, while nested plain templates in Compiler.compileFunction use compileExpr plus ret. The nested template retains is_arrow = true and is_strict = true, but its bytecode contains no tail-call opcode.
Definition of done
- Nested strict concise arrows use canonical
compileTailExprlowering. - Sloppy arrows retain ordinary call semantics.
- Async concise arrows remain excluded from proper-tail-call lowering.
- Deep recursion agrees between tree walker and required VM.
- Compiler-shape and end-to-end regression coverage pass under normal and TSan/GC-focused gates.