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