@samitouri / QOS-React-2 / commits / e381aa042f

Support spread elements in ArrayExpression

Similar to the previous, but for array expression: `const x = [...y]`

Joe Savona committed Mar 6, 2023 at 15:32 UTC e381aa042fe29943cd3e96655bce13b1fac378b4
7 files changed +88 -12
compiler/forget/src/HIR/BuildHIR.ts
+17 -5
@@ -858,9 +858,24 @@ function lowerExpression(
858 }
859 case "ArrayExpression": {
860 const expr = exprPath as NodePath<t.ArrayExpression>;
861 - let elements: Place[] = [];
861 + let elements: Array<Place | SpreadPattern> = [];
862 for (const element of expr.get("elements")) {
863 - if (element.node == null || !element.isExpression()) {
863 + if (element.node == null) {
864 + builder.errors.push({
865 + reason: `(BuildHIR::lowerExpression) Handle ${element.type} elements in ArrayExpression`,
866 + severity: ErrorSeverity.Todo,
867 + nodePath: element,
868 + });
869 + continue;
870 + } else if (element.isExpression()) {
871 + elements.push(lowerExpressionToTemporary(builder, element));
872 + } else if (element.isSpreadElement()) {
873 + const place = lowerExpressionToTemporary(
874 + builder,
875 + element.get("argument")
876 + );
877 + elements.push({ kind: "Spread", place });
878 + } else {
879 builder.errors.push({
880 reason: `(BuildHIR::lowerExpression) Handle ${element.type} elements in ArrayExpression`,
881 severity: ErrorSeverity.Todo,
@@ -868,9 +883,6 @@ function lowerExpression(
883 });
884 continue;
885 }
871 - elements.push(
872 - lowerExpressionToTemporary(builder, element as NodePath<t.Expression>)
873 - );
886 }
887 return {
888 kind: "ArrayExpression",
compiler/forget/src/HIR/HIR.ts
+5 -1
@@ -521,7 +521,11 @@ export type InstructionValue =
521 properties: Array<ObjectProperty | SpreadPattern>;
522 loc: SourceLocation;
523 }
524 - | { kind: "ArrayExpression"; elements: Array<Place>; loc: SourceLocation }
524 + | {
525 + kind: "ArrayExpression";
526 + elements: Array<Place | SpreadPattern>;
527 + loc: SourceLocation;
528 + }
529 | { kind: "JsxFragment"; children: Array<Place>; loc: SourceLocation }
530
531 // store `object.property = value`
compiler/forget/src/HIR/PrintHIR.ts
+7 -1
@@ -222,7 +222,13 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
222 switch (instrValue.kind) {
223 case "ArrayExpression": {
224 value = `Array [${instrValue.elements
225 - .map((element) => printPlace(element))
225 + .map((element) => {
226 + if (element.kind === "Identifier") {
227 + return printPlace(element);
228 + } else {
229 + return `...${printPlace(element.place)}`;
230 + }
231 + })
232 .join(", ")}]`;
233 break;
234 }
compiler/forget/src/HIR/visitors.ts
+15 -2
@@ -136,7 +136,13 @@ export function* eachInstructionValueOperand(
136 break;
137 }
138 case "ArrayExpression": {
139 - yield* instrValue.elements;
139 + for (const element of instrValue.elements) {
140 + if (element.kind === "Identifier") {
141 + yield element;
142 + } else {
143 + yield element.place;
144 + }
145 + }
146 break;
147 }
148 case "FunctionExpression": {
@@ -331,7 +337,14 @@ export function mapInstructionOperands(
337 break;
338 }
339 case "ArrayExpression": {
334 - instrValue.elements = instrValue.elements.map((e) => fn(e));
340 + instrValue.elements = instrValue.elements.map((element) => {
341 + if (element.kind === "Identifier") {
342 + return fn(element);
343 + } else {
344 + element.place = fn(element.place);
345 + return element;
346 + }
347 + });
348 break;
349 }
350 case "JsxFragment": {
compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts
+7 -3
@@ -525,9 +525,13 @@ function codegenInstructionValue(
525 let value: t.Expression;
526 switch (instrValue.kind) {
527 case "ArrayExpression": {
528 - const elements = instrValue.elements.map((element) =>
529 - codegenPlace(cx, element)
530 - );
528 + const elements = instrValue.elements.map((element) => {
529 + if (element.kind === "Identifier") {
530 + return codegenPlace(cx, element);
531 + } else {
532 + return t.spreadElement(codegenPlace(cx, element.place));
533 + }
534 + });
535 value = t.arrayExpression(elements);
536 break;
537 }
compiler/forget/src/__tests__/fixtures/hir/array-expression-spread.expect.md new
+33
@@ -0,0 +1,33 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + const x = [0, ...props.foo, null, ...props.bar, "z"];
7 + return x;
8 +}
9 +
10 +```
11 +
12 +## Code
13 +
14 +```javascript
15 +function Component(props) {
16 + const $ = React.unstable_useMemoCache(3);
17 + const c_0 = $[0] !== props.foo;
18 + const c_1 = $[1] !== props.bar;
19 + let t0;
20 + if (c_0 || c_1) {
21 + t0 = [0, ...props.foo, null, ...props.bar, "z"];
22 + $[0] = props.foo;
23 + $[1] = props.bar;
24 + $[2] = t0;
25 + } else {
26 + t0 = $[2];
27 + }
28 + const x = t0;
29 + return x;
30 +}
31 +
32 +```
33 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/array-expression-spread.js new
+4
@@ -0,0 +1,4 @@
1 +function Component(props) {
2 + const x = [0, ...props.foo, null, ...props.bar, "z"];
3 + return x;
4 +}