Summary
A var declared inside a constant-bound (compile-time unrolled) counted loop and read after the loop loses its last-iteration value — the read sees the initial/undefined slot instead. Surfaced while fixing #1803 (PR #2307); it is independent of that fix and reproduces on main both with and without it.
Repro
function h(): number {
let sum = 0;
for (let i = 0; i < 3; i++) { var t = i * 2; sum += t; }
return sum + t; // t should be the last iteration's value (4)
}
console.log(h());
// node: 10 (sum 6 + t 4)
// perry: 6 (t read as 0)
Scope
Notes
Narrow/contrived (reading a loop-body var after the loop with constant bounds); filing for backlog completeness. Not a blocker for ajv (#1680) — its loops are for...in, not unrolled counted loops.
Summary
A
vardeclared inside a constant-bound (compile-time unrolled) counted loop and read after the loop loses its last-iteration value — the read sees the initial/undefined slot instead. Surfaced while fixing #1803 (PR #2307); it is independent of that fix and reproduces onmainboth with and without it.Repro
Scope
i < n) the same code is correct (10):varhoisting / slot reuse (which bug(codegen): ajv/standalone per-property type guards miscompile (invalid input accepted) #1803 / PR fix(codegen): reuse slot for hoisted var redeclaration (#1803) #2307 addresses). The unrolled copies don't preserve the body-declaredvar's slot value for a post-loop read.Notes
Narrow/contrived (reading a loop-body
varafter the loop with constant bounds); filing for backlog completeness. Not a blocker for ajv (#1680) — its loops arefor...in, not unrolled counted loops.