@samitouri / QOS-React-2 / commits / 7537df3d4e

Support assignment expressions in value blocks

Enables support for assignment expressions in value blocks (which includes in loop init/test/update blocks). This was pretty straightforward, the main changes are: * During PropagateScopeDependencies, we currently record scope reassignments based on `Identifier` object identity. In the case where a variable is reassigned in multiple control-flow paths of a value block, however, there can be multiple object identities. So we now de-dupe reassignments based on identifier id. * MergeOverlappingScopes now treats value blocks as regular blocks, allowing it to correctly merge scopes from the value with other scopes from the outer block. Otherwise this is mostly just lots of tests. Note that there is an outstanding todo, which is that we currently error for ternaries and logicals whose value is unused (eg `cond ? (x = 1) : null`). I'll address that in a follow-up.

Joe Savona committed Mar 14, 2023 at 20:02 UTC 7537df3d4e2e31cbaff3e96782f890523d13908f
22 files changed +567 -17
compiler/forget/.eslintrc.js
+4
@@ -24,6 +24,10 @@ module.exports = {
24 // like invariant.
25 "no-fallthrough": "off",
26
27 + // Low-value: this fires even for declarations that capture references which wouldn't be as
28 + // obvious if the declaration was lifted to the parent root
29 + "no-inner-declarations": "off",
30 +
31 "@typescript-eslint/no-empty-function": "off",
32
33 // Explicitly casting to/through any is sometimes required, often for error messages to
compiler/forget/src/HIR/BuildHIR.ts
-11
@@ -1198,17 +1198,6 @@ function lowerExpression(
1198 const expr = exprPath as NodePath<t.AssignmentExpression>;
1199 const operator = expr.node.operator;
1200
1201 - if (builder.currentBlockKind() === "value") {
1202 - // try lowering the RHS in case it also contains errors
1203 - lowerExpressionToTemporary(builder, expr.get("right"));
1204 - builder.errors.push({
1205 - reason: `(BuildHIR::lowerExpression) Handle AssignmentExpression within a LogicalExpression or ConditionalExpression`,
1206 - severity: ErrorSeverity.Todo,
1207 - nodePath: expr.parentPath,
1208 - });
1209 - return { kind: "UnsupportedNode", node: exprNode, loc: exprLoc };
1210 - }
1211 -
1201 if (operator === "=") {
1202 const left = expr.get("left");
1203 return lowerAssignment(
compiler/forget/src/ReactiveScopes/MergeOverlappingReactiveScopes.ts
+16 -3
@@ -11,6 +11,7 @@ import {
11 Place,
12 ReactiveBlock,
13 ReactiveFunction,
14 + ReactiveInstruction,
15 ReactiveScope,
16 ScopeId,
17 } from "../HIR";
@@ -98,9 +99,6 @@ import { ReactiveFunctionVisitor, visitReactiveFunction } from "./visitors";
99 */
100 export function mergeOverlappingReactiveScopes(fn: ReactiveFunction): void {
101 const context = new Context();
101 - // context.enter(() => {
102 - // visitBlock(context, fn.body);
103 - // });
102 visitReactiveFunction(fn, new Visitor(), context);
103 context.complete();
104 }
@@ -120,6 +118,21 @@ class Visitor extends ReactiveFunctionVisitor<Context> {
118 this.traverseBlock(block, state);
119 });
120 }
121 + override visitInstruction(
122 + instruction: ReactiveInstruction,
123 + state: Context
124 + ): void {
125 + if (
126 + instruction.value.kind === "ConditionalExpression" ||
127 + instruction.value.kind === "LogicalExpression"
128 + ) {
129 + state.enter(() => {
130 + super.visitInstruction(instruction, state);
131 + });
132 + } else {
133 + super.visitInstruction(instruction, state);
134 + }
135 + }
136 }
137
138 class BlockScope {
compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts
+4 -1
@@ -317,7 +317,10 @@ class Context {
317 this.currentScope != null &&
318 place.identifier.scope != null &&
319 declaration !== undefined &&
320 - declaration.scope !== place.identifier.scope
320 + declaration.scope !== place.identifier.scope &&
321 + !Array.from(this.currentScope.reassignments).some(
322 + (ident) => ident.id === place.identifier.id
323 + )
324 ) {
325 this.currentScope.reassignments.add(place.identifier);
326 }
compiler/forget/src/__tests__/fixtures/compiler/ternary-assignment-expression.expect.md new
+24
@@ -0,0 +1,24 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function ternary(props) {
6 + let x = 0;
7 + const y = props.a ? (x = 1) : (x = 2);
8 + return x + y;
9 +}
10 +
11 +```
12 +
13 +## Code
14 +
15 +```javascript
16 +function ternary(props) {
17 + let x = undefined;
18 +
19 + const y = props.a ? ((x = 1), 1) : ((x = 2), 2);
20 + return x + y;
21 +}
22 +
23 +```
24 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/ternary-assignment-expression.js
-1
@@ -1,4 +1,3 @@
1 -// @skip
1 function ternary(props) {
2 let x = 0;
3 const y = props.a ? (x = 1) : (x = 2);
compiler/forget/src/__tests__/fixtures/compiler/while-logical.expect.md
+14
@@ -2,12 +2,26 @@
2 ## Input
3
4 ```javascript
5 +function foo(props) {
6 + let x = 0;
7 + while (x > props.min && x < props.max) {
8 + x *= 2;
9 + }
10 + return x;
11 +}
12
13 ```
14
15 ## Code
16
17 ```javascript
18 +function foo(props) {
19 + let x = 0;
20 + while (x > props.min && x < props.max) {
21 + x = x * 2;
22 + }
23 + return x;
24 +}
25
26 ```
27
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/while-logical.js
-1
@@ -1,4 +1,3 @@
1 -// @skip
1 function foo(props) {
2 let x = 0;
3 while (x > props.min && x < props.max) {
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction-with-mutation.expect.md new
+64
@@ -0,0 +1,64 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo(props) {
6 + let x = [];
7 + x.push(props.bar);
8 + const _ = props.cond
9 + ? (({ x } = { x: {} }), ([x] = [[]]), x.push(props.foo))
10 + : null;
11 + console.log(_);
12 + mut(x);
13 + return x;
14 +}
15 +
16 +```
17 +
18 +## HIR
19 +
20 +```javascript
21 +bb0 (block):
22 + [1] store $35[1:33] = Array []
23 + [2] store $37[2:33] = StoreLocal Let mutate x$36[2:33] = capture $35[1:33]
24 + [3] mutate $38[3:33] = LoadLocal capture x$36[2:33]
25 + [4] mutate $39 = LoadLocal read props$34
26 + [5] mutate $40 = PropertyLoad read $39.bar
27 + [6] mutate $41 = PropertyCall mutate $38[3:33].push(read $40)
28 + [7] Ternary test:bb2 fallthrough=bb1
29 +bb2 (value):
30 + predecessor blocks: bb0
31 + [8] mutate $42 = LoadLocal read props$34
32 + [9] mutate $43 = PropertyLoad read $42.cond
33 + [10] Branch (read $43) then:bb3 else:bb4
34 +bb3 (value):
35 + predecessor blocks: bb2
36 + [14] store $48[14:33] = Array []
37 + [15] store $49[15:33] = Array [capture $48[14:33]]
38 + [16] store $51[16:33] = Destructure Reassign [ mutate x$36[16:33] ] = capture $49[15:33]
39 + [17] mutate $52[17:33] = LoadLocal capture x$36[16:33]
40 + [18] mutate $53 = LoadLocal read props$34
41 + [19] mutate $54 = PropertyLoad read $53.foo
42 + [20] mutate $55[20:30] = PropertyCall mutate $52[17:33].push(read $54)
43 + [21] store $57[21:30] = StoreLocal Const mutate $56[7:30] = capture $55[20:30]
44 + [22] Goto bb1
45 +bb4 (value):
46 + predecessor blocks: bb2
47 + [23] mutate $58[23:30]:TPrimitive = null
48 + [24] store $60[24:30]:TPrimitive = StoreLocal Const mutate $56[7:30] = read $58[23:30]:TPrimitive
49 + [25] Goto bb1
50 +bb1 (block):
51 + predecessor blocks: bb3 bb4
52 + $63[7:30]:TPhi: phi(bb3: $56, bb4: $59)
53 + x$36[2:33]:TPhi: phi(bb3: x$36, bb4: x$36)
54 + [26] store $62[26:30] = StoreLocal Const mutate _$61[26:30] = capture $56[7:30]
55 + [27] mutate $64 = Global console
56 + [28] mutate $65[28:30] = LoadLocal capture _$61[26:30]
57 + [29] mutate $66 = PropertyCall read $64.log(mutate $65[28:30])
58 + [30] mutate $67:TFunction = Global mut
59 + [31] mutate $68[31:33] = LoadLocal capture x$36[2:33]
60 + [32] mutate $70 = Call read $67:TFunction(mutate $68[31:33])
61 + [33] mutate $71 = LoadLocal capture x$36[2:33]
62 + [34] Return freeze $71
63 +```
64 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction-with-mutation.js new
+10
@@ -0,0 +1,10 @@
1 +function foo(props) {
2 + let x = [];
3 + x.push(props.bar);
4 + const _ = props.cond
5 + ? (({ x } = { x: {} }), ([x] = [[]]), x.push(props.foo))
6 + : null;
7 + console.log(_);
8 + mut(x);
9 + return x;
10 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction.expect.md new
+60
@@ -0,0 +1,60 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo(props) {
6 + let x = [];
7 + x.push(props.bar);
8 + const _ = props.cond
9 + ? (({ x } = { x: {} }), ([x] = [[]]), x.push(props.foo))
10 + : null;
11 + console.log(_);
12 + return x;
13 +}
14 +
15 +```
16 +
17 +## HIR
18 +
19 +```javascript
20 +bb0 (block):
21 + [1] store $32[1:7] = Array []
22 + [2] store $34[2:7] = StoreLocal Let mutate x$33[2:7] = capture $32[1:7]
23 + [3] mutate $35[3:7] = LoadLocal capture x$33[2:7]
24 + [4] mutate $36 = LoadLocal read props$31
25 + [5] mutate $37 = PropertyLoad read $36.bar
26 + [6] mutate $38 = PropertyCall mutate $35[3:7].push(read $37)
27 + [7] Ternary test:bb2 fallthrough=bb1
28 +bb2 (value):
29 + predecessor blocks: bb0
30 + [8] mutate $39 = LoadLocal read props$31
31 + [9] mutate $40 = PropertyLoad read $39.cond
32 + [10] Branch (read $40) then:bb3 else:bb4
33 +bb3 (value):
34 + predecessor blocks: bb2
35 + [14] store $45[14:21] = Array []
36 + [15] store $46[15:21] = Array [capture $45[14:21]]
37 + [16] store $48[16:21] = Destructure Reassign [ mutate x$33[16:21] ] = capture $46[15:21]
38 + [17] mutate $49[17:21] = LoadLocal capture x$33[16:21]
39 + [18] mutate $50 = LoadLocal read props$31
40 + [19] mutate $51 = PropertyLoad read $50.foo
41 + [20] mutate $52[20:30] = PropertyCall mutate $49[17:21].push(read $51)
42 + [21] store $54[21:30] = StoreLocal Const mutate $53[7:30] = capture $52[20:30]
43 + [22] Goto bb1
44 +bb4 (value):
45 + predecessor blocks: bb2
46 + [23] mutate $55[23:30]:TPrimitive = null
47 + [24] store $57[24:30]:TPrimitive = StoreLocal Const mutate $53[7:30] = read $55[23:30]:TPrimitive
48 + [25] Goto bb1
49 +bb1 (block):
50 + predecessor blocks: bb3 bb4
51 + $60[7:30]:TPhi: phi(bb3: $53, bb4: $56)
52 + x$33:TPhi: phi(bb3: x$33, bb4: x$33)
53 + [26] store $59[26:30] = StoreLocal Const mutate _$58[26:30] = capture $53[7:30]
54 + [27] mutate $61 = Global console
55 + [28] mutate $62[28:30] = LoadLocal capture _$58[26:30]
56 + [29] mutate $63 = PropertyCall read $61.log(mutate $62[28:30])
57 + [30] mutate $64 = LoadLocal capture x$33
58 + [31] Return freeze $64
59 +```
60 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction.js new
+9
@@ -0,0 +1,9 @@
1 +function foo(props) {
2 + let x = [];
3 + x.push(props.bar);
4 + const _ = props.cond
5 + ? (({ x } = { x: {} }), ([x] = [[]]), x.push(props.foo))
6 + : null;
7 + console.log(_);
8 + return x;
9 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-with-mutation.expect.md new
+61
@@ -0,0 +1,61 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo(props) {
6 + let x = [];
7 + x.push(props.bar);
8 + const _ = props.cond ? ((x = {}), (x = []), x.push(props.foo)) : null;
9 + console.log(_);
10 + mut(x);
11 + return x;
12 +}
13 +
14 +```
15 +
16 +## HIR
17 +
18 +```javascript
19 +bb0 (block):
20 + [1] store $35[1:33] = Array []
21 + [2] store $37[2:33] = StoreLocal Let mutate x$36[2:33] = capture $35[1:33]
22 + [3] mutate $38[3:33] = LoadLocal capture x$36[2:33]
23 + [4] mutate $39 = LoadLocal read props$34
24 + [5] mutate $40 = PropertyLoad read $39.bar
25 + [6] mutate $41 = PropertyCall mutate $38[3:33].push(read $40)
26 + [7] Ternary test:bb2 fallthrough=bb1
27 +bb2 (value):
28 + predecessor blocks: bb0
29 + [8] mutate $42 = LoadLocal read props$34
30 + [9] mutate $43 = PropertyLoad read $42.cond
31 + [10] Branch (read $43) then:bb3 else:bb4
32 +bb3 (value):
33 + predecessor blocks: bb2
34 + [14] store $48[14:33] = Array []
35 + [15] store $50[15:33] = StoreLocal Reassign mutate x$36[15:33] = capture $48[14:33]
36 + [17] mutate $52[17:33] = LoadLocal capture x$36[15:33]
37 + [18] mutate $53 = LoadLocal read props$34
38 + [19] mutate $54 = PropertyLoad read $53.foo
39 + [20] mutate $55[20:30] = PropertyCall mutate $52[17:33].push(read $54)
40 + [21] store $57[21:30] = StoreLocal Const mutate $56[7:30] = capture $55[20:30]
41 + [22] Goto bb1
42 +bb4 (value):
43 + predecessor blocks: bb2
44 + [23] mutate $58[23:30]:TPrimitive = null
45 + [24] store $60[24:30]:TPrimitive = StoreLocal Const mutate $56[7:30] = read $58[23:30]:TPrimitive
46 + [25] Goto bb1
47 +bb1 (block):
48 + predecessor blocks: bb3 bb4
49 + $63[7:30]:TPhi: phi(bb3: $56, bb4: $59)
50 + x$36[2:33]:TPhi: phi(bb3: x$36, bb4: x$36)
51 + [26] store $62[26:30] = StoreLocal Const mutate _$61[26:30] = capture $56[7:30]
52 + [27] mutate $64 = Global console
53 + [28] mutate $65[28:30] = LoadLocal capture _$61[26:30]
54 + [29] mutate $66 = PropertyCall read $64.log(mutate $65[28:30])
55 + [30] mutate $67:TFunction = Global mut
56 + [31] mutate $68[31:33] = LoadLocal capture x$36[2:33]
57 + [32] mutate $70 = Call read $67:TFunction(mutate $68[31:33])
58 + [33] mutate $71 = LoadLocal capture x$36[2:33]
59 + [34] Return freeze $71
60 +```
61 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-with-mutation.js new
+8
@@ -0,0 +1,8 @@
1 +function foo(props) {
2 + let x = [];
3 + x.push(props.bar);
4 + const _ = props.cond ? ((x = {}), (x = []), x.push(props.foo)) : null;
5 + console.log(_);
6 + mut(x);
7 + return x;
8 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary.expect.md new
+57
@@ -0,0 +1,57 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo(props) {
6 + let x = [];
7 + x.push(props.bar);
8 + const _ = props.cond ? ((x = {}), (x = []), x.push(props.foo)) : null;
9 + console.log(_);
10 + return x;
11 +}
12 +
13 +```
14 +
15 +## HIR
16 +
17 +```javascript
18 +bb0 (block):
19 + [1] store $32[1:7] = Array []
20 + [2] store $34[2:7] = StoreLocal Let mutate x$33[2:7] = capture $32[1:7]
21 + [3] mutate $35[3:7] = LoadLocal capture x$33[2:7]
22 + [4] mutate $36 = LoadLocal read props$31
23 + [5] mutate $37 = PropertyLoad read $36.bar
24 + [6] mutate $38 = PropertyCall mutate $35[3:7].push(read $37)
25 + [7] Ternary test:bb2 fallthrough=bb1
26 +bb2 (value):
27 + predecessor blocks: bb0
28 + [8] mutate $39 = LoadLocal read props$31
29 + [9] mutate $40 = PropertyLoad read $39.cond
30 + [10] Branch (read $40) then:bb3 else:bb4
31 +bb3 (value):
32 + predecessor blocks: bb2
33 + [14] store $45[14:21] = Array []
34 + [15] store $47[15:21] = StoreLocal Reassign mutate x$33[15:21] = capture $45[14:21]
35 + [17] mutate $49[17:21] = LoadLocal capture x$33[15:21]
36 + [18] mutate $50 = LoadLocal read props$31
37 + [19] mutate $51 = PropertyLoad read $50.foo
38 + [20] mutate $52[20:30] = PropertyCall mutate $49[17:21].push(read $51)
39 + [21] store $54[21:30] = StoreLocal Const mutate $53[7:30] = capture $52[20:30]
40 + [22] Goto bb1
41 +bb4 (value):
42 + predecessor blocks: bb2
43 + [23] mutate $55[23:30]:TPrimitive = null
44 + [24] store $57[24:30]:TPrimitive = StoreLocal Const mutate $53[7:30] = read $55[23:30]:TPrimitive
45 + [25] Goto bb1
46 +bb1 (block):
47 + predecessor blocks: bb3 bb4
48 + $60[7:30]:TPhi: phi(bb3: $53, bb4: $56)
49 + x$33:TPhi: phi(bb3: x$33, bb4: x$33)
50 + [26] store $59[26:30] = StoreLocal Const mutate _$58[26:30] = capture $53[7:30]
51 + [27] mutate $61 = Global console
52 + [28] mutate $62[28:30] = LoadLocal capture _$58[26:30]
53 + [29] mutate $63 = PropertyCall read $61.log(mutate $62[28:30])
54 + [30] mutate $64 = LoadLocal capture x$33
55 + [31] Return freeze $64
56 +```
57 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary.js new
+7
@@ -0,0 +1,7 @@
1 +function foo(props) {
2 + let x = [];
3 + x.push(props.bar);
4 + const _ = props.cond ? ((x = {}), (x = []), x.push(props.foo)) : null;
5 + console.log(_);
6 + return x;
7 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary-with-mutation.expect.md new
+68
@@ -0,0 +1,68 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo(props) {
6 + let x = [];
7 + x.push(props.bar);
8 + const _ = props.cond
9 + ? ((x = {}), (x = []), x.push(props.foo))
10 + : ((x = []), (x = []), x.push(props.bar));
11 + console.log(_);
12 + mut(x);
13 + return x;
14 +}
15 +
16 +```
17 +
18 +## HIR
19 +
20 +```javascript
21 +bb0 (block):
22 + [1] store $44[1:7] = Array []
23 + [2] store $46[2:7] = StoreLocal Let mutate x$45[2:42] = capture $44[1:7]
24 + [3] mutate $47[3:7] = LoadLocal capture x$45[2:42]
25 + [4] mutate $48 = LoadLocal read props$43
26 + [5] mutate $49 = PropertyLoad read $48.bar
27 + [6] mutate $50 = PropertyCall mutate $47[3:7].push(read $49)
28 + [7] Ternary test:bb2 fallthrough=bb1
29 +bb2 (value):
30 + predecessor blocks: bb0
31 + [8] mutate $51 = LoadLocal read props$43
32 + [9] mutate $52 = PropertyLoad read $51.cond
33 + [10] Branch (read $52) then:bb3 else:bb4
34 +bb3 (value):
35 + predecessor blocks: bb2
36 + [14] store $57[14:42] = Array []
37 + [15] store $59[15:42] = StoreLocal Reassign mutate x$45[15:42] = capture $57[14:42]
38 + [17] mutate $61[17:42] = LoadLocal capture x$45[15:42]
39 + [18] mutate $62 = LoadLocal read props$43
40 + [19] mutate $63 = PropertyLoad read $62.foo
41 + [20] mutate $64[20:39] = PropertyCall mutate $61[17:42].push(read $63)
42 + [21] store $66[21:39] = StoreLocal Const mutate $65[7:39] = capture $64[20:39]
43 + [22] Goto bb1
44 +bb4 (value):
45 + predecessor blocks: bb2
46 + [26] store $71[26:42] = Array []
47 + [27] store $73[27:42] = StoreLocal Reassign mutate x$45[27:42] = capture $71[26:42]
48 + [29] mutate $75[29:42] = LoadLocal capture x$45[27:42]
49 + [30] mutate $76 = LoadLocal read props$43
50 + [31] mutate $77 = PropertyLoad read $76.bar
51 + [32] mutate $78[32:39] = PropertyCall mutate $75[29:42].push(read $77)
52 + [33] store $80[33:39] = StoreLocal Const mutate $65[7:39] = capture $78[32:39]
53 + [34] Goto bb1
54 +bb1 (block):
55 + predecessor blocks: bb3 bb4
56 + $83[7:39]:TPhi: phi(bb3: $65, bb4: $79)
57 + x$45[15:42]:TPhi: phi(bb3: x$45, bb4: x$45)
58 + [35] store $82[35:39] = StoreLocal Const mutate _$81[35:39] = capture $65[7:39]
59 + [36] mutate $84 = Global console
60 + [37] mutate $85[37:39] = LoadLocal capture _$81[35:39]
61 + [38] mutate $86 = PropertyCall read $84.log(mutate $85[37:39])
62 + [39] mutate $87:TFunction = Global mut
63 + [40] mutate $88[40:42] = LoadLocal capture x$45[15:42]
64 + [41] mutate $90 = Call read $87:TFunction(mutate $88[40:42])
65 + [42] mutate $91 = LoadLocal capture x$45[15:42]
66 + [43] Return freeze $91
67 +```
68 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary-with-mutation.js new
+10
@@ -0,0 +1,10 @@
1 +function foo(props) {
2 + let x = [];
3 + x.push(props.bar);
4 + const _ = props.cond
5 + ? ((x = {}), (x = []), x.push(props.foo))
6 + : ((x = []), (x = []), x.push(props.bar));
7 + console.log(_);
8 + mut(x);
9 + return x;
10 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary.expect.md new
+64
@@ -0,0 +1,64 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo(props) {
6 + let x = [];
7 + x.push(props.bar);
8 + const _ = props.cond
9 + ? ((x = {}), (x = []), x.push(props.foo))
10 + : ((x = []), (x = []), x.push(props.bar));
11 + console.log(_);
12 + return x;
13 +}
14 +
15 +```
16 +
17 +## HIR
18 +
19 +```javascript
20 +bb0 (block):
21 + [1] store $41[1:7] = Array []
22 + [2] store $43[2:7] = StoreLocal Let mutate x$42[2:7] = capture $41[1:7]
23 + [3] mutate $44[3:7] = LoadLocal capture x$42[2:7]
24 + [4] mutate $45 = LoadLocal read props$40
25 + [5] mutate $46 = PropertyLoad read $45.bar
26 + [6] mutate $47 = PropertyCall mutate $44[3:7].push(read $46)
27 + [7] Ternary test:bb2 fallthrough=bb1
28 +bb2 (value):
29 + predecessor blocks: bb0
30 + [8] mutate $48 = LoadLocal read props$40
31 + [9] mutate $49 = PropertyLoad read $48.cond
32 + [10] Branch (read $49) then:bb3 else:bb4
33 +bb3 (value):
34 + predecessor blocks: bb2
35 + [14] store $54[14:21] = Array []
36 + [15] store $56[15:21] = StoreLocal Reassign mutate x$42[15:21] = capture $54[14:21]
37 + [17] mutate $58[17:21] = LoadLocal capture x$42[15:21]
38 + [18] mutate $59 = LoadLocal read props$40
39 + [19] mutate $60 = PropertyLoad read $59.foo
40 + [20] mutate $61[20:39] = PropertyCall mutate $58[17:21].push(read $60)
41 + [21] store $63[21:39] = StoreLocal Const mutate $62[7:39] = capture $61[20:39]
42 + [22] Goto bb1
43 +bb4 (value):
44 + predecessor blocks: bb2
45 + [26] store $68[26:33] = Array []
46 + [27] store $70[27:33] = StoreLocal Reassign mutate x$42[27:33] = capture $68[26:33]
47 + [29] mutate $72[29:33] = LoadLocal capture x$42[27:33]
48 + [30] mutate $73 = LoadLocal read props$40
49 + [31] mutate $74 = PropertyLoad read $73.bar
50 + [32] mutate $75[32:39] = PropertyCall mutate $72[29:33].push(read $74)
51 + [33] store $77[33:39] = StoreLocal Const mutate $62[7:39] = capture $75[32:39]
52 + [34] Goto bb1
53 +bb1 (block):
54 + predecessor blocks: bb3 bb4
55 + $80[7:39]:TPhi: phi(bb3: $62, bb4: $76)
56 + x$42:TPhi: phi(bb3: x$42, bb4: x$42)
57 + [35] store $79[35:39] = StoreLocal Const mutate _$78[35:39] = capture $62[7:39]
58 + [36] mutate $81 = Global console
59 + [37] mutate $82[37:39] = LoadLocal capture _$78[35:39]
60 + [38] mutate $83 = PropertyCall read $81.log(mutate $82[37:39])
61 + [39] mutate $84 = LoadLocal capture x$42
62 + [40] Return freeze $84
63 +```
64 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary.js new
+9
@@ -0,0 +1,9 @@
1 +function foo(props) {
2 + let x = [];
3 + x.push(props.bar);
4 + const _ = props.cond
5 + ? ((x = {}), (x = []), x.push(props.foo))
6 + : ((x = []), (x = []), x.push(props.bar));
7 + console.log(_);
8 + return x;
9 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-with-mutation.expect.md new
+63
@@ -0,0 +1,63 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo(props) {
6 + let x = [];
7 + x.push(props.bar);
8 + if (props.cond) {
9 + x = {};
10 + x = [];
11 + x.push(props.foo);
12 + } else {
13 + x = [];
14 + x = [];
15 + x.push(props.bar);
16 + }
17 + mut(x);
18 + return x;
19 +}
20 +
21 +```
22 +
23 +## HIR
24 +
25 +```javascript
26 +bb0 (block):
27 + [1] store $36[1:7] = Array []
28 + [2] store $38[2:7] = StoreLocal Let mutate x$37[2:35] = capture $36[1:7]
29 + [3] mutate $39[3:7] = LoadLocal capture x$37[2:35]
30 + [4] mutate $40 = LoadLocal read props$35
31 + [5] mutate $41 = PropertyLoad read $40.bar
32 + [6] mutate $42 = PropertyCall mutate $39[3:7].push(read $41)
33 + [7] mutate $43 = LoadLocal read props$35
34 + [8] mutate $44 = PropertyLoad read $43.cond
35 + [9] If (read $44) then:bb2 else:bb3 fallthrough=bb1
36 +bb2 (block):
37 + predecessor blocks: bb0
38 + [13] store $49[13:35] = Array []
39 + [14] store $51[14:35] = StoreLocal Reassign mutate x$37[14:35] = capture $49[13:35]
40 + [16] mutate $53[16:35] = LoadLocal capture x$37[14:35]
41 + [17] mutate $54 = LoadLocal read props$35
42 + [18] mutate $55 = PropertyLoad read $54.foo
43 + [19] mutate $56 = PropertyCall mutate $53[16:35].push(read $55)
44 + [20] Goto bb1
45 +bb3 (block):
46 + predecessor blocks: bb0
47 + [24] store $61[24:35] = Array []
48 + [25] store $63[25:35] = StoreLocal Reassign mutate x$37[25:35] = capture $61[24:35]
49 + [27] mutate $65[27:35] = LoadLocal capture x$37[25:35]
50 + [28] mutate $66 = LoadLocal read props$35
51 + [29] mutate $67 = PropertyLoad read $66.bar
52 + [30] mutate $68 = PropertyCall mutate $65[27:35].push(read $67)
53 + [31] Goto bb1
54 +bb1 (block):
55 + predecessor blocks: bb2 bb3
56 + x$37[14:35]:TPhi: phi(bb2: x$37, bb3: x$37)
57 + [32] mutate $69:TFunction = Global mut
58 + [33] mutate $70[33:35] = LoadLocal capture x$37[14:35]
59 + [34] mutate $72 = Call read $69:TFunction(mutate $70[33:35])
60 + [35] mutate $73 = LoadLocal capture x$37[14:35]
61 + [36] Return freeze $73
62 +```
63 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-with-mutation.js new
+15
@@ -0,0 +1,15 @@
1 +function foo(props) {
2 + let x = [];
3 + x.push(props.bar);
4 + if (props.cond) {
5 + x = {};
6 + x = [];
7 + x.push(props.foo);
8 + } else {
9 + x = [];
10 + x = [];
11 + x.push(props.bar);
12 + }
13 + mut(x);
14 + return x;
15 +}