[compiler] Fix TypeError from hoisting nullable closure property deps#604
[compiler] Fix TypeError from hoisting nullable closure property deps#604everettbu wants to merge 1 commit into
Conversation
Greptile SummaryFixes a TypeError that occurs when the React Compiler incorrectly hoists property access from inner closures (e.g. event handlers, hook callbacks, JSX attribute callbacks) as cache keys in the outer render scope. The bug manifests when a closure accesses The fix adds a single guard in
Confidence Score: 5/5
Important Files Changed
Last reviewed commit: 7763e66 |
|
Upstream PR was closed or merged. Code is synced via branch mirror. |
Mirror of facebook/react#35887
Original author: fresh3nough
Summary
Fixes #35762
The compiler's hoistable property load analysis promotes non-null proofs from inner functions (JSX attribute callbacks, hook callbacks, direct calls, returned functions) to the outer render scope. However, these proofs are only valid at invocation time, not at the point where cache keys are evaluated during render.
When a closure accesses
obj.valueinside an event handler, the inner function provesobjis non-null. The compiler incorrectly promotes this proof to the outer scope, allowingobj.valueto be hoisted as a cache dependency ($[0] !== obj.value). Ifobjis null/undefined at render time, this throws a TypeError before the null guard can run.Fix
In
collectNonNullsInBlocks(CollectHoistablePropertyLoads.ts), when promoting hoistable entries from assumed-invoked inner functions to the outer scope, only promote entries whose root identifier is already proven non-null in the outer scope. This prevents unsafe property access hoisting while preserving the optimization for cases where the root is known to be non-null (e.g., component props object, variables proven non-null by prior instructions).The effect is that dependencies are truncated to the root identifier (e.g.,
$[0] !== userinstead of$[0] !== user.name), which is always safe for reference comparison and still correct for memoization.How did you test this change?
nullable-closure-property-depthat reproduces the issue from #35762Steps to reproduce the original bug
Before fix: Compiler generates
$[0] !== user.nameas cache key, which throws whenuseris null.After fix: Compiler generates
$[0] !== useras cache key, which safely compares references.