@samitouri / QOS-React-1 / commits / 8610533ed1

Infer reactive control dependencies

Updates `InferReactivePlaces` to infer control dependencies. We build on the formal definition of control dependencies, which is that statement S2 is control-dependent on statement S1 if S1 is in the post-dominance-frontier of S2. Intuitively, if S1 decides whether S2 is reached or not, then S1 is a control dependency of S2. The post dominance frontier of a given statement S is the set of statements which may or may not reach S, and captures the intuitive notion. We take advantage of phis: phis are the point where a variable may have multiple values depending on the path we took. If a phi is not already known to be reactive from data dependencies we check for control dependencies. Specifically we look at each phi operand. We check if the block that the operand came from has any reactive control dependencies, and if so we mark the phi itself as reactive. The post-dominance-frontier (PDF) algorithm requires walking the post-dominator tree a bunch, so we cache the PDF of blocks so that we don't have to recalculate on subsequent iterations. In addition, `InferReactiveIdentifiers` now uses the _union_ of its own inference plus the new `InferReactivePlaces` output when deciding what identifiers are reactive. This ensures that control dependencies are recorded correctly, fixing the previous test cases. The next diff adds the remaining features to InferReactivePlaces so that it can fully replace InferReactiveIdentifiers.

Joe Savona committed Nov 1, 2023 at 17:13 UTC 8610533ed1a38539412114a99a0390747e828235
31 files changed +287 -60
compiler/packages/babel-plugin-react-forget/src/HIR/Dominator.ts
+8 -1
@@ -98,7 +98,14 @@ export class Dominator<T> {
98 }
99
100 debug(): string {
101 - return prettyFormat(this.#nodes);
101 + const dominators = new Map();
102 + for (const [key, value] of this.#nodes) {
103 + dominators.set(`bb${key}`, `bb${value}`);
104 + }
105 + return prettyFormat({
106 + entry: `bb${this.#entry}`,
107 + dominators,
108 + });
109 }
110 }
111
compiler/packages/babel-plugin-react-forget/src/Inference/InferReactivePlaces.ts
+116 -1
@@ -7,13 +7,16 @@
7
8 import { CompilerError } from "..";
9 import {
10 + BlockId,
11 Effect,
12 HIRFunction,
13 Identifier,
14 IdentifierId,
15 Place,
16 + computePostDominatorTree,
17 getHookKind,
18 } from "../HIR";
19 +import { PostDominator } from "../HIR/Dominator";
20 import {
21 eachInstructionLValue,
22 eachInstructionValueOperand,
@@ -88,16 +91,73 @@ export function inferReactivePlaces(fn: HIRFunction): void {
91 reactiveIdentifiers.markReactive(place);
92 }
93
94 + const postDominators = computePostDominatorTree(fn, {
95 + includeThrowsAsExitNode: false,
96 + });
97 const hasLoop = hasBackEdge(fn);
98 + const postDominatorFrontierCache = new Map<BlockId, Set<BlockId>>();
99 do {
100 for (const [, block] of fn.body.blocks) {
101 for (const phi of block.phis) {
102 + if (reactiveIdentifiers.isReactiveIdentifier(phi.id)) {
103 + // Already marked reactive on a previous pass
104 + continue;
105 + }
106 + let isPhiReactive = false;
107 for (const [, operand] of phi.operands) {
108 if (reactiveIdentifiers.isReactiveIdentifier(operand)) {
97 - reactiveIdentifiers.markReactiveIdentifier(phi.id);
109 + isPhiReactive = true;
110 break;
111 }
112 }
113 + if (isPhiReactive) {
114 + reactiveIdentifiers.markReactiveIdentifier(phi.id);
115 + } else {
116 + // check to see if it has a reactive control dependency
117 + for (const [pred, _operand] of phi.operands) {
118 + let controlBlocks = postDominatorFrontierCache.get(pred);
119 + if (controlBlocks === undefined) {
120 + controlBlocks = postDominatorFrontier(fn, postDominators, pred);
121 + postDominatorFrontierCache.set(pred, controlBlocks);
122 + }
123 + control: for (const blockId of controlBlocks) {
124 + const controlBlock = fn.body.blocks.get(blockId)!;
125 + switch (controlBlock.terminal.kind) {
126 + case "if":
127 + case "branch": {
128 + if (
129 + reactiveIdentifiers.isReactive(controlBlock.terminal.test)
130 + ) {
131 + // control dependency is reactive
132 + reactiveIdentifiers.markReactiveIdentifier(phi.id);
133 + break control;
134 + }
135 + break;
136 + }
137 + case "switch": {
138 + if (
139 + reactiveIdentifiers.isReactive(controlBlock.terminal.test)
140 + ) {
141 + // control dependency is reactive
142 + reactiveIdentifiers.markReactiveIdentifier(phi.id);
143 + break control;
144 + }
145 + for (const case_ of controlBlock.terminal.cases) {
146 + if (
147 + case_.test !== null &&
148 + reactiveIdentifiers.isReactive(case_.test)
149 + ) {
150 + // control dependency is reactive
151 + reactiveIdentifiers.markReactiveIdentifier(phi.id);
152 + break control;
153 + }
154 + }
155 + break;
156 + }
157 + }
158 + }
159 + }
160 + }
161 }
162 for (const instruction of block.instructions) {
163 const { value } = instruction;
@@ -167,6 +227,61 @@ export function inferReactivePlaces(fn: HIRFunction): void {
227 } while (reactiveIdentifiers.snapshot() && hasLoop);
228 }
229
230 +/**
231 + * Computes the post-dominator frontier of @param block. These are immediate successors of nodes that
232 + * post-dominate @param targetId and from which execution may not reach @param block. Intuitively, these
233 + * are the earliest blocks from which execution branches such that it may or may not reach the target block.
234 + */
235 +function postDominatorFrontier(
236 + fn: HIRFunction,
237 + postDominators: PostDominator<BlockId>,
238 + targetId: BlockId
239 +): Set<BlockId> {
240 + const visited = new Set<BlockId>();
241 + const frontier = new Set<BlockId>();
242 + const targetPostDominators = postDominatorsOf(fn, postDominators, targetId);
243 + for (const blockId of [...targetPostDominators, targetId]) {
244 + if (visited.has(blockId)) {
245 + continue;
246 + }
247 + visited.add(blockId);
248 + const block = fn.body.blocks.get(blockId)!;
249 + for (const pred of block.preds) {
250 + if (!targetPostDominators.has(pred)) {
251 + // The predecessor does not always reach this block, we found an item on the frontier!
252 + frontier.add(pred);
253 + }
254 + }
255 + }
256 + return frontier;
257 +}
258 +
259 +function postDominatorsOf(
260 + fn: HIRFunction,
261 + postDominators: PostDominator<BlockId>,
262 + targetId: BlockId
263 +): Set<BlockId> {
264 + const result = new Set<BlockId>();
265 + const visited = new Set<BlockId>();
266 + const queue = [targetId];
267 + while (queue.length) {
268 + const currentId = queue.shift()!;
269 + if (visited.has(currentId)) {
270 + continue;
271 + }
272 + visited.add(currentId);
273 + const current = fn.body.blocks.get(currentId)!;
274 + for (const pred of current.preds) {
275 + const predPostDominator = postDominators.get(pred) ?? pred;
276 + if (predPostDominator === targetId || result.has(predPostDominator)) {
277 + result.add(pred);
278 + }
279 + queue.push(pred);
280 + }
281 + }
282 + return result;
283 +}
284 +
285 class ReactivityMap {
286 hasChanges: boolean = false;
287 reactive: Set<IdentifierId> = new Set();
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/InferReactiveIdentifiers.ts
+15
@@ -10,6 +10,8 @@ import { Environment } from "../HIR";
10 import {
11 Effect,
12 IdentifierId,
13 + InstructionId,
14 + Place,
15 ReactiveFunction,
16 ReactiveInstruction,
17 getHookKind,
@@ -35,6 +37,19 @@ class State {
37 }
38
39 class Visitor extends ReactiveFunctionVisitor<State> {
40 + override visitLValue(
41 + _id: InstructionId,
42 + _lvalue: Place,
43 + _state: State
44 + ): void {
45 + this.visitPlace(_id, _lvalue, _state);
46 + }
47 + override visitPlace(_id: InstructionId, _place: Place, _state: State): void {
48 + if (_place.reactive) {
49 + _state.reactivityMap.set(_place.identifier.id, _place.reactive);
50 + }
51 + }
52 +
53 override visitInstruction(instr: ReactiveInstruction, state: State): void {
54 this.traverseInstruction(instr, state);
55 const lval = instr.lvalue;
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/const-propagation-phi-nodes.expect.md
+7 -4
@@ -28,7 +28,7 @@ export const FIXTURE_ENTRYPOINT = {
28 ```javascript
29 import { unstable_useMemoCache as useMemoCache } from "react";
30 function useFoo(setOne) {
31 - const $ = useMemoCache(1);
31 + const $ = useMemoCache(4);
32 let x;
33 let y;
34 let z;
@@ -40,11 +40,14 @@ function useFoo(setOne) {
40 z = 5;
41 }
42 let t0;
43 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
43 + if ($[0] !== x || $[1] !== y || $[2] !== z) {
44 t0 = { x, y, z };
45 - $[0] = t0;
45 + $[0] = x;
46 + $[1] = y;
47 + $[2] = z;
48 + $[3] = t0;
49 } else {
47 - t0 = $[0];
50 + t0 = $[3];
51 }
52 return t0;
53 }
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-do-while-indirect.expect.md new
+57
@@ -0,0 +1,57 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + let x = 0;
7 + let y = 0;
8 + let z = 0;
9 + do {
10 + x += 1;
11 + y += 1;
12 + z = y;
13 + } while (x < props.limit);
14 + return [z];
15 +}
16 +
17 +export const FIXTURE_ENTRYPOINT = {
18 + fn: Component,
19 + params: [{ limit: 10 }],
20 + // TODO: test executing the sequence {limit: 10}, {limit: 1}, {limit: 10}
21 +};
22 +
23 +```
24 +
25 +## Code
26 +
27 +```javascript
28 +import { unstable_useMemoCache as useMemoCache } from "react";
29 +function Component(props) {
30 + const $ = useMemoCache(2);
31 + let x = 0;
32 + let y = 0;
33 + let z;
34 + do {
35 + x = x + 1;
36 + y = y + 1;
37 + z = y;
38 + } while (x < props.limit);
39 + let t0;
40 + if ($[0] !== z) {
41 + t0 = [z];
42 + $[0] = z;
43 + $[1] = t0;
44 + } else {
45 + t0 = $[1];
46 + }
47 + return t0;
48 +}
49 +
50 +export const FIXTURE_ENTRYPOINT = {
51 + fn: Component,
52 + params: [{ limit: 10 }],
53 + // TODO: test executing the sequence {limit: 10}, {limit: 1}, {limit: 10}
54 +};
55 +
56 +```
57 +
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-do-while-indirect.js new
+17
@@ -0,0 +1,17 @@
1 +function Component(props) {
2 + let x = 0;
3 + let y = 0;
4 + let z = 0;
5 + do {
6 + x += 1;
7 + y += 1;
8 + z = y;
9 + } while (x < props.limit);
10 + return [z];
11 +}
12 +
13 +export const FIXTURE_ENTRYPOINT = {
14 + fn: Component,
15 + params: [{ limit: 10 }],
16 + // TODO: test executing the sequence {limit: 10}, {limit: 1}, {limit: 10}
17 +};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-do-while-test.expect.md renamed
+5 -4
@@ -32,7 +32,7 @@ export const FIXTURE_ENTRYPOINT = {
32 ```javascript
33 import { unstable_useMemoCache as useMemoCache } from "react";
34 function Component(props) {
35 - const $ = useMemoCache(1);
35 + const $ = useMemoCache(2);
36 let x;
37 let i = 0;
38 do {
@@ -45,11 +45,12 @@ function Component(props) {
45 i++;
46 } while (i < props.test);
47 let t0;
48 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
48 + if ($[0] !== x) {
49 t0 = [x];
50 - $[0] = t0;
50 + $[0] = x;
51 + $[1] = t0;
52 } else {
52 - t0 = $[0];
53 + t0 = $[1];
54 }
55 return t0;
56 }
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-do-while-test.js renamed
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-for-init.expect.md renamed
+5 -4
@@ -31,7 +31,7 @@ export const FIXTURE_ENTRYPOINT = {
31 ```javascript
32 import { unstable_useMemoCache as useMemoCache } from "react";
33 function Component(props) {
34 - const $ = useMemoCache(1);
34 + const $ = useMemoCache(2);
35 let x;
36 for (const i = props.init; i < 10; ) {
37 if (i === 0) {
@@ -43,11 +43,12 @@ function Component(props) {
43 }
44 }
45 let t0;
46 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
46 + if ($[0] !== x) {
47 t0 = [x];
48 - $[0] = t0;
48 + $[0] = x;
49 + $[1] = t0;
50 } else {
50 - t0 = $[0];
51 + t0 = $[1];
52 }
53 return t0;
54 }
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-for-init.js renamed
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-for-test.expect.md renamed
+5 -4
@@ -30,7 +30,7 @@ export const FIXTURE_ENTRYPOINT = {
30 ```javascript
31 import { unstable_useMemoCache as useMemoCache } from "react";
32 function Component(props) {
33 - const $ = useMemoCache(1);
33 + const $ = useMemoCache(2);
34 let x;
35 for (let i = 0; i < props.test; i++) {
36 if (i > 10) {
@@ -40,11 +40,12 @@ function Component(props) {
40 }
41 }
42 let t0;
43 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
43 + if ($[0] !== x) {
44 t0 = [x];
45 - $[0] = t0;
45 + $[0] = x;
46 + $[1] = t0;
47 } else {
47 - t0 = $[0];
48 + t0 = $[1];
49 }
50 return t0;
51 }
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-for-test.js renamed
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-for-update.expect.md renamed
+5 -4
@@ -30,7 +30,7 @@ export const FIXTURE_ENTRYPOINT = {
30 ```javascript
31 import { unstable_useMemoCache as useMemoCache } from "react";
32 function Component(props) {
33 - const $ = useMemoCache(1);
33 + const $ = useMemoCache(2);
34 let x;
35 for (let i = 0; i < 10; i = i + props.update, i) {
36 if (i > 0 && i % 2 === 0) {
@@ -40,11 +40,12 @@ function Component(props) {
40 }
41 }
42 let t0;
43 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
43 + if ($[0] !== x) {
44 t0 = [x];
45 - $[0] = t0;
45 + $[0] = x;
46 + $[1] = t0;
47 } else {
47 - t0 = $[0];
48 + t0 = $[1];
49 }
50 return t0;
51 }
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-for-update.js renamed
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-forin-collection.expect.md renamed
+5 -4
@@ -31,7 +31,7 @@ export const FIXTURE_ENTRYPOINT = {
31 ```javascript
32 import { unstable_useMemoCache as useMemoCache } from "react";
33 function Component(props) {
34 - const $ = useMemoCache(1);
34 + const $ = useMemoCache(2);
35 let x;
36 for (const key in props.values) {
37 const i = parseInt(key, 10);
@@ -42,11 +42,12 @@ function Component(props) {
42 }
43 }
44 let t0;
45 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
45 + if ($[0] !== x) {
46 t0 = [x];
47 - $[0] = t0;
47 + $[0] = x;
48 + $[1] = t0;
49 } else {
49 - t0 = $[0];
50 + t0 = $[1];
51 }
52 return t0;
53 }
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-forin-collection.js renamed
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-forof-collection.expect.md renamed
+5 -4
@@ -30,7 +30,7 @@ export const FIXTURE_ENTRYPOINT = {
30 ```javascript
31 import { unstable_useMemoCache as useMemoCache } from "react";
32 function Component(props) {
33 - const $ = useMemoCache(1);
33 + const $ = useMemoCache(2);
34 let x;
35 for (const i of props.values) {
36 if (i > 10) {
@@ -40,11 +40,12 @@ function Component(props) {
40 }
41 }
42 let t0;
43 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
43 + if ($[0] !== x) {
44 t0 = [x];
45 - $[0] = t0;
45 + $[0] = x;
46 + $[1] = t0;
47 } else {
47 - t0 = $[0];
48 + t0 = $[1];
49 }
50 return t0;
51 }
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-forof-collection.js renamed
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-if.expect.md renamed
+5 -4
@@ -27,7 +27,7 @@ export const FIXTURE_ENTRYPOINT = {
27 ```javascript
28 import { unstable_useMemoCache as useMemoCache } from "react";
29 function Component(props) {
30 - const $ = useMemoCache(1);
30 + const $ = useMemoCache(2);
31 let x;
32 if (props.cond) {
33 x = 1;
@@ -35,11 +35,12 @@ function Component(props) {
35 x = 2;
36 }
37 let t0;
38 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
38 + if ($[0] !== x) {
39 t0 = [x];
40 - $[0] = t0;
40 + $[0] = x;
41 + $[1] = t0;
42 } else {
42 - t0 = $[0];
43 + t0 = $[1];
44 }
45 return t0;
46 }
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-if.js renamed
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-reactive-after-fixpoint.expect.md renamed
+5 -4
@@ -41,7 +41,7 @@ export const FIXTURE_ENTRYPOINT = {
41 ```javascript
42 import { unstable_useMemoCache as useMemoCache } from "react";
43 function Component(props) {
44 - const $ = useMemoCache(1);
44 + const $ = useMemoCache(2);
45 let x = 0;
46
47 let value = null;
@@ -60,11 +60,12 @@ function Component(props) {
60 value = props.value;
61 }
62 let t0;
63 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
63 + if ($[0] !== x) {
64 t0 = [x];
65 - $[0] = t0;
65 + $[0] = x;
66 + $[1] = t0;
67 } else {
67 - t0 = $[0];
68 + t0 = $[1];
69 }
70 return t0;
71 }
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-reactive-after-fixpoint.js renamed
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-switch-case-test.expect.md renamed
+5 -4
@@ -35,7 +35,7 @@ export const FIXTURE_ENTRYPOINT = {
35 ```javascript
36 import { unstable_useMemoCache as useMemoCache } from "react";
37 function Component(props) {
38 - const $ = useMemoCache(1);
38 + const $ = useMemoCache(2);
39 let x;
40 bb1: switch (props.cond) {
41 case true: {
@@ -51,11 +51,12 @@ function Component(props) {
51 }
52 }
53 let t0;
54 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
54 + if ($[0] !== x) {
55 t0 = [x];
56 - $[0] = t0;
56 + $[0] = x;
57 + $[1] = t0;
58 } else {
58 - t0 = $[0];
59 + t0 = $[1];
60 }
61 return t0;
62 }
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-switch-case-test.js renamed
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-switch-condition.expect.md renamed
+5 -4
@@ -36,7 +36,7 @@ import { unstable_useMemoCache as useMemoCache } from "react";
36 const GLOBAL = 42;
37
38 function Component(t14) {
39 - const $ = useMemoCache(1);
39 + const $ = useMemoCache(2);
40 const { value } = t14;
41 let x;
42 bb1: switch (GLOBAL) {
@@ -49,11 +49,12 @@ function Component(t14) {
49 }
50 }
51 let t0;
52 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
52 + if ($[0] !== x) {
53 t0 = [x];
54 - $[0] = t0;
54 + $[0] = x;
55 + $[1] = t0;
56 } else {
56 - t0 = $[0];
57 + t0 = $[1];
58 }
59 return t0;
60 }
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-switch-condition.js renamed
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-while-test.expect.md renamed
+5 -4
@@ -32,7 +32,7 @@ export const FIXTURE_ENTRYPOINT = {
32 ```javascript
33 import { unstable_useMemoCache as useMemoCache } from "react";
34 function Component(props) {
35 - const $ = useMemoCache(1);
35 + const $ = useMemoCache(2);
36 let x;
37 let i = 0;
38 while (i < props.test) {
@@ -45,11 +45,12 @@ function Component(props) {
45 i++;
46 }
47 let t0;
48 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
48 + if ($[0] !== x) {
49 t0 = [x];
50 - $[0] = t0;
50 + $[0] = x;
51 + $[1] = t0;
52 } else {
52 - t0 = $[0];
53 + t0 = $[1];
54 }
55 return t0;
56 }
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-while-test.js renamed
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-dependency-fixpoint.expect.md renamed
+5 -4
@@ -30,7 +30,7 @@ export const FIXTURE_ENTRYPOINT = {
30 ```javascript
31 import { unstable_useMemoCache as useMemoCache } from "react";
32 function Component(props) {
33 - const $ = useMemoCache(1);
33 + const $ = useMemoCache(2);
34 let x = 0;
35 let y = 0;
36 while (x === 0) {
@@ -38,11 +38,12 @@ function Component(props) {
38 y = props.value;
39 }
40 let t0;
41 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
41 + if ($[0] !== x) {
42 t0 = [x];
43 - $[0] = t0;
43 + $[0] = x;
44 + $[1] = t0;
45 } else {
45 - t0 = $[0];
46 + t0 = $[1];
47 }
48 return t0;
49 }
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-dependency-fixpoint.js renamed
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/ssa-cascading-eliminated-phis.expect.md
+7 -6
@@ -31,10 +31,10 @@ export const FIXTURE_ENTRYPOINT = {
31 ```javascript
32 import { unstable_useMemoCache as useMemoCache } from "react";
33 function Component(props) {
34 - const $ = useMemoCache(3);
34 + const $ = useMemoCache(4);
35 let x = 0;
36 let values;
37 - if ($[0] !== props) {
37 + if ($[0] !== props || $[1] !== x) {
38 values = [];
39 const y = props.a || props.b;
40 values.push(y);
@@ -49,11 +49,12 @@ function Component(props) {
49
50 values.push(x);
51 $[0] = props;
52 - $[1] = values;
53 - $[2] = x;
52 + $[1] = x;
53 + $[2] = values;
54 + $[3] = x;
55 } else {
55 - values = $[1];
56 - x = $[2];
56 + values = $[2];
57 + x = $[3];
58 }
59 return values;
60 }