[ReactiveHIR] Infer reactive identifiers and promote temporaries
Messed up ghstack, this is a duplicate of #1093
mofeiZ committed
Feb 3, 2023 at 14:52 UTC
ecb084c4b8b0e7dddadf5fce73e194a8b58d3187
46 files changed
+505
-344
compiler/forget/src/CompilerPipeline.ts
+8
@@ -27,6 +27,7 @@ import {
27
flattenReactiveLoops,
28
inferReactiveScopeVariables,
29
mergeOverlappingReactiveScopes,
30
+ promoteUsedTemporaries,
31
propagateScopeDependencies,
32
pruneUnusedLabels,
33
pruneUnusedLValues,
@@ -128,6 +129,13 @@ export function* run(
129
value: reactiveFunction,
130
});
131
132
+ promoteUsedTemporaries(reactiveFunction);
133
+ yield log({
134
+ kind: "reactive",
135
+ name: "promoteUsedTemporaries",
136
+ value: reactiveFunction,
137
+ });
138
+
139
pruneUnusedLabels(reactiveFunction);
140
yield log({
141
kind: "reactive",
compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts
+5
-2
@@ -185,8 +185,11 @@ function codegenReactiveScope(
185
firstOutputIndex = index;
186
}
187
188
- // TODO @josephsavona: ensure change and temp variables have non-conflicting names
189
- output.name ??= `t${index}`;
188
+ invariant(
189
+ output.name != null,
190
+ "Expected identifier '@%s' to be named",
191
+ output.id
192
+ );
193
194
const name = convertIdentifier(output);
195
cx.declare(output);
compiler/forget/src/ReactiveScopes/InferReactiveIdentifiers.ts
new
+127
@@ -0,0 +1,127 @@
1
+/**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+import {
9
+ Identifier,
10
+ ReactiveFunction,
11
+ ReactiveInstruction,
12
+ ReactiveScope,
13
+} from "../HIR/HIR";
14
+import {
15
+ eachReactiveValueOperand,
16
+ ReactiveFunctionVisitor,
17
+ visitReactiveFunction,
18
+} from "./visitors";
19
+
20
+type IdentifierReactivity = Map<Identifier, boolean>;
21
+class Environment extends ReactiveFunctionVisitor<IdentifierReactivity> {
22
+ override visitInstruction(
23
+ instr: ReactiveInstruction,
24
+ reactivityMap: IdentifierReactivity
25
+ ) {
26
+ this.traverseInstruction(instr, reactivityMap);
27
+ const lval = instr.lvalue;
28
+ if (lval == null || reactivityMap.get(lval.place.identifier) === true) {
29
+ return;
30
+ }
31
+ const { value } = instr;
32
+ let hasReactiveInput = false;
33
+ for (const operand of eachReactiveValueOperand(value)) {
34
+ // We currently treat free variables (from module or global scope) as
35
+ // non-reactive. We may later want type information about specific
36
+ // free variables, or a toggle `treatFreeVarsAsReactive`.
37
+ if (reactivityMap.get(operand.identifier)) {
38
+ hasReactiveInput = true;
39
+ break;
40
+ }
41
+ }
42
+ reactivityMap.set(lval.place.identifier, hasReactiveInput);
43
+
44
+ if (hasReactiveInput) {
45
+ // all mutating effects must also be marked as reactive
46
+ for (const operand of eachReactiveValueOperand(value)) {
47
+ if (operand.effect === "store" || operand.effect === "mutate") {
48
+ // Explicitly compare to `false` here, since absence from the
49
+ // map indicates a free variable
50
+ // todo [@mofeiZ] add knowledge about free variables
51
+ if (reactivityMap.get(operand.identifier) === false) {
52
+ reactivityMap.set(operand.identifier, true);
53
+ }
54
+ }
55
+ }
56
+ }
57
+ }
58
+}
59
+/**
60
+ * Computes a map of {@link Place} -> reactivityMap. A Place is reactive if any
61
+ * operant used in its construction is reactive. Sources of reactivity are
62
+ * {@link ReactiveFunction.params} and HookCall return values (TODO).
63
+ * Free values are currently not populated.
64
+ *
65
+ * This relies on alias analysis done by InferReactiveScopeVariables, which
66
+ * creates reactive scopes for variables that mutate together. If one value
67
+ * declared in a scope is Reactive, then the rest are marked as reactive as
68
+ * well.
69
+ * e.g.
70
+ * ```javascript
71
+ * function foo(props) {
72
+ * let x = {};
73
+ * let y = [];
74
+ * x.y = y;
75
+ * y.push(props.a)
76
+ * // references to x are reactive here
77
+ * }
78
+ * ```
79
+ * This an overestimate when two identifiers have overlapping scope, but
80
+ * one is not actually reactive. However, since the same ReactiveBlock now
81
+ * produces both identifiers, they are effectively both effective (i.e.
82
+ * object creation is not stable)
83
+ * e.g.
84
+ * ```javascript
85
+ * function bar(props) {
86
+ * let x = {};
87
+ * let y = [];
88
+ * mutate1(x, props);
89
+ * mutate2(y);
90
+ * }
91
+ * ```
92
+ */
93
+export function inferReactiveIdentifiers(
94
+ fn: ReactiveFunction
95
+): Set<Identifier> {
96
+ const visitor = new Environment();
97
+ const reactivityMap: IdentifierReactivity = new Map();
98
+ for (const param of fn.params) {
99
+ reactivityMap.set(param.identifier, true);
100
+ }
101
+ const actuallyReactiveScopes = new Set<ReactiveScope>();
102
+ let prevScopesSize = -1;
103
+
104
+ // TODO(mofeiZ): avoid fixpoint iteration by keeping a map of identifiers
105
+ // read by a ReactiveScope (that are produced outside of it)
106
+ while (actuallyReactiveScopes.size > prevScopesSize) {
107
+ prevScopesSize = actuallyReactiveScopes.size;
108
+ visitReactiveFunction(fn, visitor, reactivityMap);
109
+
110
+ for (const [id, value] of reactivityMap) {
111
+ const { scope } = id;
112
+ if (value && scope != null) {
113
+ actuallyReactiveScopes.add(scope);
114
+ }
115
+ }
116
+ for (const [id, _] of reactivityMap) {
117
+ if (id.scope && actuallyReactiveScopes.has(id.scope)) {
118
+ reactivityMap.set(id, true);
119
+ }
120
+ }
121
+ }
122
+ const result = new Set<Identifier>();
123
+ reactivityMap.forEach((isReactive, id) => {
124
+ if (isReactive) result.add(id);
125
+ });
126
+ return result;
127
+}
compiler/forget/src/ReactiveScopes/PromoteUsedTemporaries.ts
new
+37
@@ -0,0 +1,37 @@
1
+/**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+import { ReactiveFunction, ReactiveScopeBlock } from "../HIR/HIR";
9
+import { ReactiveFunctionVisitor, visitReactiveFunction } from "./visitors";
10
+
11
+type VisitorState = {
12
+ nextId: number;
13
+};
14
+class Visitor extends ReactiveFunctionVisitor<VisitorState> {
15
+ override visitScope(block: ReactiveScopeBlock, state: VisitorState) {
16
+ this.traverseScope(block, state);
17
+ for (const dep of block.scope.dependencies) {
18
+ const { identifier } = dep.place;
19
+ if (identifier.name == null) {
20
+ identifier.name = `t${state.nextId++}`;
21
+ }
22
+ }
23
+ // This is technically optional. We could prune ReactiveScopes
24
+ // whose outputs are not used in another computation or return
25
+ // value.
26
+ // Many of our current test fixtures do not return a value, so
27
+ // it is better for now to promote (and memoize) every output.
28
+ for (const identifier of block.scope.outputs) {
29
+ if (identifier.name == null) {
30
+ identifier.name = `t${state.nextId++}`;
31
+ }
32
+ }
33
+ }
34
+}
35
+export function promoteUsedTemporaries(fn: ReactiveFunction) {
36
+ visitReactiveFunction(fn, new Visitor(), { nextId: 0 });
37
+}
compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts
+18
-11
@@ -9,7 +9,6 @@ import {
9
Identifier,
10
InstructionId,
11
InstructionKind,
12
- isPrimitiveType,
12
LValue,
13
makeInstructionId,
14
Place,
@@ -22,6 +21,7 @@ import {
21
} from "../HIR/HIR";
22
import { eachInstructionValueOperand } from "../HIR/visitors";
23
import { assertExhaustive } from "../Utils/utils";
24
+import { inferReactiveIdentifiers } from "./InferReactiveIdentifiers";
25
import { eachReactiveValueOperand } from "./visitors";
26
27
/**
@@ -31,7 +31,7 @@ import { eachReactiveValueOperand } from "./visitors";
31
* their direct dependencies and those of their child scopes.
32
*/
33
export function propagateScopeDependencies(fn: ReactiveFunction): void {
34
- const context = new Context();
34
+ const context = new Context(inferReactiveIdentifiers(fn));
35
if (fn.id !== null) {
36
context.declare(fn.id, { kind: DeclKind.Const, id: makeInstructionId(0) });
37
}
@@ -57,9 +57,16 @@ type Scopes = Array<ReactiveScope>;
57
class Context {
58
#declarations: DeclMap = new Map();
59
#dependencies: Set<ReactiveScopeDependency> = new Set();
60
+ #reactiveIdentifiers: Set<Identifier>;
61
+ // Produces a de-duplicated mapping of Id -> ReactiveScopeDependency
62
+ // This helps with.. temporaries that are created only for property loads
63
+ // but can be generalized to all non-allocating temporaries
64
#properties: Map<Identifier, ReactiveScopeDependency> = new Map();
65
#scopes: Scopes = [];
66
67
+ constructor(reactiveIdentifiers: Set<Identifier>) {
68
+ this.#reactiveIdentifiers = reactiveIdentifiers;
69
+ }
70
enter(scope: ReactiveScope, fn: () => void): Set<ReactiveScopeDependency> {
71
const previousDependencies = this.#dependencies;
72
const scopedDependencies = new Set<ReactiveScopeDependency>();
@@ -97,6 +104,10 @@ class Context {
104
return this.#scopes.at(-1)!;
105
}
106
107
+ isReactive(id: Identifier): boolean {
108
+ return this.#reactiveIdentifiers.has(id);
109
+ }
110
+
111
visitOperand(place: Place): void {
112
this.visitDependency({ place, path: null });
113
}
@@ -133,6 +144,8 @@ class Context {
144
}
145
146
const decl = this.#declarations.get(maybeDependency.place.identifier);
147
+ // if decl is undefined here, then this is a free var
148
+ // (all other decls e.g. `let x;` should be initialized in BuildHIR)
149
150
// Any value used after its defining scope has concluded must be added as an
151
// output of its defining scope. Regardless of whether its a const or not,
@@ -323,19 +336,13 @@ function visitInstruction(context: Context, instr: ReactiveInstruction): void {
336
const { lvalue } = instr;
337
visitInstructionValue(context, instr.value, lvalue);
338
if (lvalue !== null && lvalue.kind !== InstructionKind.Reassign) {
326
- const range = lvalue.place.identifier.mutableRange;
339
// TODO: only assign Const if the value is never reassigned
328
- const kind =
329
- range.end === range.start + 1
330
- ? valueKind(lvalue.place.identifier)
331
- : DeclKind.Dynamic;
340
+ const kind = context.isReactive(lvalue.place.identifier)
341
+ ? DeclKind.Dynamic
342
+ : DeclKind.Const;
343
context.declare(lvalue.place.identifier, {
344
kind,
345
id: lvalue.place.identifier.mutableRange.start,
346
});
347
}
348
}
338
-
339
-function valueKind(id: Identifier): DeclKind {
340
- return isPrimitiveType(id) ? DeclKind.Const : DeclKind.Dynamic;
341
-}
compiler/forget/src/ReactiveScopes/index.ts
+1
@@ -13,6 +13,7 @@ export { flattenReactiveLoops } from "./FlattenReactiveLoops";
13
export { inferReactiveScopeVariables } from "./InferReactiveScopeVariables";
14
export { mergeOverlappingReactiveScopes } from "./MergeOverlappingReactiveScopes";
15
export { printReactiveFunction } from "./PrintReactiveFunction";
16
+export { promoteUsedTemporaries } from "./PromoteUsedTemporaries";
17
export { propagateScopeDependencies } from "./PropagateScopeDependencies";
18
export { pruneTemporaryLValues as pruneUnusedLValues } from "./PruneTemporaryLValues";
19
export { pruneUnusedLabels } from "./PruneUnusedLabels";
compiler/forget/src/__tests__/fixtures/hir/alias-nested-member-path.expect.md
+6
-10
@@ -25,25 +25,21 @@ function component() {
25
} else {
26
z = $[0];
27
}
28
- const c_1 = $[1] !== z;
28
let y;
30
- if (c_1) {
29
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
30
y = {};
31
y.z = z;
33
- $[1] = z;
34
- $[2] = y;
32
+ $[1] = y;
33
} else {
36
- y = $[2];
34
+ y = $[1];
35
}
38
- const c_3 = $[3] !== y;
36
let x;
40
- if (c_3) {
37
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
38
x = {};
39
x.y = y;
43
- $[3] = y;
44
- $[4] = x;
40
+ $[2] = x;
41
} else {
46
- x = $[4];
42
+ x = $[2];
43
}
44
return x;
45
}
compiler/forget/src/__tests__/fixtures/hir/call.expect.md
+6
-10
@@ -36,18 +36,14 @@ function Component(props) {
36
a = $[0];
37
b = $[1];
38
}
39
- const c_2 = $[2] !== a;
40
- const c_3 = $[3] !== b;
41
- let t4;
42
- if (c_2 || c_3) {
43
- t4 = <div a={a} b={b}></div>;
44
- $[2] = a;
45
- $[3] = b;
46
- $[4] = t4;
39
+ let t0;
40
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
41
+ t0 = <div a={a} b={b}></div>;
42
+ $[2] = t0;
43
} else {
48
- t4 = $[4];
44
+ t0 = $[2];
45
}
50
- return t4;
46
+ return t0;
47
}
48
49
```
compiler/forget/src/__tests__/fixtures/hir/capture-param-mutate.expect.md
+5
-5
@@ -48,9 +48,9 @@ function getNativeLogFunction(level) {
48
function getNativeLogFunction(level) {
49
const $ = React.useMemoCache();
50
const c_0 = $[0] !== level;
51
- let t1;
51
+ let t0;
52
if (c_0) {
53
- t1 = function () {
53
+ t0 = function () {
54
let str;
55
if (arguments.length === 1 && typeof arguments[0] === "string") {
56
str = arguments[0];
@@ -86,11 +86,11 @@ function getNativeLogFunction(level) {
86
global.nativeLoggingHook(str, logLevel);
87
};
88
$[0] = level;
89
- $[1] = t1;
89
+ $[1] = t0;
90
} else {
91
- t1 = $[1];
91
+ t0 = $[1];
92
}
93
- return t1;
93
+ return t0;
94
}
95
96
```
compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-call.expect.md
+7
-7
@@ -18,19 +18,19 @@ function component(a) {
18
function component(a) {
19
const $ = React.useMemoCache();
20
const c_0 = $[0] !== a;
21
- let t1;
21
+ let t0;
22
if (c_0) {
23
- t1 = { a: a };
23
+ t0 = { a: a };
24
$[0] = a;
25
- $[1] = t1;
25
+ $[1] = t0;
26
} else {
27
- t1 = $[1];
27
+ t0 = $[1];
28
}
29
- const c_2 = $[2] !== t1;
29
+ const c_2 = $[2] !== t0;
30
let z;
31
if (c_2) {
32
- z = { a: t1 };
33
- $[2] = t1;
32
+ z = { a: t0 };
33
+ $[2] = t0;
34
$[3] = z;
35
} else {
36
z = $[3];
compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr-in-nested-func.expect.md
+7
-7
@@ -20,19 +20,19 @@ function component(a) {
20
function component(a) {
21
const $ = React.useMemoCache();
22
const c_0 = $[0] !== a;
23
- let t1;
23
+ let t0;
24
if (c_0) {
25
- t1 = { a: a };
25
+ t0 = { a: a };
26
$[0] = a;
27
- $[1] = t1;
27
+ $[1] = t0;
28
} else {
29
- t1 = $[1];
29
+ t0 = $[1];
30
}
31
- const c_2 = $[2] !== t1;
31
+ const c_2 = $[2] !== t0;
32
let z;
33
if (c_2) {
34
- z = { a: t1 };
35
- $[2] = t1;
34
+ z = { a: t0 };
35
+ $[2] = t0;
36
$[3] = z;
37
} else {
38
z = $[3];
compiler/forget/src/__tests__/fixtures/hir/capturing-nested-member-expr.expect.md
+7
-7
@@ -18,19 +18,19 @@ function component(a) {
18
function component(a) {
19
const $ = React.useMemoCache();
20
const c_0 = $[0] !== a;
21
- let t1;
21
+ let t0;
22
if (c_0) {
23
- t1 = { a: a };
23
+ t0 = { a: a };
24
$[0] = a;
25
- $[1] = t1;
25
+ $[1] = t0;
26
} else {
27
- t1 = $[1];
27
+ t0 = $[1];
28
}
29
- const c_2 = $[2] !== t1;
29
+ const c_2 = $[2] !== t0;
30
let z;
31
if (c_2) {
32
- z = { a: t1 };
33
- $[2] = t1;
32
+ z = { a: t0 };
33
+ $[2] = t0;
34
$[3] = z;
35
} else {
36
z = $[3];
compiler/forget/src/__tests__/fixtures/hir/component.expect.md
+12
-12
@@ -74,31 +74,31 @@ function Component(props) {
74
75
const count = renderedItems.length;
76
const c_5 = $[5] !== count;
77
- let t6;
77
+ let t0;
78
if (c_5) {
79
- t6 = <h1>{count} Items</h1>;
79
+ t0 = <h1>{count} Items</h1>;
80
$[5] = count;
81
- $[6] = t6;
81
+ $[6] = t0;
82
} else {
83
- t6 = $[6];
83
+ t0 = $[6];
84
}
85
- const c_7 = $[7] !== t6;
85
+ const c_7 = $[7] !== t0;
86
const c_8 = $[8] !== renderedItems;
87
- let t9;
87
+ let t1;
88
if (c_7 || c_8) {
89
- t9 = (
89
+ t1 = (
90
<div>
91
- {t6}
91
+ {t0}
92
{renderedItems}
93
</div>
94
);
95
- $[7] = t6;
95
+ $[7] = t0;
96
$[8] = renderedItems;
97
- $[9] = t9;
97
+ $[9] = t1;
98
} else {
99
- t9 = $[9];
99
+ t1 = $[9];
100
}
101
- return t9;
101
+ return t1;
102
}
103
104
```
compiler/forget/src/__tests__/fixtures/hir/concise-arrow-expr.expect.md
+9
-13
@@ -24,25 +24,21 @@ function component() {
24
}
25
const x = t0[0];
26
const setX = t0[1];
27
- const c_1 = $[1] !== setX;
27
let handler;
29
- if (c_1) {
28
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
29
handler = (v) => setX(v);
31
- $[1] = setX;
32
- $[2] = handler;
30
+ $[1] = handler;
31
} else {
34
- handler = $[2];
32
+ handler = $[1];
33
}
36
- const c_3 = $[3] !== handler;
37
- let t4;
38
- if (c_3) {
39
- t4 = <Foo handler={handler}></Foo>;
40
- $[3] = handler;
41
- $[4] = t4;
34
+ let t1;
35
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
36
+ t1 = <Foo handler={handler}></Foo>;
37
+ $[2] = t1;
38
} else {
43
- t4 = $[4];
39
+ t1 = $[2];
40
}
45
- return t4;
41
+ return t1;
42
}
43
44
```
compiler/forget/src/__tests__/fixtures/hir/conditional-on-mutable.expect.md
+10
-10
@@ -61,16 +61,16 @@ function ComponentA(props) {
61
}
62
const c_5 = $[5] !== a;
63
const c_6 = $[6] !== b;
64
- let t7;
64
+ let t0;
65
if (c_5 || c_6) {
66
- t7 = <Foo a={a} b={b}></Foo>;
66
+ t0 = <Foo a={a} b={b}></Foo>;
67
$[5] = a;
68
$[6] = b;
69
- $[7] = t7;
69
+ $[7] = t0;
70
} else {
71
- t7 = $[7];
71
+ t0 = $[7];
72
}
73
- return t7;
73
+ return t0;
74
}
75
76
function ComponentB(props) {
@@ -100,16 +100,16 @@ function ComponentB(props) {
100
}
101
const c_5 = $[5] !== a;
102
const c_6 = $[6] !== b;
103
- let t7;
103
+ let t0;
104
if (c_5 || c_6) {
105
- t7 = <Foo a={a} b={b}></Foo>;
105
+ t0 = <Foo a={a} b={b}></Foo>;
106
$[5] = a;
107
$[6] = b;
108
- $[7] = t7;
108
+ $[7] = t0;
109
} else {
110
- t7 = $[7];
110
+ t0 = $[7];
111
}
112
- return t7;
112
+ return t0;
113
}
114
115
function Foo() {}
compiler/forget/src/__tests__/fixtures/hir/constructor.expect.md
+6
-10
@@ -37,18 +37,14 @@ function Component(props) {
37
a = $[0];
38
b = $[1];
39
}
40
- const c_2 = $[2] !== a;
41
- const c_3 = $[3] !== b;
42
- let t4;
43
- if (c_2 || c_3) {
44
- t4 = <div a={a} b={b}></div>;
45
- $[2] = a;
46
- $[3] = b;
47
- $[4] = t4;
40
+ let t0;
41
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
42
+ t0 = <div a={a} b={b}></div>;
43
+ $[2] = t0;
44
} else {
49
- t4 = $[4];
45
+ t0 = $[2];
46
}
51
- return t4;
47
+ return t0;
48
}
49
50
```
compiler/forget/src/__tests__/fixtures/hir/hook-call.expect.md
+9
-15
@@ -34,33 +34,27 @@ function Component(props) {
34
} else {
35
x = $[0];
36
}
37
- const c_1 = $[1] !== x;
37
let y;
39
- if (c_1) {
38
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
39
y = useFreeze(x);
41
- $[1] = x;
42
- $[2] = y;
40
+ $[1] = y;
41
} else {
44
- y = $[2];
42
+ y = $[1];
43
}
44
foo(y, x);
47
- const c_3 = $[3] !== x;
48
- const c_4 = $[4] !== y;
49
- let t5;
50
- if (c_3 || c_4) {
51
- t5 = (
45
+ let t0;
46
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
47
+ t0 = (
48
<Component>
49
{x}
50
{y}
51
</Component>
52
);
57
- $[3] = x;
58
- $[4] = y;
59
- $[5] = t5;
53
+ $[2] = t0;
54
} else {
61
- t5 = $[5];
55
+ t0 = $[2];
56
}
63
- return t5;
57
+ return t0;
58
}
59
60
```
compiler/forget/src/__tests__/fixtures/hir/independent-across-if.expect.md
+5
-5
@@ -80,16 +80,16 @@ function Component(props) {
80
}
81
const c_5 = $[5] !== a;
82
const c_6 = $[6] !== b;
83
- let t7;
83
+ let t0;
84
if (c_5 || c_6) {
85
- t7 = <Foo a={a} b={b}></Foo>;
85
+ t0 = <Foo a={a} b={b}></Foo>;
86
$[5] = a;
87
$[6] = b;
88
- $[7] = t7;
88
+ $[7] = t0;
89
} else {
90
- t7 = $[7];
90
+ t0 = $[7];
91
}
92
- return t7;
92
+ return t0;
93
}
94
95
```
compiler/forget/src/__tests__/fixtures/hir/independent.expect.md
+5
-5
@@ -59,16 +59,16 @@ function Component(props) {
59
}
60
const c_4 = $[4] !== a;
61
const c_5 = $[5] !== b;
62
- let t6;
62
+ let t0;
63
if (c_4 || c_5) {
64
- t6 = <Foo a={a} b={b}></Foo>;
64
+ t0 = <Foo a={a} b={b}></Foo>;
65
$[4] = a;
66
$[5] = b;
67
- $[6] = t6;
67
+ $[6] = t0;
68
} else {
69
- t6 = $[6];
69
+ t0 = $[6];
70
}
71
- return t6;
71
+ return t0;
72
}
73
74
function compute() {}
compiler/forget/src/__tests__/fixtures/hir/independently-memoize-object-property.expect.md
+5
-5
@@ -25,16 +25,16 @@ function foo(a, b, c) {
25
x = { a: a };
26
const c_4 = $[4] !== b;
27
const c_5 = $[5] !== c;
28
- let t6;
28
+ let t0;
29
if (c_4 || c_5) {
30
- t6 = [b, c];
30
+ t0 = [b, c];
31
$[4] = b;
32
$[5] = c;
33
- $[6] = t6;
33
+ $[6] = t0;
34
} else {
35
- t6 = $[6];
35
+ t0 = $[6];
36
}
37
- x.y = t6;
37
+ x.y = t0;
38
$[0] = a;
39
$[1] = b;
40
$[2] = c;
compiler/forget/src/__tests__/fixtures/hir/interdependent-across-if.expect.md
+5
-5
@@ -68,16 +68,16 @@ function Component(props) {
68
}
69
const c_5 = $[5] !== a;
70
const c_6 = $[6] !== b;
71
- let t7;
71
+ let t0;
72
if (c_5 || c_6) {
73
- t7 = <Foo a={a} b={b}></Foo>;
73
+ t0 = <Foo a={a} b={b}></Foo>;
74
$[5] = a;
75
$[6] = b;
76
- $[7] = t7;
76
+ $[7] = t0;
77
} else {
78
- t7 = $[7];
78
+ t0 = $[7];
79
}
80
- return t7;
80
+ return t0;
81
}
82
83
```
compiler/forget/src/__tests__/fixtures/hir/interdependent.expect.md
+5
-5
@@ -56,16 +56,16 @@ function Component(props) {
56
}
57
const c_4 = $[4] !== a;
58
const c_5 = $[5] !== b;
59
- let t6;
59
+ let t0;
60
if (c_4 || c_5) {
61
- t6 = <Foo a={a} b={b}></Foo>;
61
+ t0 = <Foo a={a} b={b}></Foo>;
62
$[4] = a;
63
$[5] = b;
64
- $[6] = t6;
64
+ $[6] = t0;
65
} else {
66
- t6 = $[6];
66
+ t0 = $[6];
67
}
68
- return t6;
68
+ return t0;
69
}
70
71
function compute() {}
compiler/forget/src/__tests__/fixtures/hir/jsx-fragment.expect.md
+14
-18
@@ -27,32 +27,28 @@ function Foo(props) {
27
} else {
28
t0 = $[0];
29
}
30
- const c_1 = $[1] !== t0;
31
- let t2;
32
- if (c_1) {
33
- t2 = <div>{t0}</div>;
34
- $[1] = t0;
35
- $[2] = t2;
30
+ let t1;
31
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
32
+ t1 = <div>{t0}</div>;
33
+ $[1] = t1;
34
} else {
37
- t2 = $[2];
35
+ t1 = $[1];
36
}
39
- const c_3 = $[3] !== props.greeting;
40
- const c_4 = $[4] !== t2;
41
- let t5;
42
- if (c_3 || c_4) {
43
- t5 = (
37
+ const c_2 = $[2] !== props.greeting;
38
+ let t2;
39
+ if (c_2) {
40
+ t2 = (
41
<>
42
Hello {props.greeting}
46
- {t2}
43
+ {t1}
44
</>
45
);
49
- $[3] = props.greeting;
50
- $[4] = t2;
51
- $[5] = t5;
46
+ $[2] = props.greeting;
47
+ $[3] = t2;
48
} else {
53
- t5 = $[5];
49
+ t2 = $[3];
50
}
55
- return t5;
51
+ return t2;
52
}
53
54
```
compiler/forget/src/__tests__/fixtures/hir/jsx-spread.expect.md
+17
-17
@@ -16,35 +16,35 @@ function Component(props) {
16
function Component(props) {
17
const $ = React.useMemoCache();
18
const c_0 = $[0] !== props;
19
- let t1;
19
+ let t0;
20
if (c_0) {
21
- t1 = props.cond ? props.foo : props.bar;
21
+ t0 = props.cond ? props.foo : props.bar;
22
$[0] = props;
23
- $[1] = t1;
23
+ $[1] = t0;
24
} else {
25
- t1 = $[1];
25
+ t0 = $[1];
26
}
27
- const c_2 = $[2] !== t1;
28
- let t3;
27
+ const c_2 = $[2] !== t0;
28
+ let t1;
29
if (c_2) {
30
- t3 = { bar: t1 };
31
- $[2] = t1;
32
- $[3] = t3;
30
+ t1 = { bar: t0 };
31
+ $[2] = t0;
32
+ $[3] = t1;
33
} else {
34
- t3 = $[3];
34
+ t1 = $[3];
35
}
36
const c_4 = $[4] !== props;
37
- const c_5 = $[5] !== t3;
38
- let t6;
37
+ const c_5 = $[5] !== t1;
38
+ let t2;
39
if (c_4 || c_5) {
40
- t6 = <Component {...props} {...t3}></Component>;
40
+ t2 = <Component {...props} {...t1}></Component>;
41
$[4] = props;
42
- $[5] = t3;
43
- $[6] = t6;
42
+ $[5] = t1;
43
+ $[6] = t2;
44
} else {
45
- t6 = $[6];
45
+ t2 = $[6];
46
}
47
- return t6;
47
+ return t2;
48
}
49
50
```
compiler/forget/src/__tests__/fixtures/hir/logical-expression-object.expect.md
+15
-15
@@ -21,37 +21,37 @@ function component(props) {
21
function component(props) {
22
const $ = React.useMemoCache();
23
const c_0 = $[0] !== props;
24
- let t1;
24
+ let t0;
25
if (c_0) {
26
- t1 = props.a || (props.b && props.c && props.d);
26
+ t0 = props.a || (props.b && props.c && props.d);
27
$[0] = props;
28
- $[1] = t1;
28
+ $[1] = t0;
29
} else {
30
- t1 = $[1];
30
+ t0 = $[1];
31
}
32
- const a = t1;
32
+ const a = t0;
33
const c_2 = $[2] !== props;
34
- let t3;
34
+ let t1;
35
if (c_2) {
36
- t3 = (props.a && props.b && props.c) || props.d;
36
+ t1 = (props.a && props.b && props.c) || props.d;
37
$[2] = props;
38
- $[3] = t3;
38
+ $[3] = t1;
39
} else {
40
- t3 = $[3];
40
+ t1 = $[3];
41
}
42
- const b = t3;
42
+ const b = t1;
43
const c_4 = $[4] !== a;
44
const c_5 = $[5] !== b;
45
- let t6;
45
+ let t2;
46
if (c_4 || c_5) {
47
- t6 = { a: a, b: b };
47
+ t2 = { a: a, b: b };
48
$[4] = a;
49
$[5] = b;
50
- $[6] = t6;
50
+ $[6] = t2;
51
} else {
52
- t6 = $[6];
52
+ t2 = $[6];
53
}
54
- return t6;
54
+ return t2;
55
}
56
57
```
compiler/forget/src/__tests__/fixtures/hir/logical-expression.expect.md
+15
-15
@@ -16,39 +16,39 @@ function component(props) {
16
function component(props) {
17
const $ = React.useMemoCache();
18
const c_0 = $[0] !== props;
19
- let t1;
19
+ let t0;
20
if (c_0) {
21
- t1 = props.a || (props.b && props.c && props.d);
21
+ t0 = props.a || (props.b && props.c && props.d);
22
$[0] = props;
23
- $[1] = t1;
23
+ $[1] = t0;
24
} else {
25
- t1 = $[1];
25
+ t0 = $[1];
26
}
27
- const a = t1;
27
+ const a = t0;
28
const c_2 = $[2] !== props;
29
- let t3;
29
+ let t1;
30
if (c_2) {
31
- t3 = (props.a && props.b && props.c) || props.d;
31
+ t1 = (props.a && props.b && props.c) || props.d;
32
$[2] = props;
33
- $[3] = t3;
33
+ $[3] = t1;
34
} else {
35
- t3 = $[3];
35
+ t1 = $[3];
36
}
37
- const b = t3;
37
+ const b = t1;
38
const c_4 = $[4] !== a;
39
const c_5 = $[5] !== b;
40
const c_6 = $[6] !== props;
41
- let t7;
41
+ let t2;
42
if (c_4 || c_5 || c_6) {
43
- t7 = a ? b : props.c;
43
+ t2 = a ? b : props.c;
44
$[4] = a;
45
$[5] = b;
46
$[6] = props;
47
- $[7] = t7;
47
+ $[7] = t2;
48
} else {
49
- t7 = $[7];
49
+ t2 = $[7];
50
}
51
- return t7;
51
+ return t2;
52
}
53
54
```
compiler/forget/src/__tests__/fixtures/hir/object-pattern-params.expect.md
+5
-5
@@ -37,16 +37,16 @@ function component(t8) {
37
}
38
const c_4 = $[4] !== y;
39
const c_5 = $[5] !== z;
40
- let t6;
40
+ let t0;
41
if (c_4 || c_5) {
42
- t6 = { y: y, z: z };
42
+ t0 = { y: y, z: z };
43
$[4] = y;
44
$[5] = z;
45
- $[6] = t6;
45
+ $[6] = t0;
46
} else {
47
- t6 = $[6];
47
+ t0 = $[6];
48
}
49
- return t6;
49
+ return t0;
50
}
51
52
```
compiler/forget/src/__tests__/fixtures/hir/overlapping-scopes-shadowing-within-block.expect.md
+5
-5
@@ -44,15 +44,15 @@ function foo(a, b, c) {
44
y = $[6];
45
}
46
const c_7 = $[7] !== y;
47
- let t8;
47
+ let t0;
48
if (c_7) {
49
- t8 = <div>{y}</div>;
49
+ t0 = <div>{y}</div>;
50
$[7] = y;
51
- $[8] = t8;
51
+ $[8] = t0;
52
} else {
53
- t8 = $[8];
53
+ t0 = $[8];
54
}
55
- x.push(t8);
55
+ x.push(t0);
56
}
57
$[0] = a;
58
$[1] = b;
compiler/forget/src/__tests__/fixtures/hir/property-assignment.expect.md
+5
-5
@@ -37,16 +37,16 @@ function Component(props) {
37
}
38
const c_3 = $[3] !== x;
39
const c_4 = $[4] !== child;
40
- let t5;
40
+ let t0;
41
if (c_3 || c_4) {
42
- t5 = <Component data={x}>{child}</Component>;
42
+ t0 = <Component data={x}>{child}</Component>;
43
$[3] = x;
44
$[4] = child;
45
- $[5] = t5;
45
+ $[5] = t0;
46
} else {
47
- t5 = $[5];
47
+ t0 = $[5];
48
}
49
- return t5;
49
+ return t0;
50
}
51
52
```
compiler/forget/src/__tests__/fixtures/hir/reactive-scopes-if.expect.md
+5
-5
@@ -39,15 +39,15 @@ function foo(a, b, c) {
39
y = $[5];
40
}
41
const c_6 = $[6] !== y;
42
- let t7;
42
+ let t0;
43
if (c_6) {
44
- t7 = <div>{y}</div>;
44
+ t0 = <div>{y}</div>;
45
$[6] = y;
46
- $[7] = t7;
46
+ $[7] = t0;
47
} else {
48
- t7 = $[7];
48
+ t0 = $[7];
49
}
50
- x.push(t7);
50
+ x.push(t0);
51
} else {
52
x.push(c);
53
}
compiler/forget/src/__tests__/fixtures/hir/reactive-scopes.expect.md
+5
-5
@@ -37,15 +37,15 @@ function f(a, b) {
37
x = $[2];
38
}
39
const c_3 = $[3] !== x;
40
- let t4;
40
+ let t0;
41
if (c_3) {
42
- t4 = <div>{x}</div>;
42
+ t0 = <div>{x}</div>;
43
$[3] = x;
44
- $[4] = t4;
44
+ $[4] = t0;
45
} else {
46
- t4 = $[4];
46
+ t0 = $[4];
47
}
48
- return t4;
48
+ return t0;
49
}
50
51
```
compiler/forget/src/__tests__/fixtures/hir/reassignment-conditional.expect.md
+5
-5
@@ -59,16 +59,16 @@ function Component(props) {
59
y.push(props.p2);
60
const c_5 = $[5] !== x$0;
61
const c_6 = $[6] !== y;
62
- let t7;
62
+ let t0;
63
if (c_5 || c_6) {
64
- t7 = <Component x={x$0} y={y}></Component>;
64
+ t0 = <Component x={x$0} y={y}></Component>;
65
$[5] = x$0;
66
$[6] = y;
67
- $[7] = t7;
67
+ $[7] = t0;
68
} else {
69
- t7 = $[7];
69
+ t0 = $[7];
70
}
71
- return t7;
71
+ return t0;
72
}
73
74
```
compiler/forget/src/__tests__/fixtures/hir/reassignment-separate-scopes.expect.md
+5
-5
@@ -98,9 +98,9 @@ function foo(a, b, c) {
98
}
99
const c_11 = $[11] !== y;
100
const c_12 = $[12] !== x$0;
101
- let t13;
101
+ let t0;
102
if (c_11 || c_12) {
103
- t13 = (
103
+ t0 = (
104
<div>
105
{y}
106
{x$0}
@@ -108,11 +108,11 @@ function foo(a, b, c) {
108
);
109
$[11] = y;
110
$[12] = x$0;
111
- $[13] = t13;
111
+ $[13] = t0;
112
} else {
113
- t13 = $[13];
113
+ t0 = $[13];
114
}
115
- return t13;
115
+ return t0;
116
}
117
118
```
compiler/forget/src/__tests__/fixtures/hir/reassignment.expect.md
+8
-10
@@ -45,18 +45,16 @@ function Component(props) {
45
} else {
46
y = $[2];
47
}
48
- const c_4 = $[4] !== x$0;
49
- const c_5 = $[5] !== y;
50
- let t6;
51
- if (c_4 || c_5) {
52
- t6 = <Component x={x$0} y={y}></Component>;
53
- $[4] = x$0;
54
- $[5] = y;
55
- $[6] = t6;
48
+ const c_4 = $[4] !== y;
49
+ let t0;
50
+ if (c_4) {
51
+ t0 = <Component x={x$0} y={y}></Component>;
52
+ $[4] = y;
53
+ $[5] = t0;
54
} else {
57
- t6 = $[6];
55
+ t0 = $[5];
56
}
59
- return t6;
57
+ return t0;
58
}
59
60
```
compiler/forget/src/__tests__/fixtures/hir/sequence-expression.expect.md
+3
-5
@@ -28,19 +28,17 @@ function sequence(props) {
28
} else {
29
t0 = $[0];
30
}
31
- const c_1 = $[1] !== t0;
31
let x;
33
- if (c_1) {
32
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
33
x = t0;
34
while ((foo(), true)) {
35
foo();
36
2;
37
x = 2;
38
}
40
- $[1] = t0;
41
- $[2] = x;
39
+ $[1] = x;
40
} else {
43
- x = $[2];
41
+ x = $[1];
42
}
43
return x;
44
}
compiler/forget/src/__tests__/fixtures/hir/simple.expect.md
+13
-9
@@ -18,22 +18,26 @@ export default function foo(x, y) {
18
const $ = React.useMemoCache();
19
if (x) {
20
const c_0 = $[0] !== y;
21
- let t1;
21
+ let t0;
22
if (c_0) {
23
- t1 = foo(false, y);
23
+ t0 = foo(false, y);
24
$[0] = y;
25
- $[1] = t1;
25
+ $[1] = t0;
26
} else {
27
- t1 = $[1];
27
+ t0 = $[1];
28
}
29
- return t1;
29
+ return t0;
30
}
31
+
32
+ const t1 = y * 10;
33
+ const c_2 = $[2] !== t1;
34
let t2;
32
- if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
33
- t2 = [y * 10];
34
- $[2] = t2;
35
+ if (c_2) {
36
+ t2 = [t1];
37
+ $[2] = t1;
38
+ $[3] = t2;
39
} else {
36
- t2 = $[2];
40
+ t2 = $[3];
41
}
42
return t2;
43
}
compiler/forget/src/__tests__/fixtures/hir/ssa-call-jsx-2.expect.md
+11
-15
@@ -32,14 +32,14 @@ function Component(props) {
32
a = [];
33
b = {};
34
foo(a, b);
35
- let t2;
35
+ let t0;
36
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
37
- t2 = foo();
38
- $[2] = t2;
37
+ t0 = foo();
38
+ $[2] = t0;
39
} else {
40
- t2 = $[2];
40
+ t0 = $[2];
41
}
42
- if (t2) {
42
+ if (t0) {
43
const _ = <div a={a}></div>;
44
}
45
@@ -50,18 +50,14 @@ function Component(props) {
50
a = $[0];
51
b = $[1];
52
}
53
- const c_3 = $[3] !== a;
54
- const c_4 = $[4] !== b;
55
- let t5;
56
- if (c_3 || c_4) {
57
- t5 = <div a={a} b={b}></div>;
58
- $[3] = a;
59
- $[4] = b;
60
- $[5] = t5;
53
+ let t1;
54
+ if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
55
+ t1 = <div a={a} b={b}></div>;
56
+ $[3] = t1;
57
} else {
62
- t5 = $[5];
58
+ t1 = $[3];
59
}
64
- return t5;
60
+ return t1;
61
}
62
63
```
compiler/forget/src/__tests__/fixtures/hir/ssa-call-jsx.expect.md
+6
-10
@@ -36,18 +36,14 @@ function Component(props) {
36
a = $[0];
37
b = $[1];
38
}
39
- const c_2 = $[2] !== a;
40
- const c_3 = $[3] !== b;
41
- let t4;
42
- if (c_2 || c_3) {
43
- t4 = <div a={a} b={b}></div>;
44
- $[2] = a;
45
- $[3] = b;
46
- $[4] = t4;
39
+ let t0;
40
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
41
+ t0 = <div a={a} b={b}></div>;
42
+ $[2] = t0;
43
} else {
48
- t4 = $[4];
44
+ t0 = $[2];
45
}
50
- return t4;
46
+ return t0;
47
}
48
49
```
compiler/forget/src/__tests__/fixtures/hir/ssa-property.expect.md
+3
-5
@@ -23,15 +23,13 @@ function foo() {
23
} else {
24
x = $[0];
25
}
26
- const c_1 = $[1] !== x;
26
let y;
28
- if (c_1) {
27
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
28
y = {};
29
y.x = x;
31
- $[1] = x;
32
- $[2] = y;
30
+ $[1] = y;
31
} else {
34
- y = $[2];
32
+ y = $[1];
33
}
34
return y;
35
}
compiler/forget/src/__tests__/fixtures/hir/switch-non-final-default.expect.md
+5
-5
@@ -85,16 +85,16 @@ function Component(props) {
85
y$0.push(props.p4);
86
const c_7 = $[7] !== y$0;
87
const c_8 = $[8] !== child;
88
- let t9;
88
+ let t0;
89
if (c_7 || c_8) {
90
- t9 = <Component data={y$0}>{child}</Component>;
90
+ t0 = <Component data={y$0}>{child}</Component>;
91
$[7] = y$0;
92
$[8] = child;
93
- $[9] = t9;
93
+ $[9] = t0;
94
} else {
95
- t9 = $[9];
95
+ t0 = $[9];
96
}
97
- return t9;
97
+ return t0;
98
}
99
100
```
compiler/forget/src/__tests__/fixtures/hir/switch.expect.md
+5
-5
@@ -69,16 +69,16 @@ function Component(props) {
69
y$0.push(props.p4);
70
const c_7 = $[7] !== y$0;
71
const c_8 = $[8] !== child;
72
- let t9;
72
+ let t0;
73
if (c_7 || c_8) {
74
- t9 = <Component data={y$0}>{child}</Component>;
74
+ t0 = <Component data={y$0}>{child}</Component>;
75
$[7] = y$0;
76
$[8] = child;
77
- $[9] = t9;
77
+ $[9] = t0;
78
} else {
79
- t9 = $[9];
79
+ t0 = $[9];
80
}
81
- return t9;
81
+ return t0;
82
}
83
84
```
compiler/forget/src/__tests__/fixtures/hir/ternary-expression.expect.md
+15
-15
@@ -16,37 +16,37 @@ function ternary(props) {
16
function ternary(props) {
17
const $ = React.useMemoCache();
18
const c_0 = $[0] !== props;
19
- let t1;
19
+ let t0;
20
if (c_0) {
21
- t1 = props.a && props.b ? props.c || props.d : props.e ?? props.f;
21
+ t0 = props.a && props.b ? props.c || props.d : props.e ?? props.f;
22
$[0] = props;
23
- $[1] = t1;
23
+ $[1] = t0;
24
} else {
25
- t1 = $[1];
25
+ t0 = $[1];
26
}
27
- const a = t1;
27
+ const a = t0;
28
const c_2 = $[2] !== props;
29
- let t3;
29
+ let t1;
30
if (c_2) {
31
- t3 = props.a ? (props.b && props.c ? props.d : props.e) : props.f;
31
+ t1 = props.a ? (props.b && props.c ? props.d : props.e) : props.f;
32
$[2] = props;
33
- $[3] = t3;
33
+ $[3] = t1;
34
} else {
35
- t3 = $[3];
35
+ t1 = $[3];
36
}
37
- const b = t3;
37
+ const b = t1;
38
const c_4 = $[4] !== a;
39
const c_5 = $[5] !== b;
40
- let t6;
40
+ let t2;
41
if (c_4 || c_5) {
42
- t6 = a ? b : (null, null);
42
+ t2 = a ? b : (null, null);
43
$[4] = a;
44
$[5] = b;
45
- $[6] = t6;
45
+ $[6] = t2;
46
} else {
47
- t6 = $[6];
47
+ t2 = $[6];
48
}
49
- return t6;
49
+ return t2;
50
}
51
52
```
compiler/forget/src/__tests__/fixtures/hir/type-test-field-load-binary-op.expect.md
+3
-7
@@ -34,16 +34,12 @@ function component() {
34
} else {
35
t1 = $[1];
36
}
37
- const c_2 = $[2] !== t0;
38
- const c_3 = $[3] !== t1;
37
let x;
40
- if (c_2 || c_3) {
38
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
39
x = { u: t0, v: t1 };
42
- $[2] = t0;
43
- $[3] = t1;
44
- $[4] = x;
40
+ $[2] = x;
41
} else {
46
- x = $[4];
42
+ x = $[2];
43
}
44
const u = x.u;
45
const v = x.v;
compiler/forget/src/__tests__/fixtures/hir/type-test-polymorphic.expect.md
+3
-5
@@ -38,18 +38,16 @@ function component() {
38
} else {
39
o = $[1];
40
}
41
- const c_2 = $[2] !== o;
41
let x;
43
- if (c_2) {
42
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
43
x = {};
44
x.t = p;
45
46
const z = x.t;
47
x.t = o;
49
- $[2] = o;
50
- $[3] = x;
48
+ $[2] = x;
49
} else {
52
- x = $[3];
50
+ x = $[2];
51
}
52
53
const y = x.t;
compiler/forget/src/__tests__/fixtures/hir/unary-expr.expect.md
+20
-6
@@ -37,14 +37,28 @@ function component(a) {
37
const m = !t.t;
38
const e = ~t.t;
39
const f = typeof t.t;
40
- let t2;
41
- if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
42
- t2 = { z: z, p: p, q: q, n: n, m: m, e: e, f: f };
43
- $[2] = t2;
40
+ const c_2 = $[2] !== z;
41
+ const c_3 = $[3] !== p;
42
+ const c_4 = $[4] !== q;
43
+ const c_5 = $[5] !== n;
44
+ const c_6 = $[6] !== m;
45
+ const c_7 = $[7] !== e;
46
+ const c_8 = $[8] !== f;
47
+ let t0;
48
+ if (c_2 || c_3 || c_4 || c_5 || c_6 || c_7 || c_8) {
49
+ t0 = { z: z, p: p, q: q, n: n, m: m, e: e, f: f };
50
+ $[2] = z;
51
+ $[3] = p;
52
+ $[4] = q;
53
+ $[5] = n;
54
+ $[6] = m;
55
+ $[7] = e;
56
+ $[8] = f;
57
+ $[9] = t0;
58
} else {
45
- t2 = $[2];
59
+ t0 = $[9];
60
}
47
- return t2;
61
+ return t0;
62
}
63
64
```
compiler/forget/src/__tests__/fixtures/hir/update-expression.expect.md
+9
-3
@@ -21,12 +21,18 @@ function foo(props) {
21
const y = x$0;
22
const x$1 = x$0 - 1;
23
const z = x$1;
24
+ const c_0 = $[0] !== x$1;
25
+ const c_1 = $[1] !== y;
26
+ const c_2 = $[2] !== z;
27
let t0;
25
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
28
+ if (c_0 || c_1 || c_2) {
29
t0 = { x: x$1, y: y, z: z };
27
- $[0] = t0;
30
+ $[0] = x$1;
31
+ $[1] = y;
32
+ $[2] = z;
33
+ $[3] = t0;
34
} else {
29
- t0 = $[0];
35
+ t0 = $[3];
36
}
37
return t0;
38
}