diff --git a/compiler/forget/.eslintrc.js b/compiler/forget/.eslintrc.js index f00a91e235..e6a68ac9f9 100644 --- a/compiler/forget/.eslintrc.js +++ b/compiler/forget/.eslintrc.js @@ -24,6 +24,10 @@ module.exports = { // like invariant. "no-fallthrough": "off", + // Low-value: this fires even for declarations that capture references which wouldn't be as + // obvious if the declaration was lifted to the parent root + "no-inner-declarations": "off", + "@typescript-eslint/no-empty-function": "off", // Explicitly casting to/through any is sometimes required, often for error messages to diff --git a/compiler/forget/src/HIR/BuildHIR.ts b/compiler/forget/src/HIR/BuildHIR.ts index 3b341daf94..d77b7db19a 100644 --- a/compiler/forget/src/HIR/BuildHIR.ts +++ b/compiler/forget/src/HIR/BuildHIR.ts @@ -1198,17 +1198,6 @@ function lowerExpression( const expr = exprPath as NodePath; const operator = expr.node.operator; - if (builder.currentBlockKind() === "value") { - // try lowering the RHS in case it also contains errors - lowerExpressionToTemporary(builder, expr.get("right")); - builder.errors.push({ - reason: `(BuildHIR::lowerExpression) Handle AssignmentExpression within a LogicalExpression or ConditionalExpression`, - severity: ErrorSeverity.Todo, - nodePath: expr.parentPath, - }); - return { kind: "UnsupportedNode", node: exprNode, loc: exprLoc }; - } - if (operator === "=") { const left = expr.get("left"); return lowerAssignment( diff --git a/compiler/forget/src/ReactiveScopes/MergeOverlappingReactiveScopes.ts b/compiler/forget/src/ReactiveScopes/MergeOverlappingReactiveScopes.ts index dfb9209c9f..9f8ee4cf56 100644 --- a/compiler/forget/src/ReactiveScopes/MergeOverlappingReactiveScopes.ts +++ b/compiler/forget/src/ReactiveScopes/MergeOverlappingReactiveScopes.ts @@ -11,6 +11,7 @@ import { Place, ReactiveBlock, ReactiveFunction, + ReactiveInstruction, ReactiveScope, ScopeId, } from "../HIR"; @@ -98,9 +99,6 @@ import { ReactiveFunctionVisitor, visitReactiveFunction } from "./visitors"; */ export function mergeOverlappingReactiveScopes(fn: ReactiveFunction): void { const context = new Context(); - // context.enter(() => { - // visitBlock(context, fn.body); - // }); visitReactiveFunction(fn, new Visitor(), context); context.complete(); } @@ -120,6 +118,21 @@ class Visitor extends ReactiveFunctionVisitor { this.traverseBlock(block, state); }); } + override visitInstruction( + instruction: ReactiveInstruction, + state: Context + ): void { + if ( + instruction.value.kind === "ConditionalExpression" || + instruction.value.kind === "LogicalExpression" + ) { + state.enter(() => { + super.visitInstruction(instruction, state); + }); + } else { + super.visitInstruction(instruction, state); + } + } } class BlockScope { diff --git a/compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts b/compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts index a97f87fe47..d010d94c17 100644 --- a/compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts +++ b/compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts @@ -317,7 +317,10 @@ class Context { this.currentScope != null && place.identifier.scope != null && declaration !== undefined && - declaration.scope !== place.identifier.scope + declaration.scope !== place.identifier.scope && + !Array.from(this.currentScope.reassignments).some( + (ident) => ident.id === place.identifier.id + ) ) { this.currentScope.reassignments.add(place.identifier); } diff --git a/compiler/forget/src/__tests__/fixtures/compiler/ternary-assignment-expression.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/ternary-assignment-expression.expect.md new file mode 100644 index 0000000000..11c65cc63d --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/ternary-assignment-expression.expect.md @@ -0,0 +1,24 @@ + +## Input + +```javascript +function ternary(props) { + let x = 0; + const y = props.a ? (x = 1) : (x = 2); + return x + y; +} + +``` + +## Code + +```javascript +function ternary(props) { + let x = undefined; + + const y = props.a ? ((x = 1), 1) : ((x = 2), 2); + return x + y; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/compiler/ternary-assignment-expression.js b/compiler/forget/src/__tests__/fixtures/compiler/ternary-assignment-expression.js index 8149ac7839..4af307f679 100644 --- a/compiler/forget/src/__tests__/fixtures/compiler/ternary-assignment-expression.js +++ b/compiler/forget/src/__tests__/fixtures/compiler/ternary-assignment-expression.js @@ -1,4 +1,3 @@ -// @skip function ternary(props) { let x = 0; const y = props.a ? (x = 1) : (x = 2); diff --git a/compiler/forget/src/__tests__/fixtures/compiler/while-logical.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/while-logical.expect.md index 3db71487a1..af03624b86 100644 --- a/compiler/forget/src/__tests__/fixtures/compiler/while-logical.expect.md +++ b/compiler/forget/src/__tests__/fixtures/compiler/while-logical.expect.md @@ -2,12 +2,26 @@ ## Input ```javascript +function foo(props) { + let x = 0; + while (x > props.min && x < props.max) { + x *= 2; + } + return x; +} ``` ## Code ```javascript +function foo(props) { + let x = 0; + while (x > props.min && x < props.max) { + x = x * 2; + } + return x; +} ``` \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/compiler/while-logical.js b/compiler/forget/src/__tests__/fixtures/compiler/while-logical.js index 0a1e6db8ce..b0c94cb3d0 100644 --- a/compiler/forget/src/__tests__/fixtures/compiler/while-logical.js +++ b/compiler/forget/src/__tests__/fixtures/compiler/while-logical.js @@ -1,4 +1,3 @@ -// @skip function foo(props) { let x = 0; while (x > props.min && x < props.max) { diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction-with-mutation.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction-with-mutation.expect.md new file mode 100644 index 0000000000..59a9cc8df1 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction-with-mutation.expect.md @@ -0,0 +1,64 @@ + +## Input + +```javascript +function foo(props) { + let x = []; + x.push(props.bar); + const _ = props.cond + ? (({ x } = { x: {} }), ([x] = [[]]), x.push(props.foo)) + : null; + console.log(_); + mut(x); + return x; +} + +``` + +## HIR + +```javascript +bb0 (block): + [1] store $35[1:33] = Array [] + [2] store $37[2:33] = StoreLocal Let mutate x$36[2:33] = capture $35[1:33] + [3] mutate $38[3:33] = LoadLocal capture x$36[2:33] + [4] mutate $39 = LoadLocal read props$34 + [5] mutate $40 = PropertyLoad read $39.bar + [6] mutate $41 = PropertyCall mutate $38[3:33].push(read $40) + [7] Ternary test:bb2 fallthrough=bb1 +bb2 (value): + predecessor blocks: bb0 + [8] mutate $42 = LoadLocal read props$34 + [9] mutate $43 = PropertyLoad read $42.cond + [10] Branch (read $43) then:bb3 else:bb4 +bb3 (value): + predecessor blocks: bb2 + [14] store $48[14:33] = Array [] + [15] store $49[15:33] = Array [capture $48[14:33]] + [16] store $51[16:33] = Destructure Reassign [ mutate x$36[16:33] ] = capture $49[15:33] + [17] mutate $52[17:33] = LoadLocal capture x$36[16:33] + [18] mutate $53 = LoadLocal read props$34 + [19] mutate $54 = PropertyLoad read $53.foo + [20] mutate $55[20:30] = PropertyCall mutate $52[17:33].push(read $54) + [21] store $57[21:30] = StoreLocal Const mutate $56[7:30] = capture $55[20:30] + [22] Goto bb1 +bb4 (value): + predecessor blocks: bb2 + [23] mutate $58[23:30]:TPrimitive = null + [24] store $60[24:30]:TPrimitive = StoreLocal Const mutate $56[7:30] = read $58[23:30]:TPrimitive + [25] Goto bb1 +bb1 (block): + predecessor blocks: bb3 bb4 + $63[7:30]:TPhi: phi(bb3: $56, bb4: $59) + x$36[2:33]:TPhi: phi(bb3: x$36, bb4: x$36) + [26] store $62[26:30] = StoreLocal Const mutate _$61[26:30] = capture $56[7:30] + [27] mutate $64 = Global console + [28] mutate $65[28:30] = LoadLocal capture _$61[26:30] + [29] mutate $66 = PropertyCall read $64.log(mutate $65[28:30]) + [30] mutate $67:TFunction = Global mut + [31] mutate $68[31:33] = LoadLocal capture x$36[2:33] + [32] mutate $70 = Call read $67:TFunction(mutate $68[31:33]) + [33] mutate $71 = LoadLocal capture x$36[2:33] + [34] Return freeze $71 +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction-with-mutation.js b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction-with-mutation.js new file mode 100644 index 0000000000..e227256a9f --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction-with-mutation.js @@ -0,0 +1,10 @@ +function foo(props) { + let x = []; + x.push(props.bar); + const _ = props.cond + ? (({ x } = { x: {} }), ([x] = [[]]), x.push(props.foo)) + : null; + console.log(_); + mut(x); + return x; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction.expect.md new file mode 100644 index 0000000000..a0055dba41 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction.expect.md @@ -0,0 +1,60 @@ + +## Input + +```javascript +function foo(props) { + let x = []; + x.push(props.bar); + const _ = props.cond + ? (({ x } = { x: {} }), ([x] = [[]]), x.push(props.foo)) + : null; + console.log(_); + return x; +} + +``` + +## HIR + +```javascript +bb0 (block): + [1] store $32[1:7] = Array [] + [2] store $34[2:7] = StoreLocal Let mutate x$33[2:7] = capture $32[1:7] + [3] mutate $35[3:7] = LoadLocal capture x$33[2:7] + [4] mutate $36 = LoadLocal read props$31 + [5] mutate $37 = PropertyLoad read $36.bar + [6] mutate $38 = PropertyCall mutate $35[3:7].push(read $37) + [7] Ternary test:bb2 fallthrough=bb1 +bb2 (value): + predecessor blocks: bb0 + [8] mutate $39 = LoadLocal read props$31 + [9] mutate $40 = PropertyLoad read $39.cond + [10] Branch (read $40) then:bb3 else:bb4 +bb3 (value): + predecessor blocks: bb2 + [14] store $45[14:21] = Array [] + [15] store $46[15:21] = Array [capture $45[14:21]] + [16] store $48[16:21] = Destructure Reassign [ mutate x$33[16:21] ] = capture $46[15:21] + [17] mutate $49[17:21] = LoadLocal capture x$33[16:21] + [18] mutate $50 = LoadLocal read props$31 + [19] mutate $51 = PropertyLoad read $50.foo + [20] mutate $52[20:30] = PropertyCall mutate $49[17:21].push(read $51) + [21] store $54[21:30] = StoreLocal Const mutate $53[7:30] = capture $52[20:30] + [22] Goto bb1 +bb4 (value): + predecessor blocks: bb2 + [23] mutate $55[23:30]:TPrimitive = null + [24] store $57[24:30]:TPrimitive = StoreLocal Const mutate $53[7:30] = read $55[23:30]:TPrimitive + [25] Goto bb1 +bb1 (block): + predecessor blocks: bb3 bb4 + $60[7:30]:TPhi: phi(bb3: $53, bb4: $56) + x$33:TPhi: phi(bb3: x$33, bb4: x$33) + [26] store $59[26:30] = StoreLocal Const mutate _$58[26:30] = capture $53[7:30] + [27] mutate $61 = Global console + [28] mutate $62[28:30] = LoadLocal capture _$58[26:30] + [29] mutate $63 = PropertyCall read $61.log(mutate $62[28:30]) + [30] mutate $64 = LoadLocal capture x$33 + [31] Return freeze $64 +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction.js b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction.js new file mode 100644 index 0000000000..f1db380d55 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction.js @@ -0,0 +1,9 @@ +function foo(props) { + let x = []; + x.push(props.bar); + const _ = props.cond + ? (({ x } = { x: {} }), ([x] = [[]]), x.push(props.foo)) + : null; + console.log(_); + return x; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-with-mutation.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-with-mutation.expect.md new file mode 100644 index 0000000000..7249aecb7f --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-with-mutation.expect.md @@ -0,0 +1,61 @@ + +## Input + +```javascript +function foo(props) { + let x = []; + x.push(props.bar); + const _ = props.cond ? ((x = {}), (x = []), x.push(props.foo)) : null; + console.log(_); + mut(x); + return x; +} + +``` + +## HIR + +```javascript +bb0 (block): + [1] store $35[1:33] = Array [] + [2] store $37[2:33] = StoreLocal Let mutate x$36[2:33] = capture $35[1:33] + [3] mutate $38[3:33] = LoadLocal capture x$36[2:33] + [4] mutate $39 = LoadLocal read props$34 + [5] mutate $40 = PropertyLoad read $39.bar + [6] mutate $41 = PropertyCall mutate $38[3:33].push(read $40) + [7] Ternary test:bb2 fallthrough=bb1 +bb2 (value): + predecessor blocks: bb0 + [8] mutate $42 = LoadLocal read props$34 + [9] mutate $43 = PropertyLoad read $42.cond + [10] Branch (read $43) then:bb3 else:bb4 +bb3 (value): + predecessor blocks: bb2 + [14] store $48[14:33] = Array [] + [15] store $50[15:33] = StoreLocal Reassign mutate x$36[15:33] = capture $48[14:33] + [17] mutate $52[17:33] = LoadLocal capture x$36[15:33] + [18] mutate $53 = LoadLocal read props$34 + [19] mutate $54 = PropertyLoad read $53.foo + [20] mutate $55[20:30] = PropertyCall mutate $52[17:33].push(read $54) + [21] store $57[21:30] = StoreLocal Const mutate $56[7:30] = capture $55[20:30] + [22] Goto bb1 +bb4 (value): + predecessor blocks: bb2 + [23] mutate $58[23:30]:TPrimitive = null + [24] store $60[24:30]:TPrimitive = StoreLocal Const mutate $56[7:30] = read $58[23:30]:TPrimitive + [25] Goto bb1 +bb1 (block): + predecessor blocks: bb3 bb4 + $63[7:30]:TPhi: phi(bb3: $56, bb4: $59) + x$36[2:33]:TPhi: phi(bb3: x$36, bb4: x$36) + [26] store $62[26:30] = StoreLocal Const mutate _$61[26:30] = capture $56[7:30] + [27] mutate $64 = Global console + [28] mutate $65[28:30] = LoadLocal capture _$61[26:30] + [29] mutate $66 = PropertyCall read $64.log(mutate $65[28:30]) + [30] mutate $67:TFunction = Global mut + [31] mutate $68[31:33] = LoadLocal capture x$36[2:33] + [32] mutate $70 = Call read $67:TFunction(mutate $68[31:33]) + [33] mutate $71 = LoadLocal capture x$36[2:33] + [34] Return freeze $71 +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-with-mutation.js b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-with-mutation.js new file mode 100644 index 0000000000..fdfe6a91bd --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-with-mutation.js @@ -0,0 +1,8 @@ +function foo(props) { + let x = []; + x.push(props.bar); + const _ = props.cond ? ((x = {}), (x = []), x.push(props.foo)) : null; + console.log(_); + mut(x); + return x; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary.expect.md new file mode 100644 index 0000000000..5067990919 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary.expect.md @@ -0,0 +1,57 @@ + +## Input + +```javascript +function foo(props) { + let x = []; + x.push(props.bar); + const _ = props.cond ? ((x = {}), (x = []), x.push(props.foo)) : null; + console.log(_); + return x; +} + +``` + +## HIR + +```javascript +bb0 (block): + [1] store $32[1:7] = Array [] + [2] store $34[2:7] = StoreLocal Let mutate x$33[2:7] = capture $32[1:7] + [3] mutate $35[3:7] = LoadLocal capture x$33[2:7] + [4] mutate $36 = LoadLocal read props$31 + [5] mutate $37 = PropertyLoad read $36.bar + [6] mutate $38 = PropertyCall mutate $35[3:7].push(read $37) + [7] Ternary test:bb2 fallthrough=bb1 +bb2 (value): + predecessor blocks: bb0 + [8] mutate $39 = LoadLocal read props$31 + [9] mutate $40 = PropertyLoad read $39.cond + [10] Branch (read $40) then:bb3 else:bb4 +bb3 (value): + predecessor blocks: bb2 + [14] store $45[14:21] = Array [] + [15] store $47[15:21] = StoreLocal Reassign mutate x$33[15:21] = capture $45[14:21] + [17] mutate $49[17:21] = LoadLocal capture x$33[15:21] + [18] mutate $50 = LoadLocal read props$31 + [19] mutate $51 = PropertyLoad read $50.foo + [20] mutate $52[20:30] = PropertyCall mutate $49[17:21].push(read $51) + [21] store $54[21:30] = StoreLocal Const mutate $53[7:30] = capture $52[20:30] + [22] Goto bb1 +bb4 (value): + predecessor blocks: bb2 + [23] mutate $55[23:30]:TPrimitive = null + [24] store $57[24:30]:TPrimitive = StoreLocal Const mutate $53[7:30] = read $55[23:30]:TPrimitive + [25] Goto bb1 +bb1 (block): + predecessor blocks: bb3 bb4 + $60[7:30]:TPhi: phi(bb3: $53, bb4: $56) + x$33:TPhi: phi(bb3: x$33, bb4: x$33) + [26] store $59[26:30] = StoreLocal Const mutate _$58[26:30] = capture $53[7:30] + [27] mutate $61 = Global console + [28] mutate $62[28:30] = LoadLocal capture _$58[26:30] + [29] mutate $63 = PropertyCall read $61.log(mutate $62[28:30]) + [30] mutate $64 = LoadLocal capture x$33 + [31] Return freeze $64 +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary.js b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary.js new file mode 100644 index 0000000000..e80445a006 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary.js @@ -0,0 +1,7 @@ +function foo(props) { + let x = []; + x.push(props.bar); + const _ = props.cond ? ((x = {}), (x = []), x.push(props.foo)) : null; + console.log(_); + return x; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary-with-mutation.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary-with-mutation.expect.md new file mode 100644 index 0000000000..d5fadb893d --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary-with-mutation.expect.md @@ -0,0 +1,68 @@ + +## Input + +```javascript +function foo(props) { + let x = []; + x.push(props.bar); + const _ = props.cond + ? ((x = {}), (x = []), x.push(props.foo)) + : ((x = []), (x = []), x.push(props.bar)); + console.log(_); + mut(x); + return x; +} + +``` + +## HIR + +```javascript +bb0 (block): + [1] store $44[1:7] = Array [] + [2] store $46[2:7] = StoreLocal Let mutate x$45[2:42] = capture $44[1:7] + [3] mutate $47[3:7] = LoadLocal capture x$45[2:42] + [4] mutate $48 = LoadLocal read props$43 + [5] mutate $49 = PropertyLoad read $48.bar + [6] mutate $50 = PropertyCall mutate $47[3:7].push(read $49) + [7] Ternary test:bb2 fallthrough=bb1 +bb2 (value): + predecessor blocks: bb0 + [8] mutate $51 = LoadLocal read props$43 + [9] mutate $52 = PropertyLoad read $51.cond + [10] Branch (read $52) then:bb3 else:bb4 +bb3 (value): + predecessor blocks: bb2 + [14] store $57[14:42] = Array [] + [15] store $59[15:42] = StoreLocal Reassign mutate x$45[15:42] = capture $57[14:42] + [17] mutate $61[17:42] = LoadLocal capture x$45[15:42] + [18] mutate $62 = LoadLocal read props$43 + [19] mutate $63 = PropertyLoad read $62.foo + [20] mutate $64[20:39] = PropertyCall mutate $61[17:42].push(read $63) + [21] store $66[21:39] = StoreLocal Const mutate $65[7:39] = capture $64[20:39] + [22] Goto bb1 +bb4 (value): + predecessor blocks: bb2 + [26] store $71[26:42] = Array [] + [27] store $73[27:42] = StoreLocal Reassign mutate x$45[27:42] = capture $71[26:42] + [29] mutate $75[29:42] = LoadLocal capture x$45[27:42] + [30] mutate $76 = LoadLocal read props$43 + [31] mutate $77 = PropertyLoad read $76.bar + [32] mutate $78[32:39] = PropertyCall mutate $75[29:42].push(read $77) + [33] store $80[33:39] = StoreLocal Const mutate $65[7:39] = capture $78[32:39] + [34] Goto bb1 +bb1 (block): + predecessor blocks: bb3 bb4 + $83[7:39]:TPhi: phi(bb3: $65, bb4: $79) + x$45[15:42]:TPhi: phi(bb3: x$45, bb4: x$45) + [35] store $82[35:39] = StoreLocal Const mutate _$81[35:39] = capture $65[7:39] + [36] mutate $84 = Global console + [37] mutate $85[37:39] = LoadLocal capture _$81[35:39] + [38] mutate $86 = PropertyCall read $84.log(mutate $85[37:39]) + [39] mutate $87:TFunction = Global mut + [40] mutate $88[40:42] = LoadLocal capture x$45[15:42] + [41] mutate $90 = Call read $87:TFunction(mutate $88[40:42]) + [42] mutate $91 = LoadLocal capture x$45[15:42] + [43] Return freeze $91 +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary-with-mutation.js b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary-with-mutation.js new file mode 100644 index 0000000000..19eda5a564 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary-with-mutation.js @@ -0,0 +1,10 @@ +function foo(props) { + let x = []; + x.push(props.bar); + const _ = props.cond + ? ((x = {}), (x = []), x.push(props.foo)) + : ((x = []), (x = []), x.push(props.bar)); + console.log(_); + mut(x); + return x; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary.expect.md new file mode 100644 index 0000000000..4a81d7e4bd --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary.expect.md @@ -0,0 +1,64 @@ + +## Input + +```javascript +function foo(props) { + let x = []; + x.push(props.bar); + const _ = props.cond + ? ((x = {}), (x = []), x.push(props.foo)) + : ((x = []), (x = []), x.push(props.bar)); + console.log(_); + return x; +} + +``` + +## HIR + +```javascript +bb0 (block): + [1] store $41[1:7] = Array [] + [2] store $43[2:7] = StoreLocal Let mutate x$42[2:7] = capture $41[1:7] + [3] mutate $44[3:7] = LoadLocal capture x$42[2:7] + [4] mutate $45 = LoadLocal read props$40 + [5] mutate $46 = PropertyLoad read $45.bar + [6] mutate $47 = PropertyCall mutate $44[3:7].push(read $46) + [7] Ternary test:bb2 fallthrough=bb1 +bb2 (value): + predecessor blocks: bb0 + [8] mutate $48 = LoadLocal read props$40 + [9] mutate $49 = PropertyLoad read $48.cond + [10] Branch (read $49) then:bb3 else:bb4 +bb3 (value): + predecessor blocks: bb2 + [14] store $54[14:21] = Array [] + [15] store $56[15:21] = StoreLocal Reassign mutate x$42[15:21] = capture $54[14:21] + [17] mutate $58[17:21] = LoadLocal capture x$42[15:21] + [18] mutate $59 = LoadLocal read props$40 + [19] mutate $60 = PropertyLoad read $59.foo + [20] mutate $61[20:39] = PropertyCall mutate $58[17:21].push(read $60) + [21] store $63[21:39] = StoreLocal Const mutate $62[7:39] = capture $61[20:39] + [22] Goto bb1 +bb4 (value): + predecessor blocks: bb2 + [26] store $68[26:33] = Array [] + [27] store $70[27:33] = StoreLocal Reassign mutate x$42[27:33] = capture $68[26:33] + [29] mutate $72[29:33] = LoadLocal capture x$42[27:33] + [30] mutate $73 = LoadLocal read props$40 + [31] mutate $74 = PropertyLoad read $73.bar + [32] mutate $75[32:39] = PropertyCall mutate $72[29:33].push(read $74) + [33] store $77[33:39] = StoreLocal Const mutate $62[7:39] = capture $75[32:39] + [34] Goto bb1 +bb1 (block): + predecessor blocks: bb3 bb4 + $80[7:39]:TPhi: phi(bb3: $62, bb4: $76) + x$42:TPhi: phi(bb3: x$42, bb4: x$42) + [35] store $79[35:39] = StoreLocal Const mutate _$78[35:39] = capture $62[7:39] + [36] mutate $81 = Global console + [37] mutate $82[37:39] = LoadLocal capture _$78[35:39] + [38] mutate $83 = PropertyCall read $81.log(mutate $82[37:39]) + [39] mutate $84 = LoadLocal capture x$42 + [40] Return freeze $84 +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary.js b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary.js new file mode 100644 index 0000000000..140005d820 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary.js @@ -0,0 +1,9 @@ +function foo(props) { + let x = []; + x.push(props.bar); + const _ = props.cond + ? ((x = {}), (x = []), x.push(props.foo)) + : ((x = []), (x = []), x.push(props.bar)); + console.log(_); + return x; +} diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-with-mutation.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-with-mutation.expect.md new file mode 100644 index 0000000000..99f7b097d1 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-with-mutation.expect.md @@ -0,0 +1,63 @@ + +## Input + +```javascript +function foo(props) { + let x = []; + x.push(props.bar); + if (props.cond) { + x = {}; + x = []; + x.push(props.foo); + } else { + x = []; + x = []; + x.push(props.bar); + } + mut(x); + return x; +} + +``` + +## HIR + +```javascript +bb0 (block): + [1] store $36[1:7] = Array [] + [2] store $38[2:7] = StoreLocal Let mutate x$37[2:35] = capture $36[1:7] + [3] mutate $39[3:7] = LoadLocal capture x$37[2:35] + [4] mutate $40 = LoadLocal read props$35 + [5] mutate $41 = PropertyLoad read $40.bar + [6] mutate $42 = PropertyCall mutate $39[3:7].push(read $41) + [7] mutate $43 = LoadLocal read props$35 + [8] mutate $44 = PropertyLoad read $43.cond + [9] If (read $44) then:bb2 else:bb3 fallthrough=bb1 +bb2 (block): + predecessor blocks: bb0 + [13] store $49[13:35] = Array [] + [14] store $51[14:35] = StoreLocal Reassign mutate x$37[14:35] = capture $49[13:35] + [16] mutate $53[16:35] = LoadLocal capture x$37[14:35] + [17] mutate $54 = LoadLocal read props$35 + [18] mutate $55 = PropertyLoad read $54.foo + [19] mutate $56 = PropertyCall mutate $53[16:35].push(read $55) + [20] Goto bb1 +bb3 (block): + predecessor blocks: bb0 + [24] store $61[24:35] = Array [] + [25] store $63[25:35] = StoreLocal Reassign mutate x$37[25:35] = capture $61[24:35] + [27] mutate $65[27:35] = LoadLocal capture x$37[25:35] + [28] mutate $66 = LoadLocal read props$35 + [29] mutate $67 = PropertyLoad read $66.bar + [30] mutate $68 = PropertyCall mutate $65[27:35].push(read $67) + [31] Goto bb1 +bb1 (block): + predecessor blocks: bb2 bb3 + x$37[14:35]:TPhi: phi(bb2: x$37, bb3: x$37) + [32] mutate $69:TFunction = Global mut + [33] mutate $70[33:35] = LoadLocal capture x$37[14:35] + [34] mutate $72 = Call read $69:TFunction(mutate $70[33:35]) + [35] mutate $73 = LoadLocal capture x$37[14:35] + [36] Return freeze $73 +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-with-mutation.js b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-with-mutation.js new file mode 100644 index 0000000000..f5d09dbf30 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-with-mutation.js @@ -0,0 +1,15 @@ +function foo(props) { + let x = []; + x.push(props.bar); + if (props.cond) { + x = {}; + x = []; + x.push(props.foo); + } else { + x = []; + x = []; + x.push(props.bar); + } + mut(x); + return x; +}