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

[rfc] Desugar FunctionDeclaration to a FunctionExpression

Sathya Gunasekaran committed Mar 30, 2023 at 15:48 UTC e81063e5ef9b42074159d2474b27147caf7f0ce5
12 files changed +237 -10
compiler/forget/src/HIR/BuildHIR.ts
+36 -1
@@ -678,6 +678,42 @@ function lowerStatement(
678 builder.terminateWithContinuation(terminal, continuationBlock);
679 return;
680 }
681 + case "FunctionDeclaration": {
682 + const stmt = stmtPath as NodePath<t.FunctionDeclaration>;
683 + stmt.skip();
684 + invariant(
685 + stmt.get("id").type === "Identifier",
686 + "function declarations must have a name"
687 + );
688 + const id = stmt.get("id") as NodePath<t.Identifier>;
689 +
690 + // Desugar FunctionDeclaration to FunctionExpression.
691 + //
692 + // For example:
693 + // function foo() {};
694 + // becomes
695 + // let foo = function foo() {};
696 + const desugared = stmt.replaceWith(
697 + t.variableDeclaration("let", [
698 + t.variableDeclarator(
699 + id.node,
700 + t.functionExpression(
701 + id.node,
702 + stmt.node.params,
703 + stmt.node.body,
704 + stmt.node.generator,
705 + stmt.node.async
706 + )
707 + ),
708 + ])
709 + );
710 + invariant(
711 + desugared.length === 1,
712 + "only one declaration is created from desugaring function declaration"
713 + );
714 + lowerStatement(builder, desugared.at(0)!);
715 + return;
716 + }
717 case "ForOfStatement":
718 case "ForInStatement":
719 case "ClassDeclaration":
@@ -697,7 +733,6 @@ function lowerStatement(
733 case "ExportAllDeclaration":
734 case "ExportDefaultDeclaration":
735 case "ExportNamedDeclaration":
700 - case "FunctionDeclaration":
736 case "ImportDeclaration":
737 case "InterfaceDeclaration":
738 case "OpaqueType":
compiler/forget/src/__tests__/fixtures/compiler/capturing-function-decl.expect.md new
+38
@@ -0,0 +1,38 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function component(a) {
6 + let t = { a };
7 + function x() {
8 + t.foo();
9 + }
10 + x(t);
11 + return t;
12 +}
13 +
14 +```
15 +
16 +## Code
17 +
18 +```javascript
19 +function component(a) {
20 + const $ = React.unstable_useMemoCache(2);
21 + const c_0 = $[0] !== a;
22 + let t;
23 + if (c_0) {
24 + t = { a };
25 + const x = function x() {
26 + t.foo();
27 + };
28 + x(t);
29 + $[0] = a;
30 + $[1] = t;
31 + } else {
32 + t = $[1];
33 + }
34 + return t;
35 +}
36 +
37 +```
38 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/capturing-function-decl.js new
+8
@@ -0,0 +1,8 @@
1 +function component(a) {
2 + let t = { a };
3 + function x() {
4 + t.foo();
5 + }
6 + x(t);
7 + return t;
8 +}
compiler/forget/src/__tests__/fixtures/compiler/error.hoisted-function-declaration.expect.md new
+23
@@ -0,0 +1,23 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function component(a) {
6 + let t = { a };
7 + x(t); // hoisted call
8 + function x(p) {
9 + p.foo();
10 + }
11 + return t;
12 +}
13 +
14 +```
15 +
16 +
17 +## Error
18 +
19 +```
20 +[ReactForget] Invariant: identifier x$6 should have been defined before use (4:4)
21 +```
22 +
23 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/error.hoisted-function-declaration.js new
+8
@@ -0,0 +1,8 @@
1 +function component(a) {
2 + let t = { a };
3 + x(t); // hoisted call
4 + function x(p) {
5 + p.foo();
6 + }
7 + return t;
8 +}
compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md
-9
@@ -292,15 +292,6 @@ let moduleLocal = false;
292 62 |
293 63 | function component(a) {
294 64 | // Add support for function declarations once we support `var` hoisting.
295 -
296 -[ReactForget] TodoError: (BuildHIR::lowerStatement) Handle FunctionDeclaration statements
297 - 61 | moduleLocal = true;
298 - 62 |
299 -> 63 | function component(a) {
300 - | ^
301 - 64 | // Add support for function declarations once we support `var` hoisting.
302 - 65 | function t() {}
303 - 66 | t();
295 ```
296
297
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/function-declaration-reassign.expect.md new
+32
@@ -0,0 +1,32 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function component() {
6 + function x(a) {
7 + a.foo();
8 + }
9 + x = {};
10 + return x;
11 +}
12 +
13 +```
14 +
15 +## Code
16 +
17 +```javascript
18 +function component() {
19 + const $ = React.unstable_useMemoCache(1);
20 + let t0;
21 + if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
22 + t0 = {};
23 + $[0] = t0;
24 + } else {
25 + t0 = $[0];
26 + }
27 + const x = t0;
28 + return x;
29 +}
30 +
31 +```
32 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/function-declaration-reassign.js new
+7
@@ -0,0 +1,7 @@
1 +function component() {
2 + function x(a) {
3 + a.foo();
4 + }
5 + x = {};
6 + return x;
7 +}
compiler/forget/src/__tests__/fixtures/compiler/function-declaration-redeclare.expect.md new
+32
@@ -0,0 +1,32 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function component() {
6 + function x(a) {
7 + a.foo();
8 + }
9 + function x() {}
10 + return x;
11 +}
12 +
13 +```
14 +
15 +## Code
16 +
17 +```javascript
18 +function component() {
19 + const $ = React.unstable_useMemoCache(1);
20 + let t0;
21 + if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
22 + t0 = function x() {};
23 + $[0] = t0;
24 + } else {
25 + t0 = $[0];
26 + }
27 + const x = t0;
28 + return x;
29 +}
30 +
31 +```
32 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/function-declaration-redeclare.js new
+7
@@ -0,0 +1,7 @@
1 +function component() {
2 + function x(a) {
3 + a.foo();
4 + }
5 + function x() {}
6 + return x;
7 +}
compiler/forget/src/__tests__/fixtures/compiler/function-declaration-simple.expect.md new
+38
@@ -0,0 +1,38 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function component(a) {
6 + let t = { a };
7 + function x(p) {
8 + p.foo();
9 + }
10 + x(t);
11 + return t;
12 +}
13 +
14 +```
15 +
16 +## Code
17 +
18 +```javascript
19 +function component(a) {
20 + const $ = React.unstable_useMemoCache(2);
21 + const c_0 = $[0] !== a;
22 + let t;
23 + if (c_0) {
24 + t = { a };
25 + const x = function x(p) {
26 + p.foo();
27 + };
28 + x(t);
29 + $[0] = a;
30 + $[1] = t;
31 + } else {
32 + t = $[1];
33 + }
34 + return t;
35 +}
36 +
37 +```
38 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/function-declaration-simple.js new
+8
@@ -0,0 +1,8 @@
1 +function component(a) {
2 + let t = { a };
3 + function x(p) {
4 + p.foo();
5 + }
6 + x(t);
7 + return t;
8 +}