Fix promotion of catch bindings w/in function expressions
One of our visitors wasn't visiting TryTerminal's handlerBinding, which meant that we missed renaming those identifiers in RenameVariables. I also updated the printers to print this binding.
Joe Savona committed
Mar 7, 2024 at 09:21 UTC
fe91bcefd2bbc3da9f1998befb466acc8b4afdca
13 files changed
+330
-29
compiler/packages/babel-plugin-react-forget/src/HIR/PrintHIR.ts
+4
-2
@@ -266,8 +266,10 @@ export function printTerminal(terminal: Terminal): Array<string> | string {
266
break;
267
}
268
case "try": {
269
- value = `Try block=bb${terminal.block} catch=bb${
270
- terminal.handler
269
+ value = `Try block=bb${terminal.block} handler=bb${terminal.handler}${
270
+ terminal.handlerBinding !== null
271
+ ? ` handlerBinding=(${printPlace(terminal.handlerBinding)})`
272
+ : ""
273
} fallthrough=${
274
terminal.fallthrough != null ? `bb${terminal.fallthrough}` : ""
275
}`;
compiler/packages/babel-plugin-react-forget/src/HIR/visitors.ts
+6
-1
@@ -1126,7 +1126,12 @@ export function* eachTerminalOperand(terminal: Terminal): Iterable<Place> {
1126
yield terminal.value;
1127
break;
1128
}
1129
- case "try":
1129
+ case "try": {
1130
+ if (terminal.handlerBinding !== null) {
1131
+ yield terminal.handlerBinding;
1132
+ }
1133
+ break;
1134
+ }
1135
case "maybe-throw":
1136
case "sequence":
1137
case "label":
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/PrintReactiveFunction.ts
+6
-1
@@ -354,7 +354,12 @@ function writeTerminal(writer: Writer, terminal: ReactiveTerminal): void {
354
case "try": {
355
writer.writeLine(`[${terminal.id}] try {`);
356
writeReactiveInstructions(writer, terminal.block);
357
- writer.writeLine(`} catch {`);
357
+ writer.write(`} catch `);
358
+ if (terminal.handlerBinding !== null) {
359
+ writer.writeLine(`(${printPlace(terminal.handlerBinding)}) {`);
360
+ } else {
361
+ writer.writeLine(`{`);
362
+ }
363
writeReactiveInstructions(writer, terminal.handler);
364
writer.writeLine("}");
365
break;
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/visitors.ts
+3
@@ -545,6 +545,9 @@ export class ReactiveFunctionTransform<
545
}
546
case "try": {
547
this.visitBlock(terminal.block, state);
548
+ if (terminal.handlerBinding !== null) {
549
+ this.visitPlace(terminal.id, terminal.handlerBinding, state);
550
+ }
551
this.visitBlock(terminal.handler, state);
552
break;
553
}
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-try-catch-within-function-expression.expect.md
deleted
-25
@@ -1,25 +0,0 @@
1
-
2
-## Input
3
-
4
-```javascript
5
-function Component(props) {
6
- const callback = () => {
7
- try {
8
- return [];
9
- } catch (e) {
10
- return;
11
- }
12
- };
13
- return callback();
14
-}
15
-
16
-```
17
-
18
-
19
-## Error
20
-
21
-```
22
-[ReactForget] Invariant: Expected temporaries to be promoted to named identifiers in an earlier pass. identifier 16 is unnamed
23
-```
24
-
25
-
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/try-catch-within-function-expression-returns-caught-value.expect.md
new
+68
@@ -0,0 +1,68 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+import { throwInput } from "shared-runtime";
6
+
7
+function Component(props) {
8
+ const callback = () => {
9
+ try {
10
+ throwInput([props.value]);
11
+ } catch (e) {
12
+ return e;
13
+ }
14
+ };
15
+ return callback();
16
+}
17
+
18
+export const FIXTURE_ENTRYPOINT = {
19
+ fn: Component,
20
+ params: [{ value: 42 }],
21
+};
22
+
23
+```
24
+
25
+## Code
26
+
27
+```javascript
28
+import { unstable_useMemoCache as useMemoCache } from "react";
29
+import { throwInput } from "shared-runtime";
30
+
31
+function Component(props) {
32
+ const $ = useMemoCache(4);
33
+ let t0;
34
+ if ($[0] !== props.value) {
35
+ t0 = () => {
36
+ try {
37
+ throwInput([props.value]);
38
+ } catch (t1) {
39
+ const e = t1;
40
+ return e;
41
+ }
42
+ };
43
+ $[0] = props.value;
44
+ $[1] = t0;
45
+ } else {
46
+ t0 = $[1];
47
+ }
48
+ const callback = t0;
49
+ let t1;
50
+ if ($[2] !== callback) {
51
+ t1 = callback();
52
+ $[2] = callback;
53
+ $[3] = t1;
54
+ } else {
55
+ t1 = $[3];
56
+ }
57
+ return t1;
58
+}
59
+
60
+export const FIXTURE_ENTRYPOINT = {
61
+ fn: Component,
62
+ params: [{ value: 42 }],
63
+};
64
+
65
+```
66
+
67
+### Eval output
68
+(kind: ok) [42]
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/try-catch-within-function-expression-returns-caught-value.js
new
+17
@@ -0,0 +1,17 @@
1
+import { throwInput } from "shared-runtime";
2
+
3
+function Component(props) {
4
+ const callback = () => {
5
+ try {
6
+ throwInput([props.value]);
7
+ } catch (e) {
8
+ return e;
9
+ }
10
+ };
11
+ return callback();
12
+}
13
+
14
+export const FIXTURE_ENTRYPOINT = {
15
+ fn: Component,
16
+ params: [{ value: 42 }],
17
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/try-catch-within-function-expression.expect.md
new
+61
@@ -0,0 +1,61 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ const callback = () => {
7
+ try {
8
+ return [];
9
+ } catch (e) {
10
+ return;
11
+ }
12
+ };
13
+ return callback();
14
+}
15
+
16
+export const FIXTURE_ENTRYPOINT = {
17
+ fn: Component,
18
+ params: [{}],
19
+};
20
+
21
+```
22
+
23
+## Code
24
+
25
+```javascript
26
+import { unstable_useMemoCache as useMemoCache } from "react";
27
+function Component(props) {
28
+ const $ = useMemoCache(2);
29
+ let t0;
30
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
31
+ t0 = () => {
32
+ try {
33
+ return [];
34
+ } catch (t1) {
35
+ return;
36
+ }
37
+ };
38
+ $[0] = t0;
39
+ } else {
40
+ t0 = $[0];
41
+ }
42
+ const callback = t0;
43
+ let t1;
44
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
45
+ t1 = callback();
46
+ $[1] = t1;
47
+ } else {
48
+ t1 = $[1];
49
+ }
50
+ return t1;
51
+}
52
+
53
+export const FIXTURE_ENTRYPOINT = {
54
+ fn: Component,
55
+ params: [{}],
56
+};
57
+
58
+```
59
+
60
+### Eval output
61
+(kind: ok) []
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/try-catch-within-function-expression.js
renamed
+5
@@ -8,3 +8,8 @@ function Component(props) {
8
};
9
return callback();
10
}
11
+
12
+export const FIXTURE_ENTRYPOINT = {
13
+ fn: Component,
14
+ params: [{}],
15
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/try-catch-within-object-method-returns-caught-value.expect.md
new
+65
@@ -0,0 +1,65 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+import { throwInput } from "shared-runtime";
6
+
7
+function Component(props) {
8
+ const object = {
9
+ foo() {
10
+ try {
11
+ throwInput([props.value]);
12
+ } catch (e) {
13
+ return e;
14
+ }
15
+ },
16
+ };
17
+ return object.foo();
18
+}
19
+
20
+export const FIXTURE_ENTRYPOINT = {
21
+ fn: Component,
22
+ params: [{ value: 42 }],
23
+};
24
+
25
+```
26
+
27
+## Code
28
+
29
+```javascript
30
+import { unstable_useMemoCache as useMemoCache } from "react";
31
+import { throwInput } from "shared-runtime";
32
+
33
+function Component(props) {
34
+ const $ = useMemoCache(2);
35
+ let t0;
36
+ if ($[0] !== props.value) {
37
+ const object = {
38
+ foo() {
39
+ try {
40
+ throwInput([props.value]);
41
+ } catch (t1) {
42
+ const e = t1;
43
+ return e;
44
+ }
45
+ },
46
+ };
47
+
48
+ t0 = object.foo();
49
+ $[0] = props.value;
50
+ $[1] = t0;
51
+ } else {
52
+ t0 = $[1];
53
+ }
54
+ return t0;
55
+}
56
+
57
+export const FIXTURE_ENTRYPOINT = {
58
+ fn: Component,
59
+ params: [{ value: 42 }],
60
+};
61
+
62
+```
63
+
64
+### Eval output
65
+(kind: ok) [42]
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/try-catch-within-object-method-returns-caught-value.js
new
+19
@@ -0,0 +1,19 @@
1
+import { throwInput } from "shared-runtime";
2
+
3
+function Component(props) {
4
+ const object = {
5
+ foo() {
6
+ try {
7
+ throwInput([props.value]);
8
+ } catch (e) {
9
+ return e;
10
+ }
11
+ },
12
+ };
13
+ return object.foo();
14
+}
15
+
16
+export const FIXTURE_ENTRYPOINT = {
17
+ fn: Component,
18
+ params: [{ value: 42 }],
19
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/try-catch-within-object-method.expect.md
new
+59
@@ -0,0 +1,59 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ const object = {
7
+ foo() {
8
+ try {
9
+ return [];
10
+ } catch (e) {
11
+ return;
12
+ }
13
+ },
14
+ };
15
+ return object.foo();
16
+}
17
+
18
+export const FIXTURE_ENTRYPOINT = {
19
+ fn: Component,
20
+ params: [{}],
21
+};
22
+
23
+```
24
+
25
+## Code
26
+
27
+```javascript
28
+import { unstable_useMemoCache as useMemoCache } from "react";
29
+function Component(props) {
30
+ const $ = useMemoCache(1);
31
+ let t0;
32
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
33
+ const object = {
34
+ foo() {
35
+ try {
36
+ return [];
37
+ } catch (t1) {
38
+ return;
39
+ }
40
+ },
41
+ };
42
+
43
+ t0 = object.foo();
44
+ $[0] = t0;
45
+ } else {
46
+ t0 = $[0];
47
+ }
48
+ return t0;
49
+}
50
+
51
+export const FIXTURE_ENTRYPOINT = {
52
+ fn: Component,
53
+ params: [{}],
54
+};
55
+
56
+```
57
+
58
+### Eval output
59
+(kind: ok) []
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/try-catch-within-object-method.js
new
+17
@@ -0,0 +1,17 @@
1
+function Component(props) {
2
+ const object = {
3
+ foo() {
4
+ try {
5
+ return [];
6
+ } catch (e) {
7
+ return;
8
+ }
9
+ },
10
+ };
11
+ return object.foo();
12
+}
13
+
14
+export const FIXTURE_ENTRYPOINT = {
15
+ fn: Component,
16
+ params: [{}],
17
+};