From b61cfc01a50e184d427bd2b873d82e140e0989d9 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 27 Sep 2023 14:04:02 -0400 Subject: [PATCH] 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. --- .../src/HIR/BuildHIR.ts | 20 ++++++++- .../compiler/error.todo-kitchensink.expect.md | 4 -- .../rest-param-with-array-pattern.expect.md | 43 +++++++++++++++++++ .../compiler/rest-param-with-array-pattern.js | 8 ++++ .../rest-param-with-identifier.expect.md | 43 +++++++++++++++++++ .../compiler/rest-param-with-identifier.js | 8 ++++ ...param-with-object-spread-pattern.expect.md | 43 +++++++++++++++++++ .../rest-param-with-object-spread-pattern.js | 8 ++++ 8 files changed, 172 insertions(+), 5 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-array-pattern.expect.md create mode 100644 compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-array-pattern.js create mode 100644 compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-identifier.expect.md create mode 100644 compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-identifier.js create mode 100644 compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-object-spread-pattern.expect.md create mode 100644 compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-object-spread-pattern.js diff --git a/compiler/packages/babel-plugin-react-forget/src/HIR/BuildHIR.ts b/compiler/packages/babel-plugin-react-forget/src/HIR/BuildHIR.ts index 11f1f97ac8..fb2dc78d5f 100644 --- a/compiler/packages/babel-plugin-react-forget/src/HIR/BuildHIR.ts +++ b/compiler/packages/babel-plugin-react-forget/src/HIR/BuildHIR.ts @@ -89,7 +89,7 @@ export function lower( id = idNode.node.name; } } - const params: Array = []; + const params: Array = []; func.get("params").forEach((param) => { if (param.isIdentifier()) { const identifier = builder.resolveIdentifier(param); @@ -128,6 +128,24 @@ export function lower( param, place ); + } else if (param.isRestElement()) { + const place: Place = { + kind: "Identifier", + identifier: builder.makeTemporary(), + effect: Effect.Unknown, + loc: param.node.loc ?? GeneratedSource, + }; + params.push({ + kind: "Spread", + place, + }); + lowerAssignment( + builder, + param.node.loc ?? GeneratedSource, + InstructionKind.Let, + param.get("argument"), + place + ); } else { builder.errors.push({ reason: `(BuildHIR::lower) Handle ${param.node.type} params`, diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md index 023cad7018..6397a4f9e1 100644 --- a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md @@ -79,16 +79,12 @@ let moduleLocal = false; ## Error ``` -[ReactForget] Todo: (BuildHIR::lower) Handle RestElement params (1:1) - [ReactForget] Todo: (BuildHIR::lowerStatement) Handle var kinds in VariableDeclaration (3:3) [ReactForget] Todo: (BuildHIR::lowerStatement) Handle ClassDeclaration statements (5:10) [ReactForget] Todo: (BuildHIR::lowerExpression) Handle ObjectMethod properties in ObjectExpression (12:12) -[ReactForget] Todo: (BuildHIR::lower) Handle RestElement params (18:18) - [ReactForget] Todo: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement (20:22) [ReactForget] Todo: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement (23:25) diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-array-pattern.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-array-pattern.expect.md new file mode 100644 index 0000000000..17a63793fb --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-array-pattern.expect.md @@ -0,0 +1,43 @@ + +## Input + +```javascript +function Component(foo, ...[bar]) { + return [foo, bar]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: ["foo", ["bar", "baz"]], +}; + +``` + +## Code + +```javascript +import { unstable_useMemoCache as useMemoCache } from "react"; +function Component(foo, ...t9) { + const $ = useMemoCache(3); + const [bar] = t9; + const c_0 = $[0] !== foo; + const c_1 = $[1] !== bar; + let t0; + if (c_0 || c_1) { + t0 = [foo, bar]; + $[0] = foo; + $[1] = bar; + $[2] = t0; + } else { + t0 = $[2]; + } + return t0; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: ["foo", ["bar", "baz"]], +}; + +``` + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-array-pattern.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-array-pattern.js new file mode 100644 index 0000000000..b3442de346 --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-array-pattern.js @@ -0,0 +1,8 @@ +function Component(foo, ...[bar]) { + return [foo, bar]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: ["foo", ["bar", "baz"]], +}; diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-identifier.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-identifier.expect.md new file mode 100644 index 0000000000..e11d8aff2a --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-identifier.expect.md @@ -0,0 +1,43 @@ + +## Input + +```javascript +function Component(foo, ...bar) { + return [foo, bar]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: ["foo", "bar", "baz"], +}; + +``` + +## Code + +```javascript +import { unstable_useMemoCache as useMemoCache } from "react"; +function Component(foo, ...t9) { + const $ = useMemoCache(3); + const bar = t9; + const c_0 = $[0] !== foo; + const c_1 = $[1] !== bar; + let t0; + if (c_0 || c_1) { + t0 = [foo, bar]; + $[0] = foo; + $[1] = bar; + $[2] = t0; + } else { + t0 = $[2]; + } + return t0; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: ["foo", "bar", "baz"], +}; + +``` + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-identifier.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-identifier.js new file mode 100644 index 0000000000..cc80507504 --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-identifier.js @@ -0,0 +1,8 @@ +function Component(foo, ...bar) { + return [foo, bar]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: ["foo", "bar", "baz"], +}; diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-object-spread-pattern.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-object-spread-pattern.expect.md new file mode 100644 index 0000000000..7420d93d45 --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-object-spread-pattern.expect.md @@ -0,0 +1,43 @@ + +## Input + +```javascript +function Component(foo, ...{ bar }) { + return [foo, bar]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: ["foo", { bar: "bar" }], +}; + +``` + +## Code + +```javascript +import { unstable_useMemoCache as useMemoCache } from "react"; +function Component(foo, ...t9) { + const $ = useMemoCache(3); + const { bar } = t9; + const c_0 = $[0] !== foo; + const c_1 = $[1] !== bar; + let t0; + if (c_0 || c_1) { + t0 = [foo, bar]; + $[0] = foo; + $[1] = bar; + $[2] = t0; + } else { + t0 = $[2]; + } + return t0; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: ["foo", { bar: "bar" }], +}; + +``` + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-object-spread-pattern.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-object-spread-pattern.js new file mode 100644 index 0000000000..7701b952c1 --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/rest-param-with-object-spread-pattern.js @@ -0,0 +1,8 @@ +function Component(foo, ...{ bar }) { + return [foo, bar]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: ["foo", { bar: "bar" }], +};