ArrayPush(N): local not in scope when pushing onto a const array initialised with an object literal (blocks TanStack Router SSR)
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 56/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- rust, typescript
- Domain
- compilers
Research direction
Start at the LLVM lowering path that handles ArrayPush and reproduce the failure with the TypeScript function in the issue; compare it with the working let variant. Trace how the array local is registered and kept in scope for the push operation. Done means the const example compiles and runs with output 2, while the documented working variants still compile.
Written by the indexing model from the issue text.
Description
Perry fails to compile a function that pushes onto a const array whose initialiser holds an object literal:
function f() {
const s = [{ v: 1 }]
s.push({ v: 2 })
return s.length
}
console.log(f())
$ perry compile repro.ts -o repro
Error compiling module 'repro.ts' (…/repro.ts) with --backend llvm: lowering function 'f': lowering body of 'f': ArrayPush(1): local not in scope
✗ ENTRY MODULE FAILED TO COMPILE — REFUSING TO LINK
Node prints 2.
Small changes make it compile:
let s = [{ v: 1 }]const s: {v: number}[] = [], then pushs[s.length] = { v: 2 }instead ofpush
Where it shows up. This isn't contrived. It's how TanStack Router's route matcher keeps its depth-first search stack. getNodeMatch in @tanstack/router-core (1.171.34, dist/esm/new-process-route-tree.js) starts with
const stack = [{ node: segmentTree, index: 1, skipped: 0, statics: 0, dynamics: 0, optionals: 0 }]
while (stack.length) {
const frame = stack.pop()
…
stack.push({ … })
}
Every TanStack Router and TanStack Start app runs this on each request. So a server-rendering bundle from either one can't compile today. In our case, an SSR render bundle failed with ArrayPush(12121): local not in scope in getNodeMatch, and the full TanStack Start server got 111 of 113 modules through codegen before stopping on the same error. A worklist seeded with one root object is a common way to write tree traversals, so other code probably hits it too.
Environment: macOS 26.3.1 arm64, --backend llvm.
- Perry 0.5.1520 (npm
@perryts/perry): fails as above. mainat7cbfde8(0.5.1659, built 2026-10-17 with LLVM 22.1.8): same error (checked with--no-link); theletvariant compiles.
- Dominant language
- Rust
- Stars
- 4.9k
- Forks
- 166
- Avg merge
- 3h 23m
- Merged PRs (30d)
- 911
Getting set up
- Ships a Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from PerryTS/perry
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 1 day
-
bug
Difficulty 3/5 1-2 days Newbie friendliness 67/100
Maintainers usually reply within 1 day
-
bug
Difficulty 4/5 3-5 days Newbie friendliness 48/100
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 76/100
Maintainers usually reply within 1 day
Similar issues
-
Difficulty 1/5 1-3 hours Newbie friendliness 88/100
fritzprix/libr-agent#2165 ·
Maintainers usually reply within 1 day
-
area:ecosystem bug
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Chelis-Lang/chelis#3942 ·
Maintainers usually reply within 1 day
-
needs-triage
Difficulty 2/5 1-3 hours Newbie friendliness 63/100
Maintainers usually reply within 1 day
-
review-bot
Difficulty 1/5 Under an hour Newbie friendliness 90/100
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 86/100
Maintainers usually reply within 1 day