dillon1000/react
Commit
Browse files [compiler][bugfix] expand StoreContext to const / let / function variants (#32747)
```js
function Component() {
useEffect(() => {
let hasCleanedUp = false;
document.addEventListener(..., () => hasCleanedUp ? foo() : bar());
// effect return values shouldn't be typed as frozen
return () => {
hasCleanedUp = true;
}
};
}
```
### Problem
`PruneHoistedContexts` currently strips hoisted declarations and
rewrites the first `StoreContext` reassignment to a declaration. For
example, in the following example, instruction 0 is removed while a
synthetic `DeclareContext let` is inserted before instruction 1.
```js
// source
const cb = () => x; // reference that causes x to be hoisted
let x = 4;
x = 5;
// React Compiler IR
[0] DeclareContext HoistedLet 'x'
...
[1] StoreContext reassign 'x' = 4
[2] StoreContext reassign 'x' = 5
```
Currently, we don't account for `DeclareContext let`. As a result, we're
rewriting to insert duplicate declarations.
```js
// source
const cb = () => x; // reference that causes x to be hoisted
let x;
x = 5;
// React Compiler IR
[0] DeclareContext HoistedLet 'x'
...
[1] DeclareContext Let 'x'
[2] StoreContext reassign 'x' = 5
```
### Solution
Instead of always lowering context variables to a DeclareContext
followed by a StoreContext reassign, we can keep `kind: 'Const' | 'Let'
| 'Reassign' | etc` on StoreContext.
Pros:
- retain more information in HIR, so we can codegen easily `const` and
`let` context variable declarations back
- pruning hoisted `DeclareContext` instructions is simple.
Cons:
- passes are more verbose as we need to check for both `DeclareContext`
and `StoreContext` declarations
~(note: also see alternative implementation in
https://github.com/facebook/react/pull/32745)~
### Testing
Context variables are tricky. I synced and diffed changes in a large
meta codebase and feel pretty confident about landing this. About 0.01%
of compiled files changed. Among these changes, ~25% were [direct
bugfixes](https://www.internalfb.com/phabricator/paste/view/P1800029094).
The [other
changes](https://www.internalfb.com/phabricator/paste/view/P1800028575)
were primarily due to changed (corrected) mutable ranges from
https://github.com/facebook/react/pull/33047. I tried to represent most
interesting changes in new test fixtures
`Changed paths36 files
First-parent comparisoncompiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts ModifiedM compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts ModifiedM compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts ModifiedM compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableLifetimes.ts ModifiedM compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts ModifiedM compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts ModifiedM compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneHoistedContexts.ts ModifiedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-3-iife.expect.md ModifiedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-3.expect.md ModifiedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-inline-iife-reassign.expect.md ModifiedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/context-variable-reassigned-outside-of-lambda.expect.md ModifiedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-loop-with-context-variable-iterator.expect.md ModifiedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-loop-with-context-variable-iterator.js ModifiedA compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisted-context-variable-in-outlined-fn.expect.md AddedA compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisted-context-variable-in-outlined-fn.js AddedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-invalid-tdz-let.expect.md ModifiedA compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-let-declaration-without-initialization.expect.md AddedA compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-let-declaration-without-initialization.js AddedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-nested-let-declaration-2.expect.md ModifiedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-nested-let-declaration.expect.md ModifiedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-reassigned-let-declaration.expect.md ModifiedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-reassigned-twice-let-declaration.expect.md ModifiedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-simple-let-declaration.expect.md ModifiedA compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-captures-context-variable.expect.md AddedA compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-captures-context-variable.js AddedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-reassign-shadowed-primitive.expect.md ModifiedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutate-captured-arg-separately.expect.md ModifiedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-extended-contextvar-scope.expect.md ModifiedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-reordering-deplist-controlflow.expect.md ModifiedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-reordering-depslist-controlflow.expect.md ModifiedA compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-context-var-reassign-no-scope.expect.md AddedA compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-context-var-reassign-no-scope.js AddedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-returned-inner-fn-reassigns-context.expect.md ModifiedA compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-effect-cleanup-reassigns.expect.md AddedA compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-effect-cleanup-reassigns.js AddedM compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-conditional.expect.md ModifiedPatch
Files changed
Rendering syntax-highlighted changes…