[compiler] Fix Stack overflow in Stack.find/contains/each/print on deeply nested scopes #37581

Open
sleitor opened 4:36am on September 11, 2026 wants to merge 1 commit into facebook/react main from
fix-37445

Pull Request Overview

  • Opened on September 11, 2026
  • Status Open
  • Commit count 1 with first commit September 11, 2026

Total Delta

0 Total Diff Delta

Open Days

Open 6 weekdays

Test Delta

0 Diff Delta in Test Files
Breakdown by Phase

How long has this pull request spent in each phase of its lifecycle?

Data pending calculation for pull request

Author avatar

[compiler] Fix Stack overflow in Stack.find/contains/each/print on deeply nested scopes

Summary

Fixes #37445

The compiler's immutable Stack data structure (compiler/packages/babel-plugin-react-compiler/src/Utils/Stack.ts) implemented find, contains, each, and print by recursing one JS call-stack frame per linked-list node. For compiler inputs with a large number of active/nested scopes (tens of thousands of stack entries), these traversals could exceed the JS call-stack depth and throw:

RangeError: Maximum call stack size exceeded

Fix

Converted find, contains, each, and print on the Node class from per-node recursion to iterative while loops that walk the linked list. Traversal order (top-to-bottom / most-recently-pushed-first) is preserved exactly; only the call-stack depth changes β€” it is now O(1) instead of O(n) in the number of stack entries.

To satisfy the @typescript-eslint/no-this-alias lint rule (no aliasing this to a local variable), each method first processes this's own value, then iterates over this.#next onward using a local node variable β€” so this itself is never aliased.

Empty#find/contains/each/print were already O(1) (terminal case) and are unchanged.

Test plan

Added src/__tests__/Stack-test.ts with:
- Basic correctness checks for find/contains/each/print on a small stack, verifying traversal order.
- A regression test that pushes 50,000 entries onto the Stack and calls find, contains, each, and print, asserting none of them throw and that results are correct β€” this reproduces the reported overflow on the old recursive implementation and passes with the iterative fix.

Ran:
- yarn workspace babel-plugin-react-compiler lint β€” passes.
- yarn jest in compiler/packages/babel-plugin-react-compiler β€” full suite passes (15 suites / 43 tests / 40 snapshots).

Description

The compiler immutable Stack implements find, contains, each, and print by recursively traversing one linked node per call. Deeply nested compiler inputs can create enough active stack entries for these helpers to throw RangeError: Maximum call stack size exceeded.

Reproduction

Push 20,000 entries onto the compiler Stack and search for the bottom value. Both find and contains overflow on current main; the complete traversals have the same recursive shape.

Expected behavior

Stack traversal should remain bounded by heap storage rather than the JavaScript call-stack depth while preserving top-to-bottom visitation order.

No comments have been left on this PR.