From 7537df3d4e2e31cbaff3e96782f890523d13908f Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Tue, 14 Mar 2023 20:02:05 -0700 Subject: [PATCH] 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. --- compiler/forget/.eslintrc.js | 4 ++ compiler/forget/src/HIR/BuildHIR.ts | 11 --- .../MergeOverlappingReactiveScopes.ts | 19 +++++- .../PropagateScopeDependencies.ts | 5 +- .../ternary-assignment-expression.expect.md | 24 +++++++ .../compiler/ternary-assignment-expression.js | 1 - .../fixtures/compiler/while-logical.expect.md | 14 ++++ .../fixtures/compiler/while-logical.js | 1 - ...ernary-destruction-with-mutation.expect.md | 64 +++++++++++++++++ ...aming-ternary-destruction-with-mutation.js | 10 +++ ...ssa-renaming-ternary-destruction.expect.md | 60 ++++++++++++++++ .../hir/ssa-renaming-ternary-destruction.js | 9 +++ ...a-renaming-ternary-with-mutation.expect.md | 61 +++++++++++++++++ .../hir/ssa-renaming-ternary-with-mutation.js | 8 +++ .../hir/ssa-renaming-ternary.expect.md | 57 ++++++++++++++++ .../fixtures/hir/ssa-renaming-ternary.js | 7 ++ ...onditional-ternary-with-mutation.expect.md | 68 +++++++++++++++++++ ...ing-unconditional-ternary-with-mutation.js | 10 +++ ...a-renaming-unconditional-ternary.expect.md | 64 +++++++++++++++++ .../hir/ssa-renaming-unconditional-ternary.js | 9 +++ ...ming-unconditional-with-mutation.expect.md | 63 +++++++++++++++++ ...sa-renaming-unconditional-with-mutation.js | 15 ++++ 22 files changed, 567 insertions(+), 17 deletions(-) create mode 100644 compiler/forget/src/__tests__/fixtures/compiler/ternary-assignment-expression.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction-with-mutation.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction-with-mutation.js create mode 100644 compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-destruction.js create mode 100644 compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-with-mutation.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary-with-mutation.js create mode 100644 compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-ternary.js create mode 100644 compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary-with-mutation.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary-with-mutation.js create mode 100644 compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-ternary.js create mode 100644 compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-with-mutation.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/hir/ssa-renaming-unconditional-with-mutation.js 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; +}