From 5aaa84a08119d006fc94b24112d6843fe5dfbcf2 Mon Sep 17 00:00:00 2001 From: magic-akari Date: Fri, 5 Jun 2026 11:07:26 +0800 Subject: [PATCH] Bail out on using declarations in HIR Emit Todo diagnostics for using and await using declarations instead of silently treating them as ordinary const declarations. Enable explicit resource management parsing in compiler test entrypoints and add snap fixtures covering using and await using bailouts. --- .prettierignore | 3 ++ compiler/apps/playground/lib/compilation.ts | 2 +- .../src/Babel/RunReactCompilerBabelPlugin.ts | 2 +- .../src/HIR/BuildHIR.ts | 30 ++++++++++++++-- ...ror.todo-await-using-declaration.expect.md | 35 +++++++++++++++++++ .../error.todo-await-using-declaration.js | 10 ++++++ .../error.todo-using-declaration.expect.md | 35 +++++++++++++++++++ .../compiler/error.todo-using-declaration.js | 10 ++++++ compiler/packages/snap/src/compiler.ts | 2 +- 9 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-await-using-declaration.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-await-using-declaration.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-using-declaration.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-using-declaration.js diff --git a/.prettierignore b/.prettierignore index 7e09af76a3a..ae076648cd4 100644 --- a/.prettierignore +++ b/.prettierignore @@ -22,6 +22,9 @@ compiler/**/.next # contains invalid graphql`...` which results in a promise rejection error from `yarn prettier-all`. compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.js +# contains explicit resource management syntax not yet parsed by prettier. +compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-await-using-declaration.js +compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-using-declaration.js compiler/crates compiler/target diff --git a/compiler/apps/playground/lib/compilation.ts b/compiler/apps/playground/lib/compilation.ts index b2bee8bd66d..6fb6ce34bb4 100644 --- a/compiler/apps/playground/lib/compilation.ts +++ b/compiler/apps/playground/lib/compilation.ts @@ -46,7 +46,7 @@ function parseInput( }); } else { return babelParse(input, { - plugins: ['typescript', 'jsx'], + plugins: ['typescript', 'jsx', 'explicitResourceManagement'], sourceType: 'module', }) as ParseResult; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/Babel/RunReactCompilerBabelPlugin.ts b/compiler/packages/babel-plugin-react-compiler/src/Babel/RunReactCompilerBabelPlugin.ts index d7960f7e612..604fd9db07f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Babel/RunReactCompilerBabelPlugin.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Babel/RunReactCompilerBabelPlugin.ts @@ -22,7 +22,7 @@ export function runBabelPluginReactCompiler( ): BabelCore.BabelFileResult { const ast = BabelParser.parse(text, { sourceFilename: file, - plugins: [language, 'jsx'], + plugins: [language, 'jsx', 'explicitResourceManagement'], sourceType: 'module', }); const result = transformFromAstSync(ast, text, { 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 452aa0ce329..1dbe6de4e74 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts @@ -903,7 +903,11 @@ function lowerStatement( case 'VariableDeclaration': { const stmt = stmtPath as NodePath; const nodeKind: t.VariableDeclaration['kind'] = stmt.node.kind; - if (nodeKind === 'var') { + if ( + nodeKind === 'var' || + nodeKind === 'using' || + nodeKind === 'await using' + ) { builder.recordError( new CompilerErrorDetail({ reason: `(BuildHIR::lowerStatement) Handle ${nodeKind} kinds in VariableDeclaration`, @@ -912,8 +916,8 @@ function lowerStatement( suggestions: null, }), ); - // Treat `var` as `let` so references to the variable don't break } + // Treat `var` as `let` so references to the variable don't break const kind = nodeKind === 'let' || nodeKind === 'var' ? InstructionKind.Let @@ -1183,6 +1187,17 @@ function lowerStatement( collection: {...value}, }); if (left.isVariableDeclaration()) { + const nodeKind = left.node.kind; + if (nodeKind === 'using' || nodeKind === 'await using') { + builder.recordError( + new CompilerErrorDetail({ + reason: `(BuildHIR::lowerStatement) Handle ${nodeKind} kinds in ForOfStatement`, + category: ErrorCategory.Todo, + loc: left.node.loc ?? null, + suggestions: null, + }), + ); + } const declarations = left.get('declarations'); CompilerError.invariant(declarations.length === 1, { reason: `Expected only one declaration in the init of a ForOfStatement, got ${declarations.length}`, @@ -1274,6 +1289,17 @@ function lowerStatement( value, }); if (left.isVariableDeclaration()) { + const nodeKind = left.node.kind; + if (nodeKind === 'using' || nodeKind === 'await using') { + builder.recordError( + new CompilerErrorDetail({ + reason: `(BuildHIR::lowerStatement) Handle ${nodeKind} kinds in ForInStatement`, + category: ErrorCategory.Todo, + loc: left.node.loc ?? null, + suggestions: null, + }), + ); + } const declarations = left.get('declarations'); CompilerError.invariant(declarations.length === 1, { reason: `Expected only one declaration in the init of a ForInStatement, got ${declarations.length}`, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-await-using-declaration.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-await-using-declaration.expect.md new file mode 100644 index 00000000000..58476d514cd --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-await-using-declaration.expect.md @@ -0,0 +1,35 @@ + +## Input + +```javascript +async function useAsyncResource() { + await using resource = createAsyncResource(); + return resource.value; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useAsyncResource, + params: [], + isComponent: false, +}; + +``` + + +## Error + +``` +Found 1 error: + +Todo: (BuildHIR::lowerStatement) Handle await using kinds in VariableDeclaration + +error.todo-await-using-declaration.ts:2:2 + 1 | async function useAsyncResource() { +> 2 | await using resource = createAsyncResource(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (BuildHIR::lowerStatement) Handle await using kinds in VariableDeclaration + 3 | return resource.value; + 4 | } + 5 | +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-await-using-declaration.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-await-using-declaration.js new file mode 100644 index 00000000000..b42e272f564 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-await-using-declaration.js @@ -0,0 +1,10 @@ +async function useAsyncResource() { + await using resource = createAsyncResource(); + return resource.value; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useAsyncResource, + params: [], + isComponent: false, +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-using-declaration.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-using-declaration.expect.md new file mode 100644 index 00000000000..b6e0829638c --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-using-declaration.expect.md @@ -0,0 +1,35 @@ + +## Input + +```javascript +function useResource() { + using resource = createResource(); + return resource.value; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useResource, + params: [], + isComponent: false, +}; + +``` + + +## Error + +``` +Found 1 error: + +Todo: (BuildHIR::lowerStatement) Handle using kinds in VariableDeclaration + +error.todo-using-declaration.ts:2:2 + 1 | function useResource() { +> 2 | using resource = createResource(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (BuildHIR::lowerStatement) Handle using kinds in VariableDeclaration + 3 | return resource.value; + 4 | } + 5 | +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-using-declaration.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-using-declaration.js new file mode 100644 index 00000000000..e74bde0435e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-using-declaration.js @@ -0,0 +1,10 @@ +function useResource() { + using resource = createResource(); + return resource.value; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useResource, + params: [], + isComponent: false, +}; diff --git a/compiler/packages/snap/src/compiler.ts b/compiler/packages/snap/src/compiler.ts index 0ee2ee0945b..7fa532988fe 100644 --- a/compiler/packages/snap/src/compiler.ts +++ b/compiler/packages/snap/src/compiler.ts @@ -120,7 +120,7 @@ export function parseInput( } else { return BabelParser.parse(input, { sourceFilename: filename, - plugins: ['typescript', 'jsx'], + plugins: ['typescript', 'jsx', 'explicitResourceManagement'], sourceType, }); }