From cebe9dc9e24c88244a1c873ffb7bb42de081fd99 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 18 Jun 2025 13:00:40 -0700 Subject: [PATCH 1/5] [compiler] Update fixtures for new inference --- ...iased-nested-scope-truncated-dep.expect.md | 16 ++-- .../aliased-nested-scope-truncated-dep.tsx | 1 + ...map-named-callback-cross-context.expect.md | 84 ++++++++++--------- .../array-map-named-callback-cross-context.js | 1 + ...ction-alias-computed-load-2-iife.expect.md | 23 +++-- ...ing-function-alias-computed-load-2-iife.js | 1 + ...ction-alias-computed-load-3-iife.expect.md | 26 ++++-- ...ing-function-alias-computed-load-3-iife.js | 1 + ...ction-alias-computed-load-4-iife.expect.md | 23 +++-- ...ing-function-alias-computed-load-4-iife.js | 1 + ...unction-alias-computed-load-iife.expect.md | 23 +++-- ...uring-function-alias-computed-load-iife.js | 1 + ...valid-impure-functions-in-render.expect.md | 4 +- ...rror.invalid-impure-functions-in-render.js | 2 +- ...n-local-variable-in-jsx-callback.expect.md | 15 ++-- ...reassign-local-variable-in-jsx-callback.js | 1 + .../error.mutate-hook-argument.expect.md | 16 ++-- .../error.mutate-hook-argument.js | 1 + ...or.not-useEffect-external-mutate.expect.md | 17 ++-- .../error.not-useEffect-external-mutate.js | 1 + ....reassignment-to-global-indirect.expect.md | 17 ++-- .../error.reassignment-to-global-indirect.js | 1 + .../error.reassignment-to-global.expect.md | 17 ++-- .../error.reassignment-to-global.js | 1 + ...on-with-shadowed-local-same-name.expect.md | 13 +-- ...-function-with-shadowed-local-same-name.js | 1 + ...e-after-useeffect-optional-chain.expect.md | 10 +-- .../mutate-after-useeffect-optional-chain.js | 2 +- ...utate-after-useeffect-ref-access.expect.md | 10 +-- .../mutate-after-useeffect-ref-access.js | 2 +- .../mutate-after-useeffect.expect.md | 10 +-- .../new-mutability/mutate-after-useeffect.js | 2 +- ...omputed-key-object-mutated-later.expect.md | 39 +++------ ...ssion-computed-key-object-mutated-later.js | 1 + ...bject-expression-computed-member.expect.md | 18 +++- .../object-expression-computed-member.js | 1 + .../reactive-setState.expect.md | 26 +++--- .../new-mutability/reactive-setState.js | 2 +- .../new-mutability/retry-no-emit.expect.md | 12 +-- .../compiler/new-mutability/retry-no-emit.js | 2 +- .../shared-hook-calls.expect.md | 81 ++++++++++-------- .../new-mutability/shared-hook-calls.js | 2 +- ...k-reordering-deplist-controlflow.expect.md | 54 +++++++----- ...allback-reordering-deplist-controlflow.tsx | 1 + ...k-reordering-depslist-assignment.expect.md | 42 ++++++---- ...allback-reordering-depslist-assignment.tsx | 1 + ...o-reordering-depslist-assignment.expect.md | 42 ++++++---- .../useMemo-reordering-depslist-assignment.ts | 1 + 48 files changed, 389 insertions(+), 280 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/aliased-nested-scope-truncated-dep.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/aliased-nested-scope-truncated-dep.expect.md index 933fafff5f1ba..8024676c65a32 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/aliased-nested-scope-truncated-dep.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/aliased-nested-scope-truncated-dep.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enableNewMutationAliasingModel import { Stringify, mutate, @@ -101,7 +102,7 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel import { Stringify, mutate, @@ -175,21 +176,14 @@ import { * and mutability. */ function Component(t0) { - const $ = _c(4); + const $ = _c(2); const { prop } = t0; let t1; if ($[0] !== prop) { const obj = shallowCopy(prop); const aliasedObj = identity(obj); - let t2; - if ($[2] !== obj) { - t2 = [obj.id]; - $[2] = obj; - $[3] = t2; - } else { - t2 = $[3]; - } - const id = t2; + + const id = [obj.id]; mutate(aliasedObj); setPropertyByKey(aliasedObj, "id", prop.id + 1); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/aliased-nested-scope-truncated-dep.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/aliased-nested-scope-truncated-dep.tsx index 4d9d7e78fb309..ecd5598cb0913 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/aliased-nested-scope-truncated-dep.tsx +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/aliased-nested-scope-truncated-dep.tsx @@ -1,3 +1,4 @@ +// @enableNewMutationAliasingModel import { Stringify, mutate, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/array-map-named-callback-cross-context.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/array-map-named-callback-cross-context.expect.md index c1a6dfb3eae11..a36b862052ab2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/array-map-named-callback-cross-context.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/array-map-named-callback-cross-context.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enableNewMutationAliasingModel import {Stringify} from 'shared-runtime'; /** @@ -43,7 +44,7 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel import { Stringify } from "shared-runtime"; /** @@ -57,62 +58,67 @@ import { Stringify } from "shared-runtime"; * - cb1 is not assumed to be called since it's only used as a call operand */ function useFoo(t0) { - const $ = _c(13); - const { arr1, arr2 } = t0; + const $ = _c(14); + let arr1; + let arr2; let t1; - if ($[0] !== arr1[0]) { - t1 = (e) => arr1[0].value + e.value; - $[0] = arr1[0]; - $[1] = t1; + if ($[0] !== t0) { + ({ arr1, arr2 } = t0); + let t2; + if ($[4] !== arr1[0]) { + t2 = (e) => arr1[0].value + e.value; + $[4] = arr1[0]; + $[5] = t2; + } else { + t2 = $[5]; + } + const cb1 = t2; + t1 = () => arr1.map(cb1); + $[0] = t0; + $[1] = arr1; + $[2] = arr2; + $[3] = t1; } else { - t1 = $[1]; + arr1 = $[1]; + arr2 = $[2]; + t1 = $[3]; } - const cb1 = t1; + const getArrMap1 = t1; let t2; - if ($[2] !== arr1 || $[3] !== cb1) { - t2 = () => arr1.map(cb1); - $[2] = arr1; - $[3] = cb1; - $[4] = t2; + if ($[6] !== arr2) { + t2 = (e_0) => arr2[0].value + e_0.value; + $[6] = arr2; + $[7] = t2; } else { - t2 = $[4]; + t2 = $[7]; } - const getArrMap1 = t2; + const cb2 = t2; let t3; - if ($[5] !== arr2) { - t3 = (e_0) => arr2[0].value + e_0.value; - $[5] = arr2; - $[6] = t3; + if ($[8] !== arr1 || $[9] !== cb2) { + t3 = () => arr1.map(cb2); + $[8] = arr1; + $[9] = cb2; + $[10] = t3; } else { - t3 = $[6]; + t3 = $[10]; } - const cb2 = t3; + const getArrMap2 = t3; let t4; - if ($[7] !== arr1 || $[8] !== cb2) { - t4 = () => arr1.map(cb2); - $[7] = arr1; - $[8] = cb2; - $[9] = t4; - } else { - t4 = $[9]; - } - const getArrMap2 = t4; - let t5; - if ($[10] !== getArrMap1 || $[11] !== getArrMap2) { - t5 = ( + if ($[11] !== getArrMap1 || $[12] !== getArrMap2) { + t4 = ( ); - $[10] = getArrMap1; - $[11] = getArrMap2; - $[12] = t5; + $[11] = getArrMap1; + $[12] = getArrMap2; + $[13] = t4; } else { - t5 = $[12]; + t4 = $[13]; } - return t5; + return t4; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/array-map-named-callback-cross-context.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/array-map-named-callback-cross-context.js index e9056562262e8..faa34747da188 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/array-map-named-callback-cross-context.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/array-map-named-callback-cross-context.js @@ -1,3 +1,4 @@ +// @enableNewMutationAliasingModel import {Stringify} from 'shared-runtime'; /** diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-2-iife.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-2-iife.expect.md index 2afc5fd25dbac..d1434e95b827a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-2-iife.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-2-iife.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enableNewMutationAliasingModel function bar(a) { let x = [a]; let y = {}; @@ -23,19 +24,27 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel function bar(a) { - const $ = _c(2); - let y; + const $ = _c(4); + let t0; if ($[0] !== a) { - const x = [a]; + t0 = [a]; + $[0] = a; + $[1] = t0; + } else { + t0 = $[1]; + } + const x = t0; + let y; + if ($[2] !== x[0][1]) { y = {}; y = x[0][1]; - $[0] = a; - $[1] = y; + $[2] = x[0][1]; + $[3] = y; } else { - y = $[1]; + y = $[3]; } return y; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-2-iife.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-2-iife.js index 4c224e28415b1..a77287910a419 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-2-iife.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-2-iife.js @@ -1,3 +1,4 @@ +// @enableNewMutationAliasingModel function bar(a) { let x = [a]; let y = {}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-3-iife.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-3-iife.expect.md index f0267c3309f5b..80bb009ba25d3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-3-iife.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-3-iife.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enableNewMutationAliasingModel function bar(a, b) { let x = [a, b]; let y = {}; @@ -27,22 +28,31 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel function bar(a, b) { - const $ = _c(3); - let y; + const $ = _c(6); + let t0; if ($[0] !== a || $[1] !== b) { - const x = [a, b]; + t0 = [a, b]; + $[0] = a; + $[1] = b; + $[2] = t0; + } else { + t0 = $[2]; + } + const x = t0; + let y; + if ($[3] !== x[0][1] || $[4] !== x[1][0]) { y = {}; let t = {}; y = x[0][1]; t = x[1][0]; - $[0] = a; - $[1] = b; - $[2] = y; + $[3] = x[0][1]; + $[4] = x[1][0]; + $[5] = y; } else { - y = $[2]; + y = $[5]; } return y; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-3-iife.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-3-iife.js index 1afc28a9922ec..9afe5994b210b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-3-iife.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-3-iife.js @@ -1,3 +1,4 @@ +// @enableNewMutationAliasingModel function bar(a, b) { let x = [a, b]; let y = {}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-4-iife.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-4-iife.expect.md index 22728aaf4323d..663d1f3d567b3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-4-iife.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-4-iife.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enableNewMutationAliasingModel function bar(a) { let x = [a]; let y = {}; @@ -23,19 +24,27 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel function bar(a) { - const $ = _c(2); - let y; + const $ = _c(4); + let t0; if ($[0] !== a) { - const x = [a]; + t0 = [a]; + $[0] = a; + $[1] = t0; + } else { + t0 = $[1]; + } + const x = t0; + let y; + if ($[2] !== x[0].a[1]) { y = {}; y = x[0].a[1]; - $[0] = a; - $[1] = y; + $[2] = x[0].a[1]; + $[3] = y; } else { - y = $[1]; + y = $[3]; } return y; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-4-iife.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-4-iife.js index ca479a7458926..5a3cb878485d4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-4-iife.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-4-iife.js @@ -1,3 +1,4 @@ +// @enableNewMutationAliasingModel function bar(a) { let x = [a]; let y = {}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-iife.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-iife.expect.md index 60f829cdc4d66..58694faf57d33 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-iife.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-iife.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enableNewMutationAliasingModel function bar(a) { let x = [a]; let y = {}; @@ -22,19 +23,27 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel function bar(a) { - const $ = _c(2); - let y; + const $ = _c(4); + let t0; if ($[0] !== a) { - const x = [a]; + t0 = [a]; + $[0] = a; + $[1] = t0; + } else { + t0 = $[1]; + } + const x = t0; + let y; + if ($[2] !== x[0]) { y = {}; y = x[0]; - $[0] = a; - $[1] = y; + $[2] = x[0]; + $[3] = y; } else { - y = $[1]; + y = $[3]; } return y; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-iife.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-iife.js index 9a0c7c19aa700..0b95fc02a2b58 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-iife.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capturing-function-alias-computed-load-iife.js @@ -1,3 +1,4 @@ +// @enableNewMutationAliasingModel function bar(a) { let x = [a]; let y = {}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-impure-functions-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-impure-functions-in-render.expect.md index a67d467df8cfd..73dd12670f159 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-impure-functions-in-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-impure-functions-in-render.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoImpureFunctionsInRender +// @validateNoImpureFunctionsInRender @enableNewMutationAliasingModel function Component() { const date = Date.now(); @@ -20,7 +20,7 @@ function Component() { 2 | 3 | function Component() { > 4 | const date = Date.now(); - | ^^^^^^^^ InvalidReact: Calling an impure function can produce unstable results. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). `Date.now` is an impure function whose results may change on every call (4:4) + | ^^^^^^^^^^ InvalidReact: Calling an impure function can produce unstable results. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). `Date.now` is an impure function whose results may change on every call (4:4) InvalidReact: Calling an impure function can produce unstable results. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). `performance.now` is an impure function whose results may change on every call (5:5) diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-impure-functions-in-render.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-impure-functions-in-render.js index 6faf98caff702..83cf3e04f2b6a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-impure-functions-in-render.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-impure-functions-in-render.js @@ -1,4 +1,4 @@ -// @validateNoImpureFunctionsInRender +// @validateNoImpureFunctionsInRender @enableNewMutationAliasingModel function Component() { const date = Date.now(); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-reassign-local-variable-in-jsx-callback.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-reassign-local-variable-in-jsx-callback.expect.md index fe684586cbd33..0461bb4b7b4a4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-reassign-local-variable-in-jsx-callback.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-reassign-local-variable-in-jsx-callback.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enableNewMutationAliasingModel function Component() { let local; @@ -41,13 +42,13 @@ function Component() { ## Error ``` - 3 | - 4 | const reassignLocal = newValue => { -> 5 | local = newValue; - | ^^^^^ InvalidReact: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead. Variable `local` cannot be reassigned after render (5:5) - 6 | }; - 7 | - 8 | const onClick = newValue => { + 4 | + 5 | const reassignLocal = newValue => { +> 6 | local = newValue; + | ^^^^^ InvalidReact: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead. Variable `local` cannot be reassigned after render (6:6) + 7 | }; + 8 | + 9 | const onClick = newValue => { ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-reassign-local-variable-in-jsx-callback.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-reassign-local-variable-in-jsx-callback.js index 121495ac1e05c..2cfb336bcf5e3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-reassign-local-variable-in-jsx-callback.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-reassign-local-variable-in-jsx-callback.js @@ -1,3 +1,4 @@ +// @enableNewMutationAliasingModel function Component() { let local; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.mutate-hook-argument.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.mutate-hook-argument.expect.md index 665fc7053b788..a26381d1d301c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.mutate-hook-argument.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.mutate-hook-argument.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enableNewMutationAliasingModel function useHook(a, b) { b.test = 1; a.test = 2; @@ -13,12 +14,15 @@ function useHook(a, b) { ## Error ``` - 1 | function useHook(a, b) { -> 2 | b.test = 1; - | ^ InvalidReact: Mutating component props or hook arguments is not allowed. Consider using a local variable instead (2:2) - 3 | a.test = 2; - 4 | } - 5 | + 1 | // @enableNewMutationAliasingModel + 2 | function useHook(a, b) { +> 3 | b.test = 1; + | ^ InvalidReact: Mutating component props or hook arguments is not allowed. Consider using a local variable instead (3:3) + +InvalidReact: Mutating component props or hook arguments is not allowed. Consider using a local variable instead (4:4) + 4 | a.test = 2; + 5 | } + 6 | ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.mutate-hook-argument.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.mutate-hook-argument.js index 321e9049cddbd..41c5b99132460 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.mutate-hook-argument.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.mutate-hook-argument.js @@ -1,3 +1,4 @@ +// @enableNewMutationAliasingModel function useHook(a, b) { b.test = 1; a.test = 2; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.not-useEffect-external-mutate.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.not-useEffect-external-mutate.expect.md index 7d829fe9b013f..6f7d6b24831a8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.not-useEffect-external-mutate.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.not-useEffect-external-mutate.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enableNewMutationAliasingModel let x = {a: 42}; function Component(props) { @@ -17,13 +18,15 @@ function Component(props) { ## Error ``` - 3 | function Component(props) { - 4 | foo(() => { -> 5 | x.a = 10; - | ^ InvalidReact: Writing to a variable defined outside a component or hook is not allowed. Consider using an effect (5:5) - 6 | x.a = 20; - 7 | }); - 8 | } + 4 | function Component(props) { + 5 | foo(() => { +> 6 | x.a = 10; + | ^ InvalidReact: Writing to a variable defined outside a component or hook is not allowed. Consider using an effect (6:6) + +InvalidReact: Writing to a variable defined outside a component or hook is not allowed. Consider using an effect (7:7) + 7 | x.a = 20; + 8 | }); + 9 | } ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.not-useEffect-external-mutate.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.not-useEffect-external-mutate.js index 3b44c4c247760..ed51080726b5a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.not-useEffect-external-mutate.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.not-useEffect-external-mutate.js @@ -1,3 +1,4 @@ +// @enableNewMutationAliasingModel let x = {a: 42}; function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global-indirect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global-indirect.expect.md index e4073947f7e15..b6f01488fc755 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global-indirect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global-indirect.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enableNewMutationAliasingModel function Component() { const foo = () => { // Cannot assign to globals @@ -17,13 +18,15 @@ function Component() { ## Error ``` - 2 | const foo = () => { - 3 | // Cannot assign to globals -> 4 | someUnknownGlobal = true; - | ^^^^^^^^^^^^^^^^^ InvalidReact: Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) (4:4) - 5 | moduleLocal = true; - 6 | }; - 7 | foo(); + 3 | const foo = () => { + 4 | // Cannot assign to globals +> 5 | someUnknownGlobal = true; + | ^^^^^^^^^^^^^^^^^ InvalidReact: Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) (5:5) + +InvalidReact: Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) (6:6) + 6 | moduleLocal = true; + 7 | }; + 8 | foo(); ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global-indirect.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global-indirect.js index 708fe643d57df..6d6681e60ad34 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global-indirect.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global-indirect.js @@ -1,3 +1,4 @@ +// @enableNewMutationAliasingModel function Component() { const foo = () => { // Cannot assign to globals diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global.expect.md index 4619cd27cb24d..a75aa397eceec 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enableNewMutationAliasingModel function Component() { // Cannot assign to globals someUnknownGlobal = true; @@ -14,13 +15,15 @@ function Component() { ## Error ``` - 1 | function Component() { - 2 | // Cannot assign to globals -> 3 | someUnknownGlobal = true; - | ^^^^^^^^^^^^^^^^^ InvalidReact: Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) (3:3) - 4 | moduleLocal = true; - 5 | } - 6 | + 2 | function Component() { + 3 | // Cannot assign to globals +> 4 | someUnknownGlobal = true; + | ^^^^^^^^^^^^^^^^^ InvalidReact: Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) (4:4) + +InvalidReact: Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) (5:5) + 5 | moduleLocal = true; + 6 | } + 7 | ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global.js index d0509a3d52a16..41b706866bf7c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global.js @@ -1,3 +1,4 @@ +// @enableNewMutationAliasingModel function Component() { // Cannot assign to globals someUnknownGlobal = true; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md index 2a935256d7a0d..3d9d0b5613857 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enableNewMutationAliasingModel function Component(props) { function hasErrors() { let hasErrors = false; @@ -19,12 +20,12 @@ function Component(props) { ## Error ``` - 7 | return hasErrors; - 8 | } -> 9 | return hasErrors(); - | ^^^^^^^^^ Invariant: [hoisting] Expected value for identifier to be initialized. hasErrors_0$15 (9:9) - 10 | } - 11 | + 8 | return hasErrors; + 9 | } +> 10 | return hasErrors(); + | ^^^^^^^^^ Invariant: [InferMutationAliasingEffects] Expected value kind to be initialized. hasErrors_0$15:TFunction (10:10) + 11 | } + 12 | ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.todo-repro-named-function-with-shadowed-local-same-name.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.todo-repro-named-function-with-shadowed-local-same-name.js index b7a450ccba028..b58c0aea7daf7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.todo-repro-named-function-with-shadowed-local-same-name.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.todo-repro-named-function-with-shadowed-local-same-name.js @@ -1,3 +1,4 @@ +// @enableNewMutationAliasingModel function Component(props) { function hasErrors() { let hasErrors = false; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.expect.md index e4560848dd5f2..8dec2e3ebe94b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly +// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel import {useEffect} from 'react'; import {print} from 'shared-runtime'; @@ -25,7 +25,7 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly +// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel import { useEffect } from "react"; import { print } from "shared-runtime"; @@ -48,9 +48,9 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":139},"end":{"line":12,"column":1,"index":384},"filename":"mutate-after-useeffect-optional-chain.ts"},"detail":{"reason":"This mutates a variable that React considers immutable","description":null,"loc":{"start":{"line":10,"column":2,"index":345},"end":{"line":10,"column":5,"index":348},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"},"suggestions":null,"severity":"InvalidReact"}} -{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":9,"column":2,"index":304},"end":{"line":9,"column":39,"index":341},"filename":"mutate-after-useeffect-optional-chain.ts"},"decorations":[{"start":{"line":9,"column":24,"index":326},"end":{"line":9,"column":27,"index":329},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"}]} -{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":139},"end":{"line":12,"column":1,"index":384},"filename":"mutate-after-useeffect-optional-chain.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0} +{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":171},"end":{"line":12,"column":1,"index":416},"filename":"mutate-after-useeffect-optional-chain.ts"},"detail":{"reason":"Updating a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the mutation before calling useEffect()","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":10,"column":2,"index":377},"end":{"line":10,"column":5,"index":380},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"}}} +{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":9,"column":2,"index":336},"end":{"line":9,"column":39,"index":373},"filename":"mutate-after-useeffect-optional-chain.ts"},"decorations":[{"start":{"line":9,"column":24,"index":358},"end":{"line":9,"column":27,"index":361},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"}]} +{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":171},"end":{"line":12,"column":1,"index":416},"filename":"mutate-after-useeffect-optional-chain.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.js index c435b72d1a9ef..dd8d6669885d2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.js @@ -1,4 +1,4 @@ -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly +// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel import {useEffect} from 'react'; import {print} from 'shared-runtime'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.expect.md index 5e6f19dd83e65..167c23c3476b5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly +// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel import {useEffect, useRef} from 'react'; import {print} from 'shared-runtime'; @@ -24,7 +24,7 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly +// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel import { useEffect, useRef } from "react"; import { print } from "shared-runtime"; @@ -47,9 +47,9 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":148},"end":{"line":11,"column":1,"index":311},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"reason":"Mutating component props or hook arguments is not allowed. Consider using a local variable instead","description":null,"loc":{"start":{"line":9,"column":2,"index":269},"end":{"line":9,"column":16,"index":283},"filename":"mutate-after-useeffect-ref-access.ts"},"suggestions":null,"severity":"InvalidReact"}} -{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":227},"end":{"line":8,"column":40,"index":265},"filename":"mutate-after-useeffect-ref-access.ts"},"decorations":[{"start":{"line":8,"column":24,"index":249},"end":{"line":8,"column":30,"index":255},"filename":"mutate-after-useeffect-ref-access.ts","identifierName":"arrRef"}]} -{"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":148},"end":{"line":11,"column":1,"index":311},"filename":"mutate-after-useeffect-ref-access.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0} +{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":180},"end":{"line":11,"column":1,"index":343},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"reason":"Mutating component props or hook arguments is not allowed. Consider using a local variable instead","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":9,"column":2,"index":301},"end":{"line":9,"column":16,"index":315},"filename":"mutate-after-useeffect-ref-access.ts"}}} +{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":259},"end":{"line":8,"column":40,"index":297},"filename":"mutate-after-useeffect-ref-access.ts"},"decorations":[{"start":{"line":8,"column":24,"index":281},"end":{"line":8,"column":30,"index":287},"filename":"mutate-after-useeffect-ref-access.ts","identifierName":"arrRef"}]} +{"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":180},"end":{"line":11,"column":1,"index":343},"filename":"mutate-after-useeffect-ref-access.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.js index bd3f6d1de54bd..f91bd14deb14c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.js @@ -1,4 +1,4 @@ -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly +// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel import {useEffect, useRef} from 'react'; import {print} from 'shared-runtime'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.expect.md index 3b61fbf834246..47a0124baa856 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly +// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel import {useEffect} from 'react'; function Component({foo}) { @@ -24,7 +24,7 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly +// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel import { useEffect } from "react"; function Component(t0) { @@ -47,9 +47,9 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":101},"end":{"line":11,"column":1,"index":222},"filename":"mutate-after-useeffect.ts"},"detail":{"reason":"This mutates a variable that React considers immutable","description":null,"loc":{"start":{"line":9,"column":2,"index":194},"end":{"line":9,"column":5,"index":197},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},"suggestions":null,"severity":"InvalidReact"}} -{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":6,"column":2,"index":149},"end":{"line":8,"column":4,"index":190},"filename":"mutate-after-useeffect.ts"},"decorations":[{"start":{"line":7,"column":4,"index":171},"end":{"line":7,"column":7,"index":174},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":4,"index":171},"end":{"line":7,"column":7,"index":174},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":13,"index":180},"end":{"line":7,"column":16,"index":183},"filename":"mutate-after-useeffect.ts","identifierName":"foo"}]} -{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":101},"end":{"line":11,"column":1,"index":222},"filename":"mutate-after-useeffect.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0} +{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":133},"end":{"line":11,"column":1,"index":254},"filename":"mutate-after-useeffect.ts"},"detail":{"reason":"Updating a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the mutation before calling useEffect()","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":9,"column":2,"index":226},"end":{"line":9,"column":5,"index":229},"filename":"mutate-after-useeffect.ts","identifierName":"arr"}}} +{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":6,"column":2,"index":181},"end":{"line":8,"column":4,"index":222},"filename":"mutate-after-useeffect.ts"},"decorations":[{"start":{"line":7,"column":4,"index":203},"end":{"line":7,"column":7,"index":206},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":4,"index":203},"end":{"line":7,"column":7,"index":206},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":13,"index":212},"end":{"line":7,"column":16,"index":215},"filename":"mutate-after-useeffect.ts","identifierName":"foo"}]} +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":133},"end":{"line":11,"column":1,"index":254},"filename":"mutate-after-useeffect.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.js index fbcbf004a308c..6f237c89b4d4f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.js @@ -1,4 +1,4 @@ -// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly +// @inferEffectDependencies @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel import {useEffect} from 'react'; function Component({foo}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-key-object-mutated-later.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-key-object-mutated-later.expect.md index bf0f9da6b1da1..5c73ce6d77adf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-key-object-mutated-later.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-key-object-mutated-later.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enableNewMutationAliasingModel import {identity, mutate} from 'shared-runtime'; function Component(props) { @@ -23,38 +24,22 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel import { identity, mutate } from "shared-runtime"; function Component(props) { - const $ = _c(5); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = {}; - $[0] = t0; + const $ = _c(2); + let context; + if ($[0] !== props.value) { + const key = {}; + context = { [key]: identity([props.value]) }; + + mutate(key); + $[0] = props.value; + $[1] = context; } else { - t0 = $[0]; + context = $[1]; } - const key = t0; - let t1; - if ($[1] !== props.value) { - t1 = identity([props.value]); - $[1] = props.value; - $[2] = t1; - } else { - t1 = $[2]; - } - let t2; - if ($[3] !== t1) { - t2 = { [key]: t1 }; - $[3] = t1; - $[4] = t2; - } else { - t2 = $[4]; - } - const context = t2; - - mutate(key); return context; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-key-object-mutated-later.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-key-object-mutated-later.js index 1edaaaef27e4b..923733b9c238d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-key-object-mutated-later.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-key-object-mutated-later.js @@ -1,3 +1,4 @@ +// @enableNewMutationAliasingModel import {identity, mutate} from 'shared-runtime'; function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-member.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-member.expect.md index 810b03e529e77..1ef3ed157f9fa 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-member.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-member.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enableNewMutationAliasingModel import {identity, mutate, mutateAndReturn} from 'shared-runtime'; function Component(props) { @@ -23,15 +24,26 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel import { identity, mutate, mutateAndReturn } from "shared-runtime"; function Component(props) { - const $ = _c(2); + const $ = _c(4); let context; if ($[0] !== props.value) { const key = { a: "key" }; - context = { [key.a]: identity([props.value]) }; + + const t0 = key.a; + const t1 = identity([props.value]); + let t2; + if ($[2] !== t1) { + t2 = { [t0]: t1 }; + $[2] = t1; + $[3] = t2; + } else { + t2 = $[3]; + } + context = t2; mutate(key); $[0] = props.value; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-member.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-member.js index 95a1d434624e9..516fdc1dbcf41 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-member.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-member.js @@ -1,3 +1,4 @@ +// @enableNewMutationAliasingModel import {identity, mutate, mutateAndReturn} from 'shared-runtime'; function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/reactive-setState.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/reactive-setState.expect.md index 3af2b9b8b1c89..de7fc2903ebd2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/reactive-setState.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/reactive-setState.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @inferEffectDependencies +// @inferEffectDependencies @enableNewMutationAliasingModel import {useEffect, useState} from 'react'; import {print} from 'shared-runtime'; @@ -26,7 +26,7 @@ function ReactiveRefInEffect(props) { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies +import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies @enableNewMutationAliasingModel import { useEffect, useState } from "react"; import { print } from "shared-runtime"; @@ -34,22 +34,28 @@ import { print } from "shared-runtime"; * setState types are not enough to determine to omit from deps. Must also take reactivity into account. */ function ReactiveRefInEffect(props) { - const $ = _c(2); + const $ = _c(4); const [, setState1] = useRef("initial value"); const [, setState2] = useRef("initial value"); let setState; - if (props.foo) { - setState = setState1; + if ($[0] !== props.foo) { + if (props.foo) { + setState = setState1; + } else { + setState = setState2; + } + $[0] = props.foo; + $[1] = setState; } else { - setState = setState2; + setState = $[1]; } let t0; - if ($[0] !== setState) { + if ($[2] !== setState) { t0 = () => print(setState); - $[0] = setState; - $[1] = t0; + $[2] = setState; + $[3] = t0; } else { - t0 = $[1]; + t0 = $[3]; } useEffect(t0, [setState]); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/reactive-setState.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/reactive-setState.js index 46a83d8ad42dd..158881eb0204d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/reactive-setState.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/reactive-setState.js @@ -1,4 +1,4 @@ -// @inferEffectDependencies +// @inferEffectDependencies @enableNewMutationAliasingModel import {useEffect, useState} from 'react'; import {print} from 'shared-runtime'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.expect.md index bd70c0138d7e2..053728ed17015 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly +// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel import {print} from 'shared-runtime'; import useEffectWrapper from 'useEffectWrapper'; @@ -27,7 +27,7 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly +// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel import { print } from "shared-runtime"; import useEffectWrapper from "useEffectWrapper"; @@ -52,10 +52,10 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":163},"end":{"line":13,"column":1,"index":357},"filename":"retry-no-emit.ts"},"detail":{"reason":"This mutates a variable that React considers immutable","description":null,"loc":{"start":{"line":11,"column":2,"index":320},"end":{"line":11,"column":6,"index":324},"filename":"retry-no-emit.ts","identifierName":"arr2"},"suggestions":null,"severity":"InvalidReact"}} -{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":7,"column":2,"index":216},"end":{"line":7,"column":36,"index":250},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":7,"column":31,"index":245},"end":{"line":7,"column":34,"index":248},"filename":"retry-no-emit.ts","identifierName":"arr"}]} -{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":10,"column":2,"index":274},"end":{"line":10,"column":44,"index":316},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":10,"column":25,"index":297},"end":{"line":10,"column":29,"index":301},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":10,"column":25,"index":297},"end":{"line":10,"column":29,"index":301},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":10,"column":35,"index":307},"end":{"line":10,"column":42,"index":314},"filename":"retry-no-emit.ts","identifierName":"propVal"}]} -{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":163},"end":{"line":13,"column":1,"index":357},"filename":"retry-no-emit.ts"},"fnName":"Foo","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0} +{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":195},"end":{"line":13,"column":1,"index":389},"filename":"retry-no-emit.ts"},"detail":{"reason":"This mutates a variable that React considers immutable","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":11,"column":2,"index":352},"end":{"line":11,"column":6,"index":356},"filename":"retry-no-emit.ts","identifierName":"arr2"}}} +{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":7,"column":2,"index":248},"end":{"line":7,"column":36,"index":282},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":7,"column":31,"index":277},"end":{"line":7,"column":34,"index":280},"filename":"retry-no-emit.ts","identifierName":"arr"}]} +{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":10,"column":2,"index":306},"end":{"line":10,"column":44,"index":348},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":10,"column":25,"index":329},"end":{"line":10,"column":29,"index":333},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":10,"column":25,"index":329},"end":{"line":10,"column":29,"index":333},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":10,"column":35,"index":339},"end":{"line":10,"column":42,"index":346},"filename":"retry-no-emit.ts","identifierName":"propVal"}]} +{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":195},"end":{"line":13,"column":1,"index":389},"filename":"retry-no-emit.ts"},"fnName":"Foo","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.js index d1dda06a044a2..c15f400d3114d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.js @@ -1,4 +1,4 @@ -// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly +// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel import {print} from 'shared-runtime'; import useEffectWrapper from 'useEffectWrapper'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/shared-hook-calls.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/shared-hook-calls.expect.md index 92dbf9843ad65..3f361c2019043 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/shared-hook-calls.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/shared-hook-calls.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @enableFire +// @enableFire @enableNewMutationAliasingModel import {fire} from 'react'; function Component({bar, baz}) { @@ -26,51 +26,64 @@ function Component({bar, baz}) { ## Code ```javascript -import { c as _c, useFire } from "react/compiler-runtime"; // @enableFire +import { c as _c, useFire } from "react/compiler-runtime"; // @enableFire @enableNewMutationAliasingModel import { fire } from "react"; function Component(t0) { - const $ = _c(9); - const { bar, baz } = t0; - let t1; - if ($[0] !== bar) { - t1 = () => { - console.log(bar); - }; - $[0] = bar; - $[1] = t1; + const $ = _c(13); + let bar; + let baz; + let foo; + if ($[0] !== t0) { + ({ bar, baz } = t0); + let t1; + if ($[4] !== bar) { + t1 = () => { + console.log(bar); + }; + $[4] = bar; + $[5] = t1; + } else { + t1 = $[5]; + } + foo = t1; + $[0] = t0; + $[1] = bar; + $[2] = baz; + $[3] = foo; } else { - t1 = $[1]; + bar = $[1]; + baz = $[2]; + foo = $[3]; } - const foo = t1; - const t2 = useFire(foo); - const t3 = useFire(baz); - let t4; - if ($[2] !== bar || $[3] !== t2 || $[4] !== t3) { - t4 = () => { + const t1 = useFire(foo); + const t2 = useFire(baz); + let t3; + if ($[6] !== bar || $[7] !== t1 || $[8] !== t2) { + t3 = () => { + t1(bar); t2(bar); - t3(bar); }; - $[2] = bar; - $[3] = t2; - $[4] = t3; - $[5] = t4; + $[6] = bar; + $[7] = t1; + $[8] = t2; + $[9] = t3; } else { - t4 = $[5]; + t3 = $[9]; } - useEffect(t4); - let t5; - if ($[6] !== bar || $[7] !== t2) { - t5 = () => { - t2(bar); + useEffect(t3); + let t4; + if ($[10] !== bar || $[11] !== t1) { + t4 = () => { + t1(bar); }; - $[6] = bar; - $[7] = t2; - $[8] = t5; + $[10] = bar; + $[11] = t1; + $[12] = t4; } else { - t5 = $[8]; + t4 = $[12]; } - useEffect(t5); + useEffect(t4); return null; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/shared-hook-calls.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/shared-hook-calls.js index 5cb51e9bd3c78..54d4cf83fe310 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/shared-hook-calls.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/shared-hook-calls.js @@ -1,4 +1,4 @@ -// @enableFire +// @enableFire @enableNewMutationAliasingModel import {fire} from 'react'; function Component({bar, baz}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-deplist-controlflow.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-deplist-controlflow.expect.md index 080cc0a74a609..e33f52396d5e5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-deplist-controlflow.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-deplist-controlflow.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enableNewMutationAliasingModel import {useCallback} from 'react'; import {Stringify} from 'shared-runtime'; @@ -35,44 +36,51 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel import { useCallback } from "react"; import { Stringify } from "shared-runtime"; function Foo(t0) { - const $ = _c(8); + const $ = _c(10); const { arr1, arr2, foo } = t0; - let getVal1; let t1; - if ($[0] !== arr1 || $[1] !== arr2 || $[2] !== foo) { - const x = [arr1]; - + if ($[0] !== arr1) { + t1 = [arr1]; + $[0] = arr1; + $[1] = t1; + } else { + t1 = $[1]; + } + const x = t1; + let getVal1; + let t2; + if ($[2] !== arr2 || $[3] !== foo || $[4] !== x) { let y = []; getVal1 = _temp; - t1 = () => [y]; + t2 = () => [y]; foo ? (y = x.concat(arr2)) : y; - $[0] = arr1; - $[1] = arr2; - $[2] = foo; - $[3] = getVal1; - $[4] = t1; + $[2] = arr2; + $[3] = foo; + $[4] = x; + $[5] = getVal1; + $[6] = t2; } else { - getVal1 = $[3]; - t1 = $[4]; + getVal1 = $[5]; + t2 = $[6]; } - const getVal2 = t1; - let t2; - if ($[5] !== getVal1 || $[6] !== getVal2) { - t2 = ; - $[5] = getVal1; - $[6] = getVal2; - $[7] = t2; + const getVal2 = t2; + let t3; + if ($[7] !== getVal1 || $[8] !== getVal2) { + t3 = ; + $[7] = getVal1; + $[8] = getVal2; + $[9] = t3; } else { - t2 = $[7]; + t3 = $[9]; } - return t2; + return t3; } function _temp() { return { x: 2 }; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-deplist-controlflow.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-deplist-controlflow.tsx index ba0abc0d7cdf0..08b9e4b2faa6c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-deplist-controlflow.tsx +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-deplist-controlflow.tsx @@ -1,3 +1,4 @@ +// @enableNewMutationAliasingModel import {useCallback} from 'react'; import {Stringify} from 'shared-runtime'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-depslist-assignment.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-depslist-assignment.expect.md index 89a6ad80c3945..d37762bbac530 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-depslist-assignment.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-depslist-assignment.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enableNewMutationAliasingModel import {useCallback} from 'react'; import {Stringify} from 'shared-runtime'; @@ -30,37 +31,44 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel import { useCallback } from "react"; import { Stringify } from "shared-runtime"; // We currently produce invalid output (incorrect scoping for `y` declaration) function useFoo(arr1, arr2) { - const $ = _c(5); + const $ = _c(7); let t0; - if ($[0] !== arr1 || $[1] !== arr2) { - const x = [arr1]; - - let y; - t0 = () => ({ y }); - - (y = x.concat(arr2)), y; + if ($[0] !== arr1) { + t0 = [arr1]; $[0] = arr1; - $[1] = arr2; - $[2] = t0; + $[1] = t0; } else { - t0 = $[2]; + t0 = $[1]; } - const getVal = t0; + const x = t0; let t1; - if ($[3] !== getVal) { - t1 = ; - $[3] = getVal; + if ($[2] !== arr2 || $[3] !== x) { + let y; + t1 = () => ({ y }); + + (y = x.concat(arr2)), y; + $[2] = arr2; + $[3] = x; $[4] = t1; } else { t1 = $[4]; } - return t1; + const getVal = t1; + let t2; + if ($[5] !== getVal) { + t2 = ; + $[5] = getVal; + $[6] = t2; + } else { + t2 = $[6]; + } + return t2; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-depslist-assignment.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-depslist-assignment.tsx index 3ac3845c47f74..43e2dfbb0504a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-depslist-assignment.tsx +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-depslist-assignment.tsx @@ -1,3 +1,4 @@ +// @enableNewMutationAliasingModel import {useCallback} from 'react'; import {Stringify} from 'shared-runtime'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useMemo-reordering-depslist-assignment.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useMemo-reordering-depslist-assignment.expect.md index 3fffec6a7dc20..26445bf9207be 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useMemo-reordering-depslist-assignment.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useMemo-reordering-depslist-assignment.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enableNewMutationAliasingModel import {useMemo} from 'react'; function useFoo(arr1, arr2) { @@ -26,33 +27,40 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel import { useMemo } from "react"; function useFoo(arr1, arr2) { - const $ = _c(5); + const $ = _c(7); + let t0; + if ($[0] !== arr1) { + t0 = [arr1]; + $[0] = arr1; + $[1] = t0; + } else { + t0 = $[1]; + } + const x = t0; let y; - if ($[0] !== arr1 || $[1] !== arr2) { - const x = [arr1]; - + if ($[2] !== arr2 || $[3] !== x) { (y = x.concat(arr2)), y; - $[0] = arr1; - $[1] = arr2; - $[2] = y; + $[2] = arr2; + $[3] = x; + $[4] = y; } else { - y = $[2]; + y = $[4]; } - let t0; let t1; - if ($[3] !== y) { - t1 = { y }; - $[3] = y; - $[4] = t1; + let t2; + if ($[5] !== y) { + t2 = { y }; + $[5] = y; + $[6] = t2; } else { - t1 = $[4]; + t2 = $[6]; } - t0 = t1; - return t0; + t1 = t2; + return t1; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useMemo-reordering-depslist-assignment.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useMemo-reordering-depslist-assignment.ts index 8025d3680fb51..5b7d799d68b13 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useMemo-reordering-depslist-assignment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useMemo-reordering-depslist-assignment.ts @@ -1,3 +1,4 @@ +// @enableNewMutationAliasingModel import {useMemo} from 'react'; function useFoo(arr1, arr2) { From f3789e4caf8ba5162c64b5e8ee295e3f239293d2 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 18 Jun 2025 13:00:40 -0700 Subject: [PATCH 2/5] [compiler] Enable new inference by default --- .../src/HIR/Environment.ts | 2 +- ...iased-nested-scope-truncated-dep.expect.md | 13 +-- ...ction-alias-computed-load-2-iife.expect.md | 20 +++-- ...ction-alias-computed-load-3-iife.expect.md | 23 ++++-- ...ction-alias-computed-load-4-iife.expect.md | 20 +++-- ...unction-alias-computed-load-iife.expect.md | 20 +++-- ...valid-impure-functions-in-render.expect.md | 2 +- ...d-reanimated-shared-value-writes.expect.md | 2 +- .../error.mutate-hook-argument.expect.md | 2 + ...or.not-useEffect-external-mutate.expect.md | 2 + ....reassignment-to-global-indirect.expect.md | 2 + .../error.reassignment-to-global.expect.md | 2 + ...on-with-shadowed-local-same-name.expect.md | 2 +- ...e-after-useeffect-optional-chain.expect.md | 2 +- ...utate-after-useeffect-ref-access.expect.md | 2 +- .../mutate-after-useeffect.expect.md | 2 +- .../no-emit/retry-no-emit.expect.md | 2 +- .../reactive-setState.expect.md | 22 +++-- ...map-named-callback-cross-context.expect.md | 81 ++++++++++--------- ...omputed-key-object-mutated-later.expect.md | 36 +++------ ...bject-expression-computed-member.expect.md | 15 +++- ...k-reordering-deplist-controlflow.expect.md | 51 +++++++----- ...k-reordering-depslist-assignment.expect.md | 39 +++++---- ...o-reordering-depslist-assignment.expect.md | 39 +++++---- .../shared-hook-calls.expect.md | 77 ++++++++++-------- 25 files changed, 277 insertions(+), 203 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index 206bfc0bca1a4..90a352620ce35 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -246,7 +246,7 @@ export const EnvironmentConfigSchema = z.object({ /** * Enable a new model for mutability and aliasing inference */ - enableNewMutationAliasingModel: z.boolean().default(false), + enableNewMutationAliasingModel: z.boolean().default(true), /** * Enables inference of optional dependency chains. Without this flag diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-truncated-dep.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-truncated-dep.expect.md index 933fafff5f1ba..12c7b4d5eab93 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-truncated-dep.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-truncated-dep.expect.md @@ -175,21 +175,14 @@ import { * and mutability. */ function Component(t0) { - const $ = _c(4); + const $ = _c(2); const { prop } = t0; let t1; if ($[0] !== prop) { const obj = shallowCopy(prop); const aliasedObj = identity(obj); - let t2; - if ($[2] !== obj) { - t2 = [obj.id]; - $[2] = obj; - $[3] = t2; - } else { - t2 = $[3]; - } - const id = t2; + + const id = [obj.id]; mutate(aliasedObj); setPropertyByKey(aliasedObj, "id", prop.id + 1); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-2-iife.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-2-iife.expect.md index 2afc5fd25dbac..50480f1b2515e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-2-iife.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-2-iife.expect.md @@ -25,17 +25,25 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function bar(a) { - const $ = _c(2); - let y; + const $ = _c(4); + let t0; if ($[0] !== a) { - const x = [a]; + t0 = [a]; + $[0] = a; + $[1] = t0; + } else { + t0 = $[1]; + } + const x = t0; + let y; + if ($[2] !== x[0][1]) { y = {}; y = x[0][1]; - $[0] = a; - $[1] = y; + $[2] = x[0][1]; + $[3] = y; } else { - y = $[1]; + y = $[3]; } return y; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-3-iife.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-3-iife.expect.md index f0267c3309f5b..9678918b3d27f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-3-iife.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-3-iife.expect.md @@ -29,20 +29,29 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function bar(a, b) { - const $ = _c(3); - let y; + const $ = _c(6); + let t0; if ($[0] !== a || $[1] !== b) { - const x = [a, b]; + t0 = [a, b]; + $[0] = a; + $[1] = b; + $[2] = t0; + } else { + t0 = $[2]; + } + const x = t0; + let y; + if ($[3] !== x[0][1] || $[4] !== x[1][0]) { y = {}; let t = {}; y = x[0][1]; t = x[1][0]; - $[0] = a; - $[1] = b; - $[2] = y; + $[3] = x[0][1]; + $[4] = x[1][0]; + $[5] = y; } else { - y = $[2]; + y = $[5]; } return y; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-4-iife.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-4-iife.expect.md index 22728aaf4323d..edddf3715a453 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-4-iife.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-4-iife.expect.md @@ -25,17 +25,25 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function bar(a) { - const $ = _c(2); - let y; + const $ = _c(4); + let t0; if ($[0] !== a) { - const x = [a]; + t0 = [a]; + $[0] = a; + $[1] = t0; + } else { + t0 = $[1]; + } + const x = t0; + let y; + if ($[2] !== x[0].a[1]) { y = {}; y = x[0].a[1]; - $[0] = a; - $[1] = y; + $[2] = x[0].a[1]; + $[3] = y; } else { - y = $[1]; + y = $[3]; } return y; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-iife.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-iife.expect.md index 60f829cdc4d66..c9ce6dda9f627 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-iife.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-iife.expect.md @@ -24,17 +24,25 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function bar(a) { - const $ = _c(2); - let y; + const $ = _c(4); + let t0; if ($[0] !== a) { - const x = [a]; + t0 = [a]; + $[0] = a; + $[1] = t0; + } else { + t0 = $[1]; + } + const x = t0; + let y; + if ($[2] !== x[0]) { y = {}; y = x[0]; - $[0] = a; - $[1] = y; + $[2] = x[0]; + $[3] = y; } else { - y = $[1]; + y = $[3]; } return y; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-impure-functions-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-impure-functions-in-render.expect.md index a67d467df8cfd..0fb17a8f6eab4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-impure-functions-in-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-impure-functions-in-render.expect.md @@ -20,7 +20,7 @@ function Component() { 2 | 3 | function Component() { > 4 | const date = Date.now(); - | ^^^^^^^^ InvalidReact: Calling an impure function can produce unstable results. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). `Date.now` is an impure function whose results may change on every call (4:4) + | ^^^^^^^^^^ InvalidReact: Calling an impure function can produce unstable results. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). `Date.now` is an impure function whose results may change on every call (4:4) InvalidReact: Calling an impure function can produce unstable results. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). `performance.now` is an impure function whose results may change on every call (5:5) diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-non-imported-reanimated-shared-value-writes.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-non-imported-reanimated-shared-value-writes.expect.md index f1399a41b6fec..d3bb7f413622b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-non-imported-reanimated-shared-value-writes.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-non-imported-reanimated-shared-value-writes.expect.md @@ -27,7 +27,7 @@ function SomeComponent() { 9 | return ( 10 |