@samitouri / QOS-React / commits / 5ab54718a5

compiler: merge reactive scopes across const StoreLocal (#29095)

@jbonta nerd-sniped me into making this optimization during conference prep, posting this as a PR now that keynote is over. Consider these two cases: ```javascript export default function MyApp1({ count }) { const cb = () => count; return <div onclick={cb}>Hello World</div>; } export default function MyApp2({ count }) { return <div onclick={() => count}>Hello World</div>; } ``` Previously, the former would create two reactive scopes (one for `cb`, one for the div) while the latter would only have a single scope for the `div` and its inline callback. The reason we created separate scopes before is that there's a `StoreLocal 'cb' = t0` instruction in-between, and i had conservatively implemented the merging pass to not allow intervening StoreLocal instructions. The observation is that intervening StoreLocals are fine _if_ the assigned variable's last usage is the next scope. We already have a check that the intervening lvalues are last-used at/before the next scope, so it's trivial to extend this to support StoreLocal. Note that we already don't merge scopes if there are intervening terminals, so we don't have to worry about things like conditional StoreLocal, conditional access of the resulting value, etc.

Joseph Savona committed May 16, 2024 at 17:29 UTC 5ab54718a52d738dcbd03fcb43a556993b445ed4
22 files changed +304 -211
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts
+29
@@ -9,6 +9,7 @@ import { CompilerError } from "..";
9 import {
10 IdentifierId,
11 InstructionId,
12 + InstructionKind,
13 Place,
14 ReactiveBlock,
15 ReactiveFunction,
@@ -20,6 +21,7 @@ import {
21 ReactiveStatement,
22 makeInstructionId,
23 } from "../HIR";
24 +import { eachInstructionLValue } from "../HIR/visitors";
25 import { assertExhaustive } from "../Utils/utils";
26 import { printReactiveScopeSummary } from "./PrintReactiveFunction";
27 import {
@@ -186,6 +188,33 @@ class Transform extends ReactiveFunctionTransform<ReactiveScopeDependencies | nu
188 }
189 break;
190 }
191 + case "StoreLocal": {
192 + /**
193 + * It's safe to have intervening StoreLocal instructions _if_ they are const
194 + * and the last usage of the variable is at or before the next scope. This is
195 + * similar to the case above for simple instructions.
196 + *
197 + * Reassignments are *not* safe to merge since they are a side-effect that we
198 + * don't want to make conditional.
199 + */
200 + if (current !== null) {
201 + if (
202 + instr.instruction.value.lvalue.kind === InstructionKind.Const
203 + ) {
204 + for (const lvalue of eachInstructionLValue(
205 + instr.instruction
206 + )) {
207 + current.lvalues.add(lvalue.identifier.id);
208 + }
209 + } else {
210 + log(
211 + `Reset scope @${current.block.scope.id} from StoreLocal in [${instr.instruction.id}]`
212 + );
213 + reset();
214 + }
215 + }
216 + break;
217 + }
218 default: {
219 // Other instructions are known to prevent merging, so we reset the scope if present
220 if (current !== null) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/alias-nested-member-path.expect.md
+5 -12
@@ -24,24 +24,17 @@ export const FIXTURE_ENTRYPOINT = {
24 ```javascript
25 import { c as _c } from "react/compiler-runtime";
26 function component() {
27 - const $ = _c(2);
28 - let t0;
29 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
30 - t0 = [];
31 - $[0] = t0;
32 - } else {
33 - t0 = $[0];
34 - }
35 - const z = t0;
27 + const $ = _c(1);
28 let x;
37 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
29 + if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
30 + const z = [];
31 const y = {};
32 y.z = z;
33 x = {};
34 x.y = y;
42 - $[1] = x;
35 + $[0] = x;
36 } else {
44 - x = $[1];
37 + x = $[0];
38 }
39 return x;
40 }
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-map-frozen-array-noAlias.expect.md
+4 -11
@@ -22,7 +22,7 @@ export const FIXTURE_ENTRYPOINT = {
22 ```javascript
23 import { c as _c } from "react/compiler-runtime";
24 function Component(props) {
25 - const $ = _c(3);
25 + const $ = _c(2);
26 let t0;
27 if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
28 t0 = [];
@@ -33,20 +33,13 @@ function Component(props) {
33 const x = t0;
34 let t1;
35 if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
36 - t1 = x.map((item) => item);
36 + const y = x.map((item) => item);
37 + t1 = [x, y];
38 $[1] = t1;
39 } else {
40 t1 = $[1];
41 }
41 - const y = t1;
42 - let t2;
43 - if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
44 - t2 = [x, y];
45 - $[2] = t2;
46 - } else {
47 - t2 = $[2];
48 - }
49 - return t2;
42 + return t1;
43 }
44
45 export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-map-frozen-array.expect.md
+4 -11
@@ -22,7 +22,7 @@ export const FIXTURE_ENTRYPOINT = {
22 ```javascript
23 import { c as _c } from "react/compiler-runtime";
24 function Component(props) {
25 - const $ = _c(3);
25 + const $ = _c(2);
26 let t0;
27 if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
28 t0 = [];
@@ -33,20 +33,13 @@ function Component(props) {
33 const x = t0;
34 let t1;
35 if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
36 - t1 = x.map((item) => item);
36 + const y = x.map((item) => item);
37 + t1 = [x, y];
38 $[1] = t1;
39 } else {
40 t1 = $[1];
41 }
41 - const y = t1;
42 - let t2;
43 - if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
44 - t2 = [x, y];
45 - $[2] = t2;
46 - } else {
47 - t2 = $[2];
48 - }
49 - return t2;
42 + return t1;
43 }
44
45 export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-map-mutable-array-mutating-lambda-noAlias.expect.md
+5 -15
@@ -24,30 +24,20 @@ export const FIXTURE_ENTRYPOINT = {
24 ```javascript
25 import { c as _c } from "react/compiler-runtime";
26 function Component(props) {
27 - const $ = _c(3);
27 + const $ = _c(1);
28 let t0;
29 - let x;
29 if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
31 - x = [];
32 - t0 = x.map((item) => {
30 + const x = [];
31 + const y = x.map((item) => {
32 item.updated = true;
33 return item;
34 });
35 + t0 = [x, y];
36 $[0] = t0;
37 - $[1] = x;
37 } else {
38 t0 = $[0];
40 - x = $[1];
39 }
42 - const y = t0;
43 - let t1;
44 - if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
45 - t1 = [x, y];
46 - $[2] = t1;
47 - } else {
48 - t1 = $[2];
49 - }
50 - return t1;
40 + return t0;
41 }
42
43 export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-map-mutable-array-mutating-lambda.expect.md
+5 -15
@@ -24,30 +24,20 @@ export const FIXTURE_ENTRYPOINT = {
24 ```javascript
25 import { c as _c } from "react/compiler-runtime";
26 function Component(props) {
27 - const $ = _c(3);
27 + const $ = _c(1);
28 let t0;
29 - let x;
29 if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
31 - x = [];
32 - t0 = x.map((item) => {
30 + const x = [];
31 + const y = x.map((item) => {
32 item.updated = true;
33 return item;
34 });
35 + t0 = [x, y];
36 $[0] = t0;
37 - $[1] = x;
37 } else {
38 t0 = $[0];
40 - x = $[1];
39 }
42 - const y = t0;
43 - let t1;
44 - if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
45 - t1 = [x, y];
46 - $[2] = t1;
47 - } else {
48 - t1 = $[2];
49 - }
50 - return t1;
40 + return t0;
41 }
42
43 export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/const-propagation-into-function-expression-global.expect.md
+5 -11
@@ -18,23 +18,17 @@ function foo() {
18 ```javascript
19 import { c as _c } from "react/compiler-runtime";
20 function foo() {
21 - const $ = _c(2);
21 + const $ = _c(1);
22 let t0;
23 if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
24 - t0 = () => <Child x={GLOBAL_IS_X} />;
24 + const getJSX = () => <Child x={GLOBAL_IS_X} />;
25 +
26 + t0 = getJSX();
27 $[0] = t0;
28 } else {
29 t0 = $[0];
30 }
29 - const getJSX = t0;
30 - let t1;
31 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
32 - t1 = getJSX();
33 - $[1] = t1;
34 - } else {
35 - t1 = $[1];
36 - }
37 - const result = t1;
31 + const result = t0;
32 return result;
33 }
34
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dont-merge-overlapping-scopes-store-const-used-later.expect.md new
+70
@@ -0,0 +1,70 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +import { Stringify, makeObject_Primitives } from "shared-runtime";
6 +
7 +function Component(props) {
8 + const array = [props.count];
9 + const x = makeObject_Primitives();
10 + const element = <div>{array}</div>;
11 + console.log(x);
12 + return <div>{element}</div>;
13 +}
14 +
15 +export const FIXTURE_ENTRYPOINT = {
16 + fn: Component,
17 + params: [{ count: 42 }],
18 +};
19 +
20 +```
21 +
22 +## Code
23 +
24 +```javascript
25 +import { c as _c } from "react/compiler-runtime";
26 +import { Stringify, makeObject_Primitives } from "shared-runtime";
27 +
28 +function Component(props) {
29 + const $ = _c(6);
30 + let t0;
31 + if ($[0] !== props.count) {
32 + t0 = [props.count];
33 + $[0] = props.count;
34 + $[1] = t0;
35 + } else {
36 + t0 = $[1];
37 + }
38 + const array = t0;
39 + const x = makeObject_Primitives();
40 + let t1;
41 + if ($[2] !== array) {
42 + t1 = <div>{array}</div>;
43 + $[2] = array;
44 + $[3] = t1;
45 + } else {
46 + t1 = $[3];
47 + }
48 + const element = t1;
49 + console.log(x);
50 + let t2;
51 + if ($[4] !== element) {
52 + t2 = <div>{element}</div>;
53 + $[4] = element;
54 + $[5] = t2;
55 + } else {
56 + t2 = $[5];
57 + }
58 + return t2;
59 +}
60 +
61 +export const FIXTURE_ENTRYPOINT = {
62 + fn: Component,
63 + params: [{ count: 42 }],
64 +};
65 +
66 +```
67 +
68 +### Eval output
69 +(kind: ok) <div><div>42</div></div>
70 +logs: [{ a: 0, b: 'value1', c: true }]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dont-merge-overlapping-scopes-store-const-used-later.js new
+14
@@ -0,0 +1,14 @@
1 +import { Stringify, makeObject_Primitives } from "shared-runtime";
2 +
3 +function Component(props) {
4 + const array = [props.count];
5 + const x = makeObject_Primitives();
6 + const element = <div>{array}</div>;
7 + console.log(x);
8 + return <div>{element}</div>;
9 +}
10 +
11 +export const FIXTURE_ENTRYPOINT = {
12 + fn: Component,
13 + params: [{ count: 42 }],
14 +};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dont-merge-overlapping-scopes-with-intermediate-reassignment.expect.md new
+80
@@ -0,0 +1,80 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +import { Stringify } from "shared-runtime";
6 +
7 +function Component(props) {
8 + let x;
9 + const array = [props.count];
10 + x = array;
11 + const element = <div>{array}</div>;
12 + return (
13 + <div>
14 + {element}
15 + {x}
16 + </div>
17 + );
18 +}
19 +
20 +export const FIXTURE_ENTRYPOINT = {
21 + fn: Component,
22 + params: [{ count: 42 }],
23 +};
24 +
25 +```
26 +
27 +## Code
28 +
29 +```javascript
30 +import { c as _c } from "react/compiler-runtime";
31 +import { Stringify } from "shared-runtime";
32 +
33 +function Component(props) {
34 + const $ = _c(7);
35 + let x;
36 + let t0;
37 + if ($[0] !== props.count) {
38 + t0 = [props.count];
39 + $[0] = props.count;
40 + $[1] = t0;
41 + } else {
42 + t0 = $[1];
43 + }
44 + const array = t0;
45 + x = array;
46 + let t1;
47 + if ($[2] !== array) {
48 + t1 = <div>{array}</div>;
49 + $[2] = array;
50 + $[3] = t1;
51 + } else {
52 + t1 = $[3];
53 + }
54 + const element = t1;
55 + let t2;
56 + if ($[4] !== element || $[5] !== x) {
57 + t2 = (
58 + <div>
59 + {element}
60 + {x}
61 + </div>
62 + );
63 + $[4] = element;
64 + $[5] = x;
65 + $[6] = t2;
66 + } else {
67 + t2 = $[6];
68 + }
69 + return t2;
70 +}
71 +
72 +export const FIXTURE_ENTRYPOINT = {
73 + fn: Component,
74 + params: [{ count: 42 }],
75 +};
76 +
77 +```
78 +
79 +### Eval output
80 +(kind: ok) <div><div>42</div>42</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dont-merge-overlapping-scopes-with-intermediate-reassignment.js new
+19
@@ -0,0 +1,19 @@
1 +import { Stringify } from "shared-runtime";
2 +
3 +function Component(props) {
4 + let x;
5 + const array = [props.count];
6 + x = array;
7 + const element = <div>{array}</div>;
8 + return (
9 + <div>
10 + {element}
11 + {x}
12 + </div>
13 + );
14 +}
15 +
16 +export const FIXTURE_ENTRYPOINT = {
17 + fn: Component,
18 + params: [{ count: 42 }],
19 +};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-of-continue.expect.md
+5 -12
@@ -27,17 +27,10 @@ export const FIXTURE_ENTRYPOINT = {
27 ```javascript
28 import { c as _c } from "react/compiler-runtime";
29 function Component() {
30 - const $ = _c(2);
31 - let t0;
32 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
33 - t0 = [0, 1, 2, 3];
34 - $[0] = t0;
35 - } else {
36 - t0 = $[0];
37 - }
38 - const x = t0;
30 + const $ = _c(1);
31 let ret;
40 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
32 + if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
33 + const x = [0, 1, 2, 3];
34 ret = [];
35 for (const item of x) {
36 if (item === 0) {
@@ -46,9 +39,9 @@ function Component() {
39
40 ret.push(item / 2);
41 }
49 - $[1] = ret;
42 + $[0] = ret;
43 } else {
51 - ret = $[1];
44 + ret = $[0];
45 }
46 return ret;
47 }
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-recursive-call-within-lambda.expect.md
+5 -11
@@ -27,10 +27,10 @@ export const FIXTURE_ENTRYPOINT = {
27 ```javascript
28 import { c as _c } from "react/compiler-runtime";
29 function Foo(t0) {
30 - const $ = _c(2);
30 + const $ = _c(1);
31 let t1;
32 if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
33 - t1 = (val) => {
33 + const outer = (val) => {
34 const fact = (x) => {
35 if (x <= 0) {
36 return 1;
@@ -39,19 +39,13 @@ function Foo(t0) {
39 };
40 return fact(val);
41 };
42 +
43 + t1 = outer(3);
44 $[0] = t1;
45 } else {
46 t1 = $[0];
47 }
46 - const outer = t1;
47 - let t2;
48 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
49 - t2 = outer(3);
50 - $[1] = t2;
51 - } else {
52 - t2 = $[1];
53 - }
54 - return t2;
48 + return t1;
49 }
50
51 export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-within-lambda.expect.md
+5 -11
@@ -25,28 +25,22 @@ export const FIXTURE_ENTRYPOINT = {
25 ```javascript
26 import { c as _c } from "react/compiler-runtime";
27 function Component(t0) {
28 - const $ = _c(2);
28 + const $ = _c(1);
29 let t1;
30 if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
31 - t1 = () => {
31 + const outer = () => {
32 const inner = () => x;
33
34 const x = 3;
35 return inner();
36 };
37 +
38 + t1 = <div>{outer()}</div>;
39 $[0] = t1;
40 } else {
41 t1 = $[0];
42 }
41 - const outer = t1;
42 - let t2;
43 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
44 - t2 = <div>{outer()}</div>;
45 - $[1] = t2;
46 - } else {
47 - t2 = $[1];
48 - }
49 - return t2;
43 + return t1;
44 }
45
46 export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-local-tag-in-lambda.expect.md
+5 -11
@@ -24,23 +24,17 @@ export const FIXTURE_ENTRYPOINT = {
24 import { c as _c } from "react/compiler-runtime";
25 import { Stringify } from "shared-runtime";
26 function useFoo() {
27 - const $ = _c(2);
27 + const $ = _c(1);
28 let t0;
29 if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
30 - t0 = () => <Stringify value={4} />;
30 + const callback = () => <Stringify value={4} />;
31 +
32 + t0 = callback();
33 $[0] = t0;
34 } else {
35 t0 = $[0];
36 }
35 - const callback = t0;
36 - let t1;
37 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
38 - t1 = callback();
39 - $[1] = t1;
40 - } else {
41 - t1 = $[1];
42 - }
43 - return t1;
37 + return t0;
38 }
39
40 export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-memberexpr-tag-in-lambda.expect.md
+5 -11
@@ -24,24 +24,18 @@ export const FIXTURE_ENTRYPOINT = {
24 import { c as _c } from "react/compiler-runtime";
25 import * as SharedRuntime from "shared-runtime";
26 function useFoo() {
27 - const $ = _c(2);
27 + const $ = _c(1);
28 const MyLocal = SharedRuntime;
29 let t0;
30 if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
31 - t0 = () => <MyLocal.Text value={4} />;
31 + const callback = () => <MyLocal.Text value={4} />;
32 +
33 + t0 = callback();
34 $[0] = t0;
35 } else {
36 t0 = $[0];
37 }
36 - const callback = t0;
37 - let t1;
38 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
39 - t1 = callback();
40 - $[1] = t1;
41 - } else {
42 - t1 = $[1];
43 - }
44 - return t1;
38 + return t0;
39 }
40
41 export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/maybe-mutate-object-in-callback.expect.md
+13 -19
@@ -32,34 +32,28 @@ import { c as _c } from "react/compiler-runtime";
32 const { mutate } = require("shared-runtime");
33
34 function Component(props) {
35 - const $ = _c(4);
35 + const $ = _c(3);
36 let t0;
37 if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
38 - t0 = {};
38 + const object = {};
39 +
40 + t0 = () => {
41 + mutate(object);
42 + };
43 $[0] = t0;
44 } else {
45 t0 = $[0];
46 }
43 - const object = t0;
47 + const onClick = t0;
48 let t1;
45 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
46 - t1 = () => {
47 - mutate(object);
48 - };
49 - $[1] = t1;
50 - } else {
51 - t1 = $[1];
52 - }
53 - const onClick = t1;
54 - let t2;
55 - if ($[2] !== props.children) {
56 - t2 = <Foo callback={onClick}>{props.children}</Foo>;
57 - $[2] = props.children;
58 - $[3] = t2;
49 + if ($[1] !== props.children) {
50 + t1 = <Foo callback={onClick}>{props.children}</Foo>;
51 + $[1] = props.children;
52 + $[2] = t1;
53 } else {
60 - t2 = $[3];
54 + t1 = $[2];
55 }
62 - return t2;
56 + return t1;
57 }
58
59 function Foo(t0) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-mutable-range-shared-inner-outer-function.expect.md
+5 -11
@@ -34,12 +34,12 @@ export const FIXTURE_ENTRYPOINT = {
34 import { c as _c } from "react/compiler-runtime"; // @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions
35 let cond = true;
36 function Component(props) {
37 - const $ = _c(2);
37 + const $ = _c(1);
38 let a;
39 let b;
40 let t0;
41 if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
42 - t0 = () => {
42 + const f = () => {
43 if (cond) {
44 a = {};
45 b = [];
@@ -51,19 +51,13 @@ function Component(props) {
51 a.property = true;
52 b.push(false);
53 };
54 +
55 + t0 = <div onClick={f} />;
56 $[0] = t0;
57 } else {
58 t0 = $[0];
59 }
58 - const f = t0;
59 - let t1;
60 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
61 - t1 = <div onClick={f} />;
62 - $[1] = t1;
63 - } else {
64 - t1 = $[1];
65 - }
66 - return t1;
60 + return t0;
61 }
62
63 export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-property.expect.md
+5 -12
@@ -22,22 +22,15 @@ export const FIXTURE_ENTRYPOINT = {
22 ```javascript
23 import { c as _c } from "react/compiler-runtime";
24 function foo() {
25 - const $ = _c(2);
26 - let t0;
27 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
28 - t0 = [];
29 - $[0] = t0;
30 - } else {
31 - t0 = $[0];
32 - }
33 - const x = t0;
25 + const $ = _c(1);
26 let y;
35 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
27 + if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
28 + const x = [];
29 y = {};
30 y.x = x;
38 - $[1] = y;
31 + $[0] = y;
32 } else {
40 - y = $[1];
33 + y = $[0];
34 }
35 return y;
36 }
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-reassign-in-rval.expect.md
+5 -15
@@ -16,27 +16,17 @@ function Component() {
16 ```javascript
17 import { c as _c } from "react/compiler-runtime"; // Forget should call the original x (x = foo()) to compute result
18 function Component() {
19 - const $ = _c(3);
19 + const $ = _c(1);
20 let t0;
21 - let x;
21 if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
23 - x = foo();
24 - t0 = x((x = bar()), 5);
22 + let x = foo();
23 + const result = x((x = bar()), 5);
24 + t0 = [result, x];
25 $[0] = t0;
26 - $[1] = x;
26 } else {
27 t0 = $[0];
29 - x = $[1];
28 }
31 - const result = t0;
32 - let t1;
33 - if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
34 - t1 = [result, x];
35 - $[2] = t1;
36 - } else {
37 - t1 = $[2];
38 - }
39 - return t1;
29 + return t0;
30 }
31
32 ```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-function-expression.expect.md
+5 -11
@@ -25,29 +25,23 @@ export const FIXTURE_ENTRYPOINT = {
25 ```javascript
26 import { c as _c } from "react/compiler-runtime";
27 function Component(props) {
28 - const $ = _c(2);
28 + const $ = _c(1);
29 let t0;
30 if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
31 - t0 = () => {
31 + const callback = () => {
32 try {
33 return [];
34 } catch (t1) {
35 return;
36 }
37 };
38 +
39 + t0 = callback();
40 $[0] = t0;
41 } else {
42 t0 = $[0];
43 }
42 - const callback = t0;
43 - let t1;
44 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
45 - t1 = callback();
46 - $[1] = t1;
47 - } else {
48 - t1 = $[1];
49 - }
50 - return t1;
44 + return t0;
45 }
46
47 export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-test-polymorphic.expect.md
+6 -12
@@ -24,26 +24,20 @@ function component() {
24 ```javascript
25 import { c as _c } from "react/compiler-runtime";
26 function component() {
27 - const $ = _c(2);
27 + const $ = _c(1);
28 const p = makePrimitive();
29 - let t0;
30 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
31 - t0 = {};
32 - $[0] = t0;
33 - } else {
34 - t0 = $[0];
35 - }
36 - const o = t0;
29 let x;
38 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
30 + if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
31 + const o = {};
32 +
33 x = {};
34
35 x.t = p;
36
37 x.t = o;
44 - $[1] = x;
38 + $[0] = x;
39 } else {
46 - x = $[1];
40 + x = $[0];
41 }
42 const y = x.t;
43 return y;