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
+}