From 81e1ee7476a68fdf13c63d3002e5ef1b699b6842 Mon Sep 17 00:00:00 2001 From: Joseph Savona <6425824+josephsavona@users.noreply.github.com> Date: Wed, 9 Jul 2025 22:21:02 -0700 Subject: [PATCH] [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 --- .../src/HIR/BuildHIR.ts | 25 +++++--- .../src/HIR/PrintHIR.ts | 3 +- .../ReactiveScopes/PruneNonEscapingScopes.ts | 14 +++-- .../compiler/flow-enum-inline.expect.md | 60 +++++++++++++++++++ .../fixtures/compiler/flow-enum-inline.js | 18 ++++++ .../compiler/ts-enum-inline.expect.md | 59 ++++++++++++++++++ .../fixtures/compiler/ts-enum-inline.tsx | 17 ++++++ 7 files changed, 179 insertions(+), 17 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/flow-enum-inline.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/flow-enum-inline.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ts-enum-inline.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ts-enum-inline.tsx diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts index efcfecce78..5bcf27b333 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts @@ -1388,10 +1388,13 @@ function lowerStatement( }); return; } - case 'TypeAlias': - case 'TSInterfaceDeclaration': - case 'TSTypeAliasDeclaration': { - // We do not preserve type annotations/syntax through transformation + case 'EnumDeclaration': + case 'TSEnumDeclaration': { + lowerValueToTemporary(builder, { + kind: 'UnsupportedNode', + loc: stmtPath.node.loc ?? GeneratedSource, + node: stmtPath.node, + }); return; } case 'DeclareClass': @@ -1404,15 +1407,19 @@ function lowerStatement( case 'DeclareOpaqueType': case 'DeclareTypeAlias': case 'DeclareVariable': - case 'EnumDeclaration': + case 'InterfaceDeclaration': + case 'OpaqueType': + case 'TSDeclareFunction': + case 'TSInterfaceDeclaration': + case 'TSTypeAliasDeclaration': + case 'TypeAlias': { + // We do not preserve type annotations/syntax through transformation + return; + } case 'ExportAllDeclaration': case 'ExportDefaultDeclaration': case 'ExportNamedDeclaration': case 'ImportDeclaration': - case 'InterfaceDeclaration': - case 'OpaqueType': - case 'TSDeclareFunction': - case 'TSEnumDeclaration': case 'TSExportAssignment': case 'TSImportEqualsDeclaration': case 'TSModuleDeclaration': diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts index caaced124e..23471a00b0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -import generate from '@babel/generator'; import {CompilerError} from '../CompilerError'; import {printReactiveScopeSummary} from '../ReactiveScopes/PrintReactiveFunction'; import DisjointSet from '../Utils/DisjointSet'; @@ -466,7 +465,7 @@ export function printInstructionValue(instrValue: ReactiveValue): string { break; } case 'UnsupportedNode': { - value = `UnsupportedNode(${generate(instrValue.node).code})`; + value = `UnsupportedNode ${instrValue.node.type}`; break; } case 'LoadLocal': { diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneNonEscapingScopes.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneNonEscapingScopes.ts index 52a0312dcd..8484a1ca8d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneNonEscapingScopes.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneNonEscapingScopes.ts @@ -829,12 +829,14 @@ class CollectDependenciesVisitor extends ReactiveFunctionVisitor< }; } case 'UnsupportedNode': { - CompilerError.invariant(false, { - reason: `Unexpected unsupported node`, - description: null, - loc: value.loc, - suggestions: null, - }); + const lvalues = []; + if (lvalue !== null) { + lvalues.push({place: lvalue, level: MemoizationLevel.Never}); + } + return { + lvalues, + rvalues: [], + }; } default: { assertExhaustive( diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/flow-enum-inline.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/flow-enum-inline.expect.md new file mode 100644 index 0000000000..dfbf4fbfd9 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/flow-enum-inline.expect.md @@ -0,0 +1,60 @@ + +## Input + +```javascript +// @flow +function Component(props) { + enum Bool { + True = 'true', + False = 'false', + } + + let bool: Bool = Bool.False; + if (props.value) { + bool = Bool.True; + } + return
{bool}
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{value: true}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +function Component(props) { + const $ = _c(2); + enum Bool { + True = "true", + False = "false", + } + + let bool = Bool.False; + if (props.value) { + bool = Bool.True; + } + let t0; + if ($[0] !== bool) { + t0 =
{bool}
; + $[0] = bool; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ value: true }], +}; + +``` + +### Eval output +(kind: exception) Bool is not defined \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/flow-enum-inline.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/flow-enum-inline.js new file mode 100644 index 0000000000..42708c19e0 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/flow-enum-inline.js @@ -0,0 +1,18 @@ +// @flow +function Component(props) { + enum Bool { + True = 'true', + False = 'false', + } + + let bool: Bool = Bool.False; + if (props.value) { + bool = Bool.True; + } + return
{bool}
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{value: true}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ts-enum-inline.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ts-enum-inline.expect.md new file mode 100644 index 0000000000..bb31427d08 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ts-enum-inline.expect.md @@ -0,0 +1,59 @@ + +## Input + +```javascript +function Component(props) { + enum Bool { + True = 'true', + False = 'false', + } + + let bool: Bool = Bool.False; + if (props.value) { + bool = Bool.True; + } + return
{bool}
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{value: true}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +function Component(props) { + const $ = _c(2); + enum Bool { + True = "true", + False = "false", + } + + let bool = Bool.False; + if (props.value) { + bool = Bool.True; + } + let t0; + if ($[0] !== bool) { + t0 =
{bool}
; + $[0] = bool; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ value: true }], +}; + +``` + +### Eval output +(kind: ok)
true
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ts-enum-inline.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ts-enum-inline.tsx new file mode 100644 index 0000000000..7fcec79259 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ts-enum-inline.tsx @@ -0,0 +1,17 @@ +function Component(props) { + enum Bool { + True = 'true', + False = 'false', + } + + let bool: Bool = Bool.False; + if (props.value) { + bool = Bool.True; + } + return
{bool}
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{value: true}], +};