diff --git a/compiler/forget/src/HIR/BuildHIR.ts b/compiler/forget/src/HIR/BuildHIR.ts index ce418cf400..2fb0e3163a 100644 --- a/compiler/forget/src/HIR/BuildHIR.ts +++ b/compiler/forget/src/HIR/BuildHIR.ts @@ -905,18 +905,7 @@ function lowerExpression( return { kind: "UnsupportedNode", node: exprNode, loc: exprLoc }; } const callee = lowerExpressionToTemporary(builder, calleePath); - let args: Place[] = []; - for (const argPath of expr.get("arguments")) { - if (!argPath.isExpression()) { - builder.errors.push({ - reason: `(BuildHIR::lowerExpression) Handle ${argPath.type} arguments in NewExpression`, - severity: ErrorSeverity.Todo, - nodePath: argPath, - }); - continue; - } - args.push(lowerExpressionToTemporary(builder, argPath)); - } + const args = lowerArguments(builder, expr.get("arguments")); return { kind: "NewExpression", @@ -938,26 +927,7 @@ function lowerExpression( } if (calleePath.isMemberExpression()) { const { object, property } = lowerMemberExpression(builder, calleePath); - let args: Array = []; - for (const argPath of expr.get("arguments")) { - if (argPath.isSpreadElement()) { - args.push({ - kind: "Spread", - place: lowerExpressionToTemporary( - builder, - argPath.get("argument") - ), - }); - } else if (argPath.isExpression()) { - args.push(lowerExpressionToTemporary(builder, argPath)); - } else { - builder.errors.push({ - reason: `(BuildHIR::lowerExpression) Handle ${argPath.type} arguments in CallExpression`, - severity: ErrorSeverity.Todo, - nodePath: argPath, - }); - } - } + const args = lowerArguments(builder, expr.get("arguments")); if (typeof property === "string") { return { kind: "PropertyCall", @@ -977,27 +947,7 @@ function lowerExpression( } } else { const callee = lowerExpressionToTemporary(builder, calleePath); - let args: Array = []; - for (const argPath of expr.get("arguments")) { - if (argPath.isSpreadElement()) { - args.push({ - kind: "Spread", - place: lowerExpressionToTemporary( - builder, - argPath.get("argument") - ), - }); - } else if (argPath.isExpression()) { - args.push(lowerExpressionToTemporary(builder, argPath)); - } else { - builder.errors.push({ - reason: `(BuildHIR::lowerExpression) Handle ${argPath.type} arguments in CallExpression`, - severity: ErrorSeverity.Todo, - nodePath: argPath, - }); - continue; - } - } + const args = lowerArguments(builder, expr.get("arguments")); return { kind: "CallExpression", callee, @@ -1695,6 +1645,37 @@ function lowerExpression( } } +function lowerArguments( + builder: HIRBuilder, + expr: Array< + NodePath< + | t.Expression + | t.SpreadElement + | t.JSXNamespacedName + | t.ArgumentPlaceholder + > + > +): Array { + let args: Array = []; + for (const argPath of expr) { + if (argPath.isSpreadElement()) { + args.push({ + kind: "Spread", + place: lowerExpressionToTemporary(builder, argPath.get("argument")), + }); + } else if (argPath.isExpression()) { + args.push(lowerExpressionToTemporary(builder, argPath)); + } else { + builder.errors.push({ + reason: `(BuildHIR::lowerExpression) Handle ${argPath.type} arguments in CallExpression`, + severity: ErrorSeverity.Todo, + nodePath: argPath, + }); + } + } + return args; +} + function lowerMemberExpression( builder: HIRBuilder, expr: NodePath diff --git a/compiler/forget/src/HIR/HIR.ts b/compiler/forget/src/HIR/HIR.ts index 8002f9af22..2fd501a46f 100644 --- a/compiler/forget/src/HIR/HIR.ts +++ b/compiler/forget/src/HIR/HIR.ts @@ -479,7 +479,7 @@ export type InstructionValue = | { kind: "NewExpression"; callee: Place; - args: Array; + args: Array; loc: SourceLocation; } | { diff --git a/compiler/forget/src/HIR/PrintHIR.ts b/compiler/forget/src/HIR/PrintHIR.ts index 1b9a423583..a8991a47c4 100644 --- a/compiler/forget/src/HIR/PrintHIR.ts +++ b/compiler/forget/src/HIR/PrintHIR.ts @@ -256,6 +256,12 @@ export function printInstructionValue(instrValue: ReactiveValue): string { } ${printPlace(instrValue.right)}`; break; } + case "NewExpression": { + value = `New ${printPlace(instrValue.callee)}(${instrValue.args + .map((arg) => printPattern(arg)) + .join(", ")})`; + break; + } case "CallExpression": { value = `Call ${printPlace(instrValue.callee)}(${instrValue.args .map((arg) => printPattern(arg)) @@ -287,7 +293,11 @@ export function printInstructionValue(instrValue: ReactiveValue): string { const propItems = []; for (const attribute of instrValue.props) { if (attribute.kind === "JsxAttribute") { - propItems.push(`${attribute.name}={${printPlace(attribute.place)}}`); + propItems.push( + `${attribute.name}={${ + attribute.place !== null ? printPlace(attribute.place) : "" + }}` + ); } else { propItems.push(`...${printPlace(attribute.argument)}`); } @@ -313,12 +323,6 @@ export function printInstructionValue(instrValue: ReactiveValue): string { .join(", ")}]`; break; } - case "NewExpression": { - value = `New ${printPlace(instrValue.callee)}(${instrValue.args - .map((arg) => printPlace(arg)) - .join(", ")})`; - break; - } case "UnsupportedNode": { value = `UnsupportedNode(${generate(instrValue.node).code})`; break; diff --git a/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts index b4883a352b..58b41a2a8f 100644 --- a/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts +++ b/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts @@ -594,7 +594,7 @@ function codegenInstructionValue( } case "NewExpression": { const callee = codegenPlace(cx, instrValue.callee); - const args = instrValue.args.map((arg) => codegenPlace(cx, arg)); + const args = instrValue.args.map((arg) => codegenArgument(cx, arg)); value = t.newExpression(callee, args); break; } diff --git a/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md index 92d06e5dce..637caca4ca 100644 --- a/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md +++ b/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md @@ -14,7 +14,6 @@ function foo([a, b], { c, d, e = "e" }, f = "f", ...args) { } const g = { b() {}, c: () => {} }; - new c(...args); const { z, aa = "aa" } = useCustom(); ; @@ -126,234 +125,225 @@ let moduleLocal = false; 11 | > 12 | const g = { b() {}, c: () => {} }; | ^^^^^^ - 13 | new c(...args); - 14 | const { z, aa = "aa" } = useCustom(); - 15 | - -[ReactForget] TodoError: (BuildHIR::lowerExpression) Handle SpreadElement arguments in NewExpression - 11 | - 12 | const g = { b() {}, c: () => {} }; -> 13 | new c(...args); - | ^^^^^^^ - 14 | const { z, aa = "aa" } = useCustom(); - 15 | - 16 | ; + 13 | const { z, aa = "aa" } = useCustom(); + 14 | + 15 | ; [ReactForget] TodoError: (BuildHIR::lowerAssignment) Handle AssignmentPattern assignments + 11 | 12 | const g = { b() {}, c: () => {} }; - 13 | new c(...args); -> 14 | const { z, aa = "aa" } = useCustom(); +> 13 | const { z, aa = "aa" } = useCustom(); | ^^^^^^^^^ - 15 | - 16 | ; - 17 | ; + 14 | + 15 | ; + 16 | ; [ReactForget] TodoError: (BuildHIR::lowerExpression) Handle JSXNamespacedName attribute names in JSXElement - 14 | const { z, aa = "aa" } = useCustom(); - 15 | -> 16 | ; + 13 | const { z, aa = "aa" } = useCustom(); + 14 | +> 15 | ; | ^^^^^^^^^^ - 17 | ; - 18 | ; - 19 | ; + 16 | ; + 17 | ; + 18 | ; [ReactForget] TodoError: (BuildHIR::lowerJsxElement) Handle JSXEmptyExpression expressions - 16 | ; - 17 | ; -> 18 | ; + 15 | ; + 16 | ; +> 17 | ; | ^^^^^^^^^^^^ - 19 | ; - 20 | - 21 | const j = function bar([quz, qux], ...args) {}; + 18 | ; + 19 | + 20 | const j = function bar([quz, qux], ...args) {}; [ReactForget] TodoError: (BuildHIR::lower) Handle RestElement params - 19 | ; - 20 | -> 21 | const j = function bar([quz, qux], ...args) {}; + 18 | ; + 19 | +> 20 | const j = function bar([quz, qux], ...args) {}; | ^^^^^^^ - 22 | - 23 | for (; i < 3; i += 1) { - 24 | x.push(i); + 21 | + 22 | for (; i < 3; i += 1) { + 23 | x.push(i); [ReactForget] TodoError: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement - 21 | const j = function bar([quz, qux], ...args) {}; - 22 | -> 23 | for (; i < 3; i += 1) { + 20 | const j = function bar([quz, qux], ...args) {}; + 21 | +> 22 | for (; i < 3; i += 1) { | ^ - 24 | x.push(i); - 25 | } - 26 | for (; i < 3; ) { + 23 | x.push(i); + 24 | } + 25 | for (; i < 3; ) { [ReactForget] TodoError: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement - 24 | x.push(i); - 25 | } -> 26 | for (; i < 3; ) { + 23 | x.push(i); + 24 | } +> 25 | for (; i < 3; ) { | ^ - 27 | break; - 28 | } - 29 | for (;;) { + 26 | break; + 27 | } + 28 | for (;;) { [ReactForget] TodoError: (BuildHIR::lowerStatement) Handle empty update in ForStatement - 24 | x.push(i); - 25 | } -> 26 | for (; i < 3; ) { + 23 | x.push(i); + 24 | } +> 25 | for (; i < 3; ) { | ^ - 27 | break; - 28 | } - 29 | for (;;) { + 26 | break; + 27 | } + 28 | for (;;) { [ReactForget] TodoError: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement - 27 | break; - 28 | } -> 29 | for (;;) { + 26 | break; + 27 | } +> 28 | for (;;) { | ^ - 30 | break; - 31 | } - 32 | + 29 | break; + 30 | } + 31 | [ReactForget] TodoError: (BuildHIR::lowerStatement) Handle empty update in ForStatement - 27 | break; - 28 | } -> 29 | for (;;) { + 26 | break; + 27 | } +> 28 | for (;;) { | ^ - 30 | break; - 31 | } - 32 | + 29 | break; + 30 | } + 31 | [ReactForget] TodoError: (BuildHIR::lowerStatement) Handle empty test in ForStatement - 27 | break; - 28 | } -> 29 | for (;;) { + 26 | break; + 27 | } +> 28 | for (;;) { | ^ - 30 | break; - 31 | } - 32 | + 29 | break; + 30 | } + 31 | [ReactForget] TodoError: (BuildHIR::lowerExpression) Handle tagged template with interpolations - 31 | } - 32 | -> 33 | graphql` + 30 | } + 31 | +> 32 | graphql` | ^ - 34 | ${g} - 35 | `; - 36 | + 33 | ${g} + 34 | `; + 35 | [ReactForget] TodoError: (BuildHIR::lowerExpression) Handle tagged template where cooked value is different from raw value - 35 | `; - 36 | -> 37 | graphql`\\t\n`; + 34 | `; + 35 | +> 36 | graphql`\\t\n`; | ^^^^^^^^^^^^^^ - 38 | - 39 | for (const c of [1, 2]) { - 40 | } + 37 | + 38 | for (const c of [1, 2]) { + 39 | } [ReactForget] TodoError: (BuildHIR::lowerStatement) Handle ForOfStatement statements - 37 | graphql`\\t\n`; - 38 | -> 39 | for (const c of [1, 2]) { + 36 | graphql`\\t\n`; + 37 | +> 38 | for (const c of [1, 2]) { | ^ - 40 | } - 41 | - 42 | for (let x in { a: 1 }) { + 39 | } + 40 | + 41 | for (let x in { a: 1 }) { [ReactForget] TodoError: (BuildHIR::lowerStatement) Handle ForInStatement statements - 40 | } - 41 | -> 42 | for (let x in { a: 1 }) { + 39 | } + 40 | +> 41 | for (let x in { a: 1 }) { | ^ - 43 | } - 44 | - 45 | let updateIdentifier = 0; + 42 | } + 43 | + 44 | let updateIdentifier = 0; [ReactForget] TodoError: (BuildHIR::lowerExpression) Handle prefix UpdateExpression - 44 | - 45 | let updateIdentifier = 0; -> 46 | --updateIdentifier; + 43 | + 44 | let updateIdentifier = 0; +> 45 | --updateIdentifier; | ^^^^^^^^^^^^^^^^^^ - 47 | ++updateIdentifier; - 48 | updateIdentifier.y++; - 49 | updateIdentifier.y--; + 46 | ++updateIdentifier; + 47 | updateIdentifier.y++; + 48 | updateIdentifier.y--; [ReactForget] TodoError: (BuildHIR::lowerExpression) Handle prefix UpdateExpression - 45 | let updateIdentifier = 0; - 46 | --updateIdentifier; -> 47 | ++updateIdentifier; + 44 | let updateIdentifier = 0; + 45 | --updateIdentifier; +> 46 | ++updateIdentifier; | ^^^^^^^^^^^^^^^^^^ - 48 | updateIdentifier.y++; - 49 | updateIdentifier.y--; - 50 | + 47 | updateIdentifier.y++; + 48 | updateIdentifier.y--; + 49 | [ReactForget] TodoError: (BuildHIR::lowerExpression) Handle UpdateExpression with MemberExpression argument - 46 | --updateIdentifier; - 47 | ++updateIdentifier; -> 48 | updateIdentifier.y++; + 45 | --updateIdentifier; + 46 | ++updateIdentifier; +> 47 | updateIdentifier.y++; | ^^^^^^^^^^^^^^^^^^^^ - 49 | updateIdentifier.y--; - 50 | - 51 | switch (i) { + 48 | updateIdentifier.y--; + 49 | + 50 | switch (i) { [ReactForget] TodoError: (BuildHIR::lowerExpression) Handle UpdateExpression with MemberExpression argument - 47 | ++updateIdentifier; - 48 | updateIdentifier.y++; -> 49 | updateIdentifier.y--; + 46 | ++updateIdentifier; + 47 | updateIdentifier.y++; +> 48 | updateIdentifier.y--; | ^^^^^^^^^^^^^^^^^^^^ - 50 | - 51 | switch (i) { - 52 | case 1 + 1: { + 49 | + 50 | switch (i) { + 51 | case 1 + 1: { [ReactForget] TodoError: (BuildHIR::lowerStatement) Switch case test values must be identifiers or primitives, compound values are not yet supported - 54 | case foo(): { - 55 | } -> 56 | case x.y: { + 53 | case foo(): { + 54 | } +> 55 | case x.y: { | ^^^ - 57 | } - 58 | default: { - 59 | } + 56 | } + 57 | default: { + 58 | } [ReactForget] TodoError: (BuildHIR::lowerStatement) Switch case test values must be identifiers or primitives, compound values are not yet supported - 52 | case 1 + 1: { - 53 | } -> 54 | case foo(): { + 51 | case 1 + 1: { + 52 | } +> 53 | case foo(): { | ^^^^^ - 55 | } - 56 | case x.y: { - 57 | } + 54 | } + 55 | case x.y: { + 56 | } [ReactForget] TodoError: (BuildHIR::lowerStatement) Switch case test values must be identifiers or primitives, compound values are not yet supported - 50 | - 51 | switch (i) { -> 52 | case 1 + 1: { + 49 | + 50 | switch (i) { +> 51 | case 1 + 1: { | ^^^^^ - 53 | } - 54 | case foo(): { - 55 | } + 52 | } + 53 | case foo(): { + 54 | } [ReactForget] InvalidInputError: (BuildHIR::lowerAssignment) Assigning to an identifier defined outside the function scope is not supported. - 61 | - 62 | // Cannot assign to globals -> 63 | someUnknownGlobal = true; + 60 | + 61 | // Cannot assign to globals +> 62 | someUnknownGlobal = true; | ^^^^^^^^^^^^^^^^^ - 64 | moduleLocal = true; - 65 | - 66 | function component(a) { + 63 | moduleLocal = true; + 64 | + 65 | function component(a) { [ReactForget] InvalidInputError: (BuildHIR::lowerAssignment) Assigning to an identifier defined outside the function scope is not supported. - 62 | // Cannot assign to globals - 63 | someUnknownGlobal = true; -> 64 | moduleLocal = true; + 61 | // Cannot assign to globals + 62 | someUnknownGlobal = true; +> 63 | moduleLocal = true; | ^^^^^^^^^^^ - 65 | - 66 | function component(a) { - 67 | // Add support for function declarations once we support `var` hoisting. + 64 | + 65 | function component(a) { + 66 | // Add support for function declarations once we support `var` hoisting. [ReactForget] TodoError: (BuildHIR::lowerStatement) Handle FunctionDeclaration statements - 64 | moduleLocal = true; - 65 | -> 66 | function component(a) { + 63 | moduleLocal = true; + 64 | +> 65 | function component(a) { | ^ - 67 | // Add support for function declarations once we support `var` hoisting. - 68 | function t() {} - 69 | t(); + 66 | // Add support for function declarations once we support `var` hoisting. + 67 | function t() {} + 68 | t(); ``` \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.js b/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.js index 8054719c52..6addd8d50e 100644 --- a/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.js +++ b/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.js @@ -10,7 +10,6 @@ function foo([a, b], { c, d, e = "e" }, f = "f", ...args) { } const g = { b() {}, c: () => {} }; - new c(...args); const { z, aa = "aa" } = useCustom(); ; diff --git a/compiler/forget/src/__tests__/fixtures/compiler/new-spread.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/new-spread.expect.md new file mode 100644 index 0000000000..784e5a599c --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/new-spread.expect.md @@ -0,0 +1,33 @@ + +## Input + +```javascript +function Component(props) { + const x = new Foo(...props.foo, null, ...[props.bar]); + return x; +} + +``` + +## Code + +```javascript +function Component(props) { + const $ = React.unstable_useMemoCache(3); + const c_0 = $[0] !== props.bar; + const c_1 = $[1] !== props.foo; + let t0; + if (c_0 || c_1) { + t0 = new Foo(...props.foo, null, ...[props.bar]); + $[0] = props.bar; + $[1] = props.foo; + $[2] = t0; + } else { + t0 = $[2]; + } + const x = t0; + return x; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/compiler/new-spread.js b/compiler/forget/src/__tests__/fixtures/compiler/new-spread.js new file mode 100644 index 0000000000..f8a139d588 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/new-spread.js @@ -0,0 +1,4 @@ +function Component(props) { + const x = new Foo(...props.foo, null, ...[props.bar]); + return x; +}