Skip to content

[commit] Fix for nested optional chaining within other value blocks#401

Open
everettbu wants to merge 4 commits into
mainfrom
pr35596
Open

[commit] Fix for nested optional chaining within other value blocks#401
everettbu wants to merge 4 commits into
mainfrom
pr35596

Conversation

@everettbu

@everettbu everettbu commented Jan 22, 2026

Copy link
Copy Markdown

Mirror of facebook/react#35596
Original author: josephsavona


Fixes a longstanding issue where we didn't support code like useFoo(value?.bar(), value?.bar()) ?? {} - we would attempt to construct a ReactiveFunction, recursively processing the blocks, but the inner optional value?.bar() wouldn't match with what the outer optional was expecting to find. It's a one-line fix!

Note: memoization in the examples is not ideal, but i've confirmed that it is not strictly related to the optional issue.


Stack created with Sapling. Best reviewed with ReviewStack.

  • #35607
  • #35298
  • -> #35596
  • #35573
  • #35595
  • #35539

@everettbu everettbu added CLA Signed React Core Team Opened by a member of the React Core Team labels Jan 22, 2026
@greptile-apps

greptile-apps Bot commented Jan 22, 2026

Copy link
Copy Markdown

Greptile Summary

Fixed a longstanding bug in the React compiler where nested optional chaining within other value blocks (like ternaries, logical expressions, or nullish coalescing) would fail to compile. The issue occurred when constructing ReactiveFunction representations - the code was incorrectly using init.fallthrough instead of final.block when stitching together nested value terminals.

Key changes:

  • One-line fix in BuildReactiveFunction.ts:1107 changes return block from init.fallthrough to final.block
  • Renamed 4 error.todo test files to working tests (removed error prefix)
  • Added 19 new comprehensive test fixtures covering various combinations of optional chaining with ternaries, logical operators, and nullish coalescing
  • Added extensive documentation for all 55 compiler passes in the docs/passes/ directory

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The fix is a precise one-line change that correctly resolves a block reference bug in the compiler. The PR includes comprehensive test coverage with 19 new test fixtures and converts 4 previously failing tests to passing. All tests validate various edge cases of nested optional chaining. The change is well-understood and directly addresses the root cause described in the PR description.
  • No files require special attention

Important Files Changed

Filename Overview
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/BuildReactiveFunction.ts One-line fix changes init.fallthrough to final.block to correctly handle nested optional chaining in value blocks
compiler/packages/babel-plugin-react-compiler/src/tests/fixtures/compiler/optional-call-chain-in-logical-expr.ts Renamed from error.todo file, now passes with the fix - tests useNoAlias(value?.x, value?.y) ?? {}
compiler/packages/babel-plugin-react-compiler/src/tests/fixtures/compiler/chained-optionals-with-nullish-coalesce.ts New test for chained optional property access with nullish coalescing: props.obj?.a?.b?.c ?? 'default'

@everettbu everettbu changed the title [commit] Fix for nested optional chainining within other value blocks [commit] Fix for nested optional chaining within other value blocks Jan 22, 2026
Much nicer workflow for working through errors in the compiler:
* Run `yarn snap -w`, oops there are are errors
* Hit 'p' to select a fixture => the suggestions populate with recent failures, sorted alphabetically. No need to copy/paste the name of the fixture you want to focus on!
* tab/shift-tab to pick one, hit enter to select that one
* ...Focus on fixing that test...
* 'p' to re-enter the picker. Snap tracks the last state of each fixture and continues to show all tests that failed on their last run, so you can easily move on to the next one. The currently selected test is highlighted, making it easy to move to the next one.
* 'a' at any time to run all tests
* 'd' at any time to toggle debug output on/off (while focusing on a single test)
…opment

Autogenerated summaries of each of the compiler passes which allow agents to get the key ideas of a compiler pass, including key input/output invariants, without having to reprocess the file each time. In the subsequent diff this seemed to help.
Optional chaining and other value blocks within try/catch blocks were throwing an Invariant error ("Unexpected terminal in optional") instead of the expected Todo error. This caused hard failures instead of graceful bailouts.

The issue occurred because DropManualMemoization and ValidateExhaustiveDependencies ran before BuildReactiveFunction, and encountered `maybe-throw` terminals in their switch statements without a handler, falling through to the invariant case.

Fixed by adding explicit `maybe-throw` cases in both files that throw the proper Todo error with the message "Support value blocks (conditional, logical, optional chaining, etc) within a try/catch statement".

Also renamed the existing bug test to reflect it's now correctly handled:
- error.bug-invariant-unexpected-terminal-in-optional → error.todo-optional-chaining-within-try-catch

Closes #35570
Fixes a longstanding issue where we didn't support code like `useFoo(value?.bar(), value?.bar()) ?? {}` - we would attempt to construct a ReactiveFunction, recursively processing the blocks, but the inner optional `value?.bar()` wouldn't match with what the outer optional was expecting to find. It's a one-line fix!

Note: memoization in the examples is not ideal, but i've confirmed that it is not strictly related to the optional issue.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed React Core Team Opened by a member of the React Core Team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants