Support rest params
Adds support for lowering rest element parameters to spreads. We eagerly create a temporary, similar to the approach for destructuring. In theory we could do something more optimal if you have a `...foo` (rest element where the argument is an Identifier) but it doesn't seem worth optimizing yet.
Joe Savona committed
Sep 27, 2023 at 14:04 UTC
b61cfc01a50e184d427bd2b873d82e140e0989d9
8 files changed
+172
-5
compiler/packages/babel-plugin-react-forget/src/HIR/BuildHIR.ts
+19
-1
@@ -89,7 +89,7 @@ export function lower(
89
id = idNode.node.name;
90
}
91
}
92
- const params: Array<Place> = [];
92
+ const params: Array<Place | SpreadPattern> = [];
93
func.get("params").forEach((param) => {
94
if (param.isIdentifier()) {
95
const identifier = builder.resolveIdentifier(param);
@@ -128,6 +128,24 @@ export function lower(
128
param,
129
place
130
);
131
+ } else if (param.isRestElement()) {
132
+ const place: Place = {
133
+ kind: "Identifier",
134
+ identifier: builder.makeTemporary(),
135
+ effect: Effect.Unknown,
136
+ loc: param.node.loc ?? GeneratedSource,
137
+ };
138
+ params.push({
139
+ kind: "Spread",
140
+ place,
141
+ });
142
+ lowerAssignment(
143
+ builder,
144
+ param.node.loc ?? GeneratedSource,
145
+ InstructionKind.Let,
146
+ param.get("argument"),
147
+ place
148
+ );
149
} else {
150
builder.errors.push({
151
reason: `(BuildHIR::lower) Handle ${param.node.type} params`,
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md
-4
@@ -79,16 +79,12 @@ let moduleLocal = false;
79
## Error
80
81
```
82
-[ReactForget] Todo: (BuildHIR::lower) Handle RestElement params (1:1)
83
-
82
[ReactForget] Todo: (BuildHIR::lowerStatement) Handle var kinds in VariableDeclaration (3:3)
83
84
[ReactForget] Todo: (BuildHIR::lowerStatement) Handle ClassDeclaration statements (5:10)
85
86
[ReactForget] Todo: (BuildHIR::lowerExpression) Handle ObjectMethod properties in ObjectExpression (12:12)
87
90
-[ReactForget] Todo: (BuildHIR::lower) Handle RestElement params (18:18)
91
-
88
[ReactForget] Todo: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement (20:22)
89
90
[ReactForget] Todo: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement (23:25)
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-array-pattern.expect.md
new
+43
@@ -0,0 +1,43 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(foo, ...[bar]) {
6
+ return [foo, bar];
7
+}
8
+
9
+export const FIXTURE_ENTRYPOINT = {
10
+ fn: Component,
11
+ params: ["foo", ["bar", "baz"]],
12
+};
13
+
14
+```
15
+
16
+## Code
17
+
18
+```javascript
19
+import { unstable_useMemoCache as useMemoCache } from "react";
20
+function Component(foo, ...t9) {
21
+ const $ = useMemoCache(3);
22
+ const [bar] = t9;
23
+ const c_0 = $[0] !== foo;
24
+ const c_1 = $[1] !== bar;
25
+ let t0;
26
+ if (c_0 || c_1) {
27
+ t0 = [foo, bar];
28
+ $[0] = foo;
29
+ $[1] = bar;
30
+ $[2] = t0;
31
+ } else {
32
+ t0 = $[2];
33
+ }
34
+ return t0;
35
+}
36
+
37
+export const FIXTURE_ENTRYPOINT = {
38
+ fn: Component,
39
+ params: ["foo", ["bar", "baz"]],
40
+};
41
+
42
+```
43
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-array-pattern.js
new
+8
@@ -0,0 +1,8 @@
1
+function Component(foo, ...[bar]) {
2
+ return [foo, bar];
3
+}
4
+
5
+export const FIXTURE_ENTRYPOINT = {
6
+ fn: Component,
7
+ params: ["foo", ["bar", "baz"]],
8
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-identifier.expect.md
new
+43
@@ -0,0 +1,43 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(foo, ...bar) {
6
+ return [foo, bar];
7
+}
8
+
9
+export const FIXTURE_ENTRYPOINT = {
10
+ fn: Component,
11
+ params: ["foo", "bar", "baz"],
12
+};
13
+
14
+```
15
+
16
+## Code
17
+
18
+```javascript
19
+import { unstable_useMemoCache as useMemoCache } from "react";
20
+function Component(foo, ...t9) {
21
+ const $ = useMemoCache(3);
22
+ const bar = t9;
23
+ const c_0 = $[0] !== foo;
24
+ const c_1 = $[1] !== bar;
25
+ let t0;
26
+ if (c_0 || c_1) {
27
+ t0 = [foo, bar];
28
+ $[0] = foo;
29
+ $[1] = bar;
30
+ $[2] = t0;
31
+ } else {
32
+ t0 = $[2];
33
+ }
34
+ return t0;
35
+}
36
+
37
+export const FIXTURE_ENTRYPOINT = {
38
+ fn: Component,
39
+ params: ["foo", "bar", "baz"],
40
+};
41
+
42
+```
43
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-identifier.js
new
+8
@@ -0,0 +1,8 @@
1
+function Component(foo, ...bar) {
2
+ return [foo, bar];
3
+}
4
+
5
+export const FIXTURE_ENTRYPOINT = {
6
+ fn: Component,
7
+ params: ["foo", "bar", "baz"],
8
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-object-spread-pattern.expect.md
new
+43
@@ -0,0 +1,43 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(foo, ...{ bar }) {
6
+ return [foo, bar];
7
+}
8
+
9
+export const FIXTURE_ENTRYPOINT = {
10
+ fn: Component,
11
+ params: ["foo", { bar: "bar" }],
12
+};
13
+
14
+```
15
+
16
+## Code
17
+
18
+```javascript
19
+import { unstable_useMemoCache as useMemoCache } from "react";
20
+function Component(foo, ...t9) {
21
+ const $ = useMemoCache(3);
22
+ const { bar } = t9;
23
+ const c_0 = $[0] !== foo;
24
+ const c_1 = $[1] !== bar;
25
+ let t0;
26
+ if (c_0 || c_1) {
27
+ t0 = [foo, bar];
28
+ $[0] = foo;
29
+ $[1] = bar;
30
+ $[2] = t0;
31
+ } else {
32
+ t0 = $[2];
33
+ }
34
+ return t0;
35
+}
36
+
37
+export const FIXTURE_ENTRYPOINT = {
38
+ fn: Component,
39
+ params: ["foo", { bar: "bar" }],
40
+};
41
+
42
+```
43
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-object-spread-pattern.js
new
+8
@@ -0,0 +1,8 @@
1
+function Component(foo, ...{ bar }) {
2
+ return [foo, bar];
3
+}
4
+
5
+export const FIXTURE_ENTRYPOINT = {
6
+ fn: Component,
7
+ params: ["foo", { bar: "bar" }],
8
+};