[compiler] Support inline enums (flow/ts), type declarations (#33747)
Supports inline enum declarations in both Flow and TS by treating the node as pass-through (enums can't capture values mutably). Related, this PR extends the set of type-related declarations that we ignore. Previously we threw a todo for things like DeclareClass or DeclareVariable, but these are type related and can simply be dropped just like we dropped TypeAlias. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33747). * #33753 * #33752 * #33751 * #33750 * #33748 * __->__ #33747
Joseph Savona committed
Jul 9, 2025 at 22:21 UTC
81e1ee7476a68fdf13c63d3002e5ef1b699b6842
7 files changed
+179
-17
compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts
+16
-9
@@ -1388,10 +1388,13 @@ function lowerStatement(
1388
});
1389
return;
1390
}
1391
- case 'TypeAlias':
1392
- case 'TSInterfaceDeclaration':
1393
- case 'TSTypeAliasDeclaration': {
1394
- // We do not preserve type annotations/syntax through transformation
1391
+ case 'EnumDeclaration':
1392
+ case 'TSEnumDeclaration': {
1393
+ lowerValueToTemporary(builder, {
1394
+ kind: 'UnsupportedNode',
1395
+ loc: stmtPath.node.loc ?? GeneratedSource,
1396
+ node: stmtPath.node,
1397
+ });
1398
return;
1399
}
1400
case 'DeclareClass':
@@ -1404,15 +1407,19 @@ function lowerStatement(
1407
case 'DeclareOpaqueType':
1408
case 'DeclareTypeAlias':
1409
case 'DeclareVariable':
1407
- case 'EnumDeclaration':
1410
+ case 'InterfaceDeclaration':
1411
+ case 'OpaqueType':
1412
+ case 'TSDeclareFunction':
1413
+ case 'TSInterfaceDeclaration':
1414
+ case 'TSTypeAliasDeclaration':
1415
+ case 'TypeAlias': {
1416
+ // We do not preserve type annotations/syntax through transformation
1417
+ return;
1418
+ }
1419
case 'ExportAllDeclaration':
1420
case 'ExportDefaultDeclaration':
1421
case 'ExportNamedDeclaration':
1422
case 'ImportDeclaration':
1412
- case 'InterfaceDeclaration':
1413
- case 'OpaqueType':
1414
- case 'TSDeclareFunction':
1415
- case 'TSEnumDeclaration':
1423
case 'TSExportAssignment':
1424
case 'TSImportEqualsDeclaration':
1425
case 'TSModuleDeclaration':
compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts
+1
-2
@@ -5,7 +5,6 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import generate from '@babel/generator';
8
import {CompilerError} from '../CompilerError';
9
import {printReactiveScopeSummary} from '../ReactiveScopes/PrintReactiveFunction';
10
import DisjointSet from '../Utils/DisjointSet';
@@ -466,7 +465,7 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
465
break;
466
}
467
case 'UnsupportedNode': {
469
- value = `UnsupportedNode(${generate(instrValue.node).code})`;
468
+ value = `UnsupportedNode ${instrValue.node.type}`;
469
break;
470
}
471
case 'LoadLocal': {
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneNonEscapingScopes.ts
+8
-6
@@ -829,12 +829,14 @@ class CollectDependenciesVisitor extends ReactiveFunctionVisitor<
829
};
830
}
831
case 'UnsupportedNode': {
832
- CompilerError.invariant(false, {
833
- reason: `Unexpected unsupported node`,
834
- description: null,
835
- loc: value.loc,
836
- suggestions: null,
837
- });
832
+ const lvalues = [];
833
+ if (lvalue !== null) {
834
+ lvalues.push({place: lvalue, level: MemoizationLevel.Never});
835
+ }
836
+ return {
837
+ lvalues,
838
+ rvalues: [],
839
+ };
840
}
841
default: {
842
assertExhaustive(
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/flow-enum-inline.expect.md
new
+60
@@ -0,0 +1,60 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @flow
6
+function Component(props) {
7
+ enum Bool {
8
+ True = 'true',
9
+ False = 'false',
10
+ }
11
+
12
+ let bool: Bool = Bool.False;
13
+ if (props.value) {
14
+ bool = Bool.True;
15
+ }
16
+ return <div>{bool}</div>;
17
+}
18
+
19
+export const FIXTURE_ENTRYPOINT = {
20
+ fn: Component,
21
+ params: [{value: true}],
22
+};
23
+
24
+```
25
+
26
+## Code
27
+
28
+```javascript
29
+import { c as _c } from "react/compiler-runtime";
30
+function Component(props) {
31
+ const $ = _c(2);
32
+ enum Bool {
33
+ True = "true",
34
+ False = "false",
35
+ }
36
+
37
+ let bool = Bool.False;
38
+ if (props.value) {
39
+ bool = Bool.True;
40
+ }
41
+ let t0;
42
+ if ($[0] !== bool) {
43
+ t0 = <div>{bool}</div>;
44
+ $[0] = bool;
45
+ $[1] = t0;
46
+ } else {
47
+ t0 = $[1];
48
+ }
49
+ return t0;
50
+}
51
+
52
+export const FIXTURE_ENTRYPOINT = {
53
+ fn: Component,
54
+ params: [{ value: true }],
55
+};
56
+
57
+```
58
+
59
+### Eval output
60
+(kind: exception) Bool is not defined
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/flow-enum-inline.js
new
+18
@@ -0,0 +1,18 @@
1
+// @flow
2
+function Component(props) {
3
+ enum Bool {
4
+ True = 'true',
5
+ False = 'false',
6
+ }
7
+
8
+ let bool: Bool = Bool.False;
9
+ if (props.value) {
10
+ bool = Bool.True;
11
+ }
12
+ return <div>{bool}</div>;
13
+}
14
+
15
+export const FIXTURE_ENTRYPOINT = {
16
+ fn: Component,
17
+ params: [{value: true}],
18
+};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ts-enum-inline.expect.md
new
+59
@@ -0,0 +1,59 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ enum Bool {
7
+ True = 'true',
8
+ False = 'false',
9
+ }
10
+
11
+ let bool: Bool = Bool.False;
12
+ if (props.value) {
13
+ bool = Bool.True;
14
+ }
15
+ return <div>{bool}</div>;
16
+}
17
+
18
+export const FIXTURE_ENTRYPOINT = {
19
+ fn: Component,
20
+ params: [{value: true}],
21
+};
22
+
23
+```
24
+
25
+## Code
26
+
27
+```javascript
28
+import { c as _c } from "react/compiler-runtime";
29
+function Component(props) {
30
+ const $ = _c(2);
31
+ enum Bool {
32
+ True = "true",
33
+ False = "false",
34
+ }
35
+
36
+ let bool = Bool.False;
37
+ if (props.value) {
38
+ bool = Bool.True;
39
+ }
40
+ let t0;
41
+ if ($[0] !== bool) {
42
+ t0 = <div>{bool}</div>;
43
+ $[0] = bool;
44
+ $[1] = t0;
45
+ } else {
46
+ t0 = $[1];
47
+ }
48
+ return t0;
49
+}
50
+
51
+export const FIXTURE_ENTRYPOINT = {
52
+ fn: Component,
53
+ params: [{ value: true }],
54
+};
55
+
56
+```
57
+
58
+### Eval output
59
+(kind: ok) <div>true</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ts-enum-inline.tsx
new
+17
@@ -0,0 +1,17 @@
1
+function Component(props) {
2
+ enum Bool {
3
+ True = 'true',
4
+ False = 'false',
5
+ }
6
+
7
+ let bool: Bool = Bool.False;
8
+ if (props.value) {
9
+ bool = Bool.True;
10
+ }
11
+ return <div>{bool}</div>;
12
+}
13
+
14
+export const FIXTURE_ENTRYPOINT = {
15
+ fn: Component,
16
+ params: [{value: true}],
17
+};