diff --git a/compiler/forget/src/HIR/BuildHIR.ts b/compiler/forget/src/HIR/BuildHIR.ts index 3543bb8566..0cb6f316ac 100644 --- a/compiler/forget/src/HIR/BuildHIR.ts +++ b/compiler/forget/src/HIR/BuildHIR.ts @@ -678,6 +678,42 @@ function lowerStatement( builder.terminateWithContinuation(terminal, continuationBlock); return; } + case "FunctionDeclaration": { + const stmt = stmtPath as NodePath; + stmt.skip(); + invariant( + stmt.get("id").type === "Identifier", + "function declarations must have a name" + ); + const id = stmt.get("id") as NodePath; + + // Desugar FunctionDeclaration to FunctionExpression. + // + // For example: + // function foo() {}; + // becomes + // let foo = function foo() {}; + const desugared = stmt.replaceWith( + t.variableDeclaration("let", [ + t.variableDeclarator( + id.node, + t.functionExpression( + id.node, + stmt.node.params, + stmt.node.body, + stmt.node.generator, + stmt.node.async + ) + ), + ]) + ); + invariant( + desugared.length === 1, + "only one declaration is created from desugaring function declaration" + ); + lowerStatement(builder, desugared.at(0)!); + return; + } case "ForOfStatement": case "ForInStatement": case "ClassDeclaration": @@ -697,7 +733,6 @@ function lowerStatement( case "ExportAllDeclaration": case "ExportDefaultDeclaration": case "ExportNamedDeclaration": - case "FunctionDeclaration": case "ImportDeclaration": case "InterfaceDeclaration": case "OpaqueType": diff --git a/compiler/forget/src/__tests__/fixtures/compiler/capturing-function-decl.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/capturing-function-decl.expect.md new file mode 100644 index 0000000000..b56e2c01e3 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/capturing-function-decl.expect.md @@ -0,0 +1,38 @@ + +## Input + +```javascript +function component(a) { + let t = { a }; + function x() { + t.foo(); + } + x(t); + return t; +} + +``` + +## Code + +```javascript +function component(a) { + const $ = React.unstable_useMemoCache(2); + const c_0 = $[0] !== a; + let t; + if (c_0) { + t = { a }; + const x = function x() { + t.foo(); + }; + x(t); + $[0] = a; + $[1] = t; + } else { + t = $[1]; + } + return t; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/compiler/capturing-function-decl.js b/compiler/forget/src/__tests__/fixtures/compiler/capturing-function-decl.js new file mode 100644 index 0000000000..e7cb39a153 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/capturing-function-decl.js @@ -0,0 +1,8 @@ +function component(a) { + let t = { a }; + function x() { + t.foo(); + } + x(t); + return t; +} diff --git a/compiler/forget/src/__tests__/fixtures/compiler/error.hoisted-function-declaration.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/error.hoisted-function-declaration.expect.md new file mode 100644 index 0000000000..6f20cf0269 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/error.hoisted-function-declaration.expect.md @@ -0,0 +1,23 @@ + +## Input + +```javascript +function component(a) { + let t = { a }; + x(t); // hoisted call + function x(p) { + p.foo(); + } + return t; +} + +``` + + +## Error + +``` +[ReactForget] Invariant: identifier x$6 should have been defined before use (4:4) +``` + + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/compiler/error.hoisted-function-declaration.js b/compiler/forget/src/__tests__/fixtures/compiler/error.hoisted-function-declaration.js new file mode 100644 index 0000000000..9e5fec3f36 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/error.hoisted-function-declaration.js @@ -0,0 +1,8 @@ +function component(a) { + let t = { a }; + x(t); // hoisted call + function x(p) { + p.foo(); + } + return t; +} diff --git a/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md index b98d77e1de..c3afa3e307 100644 --- a/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md +++ b/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md @@ -292,15 +292,6 @@ let moduleLocal = false; 62 | 63 | function component(a) { 64 | // Add support for function declarations once we support `var` hoisting. - -[ReactForget] TodoError: (BuildHIR::lowerStatement) Handle FunctionDeclaration statements - 61 | moduleLocal = true; - 62 | -> 63 | function component(a) { - | ^ - 64 | // Add support for function declarations once we support `var` hoisting. - 65 | function t() {} - 66 | t(); ``` \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-reassign.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-reassign.expect.md new file mode 100644 index 0000000000..5ece9e9958 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-reassign.expect.md @@ -0,0 +1,32 @@ + +## Input + +```javascript +function component() { + function x(a) { + a.foo(); + } + x = {}; + return x; +} + +``` + +## Code + +```javascript +function component() { + const $ = React.unstable_useMemoCache(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = {}; + $[0] = t0; + } else { + t0 = $[0]; + } + const x = t0; + return x; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-reassign.js b/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-reassign.js new file mode 100644 index 0000000000..92ee854664 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-reassign.js @@ -0,0 +1,7 @@ +function component() { + function x(a) { + a.foo(); + } + x = {}; + return x; +} diff --git a/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-redeclare.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-redeclare.expect.md new file mode 100644 index 0000000000..79b7c04ca9 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-redeclare.expect.md @@ -0,0 +1,32 @@ + +## Input + +```javascript +function component() { + function x(a) { + a.foo(); + } + function x() {} + return x; +} + +``` + +## Code + +```javascript +function component() { + const $ = React.unstable_useMemoCache(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = function x() {}; + $[0] = t0; + } else { + t0 = $[0]; + } + const x = t0; + return x; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-redeclare.js b/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-redeclare.js new file mode 100644 index 0000000000..03ba36473d --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-redeclare.js @@ -0,0 +1,7 @@ +function component() { + function x(a) { + a.foo(); + } + function x() {} + return x; +} diff --git a/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-simple.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-simple.expect.md new file mode 100644 index 0000000000..2aa3d5203c --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-simple.expect.md @@ -0,0 +1,38 @@ + +## Input + +```javascript +function component(a) { + let t = { a }; + function x(p) { + p.foo(); + } + x(t); + return t; +} + +``` + +## Code + +```javascript +function component(a) { + const $ = React.unstable_useMemoCache(2); + const c_0 = $[0] !== a; + let t; + if (c_0) { + t = { a }; + const x = function x(p) { + p.foo(); + }; + x(t); + $[0] = a; + $[1] = t; + } else { + t = $[1]; + } + return t; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-simple.js b/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-simple.js new file mode 100644 index 0000000000..f37d5e13ee --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/function-declaration-simple.js @@ -0,0 +1,8 @@ +function component(a) { + let t = { a }; + function x(p) { + p.foo(); + } + x(t); + return t; +}