diff --git a/compiler/forget/src/HIR/BuildHIR.ts b/compiler/forget/src/HIR/BuildHIR.ts index 9aa8b70542..00d3ae87e1 100644 --- a/compiler/forget/src/HIR/BuildHIR.ts +++ b/compiler/forget/src/HIR/BuildHIR.ts @@ -858,9 +858,24 @@ function lowerExpression( } case "ArrayExpression": { const expr = exprPath as NodePath; - let elements: Place[] = []; + let elements: Array = []; for (const element of expr.get("elements")) { - if (element.node == null || !element.isExpression()) { + if (element.node == null) { + builder.errors.push({ + reason: `(BuildHIR::lowerExpression) Handle ${element.type} elements in ArrayExpression`, + severity: ErrorSeverity.Todo, + nodePath: element, + }); + continue; + } else if (element.isExpression()) { + elements.push(lowerExpressionToTemporary(builder, element)); + } else if (element.isSpreadElement()) { + const place = lowerExpressionToTemporary( + builder, + element.get("argument") + ); + elements.push({ kind: "Spread", place }); + } else { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${element.type} elements in ArrayExpression`, severity: ErrorSeverity.Todo, @@ -868,9 +883,6 @@ function lowerExpression( }); continue; } - elements.push( - lowerExpressionToTemporary(builder, element as NodePath) - ); } return { kind: "ArrayExpression", diff --git a/compiler/forget/src/HIR/HIR.ts b/compiler/forget/src/HIR/HIR.ts index 2b3a56fa66..af34e9e531 100644 --- a/compiler/forget/src/HIR/HIR.ts +++ b/compiler/forget/src/HIR/HIR.ts @@ -521,7 +521,11 @@ export type InstructionValue = properties: Array; loc: SourceLocation; } - | { kind: "ArrayExpression"; elements: Array; loc: SourceLocation } + | { + kind: "ArrayExpression"; + elements: Array; + loc: SourceLocation; + } | { kind: "JsxFragment"; children: Array; loc: SourceLocation } // store `object.property = value` diff --git a/compiler/forget/src/HIR/PrintHIR.ts b/compiler/forget/src/HIR/PrintHIR.ts index 07f0d29d48..690828ffcf 100644 --- a/compiler/forget/src/HIR/PrintHIR.ts +++ b/compiler/forget/src/HIR/PrintHIR.ts @@ -222,7 +222,13 @@ export function printInstructionValue(instrValue: ReactiveValue): string { switch (instrValue.kind) { case "ArrayExpression": { value = `Array [${instrValue.elements - .map((element) => printPlace(element)) + .map((element) => { + if (element.kind === "Identifier") { + return printPlace(element); + } else { + return `...${printPlace(element.place)}`; + } + }) .join(", ")}]`; break; } diff --git a/compiler/forget/src/HIR/visitors.ts b/compiler/forget/src/HIR/visitors.ts index 899b96cdf7..2ee5644fc3 100644 --- a/compiler/forget/src/HIR/visitors.ts +++ b/compiler/forget/src/HIR/visitors.ts @@ -136,7 +136,13 @@ export function* eachInstructionValueOperand( break; } case "ArrayExpression": { - yield* instrValue.elements; + for (const element of instrValue.elements) { + if (element.kind === "Identifier") { + yield element; + } else { + yield element.place; + } + } break; } case "FunctionExpression": { @@ -331,7 +337,14 @@ export function mapInstructionOperands( break; } case "ArrayExpression": { - instrValue.elements = instrValue.elements.map((e) => fn(e)); + instrValue.elements = instrValue.elements.map((element) => { + if (element.kind === "Identifier") { + return fn(element); + } else { + element.place = fn(element.place); + return element; + } + }); break; } case "JsxFragment": { diff --git a/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts index 1db1c89ac1..fbec7b76b7 100644 --- a/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts +++ b/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts @@ -525,9 +525,13 @@ function codegenInstructionValue( let value: t.Expression; switch (instrValue.kind) { case "ArrayExpression": { - const elements = instrValue.elements.map((element) => - codegenPlace(cx, element) - ); + const elements = instrValue.elements.map((element) => { + if (element.kind === "Identifier") { + return codegenPlace(cx, element); + } else { + return t.spreadElement(codegenPlace(cx, element.place)); + } + }); value = t.arrayExpression(elements); break; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/array-expression-spread.expect.md b/compiler/forget/src/__tests__/fixtures/hir/array-expression-spread.expect.md new file mode 100644 index 0000000000..5b239910a8 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/array-expression-spread.expect.md @@ -0,0 +1,33 @@ + +## Input + +```javascript +function Component(props) { + const x = [0, ...props.foo, null, ...props.bar, "z"]; + return x; +} + +``` + +## Code + +```javascript +function Component(props) { + const $ = React.unstable_useMemoCache(3); + const c_0 = $[0] !== props.foo; + const c_1 = $[1] !== props.bar; + let t0; + if (c_0 || c_1) { + t0 = [0, ...props.foo, null, ...props.bar, "z"]; + $[0] = props.foo; + $[1] = props.bar; + $[2] = t0; + } else { + t0 = $[2]; + } + const x = t0; + return x; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/array-expression-spread.js b/compiler/forget/src/__tests__/fixtures/hir/array-expression-spread.js new file mode 100644 index 0000000000..74a101b11d --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/array-expression-spread.js @@ -0,0 +1,4 @@ +function Component(props) { + const x = [0, ...props.foo, null, ...props.bar, "z"]; + return x; +}