Skip to content

Commit 755c9dd

Browse files
committed
[compiler] Fix invariant error for optional chaining in try/catch
Optional chaining and other value blocks within try/catch blocks were throwing an Invariant error ("Unexpected terminal in optional") instead of the expected Todo error. This caused hard failures instead of graceful bailouts. The issue occurred because DropManualMemoization and ValidateExhaustiveDependencies ran before BuildReactiveFunction, and encountered `maybe-throw` terminals in their switch statements without a handler, falling through to the invariant case. Fixed by adding explicit `maybe-throw` cases in both files that throw the proper Todo error with the message "Support value blocks (conditional, logical, optional chaining, etc) within a try/catch statement". Also renamed the existing bug test to reflect it's now correctly handled: - error.bug-invariant-unexpected-terminal-in-optional → error.todo-optional-chaining-within-try-catch Closes #35570
1 parent e2cb507 commit 755c9dd

6 files changed

Lines changed: 67 additions & 3 deletions

compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,14 @@ function findOptionalPlaces(fn: HIRFunction): Set<IdentifierId> {
583583
testBlock = fn.body.blocks.get(terminal.fallthrough)!;
584584
break;
585585
}
586+
case 'maybe-throw': {
587+
CompilerError.throwTodo({
588+
reason: `Support value blocks (conditional, logical, optional chaining, etc) within a try/catch statement`,
589+
description: null,
590+
loc: terminal.loc,
591+
suggestions: null,
592+
});
593+
}
586594
default: {
587595
CompilerError.invariant(false, {
588596
reason: `Unexpected terminal in optional`,

compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateExhaustiveDependencies.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,14 @@ export function findOptionalPlaces(
10161016
testBlock = fn.body.blocks.get(terminal.block)!;
10171017
break;
10181018
}
1019+
case 'maybe-throw': {
1020+
CompilerError.throwTodo({
1021+
reason: `Support value blocks (conditional, logical, optional chaining, etc) within a try/catch statement`,
1022+
description: null,
1023+
loc: terminal.loc,
1024+
suggestions: null,
1025+
});
1026+
}
10191027
default: {
10201028
CompilerError.simpleInvariant(false, {
10211029
reason: `Unexpected terminal in optional`,
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
## Input
3+
4+
```javascript
5+
function Component(props) {
6+
const callback = async () => {
7+
try {
8+
const result = await fetch(props.url);
9+
return result?.error;
10+
} catch (e) {
11+
return null;
12+
}
13+
};
14+
return callback;
15+
}
16+
17+
```
18+
19+
20+
## Error
21+
22+
```
23+
Found 1 error:
24+
25+
Todo: Support value blocks (conditional, logical, optional chaining, etc) within a try/catch statement
26+
27+
error.todo-optional-chaining-within-try-catch-in-callback.ts:5:13
28+
3 | try {
29+
4 | const result = await fetch(props.url);
30+
> 5 | return result?.error;
31+
| ^^^^^^ Support value blocks (conditional, logical, optional chaining, etc) within a try/catch statement
32+
6 | } catch (e) {
33+
7 | return null;
34+
8 | }
35+
```
36+
37+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
function Component(props) {
2+
const callback = async () => {
3+
try {
4+
const result = await fetch(props.url);
5+
return result?.error;
6+
} catch (e) {
7+
return null;
8+
}
9+
};
10+
return callback;
11+
}

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unexpected-terminal-in-optional.expect.md renamed to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-chaining-within-try-catch.expect.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ const Foo = ({json}) => {
1919
```
2020
Found 1 error:
2121

22-
Invariant: Unexpected terminal in optional
22+
Todo: Support value blocks (conditional, logical, optional chaining, etc) within a try/catch statement
2323

24-
error.bug-invariant-unexpected-terminal-in-optional.ts:3:16
24+
error.todo-optional-chaining-within-try-catch.ts:3:16
2525
1 | const Foo = ({json}) => {
2626
2 | try {
2727
> 3 | const foo = JSON.parse(json)?.foo;
28-
| ^^^^ Unexpected maybe-throw in optional
28+
| ^^^^ Support value blocks (conditional, logical, optional chaining, etc) within a try/catch statement
2929
4 | return <span>{foo}</span>;
3030
5 | } catch {
3131
6 | return null;

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unexpected-terminal-in-optional.js renamed to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-chaining-within-try-catch.js

File renamed without changes.

0 commit comments

Comments
 (0)