From 508dd4c2fc14317029fa3bd36ffed45d290011a2 Mon Sep 17 00:00:00 2001 From: Mofei Zhang Date: Tue, 18 Mar 2025 16:35:51 -0400 Subject: [PATCH] [compiler] Avoid failing builds when import specifiers conflict or shadow vars Avoid failing builds when imported function specifiers conflict by using babel's `generateUid`. Failing a build is very disruptive, as it usually presents to developers similar to a javascript parse error. ```js import {logRender as _logRender} from 'instrument-runtime'; const logRender = () => { /* local conflicting implementation */ } function Component_optimized() { _logRender(); // inserted by compiler } ``` Currently, we fail builds (even in `panicThreshold:none` cases) when import specifiers are detected to conflict with existing local variables. The reason we destructively throw (instead of bailing out) is because (1) we first generate identifier references to the conflicting name in compiled functions, (2) replaced original functions with compiled functions, and then (3) finally check for conflicts. When we finally check for conflicts, it's too late to bail out. ```js // import {logRender} from 'instrument-runtime'; const logRender = () => { /* local conflicting implementation */ } function Component_optimized() { logRender(); // inserted by compiler } ``` --- .../scripts/jest/makeTransform.ts | 11 +- .../src/Entrypoint/Gating.ts | 13 +- .../src/Entrypoint/Imports.ts | 48 ++-- .../src/Entrypoint/Pipeline.ts | 9 +- .../src/Entrypoint/Program.ts | 253 +++++++++++++----- .../src/HIR/Environment.ts | 24 +- .../src/Optimization/LowerContextAccess.ts | 14 +- .../ReactiveScopes/CodegenReactiveFunction.ts | 53 ++-- .../src/Transform/TransformFire.ts | 9 +- .../compiler/change-detect-reassign.expect.md | 6 +- ...codegen-emit-imports-same-source.expect.md | 12 +- .../codegen-emit-make-read-only.expect.md | 4 +- .../codegen-instrument-forget-test.expect.md | 13 +- ...nflict-codegen-instrument-forget.expect.md | 97 +++++++ .../conflict-codegen-instrument-forget.js | 23 ++ .../emit-freeze-conflicting-imports.expect.md | 37 +++ ....js => emit-freeze-conflicting-imports.js} | 0 ...-nonconflicting-global-reference.expect.md | 33 +++ ...-freeze-nonconflicting-global-reference.js | 4 + ....emit-freeze-conflicting-global.expect.md} | 6 +- .../error.emit-freeze-conflicting-global.js | 6 + .../flag-enable-emit-hook-guards.expect.md | 22 +- .../arrow-function-expr-gating-test.expect.md | 4 +- ...en-instrument-forget-gating-test.expect.md | 19 +- ...component-syntax-ref-gating.flow.expect.md | 4 +- .../gating/conflicting-gating-fn.expect.md | 62 +++++ .../compiler/gating/conflicting-gating-fn.js | 16 ++ ...ccess-function-name-in-component.expect.md | 4 +- ...nreferenced-identifier-collision.expect.md | 6 +- ...ng-preserves-function-properties.expect.md | 6 +- ...ing-test-export-default-function.expect.md | 6 +- ...test-export-function-and-default.expect.md | 6 +- .../gating-test-export-function.expect.md | 6 +- .../compiler/gating/gating-test.expect.md | 6 +- .../gating-use-before-decl-ref.expect.md | 4 +- .../gating/gating-use-before-decl.expect.md | 4 +- ...with-hoisted-type-reference.flow.expect.md | 4 +- ...ion-expression-React-memo-gating.expect.md | 4 +- .../gating/invalid-fnexpr-reference.expect.md | 6 +- ...-expr-export-default-gating-test.expect.md | 6 +- ...ti-arrow-expr-export-gating-test.expect.md | 6 +- .../multi-arrow-expr-gating-test.expect.md | 6 +- .../reassigned-fnexpr-variable.expect.md | 6 +- .../lower-context-access-hook-guard.expect.md | 66 +++++ .../lower-context-access-hook-guard.js | 6 + .../lower-context-acess-multiple.expect.md | 6 +- .../lower-context-selector-simple.expect.md | 4 +- .../bailout-capitalized-fn-call.expect.md | 6 +- .../bailout-eslint-suppressions.expect.md | 6 +- .../bailout-validate-preserve-memo.expect.md | 6 +- .../bailout-validate-prop-write.expect.md | 4 +- ...lout-validate-ref-current-access.expect.md | 4 +- ...-fire-todo-syntax-shouldnt-throw.expect.md | 4 +- ...ailout-validate-conditional-hook.expect.md | 4 +- .../compiler/transform-fire/basic.expect.md | 4 +- .../transform-fire/deep-scope.expect.md | 4 +- .../fire-and-autodeps.expect.md | 4 +- .../transform-fire/hook-guard.expect.md | 73 +++++ .../compiler/transform-fire/hook-guard.js | 13 + .../transform-fire/multiple-scope.expect.md | 4 +- .../transform-fire/repeated-calls.expect.md | 4 +- .../transform-fire/rewrite-deps.expect.md | 4 +- .../shared-hook-calls.expect.md | 6 +- ...d-other-hook-unpruned-dependency.expect.md | 10 +- ...-pruned-dependency-change-detect.expect.md | 6 +- .../useState-unpruned-dependency.expect.md | 10 +- 66 files changed, 875 insertions(+), 271 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conflict-codegen-instrument-forget.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conflict-codegen-instrument-forget.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-conflicting-imports.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{error.codegen-error-on-conflicting-imports.js => emit-freeze-conflicting-imports.js} (100%) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-nonconflicting-global-reference.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-nonconflicting-global-reference.js rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{error.codegen-error-on-conflicting-imports.expect.md => error.emit-freeze-conflicting-global.expect.md} (53%) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.emit-freeze-conflicting-global.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/conflicting-gating-fn.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/conflicting-gating-fn.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-access-hook-guard.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-access-hook-guard.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/hook-guard.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/hook-guard.js diff --git a/compiler/packages/babel-plugin-react-compiler/scripts/jest/makeTransform.ts b/compiler/packages/babel-plugin-react-compiler/scripts/jest/makeTransform.ts index 99291c2984..8452ad49d8 100644 --- a/compiler/packages/babel-plugin-react-compiler/scripts/jest/makeTransform.ts +++ b/compiler/packages/babel-plugin-react-compiler/scripts/jest/makeTransform.ts @@ -182,7 +182,16 @@ function ReactForgetFunctionTransform() { forgetOptions, 'Other', 'all_features', - '_c', + { + useMemoCacheIdentifier: '_c', + gating: null, + lowerContextAccess: null, + enableEmitInstrumentForget: null, + enableEmitFreeze: null, + enableEmitHookGuards: null, + enableChangeDetectionForDebugging: null, + enableFire: null, + }, null, null, null, diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Gating.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Gating.ts index 16ef7986ef..d5cd95c61f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Gating.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Gating.ts @@ -7,7 +7,6 @@ import {NodePath} from '@babel/core'; import * as t from '@babel/types'; -import {PluginOptions} from './Options'; import {CompilerError} from '../CompilerError'; /** @@ -34,7 +33,7 @@ import {CompilerError} from '../CompilerError'; function insertAdditionalFunctionDeclaration( fnPath: NodePath, compiled: t.FunctionDeclaration, - gating: NonNullable, + gatingImportedName: string, ): void { const originalFnName = fnPath.node.id; const originalFnParams = fnPath.node.params; @@ -58,7 +57,7 @@ function insertAdditionalFunctionDeclaration( }); const gatingCondition = fnPath.scope.generateUidIdentifier( - `${gating.importSpecifierName}_result`, + `${gatingImportedName}_result`, ); const unoptimizedFnName = fnPath.scope.generateUidIdentifier( `${originalFnName.name}_unoptimized`, @@ -115,7 +114,7 @@ function insertAdditionalFunctionDeclaration( t.variableDeclaration('const', [ t.variableDeclarator( gatingCondition, - t.callExpression(t.identifier(gating.importSpecifierName), []), + t.callExpression(t.identifier(gatingImportedName), []), ), ]), ); @@ -129,7 +128,7 @@ export function insertGatedFunctionDeclaration( | t.FunctionDeclaration | t.ArrowFunctionExpression | t.FunctionExpression, - gating: NonNullable, + gatingImportedName: string, referencedBeforeDeclaration: boolean, ): void { if (referencedBeforeDeclaration && fnPath.isFunctionDeclaration()) { @@ -138,10 +137,10 @@ export function insertGatedFunctionDeclaration( description: `Got ${compiled.type} but expected FunctionDeclaration`, loc: fnPath.node.loc ?? null, }); - insertAdditionalFunctionDeclaration(fnPath, compiled, gating); + insertAdditionalFunctionDeclaration(fnPath, compiled, gatingImportedName); } else { const gatingExpression = t.conditionalExpression( - t.callExpression(t.identifier(gating.importSpecifierName), []), + t.callExpression(t.identifier(gatingImportedName), []), buildFunctionExpression(compiled), buildFunctionExpression(fnPath.node), ); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts index 1a19d01976..4dca973418 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts @@ -8,8 +8,9 @@ import {NodePath} from '@babel/core'; import * as t from '@babel/types'; import {CompilerError, ErrorSeverity} from '../CompilerError'; -import {EnvironmentConfig, ExternalFunction, GeneratedSource} from '../HIR'; +import {EnvironmentConfig, GeneratedSource} from '../HIR'; import {getOrInsertDefault} from '../Utils/utils'; +import {ImportedExternalFunction} from '../HIR/Environment'; export function validateRestrictedImports( path: NodePath, @@ -44,45 +45,36 @@ export function validateRestrictedImports( export function addImportsToProgram( path: NodePath, - importList: Array, + importList: Array, ): void { - const identifiers: Set = new Set(); - const sortedImports: Map> = new Map(); - for (const {importSpecifierName, source} of importList) { - /* - * Codegen currently does not rename import specifiers, so we do additional - * validation here + const sortedImports: Map> = new Map(); + for (const import_ of importList) { + /** + * Assert that the import identifier hasn't already be declared in the program. + * Note: we use getBinding here since `Scope.hasBinding` pessimistically returns true + * for all allocated uids (from `Scope.getUid`) */ - CompilerError.invariant(identifiers.has(importSpecifierName) === false, { - reason: `Encountered conflicting import specifier for ${importSpecifierName} in Forget config.`, - description: null, + CompilerError.invariant(path.scope.getBinding(import_.local) == null, { + reason: 'Encountered conflicting import specifiers in generated program', + description: `Conflict from import ${import_.source}:(${import_.importSpecifierName} as ${import_.local}).`, loc: GeneratedSource, suggestions: null, }); - CompilerError.invariant( - path.scope.hasBinding(importSpecifierName) === false, - { - reason: `Encountered conflicting import specifiers for ${importSpecifierName} in generated program.`, - description: null, - loc: GeneratedSource, - suggestions: null, - }, - ); - identifiers.add(importSpecifierName); - const importSpecifierNameList = getOrInsertDefault( sortedImports, - source, + import_.source, [], ); - importSpecifierNameList.push(importSpecifierName); + importSpecifierNameList.push(import_); } const stmts: Array = []; - for (const [source, importSpecifierNameList] of sortedImports) { - const importSpecifiers = importSpecifierNameList.map(name => { - const id = t.identifier(name); - return t.importSpecifier(id, id); + for (const [source, import_] of sortedImports) { + const importSpecifiers = import_.map(specifier => { + return t.importSpecifier( + t.identifier(specifier.local), + t.identifier(specifier.importSpecifierName), + ); }); stmts.push(t.importDeclaration(importSpecifiers, t.stringLiteral(source))); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts index 994aa8f18c..4f36549786 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts @@ -28,6 +28,7 @@ import { Environment, EnvironmentConfig, ReactFunctionType, + ImportedUids, } from '../HIR/Environment'; import {findContextIdentifiers} from '../HIR/FindContextIdentifiers'; import { @@ -116,7 +117,7 @@ function run( config: EnvironmentConfig, fnType: ReactFunctionType, mode: CompilerMode, - useMemoCacheIdentifier: string, + uniquedImports: ImportedUids, logger: Logger | null, filename: string | null, code: string | null, @@ -131,7 +132,7 @@ function run( logger, filename, code, - useMemoCacheIdentifier, + uniquedImports, ); env.logger?.debugLogIRs?.({ kind: 'debug', @@ -547,7 +548,7 @@ export function compileFn( config: EnvironmentConfig, fnType: ReactFunctionType, mode: CompilerMode, - useMemoCacheIdentifier: string, + uniquedImports: ImportedUids, logger: Logger | null, filename: string | null, code: string | null, @@ -557,7 +558,7 @@ export function compileFn( config, fnType, mode, - useMemoCacheIdentifier, + uniquedImports, logger, filename, code, diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts index 72fa101260..722350f0d0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts @@ -16,6 +16,10 @@ import { EnvironmentConfig, ExternalFunction, ReactFunctionType, + ImportedExternalFunction, + ImportedUids, + EMIT_FREEZE_GLOBAL_GATING, + USE_FIRE_FUNCTION_NAME, } from '../HIR/Environment'; import {CodegenFunction} from '../ReactiveScopes'; import {isComponentDeclaration} from '../Utils/ComponentDeclaration'; @@ -34,6 +38,7 @@ import { findProgramSuppressions, suppressionsToCompilerError, } from './Suppression'; +import {Err, Ok, Result} from '../Utils/Result'; export type CompilerPass = { opts: PluginOptions; @@ -271,6 +276,137 @@ function isFilePartOfSources( return false; } +function getExternalFunctions( + program: NodePath, + options: PluginOptions, +): Result< + { + importedIdentifierNames: ImportedUids; + importedFunctions: Array; + }, + CompilerError +> { + const environment = options.environment; + const importedFunctions: Array = []; + const pushUid = (fn: ExternalFunction): string => { + /** + * TODO: Don't call babel's generateUid for known hook imports, as + * InferTypes might eventually type `HookKind` based on callee naming + * convention and `_useFoo` is not named as a hook. + * + * Local uid generation is susceptible to check-before-use bugs since we're + * checking for naming conflicts / references long before we actually insert + * the import. (see similar logic in HIRBuilder:resolveBinding) + * + * Instead, implement a program-scoped `generateUid` that generates and + * tracks all generated identifiers. While babel apis allow for registering + * new identifiers and references, at this point we have no concrete + * NodePath to point the new declaration to. + */ + const uid = program.scope.generateUid(fn.importSpecifierName); + importedFunctions.push({...fn, local: uid}); + return uid; + }; + const useMemoCacheIdentifier = program.scope.generateUid('c'); + + const importedIdentifierNames: ImportedUids = { + useMemoCacheIdentifier, + gating: null, + lowerContextAccess: null, + enableEmitInstrumentForget: null, + enableEmitFreeze: null, + enableEmitHookGuards: null, + enableChangeDetectionForDebugging: null, + enableFire: null, + }; + + // TODO: check for duplicate import specifiers + if (options.gating != null) { + importedIdentifierNames.gating = pushUid(options.gating); + } + + if (environment.lowerContextAccess) { + importedIdentifierNames.lowerContextAccess = pushUid( + environment.lowerContextAccess, + ); + } + + const enableEmitInstrumentForget = environment.enableEmitInstrumentForget; + if (enableEmitInstrumentForget != null) { + importedIdentifierNames.enableEmitInstrumentForget = { + fn: pushUid(enableEmitInstrumentForget.fn), + gating: null, + globalGating: null, + }; + if (enableEmitInstrumentForget.gating != null) { + importedIdentifierNames.enableEmitInstrumentForget.gating = pushUid( + enableEmitInstrumentForget.gating, + ); + } + if (enableEmitInstrumentForget.globalGating != null) { + if (program.scope.hasReference(enableEmitInstrumentForget.globalGating)) { + /** + * Note that getBinding returns undefined for declared-but-not-defined + * uids generated with `Scope:generateUidIdentifier`. + */ + const maybeBinding = program.scope.getBinding( + enableEmitInstrumentForget.globalGating, + ); + return Err( + new CompilerError({ + severity: ErrorSeverity.Todo, + reason: + 'Found conflicting local binding for `enableEmitInstrumentForget.globalGating`', + description: `Identifier name: ${enableEmitInstrumentForget.globalGating}`, + loc: maybeBinding?.path.node.loc ?? null, + }), + ); + } + importedIdentifierNames.enableEmitInstrumentForget.globalGating = + enableEmitInstrumentForget.globalGating; + } + } + + if (environment.enableEmitFreeze != null) { + if (program.scope.hasReference(EMIT_FREEZE_GLOBAL_GATING)) { + /** + * Note that getBinding returns undefined for declared-but-not-defined + * uids generated with `Scope:generateUidIdentifier`. + */ + const maybeBinding = program.scope.getBinding(EMIT_FREEZE_GLOBAL_GATING); + return Err( + new CompilerError({ + severity: ErrorSeverity.Todo, + reason: + 'Found conflicting local binding for enableEmitFreeze global gating', + description: `Identifier name: ${EMIT_FREEZE_GLOBAL_GATING}`, + loc: maybeBinding?.path.node.loc ?? null, + }), + ); + } + importedIdentifierNames.enableEmitFreeze = pushUid( + environment.enableEmitFreeze, + ); + } + + if (environment.enableEmitHookGuards != null) { + importedIdentifierNames.enableEmitHookGuards = pushUid( + environment.enableEmitHookGuards, + ); + } + + if (environment.enableChangeDetectionForDebugging != null) { + importedIdentifierNames.enableChangeDetectionForDebugging = pushUid( + environment.enableChangeDetectionForDebugging, + ); + } + + if (environment.enableFire) { + importedIdentifierNames.enableFire = pushUid(getUseFireFunction(options)); + } + return Ok({importedIdentifierNames, importedFunctions}); +} + type CompileProgramResult = { retryErrors: Array<{fn: BabelFn; error: CompilerError}>; }; @@ -299,7 +435,14 @@ export function compileProgram( handleError(restrictedImportsErr, pass, null); return null; } - const useMemoCacheIdentifier = program.scope.generateUidIdentifier('c'); + + const externalFunctionsResult = getExternalFunctions(program, pass.opts); + if (externalFunctionsResult.isErr()) { + handleError(externalFunctionsResult.unwrapErr(), pass, null); + return null; + } + const {importedIdentifierNames, importedFunctions} = + externalFunctionsResult.unwrap(); /* * Record lint errors and critical errors as depending on Forget's config, @@ -410,7 +553,7 @@ export function compileProgram( environment, fnType, 'all_features', - useMemoCacheIdentifier.name, + importedIdentifierNames, pass.opts.logger, pass.filename, pass.code, @@ -445,7 +588,7 @@ export function compileProgram( environment, fnType, 'no_inferred_memo', - useMemoCacheIdentifier.name, + importedIdentifierNames, pass.opts.logger, pass.filename, pass.code, @@ -548,79 +691,63 @@ export function compileProgram( if (moduleScopeOptOutDirectives.length > 0) { return null; } - let gating: null | { - gatingFn: ExternalFunction; - referencedBeforeDeclared: Set; - } = null; - if (pass.opts.gating != null) { - gating = { - gatingFn: pass.opts.gating, - referencedBeforeDeclared: - getFunctionReferencedBeforeDeclarationAtTopLevel(program, compiledFns), - }; - } const hasLoweredContextAccess = compiledFns.some( c => c.compiledFn.hasLoweredContextAccess, ); - const externalFunctions: Array = []; - try { - // TODO: check for duplicate import specifiers - if (gating != null) { - externalFunctions.push(gating.gatingFn); - } + const lowerContextAccess = environment.lowerContextAccess; + if (!hasLoweredContextAccess && lowerContextAccess != null) { + // remove loweredContextAccess import if not used + const idx = importedFunctions.findIndex( + f => + f.source === lowerContextAccess.source && + f.importSpecifierName === lowerContextAccess.importSpecifierName, + ); + CompilerError.invariant(idx >= 0, { + reason: 'Expected to find loweredContextAccess import', + loc: null, + }); + importedFunctions.splice(idx, 1); + } - const lowerContextAccess = environment.lowerContextAccess; - if (lowerContextAccess && hasLoweredContextAccess) { - externalFunctions.push(lowerContextAccess); - } - - const enableEmitInstrumentForget = environment.enableEmitInstrumentForget; - if (enableEmitInstrumentForget != null) { - externalFunctions.push(enableEmitInstrumentForget.fn); - if (enableEmitInstrumentForget.gating != null) { - externalFunctions.push(enableEmitInstrumentForget.gating); - } - } - - if (environment.enableEmitFreeze != null) { - externalFunctions.push(environment.enableEmitFreeze); - } - - if (environment.enableEmitHookGuards != null) { - externalFunctions.push(environment.enableEmitHookGuards); - } - - if (environment.enableChangeDetectionForDebugging != null) { - externalFunctions.push(environment.enableChangeDetectionForDebugging); - } - - const hasFireRewrite = compiledFns.some(c => c.compiledFn.hasFireRewrite); - if (environment.enableFire && hasFireRewrite) { - externalFunctions.push({ - source: getReactCompilerRuntimeModule(pass.opts), - importSpecifierName: 'useFire', - }); - } - } catch (err) { - handleError(err, pass, null); - return null; + const hasFireRewrite = compiledFns.some(c => c.compiledFn.hasFireRewrite); + if (!hasFireRewrite && environment.enableFire) { + const fireFunction = getUseFireFunction(pass.opts); + // remove useFire import if not used + const idx = importedFunctions.findIndex( + f => + f.source === fireFunction.source && + f.importSpecifierName === fireFunction.importSpecifierName, + ); + CompilerError.invariant(idx >= 0, { + reason: 'Expected to find useFire import', + loc: null, + }); + importedFunctions.splice(idx, 1); } /* * Only insert Forget-ified functions if we have not encountered a critical * error elsewhere in the file, regardless of bailout mode. */ + const referencedBeforeDeclared = + pass.opts.gating != null + ? getFunctionReferencedBeforeDeclarationAtTopLevel(program, compiledFns) + : null; for (const result of compiledFns) { const {kind, originalFn, compiledFn} = result; const transformedFn = createNewFunctionNode(originalFn, compiledFn); - if (gating != null && kind === 'original') { + if (referencedBeforeDeclared != null && kind === 'original') { + CompilerError.invariant(importedIdentifierNames.gating != null, { + reason: "Expected 'gating' import to be present", + loc: null, + }); insertGatedFunctionDeclaration( originalFn, transformedFn, - gating.gatingFn, - gating.referencedBeforeDeclared.has(result), + importedIdentifierNames.gating, + referencedBeforeDeclared.has(result), ); } else { originalFn.replaceWith(transformedFn); @@ -641,10 +768,10 @@ export function compileProgram( updateMemoCacheFunctionImport( program, getReactCompilerRuntimeModule(pass.opts), - useMemoCacheIdentifier.name, + importedIdentifierNames.useMemoCacheIdentifier, ); } - addImportsToProgram(program, externalFunctions); + addImportsToProgram(program, importedFunctions); } return {retryErrors}; } @@ -1162,6 +1289,12 @@ function getFunctionReferencedBeforeDeclarationAtTopLevel( return referencedBeforeDeclaration; } +function getUseFireFunction(options: PluginOptions): ExternalFunction { + return { + source: getReactCompilerRuntimeModule(options), + importSpecifierName: USE_FIRE_FUNCTION_NAME, + }; +} function getReactCompilerRuntimeModule(opts: PluginOptions): string { if (opts.target === '19') { diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index 1f64452e4b..b4882c8419 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -84,6 +84,8 @@ export const InstrumentationSchema = z ); export type ExternalFunction = z.infer; +export type ImportedExternalFunction = ExternalFunction & {local: string}; +export const USE_FIRE_FUNCTION_NAME = 'useFire'; export const MacroMethodSchema = z.union([ z.object({type: z.literal('wildcard')}), @@ -823,6 +825,22 @@ export function printFunctionType(type: ReactFunctionType): string { } } +export const EMIT_FREEZE_GLOBAL_GATING = '__DEV__'; +export type ImportedUids = { + useMemoCacheIdentifier: string; + gating: string | null; + lowerContextAccess: string | null; + enableEmitInstrumentForget: { + fn: string; + gating: string | null; + globalGating: string | null; + } | null; + enableEmitFreeze: string | null; + enableEmitHookGuards: string | null; + enableChangeDetectionForDebugging: string | null; + enableFire: string | null; +}; + export class Environment { #globals: GlobalRegistry; #shapes: ShapeRegistry; @@ -841,7 +859,7 @@ export class Environment { config: EnvironmentConfig; fnType: ReactFunctionType; compilerMode: CompilerMode; - useMemoCacheIdentifier: string; + importedUids: ImportedUids; hasLoweredContextAccess: boolean; hasFireRewrite: boolean; @@ -857,7 +875,7 @@ export class Environment { logger: Logger | null, filename: string | null, code: string | null, - useMemoCacheIdentifier: string, + importedUids: ImportedUids, ) { this.#scope = scope; this.fnType = fnType; @@ -866,7 +884,7 @@ export class Environment { this.filename = filename; this.code = code; this.logger = logger; - this.useMemoCacheIdentifier = useMemoCacheIdentifier; + this.importedUids = importedUids; this.#shapes = new Map(DEFAULT_SHAPES); this.#globals = new Map(DEFAULT_GLOBALS); this.hasLoweredContextAccess = false; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts index b636c7b171..bc9a1533f7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts @@ -29,16 +29,21 @@ import { promoteTemporary, reversePostorderBlocks, } from '../HIR'; +import {ImportedExternalFunction} from '../HIR/Environment'; import {createTemporaryPlace} from '../HIR/HIRBuilder'; import {enterSSA} from '../SSA'; import {inferTypes} from '../TypeInference'; export function lowerContextAccess( fn: HIRFunction, - loweredContextCallee: ExternalFunction, + loweredContextCalleeConfig: ExternalFunction, ): void { const contextAccess: Map = new Map(); const contextKeys: Map> = new Map(); + const loweredContextCallee: ImportedExternalFunction = { + ...loweredContextCalleeConfig, + local: fn.env.importedUids.lowerContextAccess!, + }; // collect context access and keys for (const [, block] of fn.body.blocks) { @@ -128,14 +133,15 @@ export function lowerContextAccess( function emitLoadLoweredContextCallee( env: Environment, - loweredContextCallee: ExternalFunction, + loweredContextCallee: ImportedExternalFunction, ): Instruction { const loadGlobal: LoadGlobal = { kind: 'LoadGlobal', binding: { - kind: 'ImportNamespace', + kind: 'ImportSpecifier', module: loweredContextCallee.source, - name: loweredContextCallee.importSpecifierName, + name: loweredContextCallee.local, + imported: loweredContextCallee.importSpecifierName, }, loc: GeneratedSource, }; diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts index f8a2bc4989..3b8cae2bf6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts @@ -14,7 +14,7 @@ import { renameVariables, } from '.'; import {CompilerError, ErrorSeverity} from '../CompilerError'; -import {Environment, EnvironmentConfig, ExternalFunction} from '../HIR'; +import {Environment} from '../HIR'; import { ArrayPattern, BlockId, @@ -155,7 +155,7 @@ export function codegenFunction( } const compiled = compileResult.unwrap(); - const hookGuard = fn.env.config.enableEmitHookGuards; + const hookGuard = fn.env.importedUids.enableEmitHookGuards; if (hookGuard != null) { compiled.body = t.blockStatement([ createHookGuard( @@ -176,9 +176,10 @@ export function codegenFunction( t.variableDeclaration('const', [ t.variableDeclarator( t.identifier(cx.synthesizeName('$')), - t.callExpression(t.identifier(fn.env.useMemoCacheIdentifier), [ - t.numericLiteral(cacheCount), - ]), + t.callExpression( + t.identifier(fn.env.importedUids.useMemoCacheIdentifier), + [t.numericLiteral(cacheCount)], + ), ), ]), ); @@ -249,7 +250,7 @@ export function codegenFunction( compiled.body.body.unshift(...preface); } - const emitInstrumentForget = fn.env.config.enableEmitInstrumentForget; + const emitInstrumentForget = fn.env.importedUids.enableEmitInstrumentForget; if (emitInstrumentForget != null && fn.id != null) { /* * Technically, this is a conditional hook call. However, we expect @@ -263,10 +264,10 @@ export function codegenFunction( gating = t.logicalExpression( '&&', t.identifier(emitInstrumentForget.globalGating), - t.identifier(emitInstrumentForget.gating.importSpecifierName), + t.identifier(emitInstrumentForget.gating), ); } else if (emitInstrumentForget.gating != null) { - gating = t.identifier(emitInstrumentForget.gating.importSpecifierName); + gating = t.identifier(emitInstrumentForget.gating); } else { CompilerError.invariant(emitInstrumentForget.globalGating != null, { reason: @@ -279,10 +280,10 @@ export function codegenFunction( const test: t.IfStatement = t.ifStatement( gating, t.expressionStatement( - t.callExpression( - t.identifier(emitInstrumentForget.fn.importSpecifierName), - [t.stringLiteral(fn.id), t.stringLiteral(fn.env.filename ?? '')], - ), + t.callExpression(t.identifier(emitInstrumentForget.fn), [ + t.stringLiteral(fn.id), + t.stringLiteral(fn.env.filename ?? ''), + ]), ), ); compiled.body.body.unshift(test); @@ -548,14 +549,14 @@ function codegenBlockNoReset( } function wrapCacheDep(cx: Context, value: t.Expression): t.Expression { - if (cx.env.config.enableEmitFreeze != null) { + if (cx.env.importedUids.enableEmitFreeze != null) { // The import declaration for emitFreeze is inserted in the Babel plugin return t.conditionalExpression( t.identifier('__DEV__'), - t.callExpression( - t.identifier(cx.env.config.enableEmitFreeze.importSpecifierName), - [value, t.stringLiteral(cx.fnName)], - ), + t.callExpression(t.identifier(cx.env.importedUids.enableEmitFreeze), [ + value, + t.stringLiteral(cx.fnName), + ]), value, ); } else { @@ -710,7 +711,7 @@ function codegenReactiveScope( let memoStatement; if ( - cx.env.config.enableChangeDetectionForDebugging != null && + cx.env.importedUids.enableChangeDetectionForDebugging != null && changeExpressions.length > 0 ) { const loc = @@ -718,7 +719,7 @@ function codegenReactiveScope( ? 'unknown location' : `(${scope.loc.start.line}:${scope.loc.end.line})`; const detectionFunction = - cx.env.config.enableChangeDetectionForDebugging.importSpecifierName; + cx.env.importedUids.enableChangeDetectionForDebugging; const cacheLoadOldValueStatements: Array = []; const changeDetectionStatements: Array = []; const idempotenceDetectionStatements: Array = []; @@ -1513,16 +1514,14 @@ const createJsxOpeningElement = withLoc(t.jsxOpeningElement); const createStringLiteral = withLoc(t.stringLiteral); function createHookGuard( - guard: ExternalFunction, + guardFnName: string, stmts: Array, before: GuardKind, after: GuardKind, ): t.TryStatement { function createHookGuardImpl(kind: number): t.ExpressionStatement { return t.expressionStatement( - t.callExpression(t.identifier(guard.importSpecifierName), [ - t.numericLiteral(kind), - ]), + t.callExpression(t.identifier(guardFnName), [t.numericLiteral(kind)]), ); } @@ -1553,7 +1552,7 @@ function createHookGuard( * ``` */ function createCallExpression( - config: EnvironmentConfig, + env: Environment, callee: t.Expression, args: Array, loc: SourceLocation | null, @@ -1564,7 +1563,7 @@ function createCallExpression( callExpr.loc = loc; } - const hookGuard = config.enableEmitHookGuards; + const hookGuard = env.importedUids.enableEmitHookGuards; if (hookGuard != null && isHook) { const iife = t.functionExpression( null, @@ -1701,7 +1700,7 @@ function codegenInstructionValue( const callee = codegenPlaceToExpression(cx, instrValue.callee); const args = instrValue.args.map(arg => codegenArgument(cx, arg)); value = createCallExpression( - cx.env.config, + cx.env, callee, args, instrValue.loc, @@ -1791,7 +1790,7 @@ function codegenInstructionValue( ); const args = instrValue.args.map(arg => codegenArgument(cx, arg)); value = createCallExpression( - cx.env.config, + cx.env, memberExpr, args, instrValue.loc, diff --git a/compiler/packages/babel-plugin-react-compiler/src/Transform/TransformFire.ts b/compiler/packages/babel-plugin-react-compiler/src/Transform/TransformFire.ts index a480b5d7c7..93caa0fe82 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Transform/TransformFire.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Transform/TransformFire.ts @@ -36,6 +36,7 @@ import {getOrInsertWith} from '../Utils/utils'; import {BuiltInFireId, DefaultNonmutatingHook} from '../HIR/ObjectShape'; import {eachInstructionOperand} from '../HIR/visitors'; import {printSourceLocationLine} from '../HIR/PrintHIR'; +import {USE_FIRE_FUNCTION_NAME} from '../HIR/Environment'; /* * TODO(jmbrown): @@ -408,13 +409,17 @@ function makeLoadUseFireInstruction(env: Environment): Instruction { const useFirePlace = createTemporaryPlace(env, GeneratedSource); useFirePlace.effect = Effect.Read; useFirePlace.identifier.type = DefaultNonmutatingHook; + CompilerError.invariant(env.importedUids.enableFire != null, { + reason: "Couldn't find useFire import", + loc: GeneratedSource, + }); const instrValue: InstructionValue = { kind: 'LoadGlobal', binding: { kind: 'ImportSpecifier', - name: 'useFire', + name: env.importedUids.enableFire, module: 'react', - imported: 'useFire', + imported: USE_FIRE_FUNCTION_NAME, }, loc: GeneratedSource, }; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/change-detect-reassign.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/change-detect-reassign.expect.md index 099faadced..785057b7ef 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/change-detect-reassign.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/change-detect-reassign.expect.md @@ -17,7 +17,7 @@ function Component(props) { ## Code ```javascript -import { $structuralCheck } from "react-compiler-runtime"; +import { $structuralCheck as _$structuralCheck } from "react-compiler-runtime"; import { c as _c } from "react/compiler-runtime"; // @enableChangeDetectionForDebugging function Component(props) { const $ = _c(2); @@ -29,14 +29,14 @@ function Component(props) { let condition = $[0] !== props.value; if (!condition) { let old$x = $[1]; - $structuralCheck(old$x, x, "x", "Component", "cached", "(3:6)"); + _$structuralCheck(old$x, x, "x", "Component", "cached", "(3:6)"); } $[0] = props.value; $[1] = x; if (condition) { x = []; x.push(props.value); - $structuralCheck($[1], x, "x", "Component", "recomputed", "(3:6)"); + _$structuralCheck($[1], x, "x", "Component", "recomputed", "(3:6)"); x = $[1]; } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-imports-same-source.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-imports-same-source.expect.md index 161b42dc6d..220306b2de 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-imports-same-source.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-imports-same-source.expect.md @@ -14,21 +14,21 @@ function useFoo(props) { ```javascript import { - useRenderCounter, - shouldInstrument, - makeReadOnly, + useRenderCounter as _useRenderCounter, + shouldInstrument as _shouldInstrument, + makeReadOnly as _makeReadOnly, } from "react-compiler-runtime"; import { c as _c } from "react/compiler-runtime"; // @enableEmitFreeze @enableEmitInstrumentForget function useFoo(props) { - if (DEV && shouldInstrument) - useRenderCounter("useFoo", "/codegen-emit-imports-same-source.ts"); + if (DEV && _shouldInstrument) + _useRenderCounter("useFoo", "/codegen-emit-imports-same-source.ts"); const $ = _c(2); let t0; if ($[0] !== props.x) { t0 = foo(props.x); $[0] = props.x; - $[1] = __DEV__ ? makeReadOnly(t0, "useFoo") : t0; + $[1] = __DEV__ ? _makeReadOnly(t0, "useFoo") : t0; } else { t0 = $[1]; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-make-read-only.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-make-read-only.expect.md index ba9e39e691..53c3cf12f7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-make-read-only.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-make-read-only.expect.md @@ -19,7 +19,7 @@ function MyComponentName(props) { ## Code ```javascript -import { makeReadOnly } from "react-compiler-runtime"; +import { makeReadOnly as _makeReadOnly } from "react-compiler-runtime"; import { c as _c } from "react/compiler-runtime"; // @enableEmitFreeze true function MyComponentName(props) { @@ -34,7 +34,7 @@ function MyComponentName(props) { y.push(x); $[0] = props.a; $[1] = props.b; - $[2] = __DEV__ ? makeReadOnly(y, "MyComponentName") : y; + $[2] = __DEV__ ? _makeReadOnly(y, "MyComponentName") : y; } else { y = $[2]; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-test.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-test.expect.md index 319de18794..e0b6ef0023 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-test.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-test.expect.md @@ -23,13 +23,16 @@ function Foo(props) { ## Code ```javascript -import { useRenderCounter, shouldInstrument } from "react-compiler-runtime"; +import { + useRenderCounter as _useRenderCounter, + shouldInstrument as _shouldInstrument, +} from "react-compiler-runtime"; import { c as _c } from "react/compiler-runtime"; // @enableEmitInstrumentForget @compilationMode(annotation) function Bar(props) { "use forget"; - if (DEV && shouldInstrument) - useRenderCounter("Bar", "/codegen-instrument-forget-test.ts"); + if (DEV && _shouldInstrument) + _useRenderCounter("Bar", "/codegen-instrument-forget-test.ts"); const $ = _c(2); let t0; if ($[0] !== props.bar) { @@ -48,8 +51,8 @@ function NoForget(props) { function Foo(props) { "use forget"; - if (DEV && shouldInstrument) - useRenderCounter("Foo", "/codegen-instrument-forget-test.ts"); + if (DEV && _shouldInstrument) + _useRenderCounter("Foo", "/codegen-instrument-forget-test.ts"); const $ = _c(2); let t0; if ($[0] !== props.bar) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conflict-codegen-instrument-forget.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conflict-codegen-instrument-forget.expect.md new file mode 100644 index 0000000000..8a52292d54 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conflict-codegen-instrument-forget.expect.md @@ -0,0 +1,97 @@ + +## Input + +```javascript +// @enableEmitInstrumentForget @compilationMode(annotation) + +import {identity} from 'shared-runtime'; + +function Bar(props) { + 'use forget'; + const shouldInstrument = identity(null); + const _shouldInstrument = identity(null); + const _x2 = () => { + const _shouldInstrument2 = 'hello world'; + return identity({_shouldInstrument2}); + }; + return ( +
+ {props.bar} +
+ ); +} + +function Foo(props) { + 'use forget'; + return {props.bar}; +} + +``` + +## Code + +```javascript +import { + useRenderCounter as _useRenderCounter, + shouldInstrument as _shouldInstrument3, +} from "react-compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enableEmitInstrumentForget @compilationMode(annotation) + +import { identity } from "shared-runtime"; + +function Bar(props) { + "use forget"; + if (DEV && _shouldInstrument3) + _useRenderCounter("Bar", "/conflict-codegen-instrument-forget.ts"); + const $ = _c(4); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = identity(null); + $[0] = t0; + } else { + t0 = $[0]; + } + const shouldInstrument = t0; + let t1; + if ($[1] === Symbol.for("react.memo_cache_sentinel")) { + t1 = identity(null); + $[1] = t1; + } else { + t1 = $[1]; + } + const _shouldInstrument = t1; + let t2; + if ($[2] !== props.bar) { + t2 = ( +
+ {props.bar} +
+ ); + $[2] = props.bar; + $[3] = t2; + } else { + t2 = $[3]; + } + return t2; +} + +function Foo(props) { + "use forget"; + if (DEV && _shouldInstrument3) + _useRenderCounter("Foo", "/conflict-codegen-instrument-forget.ts"); + const $ = _c(2); + let t0; + if ($[0] !== props.bar) { + t0 = {props.bar}; + $[0] = props.bar; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conflict-codegen-instrument-forget.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conflict-codegen-instrument-forget.js new file mode 100644 index 0000000000..88ffefe220 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conflict-codegen-instrument-forget.js @@ -0,0 +1,23 @@ +// @enableEmitInstrumentForget @compilationMode(annotation) + +import {identity} from 'shared-runtime'; + +function Bar(props) { + 'use forget'; + const shouldInstrument = identity(null); + const _shouldInstrument = identity(null); + const _x2 = () => { + const _shouldInstrument2 = 'hello world'; + return identity({_shouldInstrument2}); + }; + return ( +
+ {props.bar} +
+ ); +} + +function Foo(props) { + 'use forget'; + return {props.bar}; +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-conflicting-imports.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-conflicting-imports.expect.md new file mode 100644 index 0000000000..9b30c1b8cb --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-conflicting-imports.expect.md @@ -0,0 +1,37 @@ + +## Input + +```javascript +// @enableEmitFreeze @instrumentForget + +let makeReadOnly = 'conflicting identifier'; +function useFoo(props) { + return foo(props.x); +} + +``` + +## Code + +```javascript +import { makeReadOnly as _makeReadOnly } from "react-compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enableEmitFreeze @instrumentForget + +let makeReadOnly = "conflicting identifier"; +function useFoo(props) { + const $ = _c(2); + let t0; + if ($[0] !== props.x) { + t0 = foo(props.x); + $[0] = props.x; + $[1] = __DEV__ ? _makeReadOnly(t0, "useFoo") : t0; + } else { + t0 = $[1]; + } + return t0; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.codegen-error-on-conflicting-imports.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-conflicting-imports.js similarity index 100% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.codegen-error-on-conflicting-imports.js rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-conflicting-imports.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-nonconflicting-global-reference.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-nonconflicting-global-reference.expect.md new file mode 100644 index 0000000000..09a3508092 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-nonconflicting-global-reference.expect.md @@ -0,0 +1,33 @@ + +## Input + +```javascript +// @enableEmitFreeze @instrumentForget +function useFoo(props) { + return foo(props.x, __DEV__); +} + +``` + +## Code + +```javascript +import { makeReadOnly as _makeReadOnly } from "react-compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enableEmitFreeze @instrumentForget +function useFoo(props) { + const $ = _c(2); + let t0; + if ($[0] !== props.x) { + t0 = foo(props.x, __DEV__); + $[0] = props.x; + $[1] = __DEV__ ? _makeReadOnly(t0, "useFoo") : t0; + } else { + t0 = $[1]; + } + return t0; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-nonconflicting-global-reference.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-nonconflicting-global-reference.js new file mode 100644 index 0000000000..62c313b67d --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/emit-freeze-nonconflicting-global-reference.js @@ -0,0 +1,4 @@ +// @enableEmitFreeze @instrumentForget +function useFoo(props) { + return foo(props.x, __DEV__); +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.codegen-error-on-conflicting-imports.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.emit-freeze-conflicting-global.expect.md similarity index 53% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.codegen-error-on-conflicting-imports.expect.md rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.emit-freeze-conflicting-global.expect.md index 2bd0eee1b1..cb7aef074e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.codegen-error-on-conflicting-imports.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.emit-freeze-conflicting-global.expect.md @@ -3,9 +3,9 @@ ```javascript // @enableEmitFreeze @instrumentForget - -let makeReadOnly = 'conflicting identifier'; function useFoo(props) { + const __DEV__ = 'conflicting global'; + console.log(__DEV__); return foo(props.x); } @@ -15,7 +15,7 @@ function useFoo(props) { ## Error ``` -Invariant: Encountered conflicting import specifiers for makeReadOnly in generated program. +[object Object] ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.emit-freeze-conflicting-global.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.emit-freeze-conflicting-global.js new file mode 100644 index 0000000000..4391ad76e7 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.emit-freeze-conflicting-global.js @@ -0,0 +1,6 @@ +// @enableEmitFreeze @instrumentForget +function useFoo(props) { + const __DEV__ = 'conflicting global'; + console.log(__DEV__); + return foo(props.x); +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/flag-enable-emit-hook-guards.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/flag-enable-emit-hook-guards.expect.md index 301a46a45c..2ae9309ec3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/flag-enable-emit-hook-guards.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/flag-enable-emit-hook-guards.expect.md @@ -36,7 +36,7 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { $dispatcherGuard } from "react-compiler-runtime"; +import { $dispatcherGuard as _$dispatcherGuard } from "react-compiler-runtime"; import { c as _c } from "react/compiler-runtime"; // @enableEmitHookGuards import { createContext, useContext, useEffect, useState } from "react"; import { @@ -51,7 +51,7 @@ const MyContext = createContext("my context value"); function Component(t0) { const $ = _c(4); try { - $dispatcherGuard(0); + _$dispatcherGuard(0); const { value } = t0; print(identity(CONST_STRING0)); let t1; @@ -63,10 +63,10 @@ function Component(t0) { } const [state, setState] = (function () { try { - $dispatcherGuard(2); + _$dispatcherGuard(2); return useState(t1); } finally { - $dispatcherGuard(3); + _$dispatcherGuard(3); } })(); print(value, state); @@ -89,32 +89,32 @@ function Component(t0) { } (function () { try { - $dispatcherGuard(2); + _$dispatcherGuard(2); return useEffect(t2, t3); } finally { - $dispatcherGuard(3); + _$dispatcherGuard(3); } })(); print(identity(value + state)); return (function () { try { - $dispatcherGuard(2); + _$dispatcherGuard(2); return ObjectWithHooks.useIdentity( (function () { try { - $dispatcherGuard(2); + _$dispatcherGuard(2); return useContext(MyContext); } finally { - $dispatcherGuard(3); + _$dispatcherGuard(3); } })(), ); } finally { - $dispatcherGuard(3); + _$dispatcherGuard(3); } })(); } finally { - $dispatcherGuard(1); + _$dispatcherGuard(1); } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/arrow-function-expr-gating-test.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/arrow-function-expr-gating-test.expect.md index 659e2c9ff9..497d0211bf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/arrow-function-expr-gating-test.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/arrow-function-expr-gating-test.expect.md @@ -18,10 +18,10 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; // @gating import { Stringify } from "shared-runtime"; -const ErrorView = isForgetEnabled_Fixtures() +const ErrorView = _isForgetEnabled_Fixtures() ? (t0) => { const $ = _c(2); const { error } = t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/codegen-instrument-forget-gating-test.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/codegen-instrument-forget-gating-test.expect.md index fe85e38e10..3aae53796c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/codegen-instrument-forget-gating-test.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/codegen-instrument-forget-gating-test.expect.md @@ -36,14 +36,17 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; -import { useRenderCounter, shouldInstrument } from "react-compiler-runtime"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { + useRenderCounter as _useRenderCounter, + shouldInstrument as _shouldInstrument, +} from "react-compiler-runtime"; import { c as _c } from "react/compiler-runtime"; // @enableEmitInstrumentForget @compilationMode(annotation) @gating -const Bar = isForgetEnabled_Fixtures() +const Bar = _isForgetEnabled_Fixtures() ? function Bar(props) { "use forget"; - if (DEV && shouldInstrument) - useRenderCounter("Bar", "/codegen-instrument-forget-gating-test.ts"); + if (DEV && _shouldInstrument) + _useRenderCounter("Bar", "/codegen-instrument-forget-gating-test.ts"); const $ = _c(2); let t0; if ($[0] !== props.bar) { @@ -63,11 +66,11 @@ const Bar = isForgetEnabled_Fixtures() function NoForget(props) { return {props.noForget}; } -const Foo = isForgetEnabled_Fixtures() +const Foo = _isForgetEnabled_Fixtures() ? function Foo(props) { "use forget"; - if (DEV && shouldInstrument) - useRenderCounter("Foo", "/codegen-instrument-forget-gating-test.ts"); + if (DEV && _shouldInstrument) + _useRenderCounter("Foo", "/codegen-instrument-forget-gating-test.ts"); const $ = _c(3); if (props.bar < 0) { return props.children; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/component-syntax-ref-gating.flow.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/component-syntax-ref-gating.flow.expect.md index 25215580c8..1d13d46223 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/component-syntax-ref-gating.flow.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/component-syntax-ref-gating.flow.expect.md @@ -20,13 +20,13 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; import { Stringify } from "shared-runtime"; import * as React from "react"; const Foo = React.forwardRef(Foo_withRef); -const _isForgetEnabled_Fixtures_result = isForgetEnabled_Fixtures(); +const _isForgetEnabled_Fixtures_result = _isForgetEnabled_Fixtures(); function _Foo_withRef_optimized(_$$empty_props_placeholder$$, ref) { const $ = _c(2); let t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/conflicting-gating-fn.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/conflicting-gating-fn.expect.md new file mode 100644 index 0000000000..a04611f6c2 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/conflicting-gating-fn.expect.md @@ -0,0 +1,62 @@ + +## Input + +```javascript +// @gating + +export const isForgetEnabled_Fixtures = () => { + 'use no forget'; + return false; +}; + +export function Bar(props) { + 'use forget'; + return
{props.bar}
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: eval('Bar'), + params: [{bar: 2}], +}; + +``` + +## Code + +```javascript +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { c as _c } from "react/compiler-runtime"; // @gating + +export const isForgetEnabled_Fixtures = () => { + "use no forget"; + return false; +}; + +export const Bar = _isForgetEnabled_Fixtures() + ? function Bar(props) { + "use forget"; + const $ = _c(2); + let t0; + if ($[0] !== props.bar) { + t0 =
{props.bar}
; + $[0] = props.bar; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; + } + : function Bar(props) { + "use forget"; + return
{props.bar}
; + }; + +export const FIXTURE_ENTRYPOINT = { + fn: eval("Bar"), + params: [{ bar: 2 }], +}; + +``` + +### Eval output +(kind: ok)
2
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/conflicting-gating-fn.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/conflicting-gating-fn.js new file mode 100644 index 0000000000..3e5757dc91 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/conflicting-gating-fn.js @@ -0,0 +1,16 @@ +// @gating + +export const isForgetEnabled_Fixtures = () => { + 'use no forget'; + return false; +}; + +export function Bar(props) { + 'use forget'; + return
{props.bar}
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: eval('Bar'), + params: [{bar: 2}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-access-function-name-in-component.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-access-function-name-in-component.expect.md index e056b6fa1c..274e92cb24 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-access-function-name-in-component.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-access-function-name-in-component.expect.md @@ -18,9 +18,9 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; // @gating -const Component = isForgetEnabled_Fixtures() +const Component = _isForgetEnabled_Fixtures() ? function Component() { const $ = _c(1); const name = Component.name; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-nonreferenced-identifier-collision.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-nonreferenced-identifier-collision.expect.md index a8f2a8dc58..52b21e761d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-nonreferenced-identifier-collision.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-nonreferenced-identifier-collision.expect.md @@ -24,14 +24,14 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; // @gating import { identity, useHook as useRenamed } from "shared-runtime"; const _ = { - useHook: isForgetEnabled_Fixtures() ? () => {} : () => {}, + useHook: _isForgetEnabled_Fixtures() ? () => {} : () => {}, }; identity(_.useHook); -const useHook = isForgetEnabled_Fixtures() +const useHook = _isForgetEnabled_Fixtures() ? function useHook() { const $ = _c(1); useRenamed(); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-preserves-function-properties.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-preserves-function-properties.expect.md index 053fff651e..fd26148149 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-preserves-function-properties.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-preserves-function-properties.expect.md @@ -26,9 +26,9 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; // @gating -const Component = isForgetEnabled_Fixtures() +const Component = _isForgetEnabled_Fixtures() ? function Component() { const $ = _c(1); let t0; @@ -45,7 +45,7 @@ const Component = isForgetEnabled_Fixtures() }; export default Component; -export const Component2 = isForgetEnabled_Fixtures() +export const Component2 = _isForgetEnabled_Fixtures() ? function Component2() { const $ = _c(1); let t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-test-export-default-function.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-test-export-default-function.expect.md index 4e4a35c375..77c099fecd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-test-export-default-function.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-test-export-default-function.expect.md @@ -27,9 +27,9 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; // @gating @compilationMode(annotation) -const Bar = isForgetEnabled_Fixtures() +const Bar = _isForgetEnabled_Fixtures() ? function Bar(props) { "use forget"; const $ = _c(2); @@ -52,7 +52,7 @@ export default Bar; function NoForget(props) { return {props.noForget}; } -const Foo = isForgetEnabled_Fixtures() +const Foo = _isForgetEnabled_Fixtures() ? function Foo(props) { "use forget"; const $ = _c(2); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-test-export-function-and-default.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-test-export-function-and-default.expect.md index 95c629aa11..7bbb5644b5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-test-export-function-and-default.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-test-export-function-and-default.expect.md @@ -34,9 +34,9 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; // @gating @compilationMode(annotation) -const Bar = isForgetEnabled_Fixtures() +const Bar = _isForgetEnabled_Fixtures() ? function Bar(props) { "use forget"; const $ = _c(2); @@ -59,7 +59,7 @@ export default Bar; function NoForget(props) { return {props.noForget}; } -const Foo = isForgetEnabled_Fixtures() +const Foo = _isForgetEnabled_Fixtures() ? function Foo(props) { "use forget"; const $ = _c(3); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-test-export-function.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-test-export-function.expect.md index ab31d2939d..82a6597932 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-test-export-function.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-test-export-function.expect.md @@ -27,9 +27,9 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; // @gating @compilationMode(annotation) -export const Bar = isForgetEnabled_Fixtures() +export const Bar = _isForgetEnabled_Fixtures() ? function Bar(props) { "use forget"; const $ = _c(2); @@ -52,7 +52,7 @@ export function NoForget(props) { return {props.noForget}; } -export const Foo = isForgetEnabled_Fixtures() +export const Foo = _isForgetEnabled_Fixtures() ? function Foo(props) { "use forget"; const $ = _c(2); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-test.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-test.expect.md index e68e4840cf..58aa5113be 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-test.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-test.expect.md @@ -27,9 +27,9 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; // @gating @compilationMode(annotation) -const Bar = isForgetEnabled_Fixtures() +const Bar = _isForgetEnabled_Fixtures() ? function Bar(props) { "use forget"; const $ = _c(2); @@ -51,7 +51,7 @@ const Bar = isForgetEnabled_Fixtures() function NoForget(props) { return {props.noForget}; } -const Foo = isForgetEnabled_Fixtures() +const Foo = _isForgetEnabled_Fixtures() ? function Foo(props) { "use forget"; const $ = _c(2); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-use-before-decl-ref.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-use-before-decl-ref.expect.md index d09c98dffd..c980040f7b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-use-before-decl-ref.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-use-before-decl-ref.expect.md @@ -21,13 +21,13 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; // @gating import { createRef, forwardRef } from "react"; import { Stringify } from "shared-runtime"; const Foo = forwardRef(Foo_withRef); -const _isForgetEnabled_Fixtures_result = isForgetEnabled_Fixtures(); +const _isForgetEnabled_Fixtures_result = _isForgetEnabled_Fixtures(); function _Foo_withRef_optimized(props, ref) { const $ = _c(3); let t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-use-before-decl.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-use-before-decl.expect.md index 0bbfc96756..2da74ea9c7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-use-before-decl.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-use-before-decl.expect.md @@ -22,13 +22,13 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; // @gating import { memo } from "react"; import { Stringify } from "shared-runtime"; export default memo(Foo); -const _isForgetEnabled_Fixtures_result = isForgetEnabled_Fixtures(); +const _isForgetEnabled_Fixtures_result = _isForgetEnabled_Fixtures(); function _Foo_optimized(t0) { "use memo"; const $ = _c(3); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-with-hoisted-type-reference.flow.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-with-hoisted-type-reference.flow.expect.md index 26c6e510d1..7cf86f666c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-with-hoisted-type-reference.flow.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/gating-with-hoisted-type-reference.flow.expect.md @@ -23,12 +23,12 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; import { memo } from "react"; type Props = React.ElementConfig; -const Component = isForgetEnabled_Fixtures() +const Component = _isForgetEnabled_Fixtures() ? function Component(t0) { const $ = _c(2); const { value } = t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/infer-function-expression-React-memo-gating.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/infer-function-expression-React-memo-gating.expect.md index 4931b87b01..7e6c9fc1c9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/infer-function-expression-React-memo-gating.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/infer-function-expression-React-memo-gating.expect.md @@ -13,11 +13,11 @@ export default React.forwardRef(function notNamedLikeAComponent(props) { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; // @gating @compilationMode(infer) import React from "react"; export default React.forwardRef( - isForgetEnabled_Fixtures() + _isForgetEnabled_Fixtures() ? function notNamedLikeAComponent(props) { const $ = _c(1); let t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/invalid-fnexpr-reference.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/invalid-fnexpr-reference.expect.md index 47b58453ca..da046f0d21 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/invalid-fnexpr-reference.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/invalid-fnexpr-reference.expect.md @@ -23,13 +23,13 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; // @gating import * as React from "react"; let Foo; const MemoFoo = React.memo(Foo); -Foo = isForgetEnabled_Fixtures() +Foo = _isForgetEnabled_Fixtures() ? () => { const $ = _c(1); let t0; @@ -48,7 +48,7 @@ Foo = isForgetEnabled_Fixtures() * runtime error message. */ export const FIXTURE_ENTRYPOINT = { - fn: isForgetEnabled_Fixtures() ? () => {} : () => {}, + fn: _isForgetEnabled_Fixtures() ? () => {} : () => {}, params: [], }; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/multi-arrow-expr-export-default-gating-test.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/multi-arrow-expr-export-default-gating-test.expect.md index b3dc5011f9..573d57ee6e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/multi-arrow-expr-export-default-gating-test.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/multi-arrow-expr-export-default-gating-test.expect.md @@ -19,11 +19,11 @@ export default props => ( ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; // @gating import { Stringify } from "shared-runtime"; -const ErrorView = isForgetEnabled_Fixtures() +const ErrorView = _isForgetEnabled_Fixtures() ? (error, _retry) => { const $ = _c(2); let t0; @@ -38,7 +38,7 @@ const ErrorView = isForgetEnabled_Fixtures() } : (error, _retry) => ; -export default isForgetEnabled_Fixtures() +export default _isForgetEnabled_Fixtures() ? (props) => { const $ = _c(1); let t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/multi-arrow-expr-export-gating-test.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/multi-arrow-expr-export-gating-test.expect.md index ea2a1c1541..c6824682ae 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/multi-arrow-expr-export-gating-test.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/multi-arrow-expr-export-gating-test.expect.md @@ -24,11 +24,11 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; // @gating import { Stringify } from "shared-runtime"; -const ErrorView = isForgetEnabled_Fixtures() +const ErrorView = _isForgetEnabled_Fixtures() ? (error, _retry) => { const $ = _c(2); let t0; @@ -43,7 +43,7 @@ const ErrorView = isForgetEnabled_Fixtures() } : (error, _retry) => ; -export const Renderer = isForgetEnabled_Fixtures() +export const Renderer = _isForgetEnabled_Fixtures() ? (props) => { const $ = _c(1); let t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/multi-arrow-expr-gating-test.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/multi-arrow-expr-gating-test.expect.md index cc5195edb2..b56dce9512 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/multi-arrow-expr-gating-test.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/multi-arrow-expr-gating-test.expect.md @@ -26,11 +26,11 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; // @gating import { Stringify } from "shared-runtime"; -const ErrorView = isForgetEnabled_Fixtures() +const ErrorView = _isForgetEnabled_Fixtures() ? (error, _retry) => { const $ = _c(2); let t0; @@ -45,7 +45,7 @@ const ErrorView = isForgetEnabled_Fixtures() } : (error, _retry) => ; -const Renderer = isForgetEnabled_Fixtures() +const Renderer = _isForgetEnabled_Fixtures() ? (props) => { const $ = _c(1); let t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/reassigned-fnexpr-variable.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/reassigned-fnexpr-variable.expect.md index 5f18d98491..e3507f7f6e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/reassigned-fnexpr-variable.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/reassigned-fnexpr-variable.expect.md @@ -31,14 +31,14 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; +import { isForgetEnabled_Fixtures as _isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { c as _c } from "react/compiler-runtime"; // @gating import * as React from "react"; /** * Test that the correct `Foo` is printed */ -let Foo = isForgetEnabled_Fixtures() +let Foo = _isForgetEnabled_Fixtures() ? () => { const $ = _c(1); let t0; @@ -52,7 +52,7 @@ let Foo = isForgetEnabled_Fixtures() } : () =>
hello world 1!
; const MemoOne = React.memo(Foo); -Foo = isForgetEnabled_Fixtures() +Foo = _isForgetEnabled_Fixtures() ? () => { const $ = _c(1); let t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-access-hook-guard.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-access-hook-guard.expect.md new file mode 100644 index 0000000000..8a5f7c2af3 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-access-hook-guard.expect.md @@ -0,0 +1,66 @@ + +## Input + +```javascript +// @lowerContextAccess @enableEmitHookGuards +function App() { + const {foo} = useContext(MyContext); + const {bar} = useContext(MyContext); + return ; +} + +``` + +## Code + +```javascript +import { + useContext_withSelector as _useContext_withSelector, + $dispatcherGuard as _$dispatcherGuard, +} from "react-compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @lowerContextAccess @enableEmitHookGuards +function App() { + const $ = _c(3); + try { + _$dispatcherGuard(0); + const { foo } = (function () { + try { + _$dispatcherGuard(2); + return _useContext_withSelector(MyContext, _temp); + } finally { + _$dispatcherGuard(3); + } + })(); + const { bar } = (function () { + try { + _$dispatcherGuard(2); + return _useContext_withSelector(MyContext, _temp2); + } finally { + _$dispatcherGuard(3); + } + })(); + let t0; + if ($[0] !== bar || $[1] !== foo) { + t0 = ; + $[0] = bar; + $[1] = foo; + $[2] = t0; + } else { + t0 = $[2]; + } + return t0; + } finally { + _$dispatcherGuard(1); + } +} +function _temp2(t0) { + return [t0.bar]; +} +function _temp(t0) { + return [t0.foo]; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-access-hook-guard.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-access-hook-guard.js new file mode 100644 index 0000000000..da881ea124 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-access-hook-guard.js @@ -0,0 +1,6 @@ +// @lowerContextAccess @enableEmitHookGuards +function App() { + const {foo} = useContext(MyContext); + const {bar} = useContext(MyContext); + return ; +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-acess-multiple.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-acess-multiple.expect.md index af9b1df36a..78f63cce99 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-acess-multiple.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-acess-multiple.expect.md @@ -14,12 +14,12 @@ function App() { ## Code ```javascript -import { useContext_withSelector } from "react-compiler-runtime"; +import { useContext_withSelector as _useContext_withSelector } from "react-compiler-runtime"; import { c as _c } from "react/compiler-runtime"; // @lowerContextAccess function App() { const $ = _c(3); - const { foo } = useContext_withSelector(MyContext, _temp); - const { bar } = useContext_withSelector(MyContext, _temp2); + const { foo } = _useContext_withSelector(MyContext, _temp); + const { bar } = _useContext_withSelector(MyContext, _temp2); let t0; if ($[0] !== bar || $[1] !== foo) { t0 = ; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-selector-simple.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-selector-simple.expect.md index d13682467b..c087f6f25e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-selector-simple.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-selector-simple.expect.md @@ -13,11 +13,11 @@ function App() { ## Code ```javascript -import { useContext_withSelector } from "react-compiler-runtime"; +import { useContext_withSelector as _useContext_withSelector } from "react-compiler-runtime"; import { c as _c } from "react/compiler-runtime"; // @lowerContextAccess function App() { const $ = _c(3); - const { foo, bar } = useContext_withSelector(MyContext, _temp); + const { foo, bar } = _useContext_withSelector(MyContext, _temp); let t0; if ($[0] !== bar || $[1] !== foo) { t0 = ; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-capitalized-fn-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-capitalized-fn-call.expect.md index 77bdd31275..6537b31df3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-capitalized-fn-call.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-capitalized-fn-call.expect.md @@ -24,7 +24,7 @@ function Component({prop1, bar}) { ## Code ```javascript -import { useFire } from "react/compiler-runtime"; // @validateNoCapitalizedCalls @enableFire @panicThreshold(none) +import { useFire as _useFire } from "react/compiler-runtime"; // @validateNoCapitalizedCalls @enableFire @panicThreshold(none) import { fire } from "react"; const CapitalizedCall = require("shared-runtime").sum; @@ -33,8 +33,8 @@ function Component(t0) { const foo = () => { console.log(prop1); }; - const t1 = useFire(foo); - const t2 = useFire(bar); + const t1 = _useFire(foo); + const t2 = _useFire(bar); useEffect(() => { t1(prop1); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-eslint-suppressions.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-eslint-suppressions.expect.md index 30bd6d42e5..0f9258b9dd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-eslint-suppressions.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-eslint-suppressions.expect.md @@ -26,7 +26,7 @@ function Component({props, bar}) { ## Code ```javascript -import { useFire } from "react/compiler-runtime"; // @enableFire @panicThreshold(none) +import { useFire as _useFire } from "react/compiler-runtime"; // @enableFire @panicThreshold(none) import { useRef } from "react"; function Component(t0) { @@ -34,8 +34,8 @@ function Component(t0) { const foo = () => { console.log(props); }; - const t1 = useFire(foo); - const t2 = useFire(bar); + const t1 = _useFire(foo); + const t2 = _useFire(bar); useEffect(() => { t1(props); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-preserve-memo.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-preserve-memo.expect.md index 6477a01126..a4c6552bce 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-preserve-memo.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-preserve-memo.expect.md @@ -24,7 +24,7 @@ function Component({prop1, bar}) { ## Code ```javascript -import { useFire } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees @enableFire @panicThreshold(none) +import { useFire as _useFire } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees @enableFire @panicThreshold(none) import { fire } from "react"; import { sum } from "shared-runtime"; @@ -33,8 +33,8 @@ function Component(t0) { const foo = () => { console.log(prop1); }; - const t1 = useFire(foo); - const t2 = useFire(bar); + const t1 = _useFire(foo); + const t2 = _useFire(bar); useEffect(() => { t1(prop1); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-prop-write.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-prop-write.expect.md index e6ce051f10..d7b9054631 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-prop-write.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-prop-write.expect.md @@ -20,7 +20,7 @@ function Component({prop1}) { ## Code ```javascript -import { useFire } from "react/compiler-runtime"; // @enableFire @panicThreshold(none) +import { useFire as _useFire } from "react/compiler-runtime"; // @enableFire @panicThreshold(none) import { fire } from "react"; function Component(t0) { @@ -28,7 +28,7 @@ function Component(t0) { const foo = () => { console.log(prop1); }; - const t1 = useFire(foo); + const t1 = _useFire(foo); useEffect(() => { t1(prop1); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-ref-current-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-ref-current-access.expect.md index 79f5a2986d..f8b1295a40 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-ref-current-access.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/bailout-validate-ref-current-access.expect.md @@ -25,7 +25,7 @@ component Component(prop1, ref) { ## Code ```javascript -import { useFire } from "react/compiler-runtime"; +import { useFire as _useFire } from "react/compiler-runtime"; import { fire } from "react"; import { print } from "shared-runtime"; @@ -35,7 +35,7 @@ function Component_withRef(t0, ref) { const foo = () => { console.log(prop1); }; - const t1 = useFire(foo); + const t1 = _useFire(foo); useEffect(() => { t1(prop1); bar(); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/no-fire-todo-syntax-shouldnt-throw.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/no-fire-todo-syntax-shouldnt-throw.expect.md index fecc28bb00..6b767c2a66 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/no-fire-todo-syntax-shouldnt-throw.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/no-fire-todo-syntax-shouldnt-throw.expect.md @@ -43,7 +43,7 @@ function FireComponent(props) { ## Code ```javascript -import { useFire } from "react/compiler-runtime"; +import { useFire as _useFire } from "react/compiler-runtime"; import { c as _c } from "react/compiler-runtime"; // @enableFire @panicThreshold(none) import { fire } from "react"; @@ -70,7 +70,7 @@ function FireComponent(props) { const $ = _c(3); const foo = _temp; - const t0 = useFire(foo); + const t0 = _useFire(foo); let t1; if ($[0] !== props || $[1] !== t0) { t1 = () => { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-validate-conditional-hook.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-validate-conditional-hook.expect.md index dde2b692f4..f88a1730c9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-validate-conditional-hook.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-validate-conditional-hook.expect.md @@ -29,7 +29,7 @@ function Component(props) { ## Code ```javascript -import { useFire } from "react/compiler-runtime"; // @enableFire @panicThreshold(none) +import { useFire as _useFire } from "react/compiler-runtime"; // @enableFire @panicThreshold(none) import { fire, useEffect } from "react"; import { Stringify } from "shared-runtime"; @@ -40,7 +40,7 @@ import { Stringify } from "shared-runtime"; function Component(props) { const foo = _temp; if (props.cond) { - const t0 = useFire(foo); + const t0 = _useFire(foo); useEffect(() => { t0(props); }); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/basic.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/basic.expect.md index 8d8bc179a2..3ecbb60fb6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/basic.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/basic.expect.md @@ -21,14 +21,14 @@ function Component(props) { ## Code ```javascript -import { useFire } from "react/compiler-runtime"; +import { useFire as _useFire } from "react/compiler-runtime"; import { c as _c } from "react/compiler-runtime"; // @enableFire import { fire } from "react"; function Component(props) { const $ = _c(3); const foo = _temp; - const t0 = useFire(foo); + const t0 = _useFire(foo); let t1; if ($[0] !== props || $[1] !== t0) { t1 = () => { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/deep-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/deep-scope.expect.md index a335fea886..bfd9d5e141 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/deep-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/deep-scope.expect.md @@ -30,14 +30,14 @@ function Component(props) { ## Code ```javascript -import { useFire } from "react/compiler-runtime"; +import { useFire as _useFire } from "react/compiler-runtime"; import { c as _c } from "react/compiler-runtime"; // @enableFire import { fire } from "react"; function Component(props) { const $ = _c(3); const foo = _temp; - const t0 = useFire(foo); + const t0 = _useFire(foo); let t1; if ($[0] !== props || $[1] !== t0) { t1 = () => { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/fire-and-autodeps.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/fire-and-autodeps.expect.md index 5767ff0746..6c8ba78f8c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/fire-and-autodeps.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/fire-and-autodeps.expect.md @@ -21,7 +21,7 @@ function Component(props) { ## Code ```javascript -import { useFire } from "react/compiler-runtime"; +import { useFire as _useFire } from "react/compiler-runtime"; import { c as _c } from "react/compiler-runtime"; // @enableFire @inferEffectDependencies import { fire, useEffect } from "react"; @@ -38,7 +38,7 @@ function Component(props) { t0 = $[1]; } const foo = t0; - const t1 = useFire(foo); + const t1 = _useFire(foo); let t2; if ($[2] !== props || $[3] !== t1) { t2 = () => { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/hook-guard.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/hook-guard.expect.md new file mode 100644 index 0000000000..925f4c95b9 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/hook-guard.expect.md @@ -0,0 +1,73 @@ + +## Input + +```javascript +// @enableFire @enableEmitHookGuards +import {fire} from 'react'; + +function Component(props) { + const foo = props => { + console.log(props); + }; + useEffect(() => { + fire(foo(props)); + }); + + return null; +} + +``` + +## Code + +```javascript +import { $dispatcherGuard as _$dispatcherGuard } from "react-compiler-runtime"; +import { useFire as _useFire } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enableFire @enableEmitHookGuards +import { fire } from "react"; + +function Component(props) { + const $ = _c(3); + try { + _$dispatcherGuard(0); + const foo = _temp; + const t0 = (function () { + try { + _$dispatcherGuard(2); + return _useFire(foo); + } finally { + _$dispatcherGuard(3); + } + })(); + let t1; + if ($[0] !== props || $[1] !== t0) { + t1 = () => { + t0(props); + }; + $[0] = props; + $[1] = t0; + $[2] = t1; + } else { + t1 = $[2]; + } + (function () { + try { + _$dispatcherGuard(2); + return useEffect(t1); + } finally { + _$dispatcherGuard(3); + } + })(); + return null; + } finally { + _$dispatcherGuard(1); + } +} +function _temp(props_0) { + console.log(props_0); +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/hook-guard.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/hook-guard.js new file mode 100644 index 0000000000..bc0b1a2d7c --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/hook-guard.js @@ -0,0 +1,13 @@ +// @enableFire @enableEmitHookGuards +import {fire} from 'react'; + +function Component(props) { + const foo = props => { + console.log(props); + }; + useEffect(() => { + fire(foo(props)); + }); + + return null; +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/multiple-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/multiple-scope.expect.md index 02f3935171..d247b0fe2b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/multiple-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/multiple-scope.expect.md @@ -29,14 +29,14 @@ function Component(props) { ## Code ```javascript -import { useFire } from "react/compiler-runtime"; +import { useFire as _useFire } from "react/compiler-runtime"; import { c as _c } from "react/compiler-runtime"; // @enableFire import { fire } from "react"; function Component(props) { const $ = _c(3); const foo = _temp; - const t0 = useFire(foo); + const t0 = _useFire(foo); let t1; if ($[0] !== props || $[1] !== t0) { t1 = () => { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/repeated-calls.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/repeated-calls.expect.md index 1734ca3ab4..30f5e52c36 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/repeated-calls.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/repeated-calls.expect.md @@ -22,7 +22,7 @@ function Component(props) { ## Code ```javascript -import { useFire } from "react/compiler-runtime"; +import { useFire as _useFire } from "react/compiler-runtime"; import { c as _c } from "react/compiler-runtime"; // @enableFire import { fire } from "react"; @@ -39,7 +39,7 @@ function Component(props) { t0 = $[1]; } const foo = t0; - const t1 = useFire(foo); + const t1 = _useFire(foo); let t2; if ($[2] !== props || $[3] !== t1) { t2 = () => { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/rewrite-deps.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/rewrite-deps.expect.md index ae71f60393..b921d57970 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/rewrite-deps.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/rewrite-deps.expect.md @@ -21,14 +21,14 @@ function Component(props) { ## Code ```javascript -import { useFire } from "react/compiler-runtime"; +import { useFire as _useFire } from "react/compiler-runtime"; import { c as _c } from "react/compiler-runtime"; // @enableFire import { fire } from "react"; function Component(props) { const $ = _c(4); const foo = _temp; - const t0 = useFire(foo); + const t0 = _useFire(foo); let t1; let t2; if ($[0] !== props || $[1] !== t0) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/shared-hook-calls.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/shared-hook-calls.expect.md index 9b689b31c7..3e60f1cb7c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/shared-hook-calls.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/shared-hook-calls.expect.md @@ -26,7 +26,7 @@ function Component({bar, baz}) { ## Code ```javascript -import { useFire } from "react/compiler-runtime"; +import { useFire as _useFire } from "react/compiler-runtime"; import { c as _c } from "react/compiler-runtime"; // @enableFire import { fire } from "react"; @@ -44,8 +44,8 @@ function Component(t0) { t1 = $[1]; } const foo = t1; - const t2 = useFire(foo); - const t3 = useFire(baz); + const t2 = _useFire(foo); + const t3 = _useFire(baz); let t4; if ($[2] !== bar || $[3] !== t2 || $[4] !== t3) { t4 = () => { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-and-other-hook-unpruned-dependency.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-and-other-hook-unpruned-dependency.expect.md index 27dcf877e0..dad467deaa 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-and-other-hook-unpruned-dependency.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-and-other-hook-unpruned-dependency.expect.md @@ -30,7 +30,7 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { $structuralCheck } from "react-compiler-runtime"; +import { $structuralCheck as _$structuralCheck } from "react-compiler-runtime"; import { c as _c } from "react/compiler-runtime"; import { useState } from "react"; // @enableChangeDetectionForDebugging @@ -46,13 +46,13 @@ function Component(props) { let condition = $[0] !== props.x; if (!condition) { let old$t0 = $[1]; - $structuralCheck(old$t0, t0, "t0", "Component", "cached", "(8:8)"); + _$structuralCheck(old$t0, t0, "t0", "Component", "cached", "(8:8)"); } $[0] = props.x; $[1] = t0; if (condition) { t0 = f(props.x); - $structuralCheck($[1], t0, "t0", "Component", "recomputed", "(8:8)"); + _$structuralCheck($[1], t0, "t0", "Component", "recomputed", "(8:8)"); t0 = $[1]; } } @@ -65,13 +65,13 @@ function Component(props) { let condition = $[2] !== x; if (!condition) { let old$t1 = $[3]; - $structuralCheck(old$t1, t1, "t1", "Component", "cached", "(11:11)"); + _$structuralCheck(old$t1, t1, "t1", "Component", "cached", "(11:11)"); } $[2] = x; $[3] = t1; if (condition) { t1 =
{x}
; - $structuralCheck($[3], t1, "t1", "Component", "recomputed", "(11:11)"); + _$structuralCheck($[3], t1, "t1", "Component", "recomputed", "(11:11)"); t1 = $[3]; } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-pruned-dependency-change-detect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-pruned-dependency-change-detect.expect.md index 99abce5122..ab6e8b5f1c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-pruned-dependency-change-detect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-pruned-dependency-change-detect.expect.md @@ -15,7 +15,7 @@ function Component(props) { ## Code ```javascript -import { $structuralCheck } from "react-compiler-runtime"; +import { $structuralCheck as _$structuralCheck } from "react-compiler-runtime"; import { c as _c } from "react/compiler-runtime"; // @enableChangeDetectionForDebugging import { useState } from "react"; @@ -35,13 +35,13 @@ function Component(props) { let condition = $[1] !== x; if (!condition) { let old$t1 = $[2]; - $structuralCheck(old$t1, t1, "t1", "Component", "cached", "(6:6)"); + _$structuralCheck(old$t1, t1, "t1", "Component", "cached", "(6:6)"); } $[1] = x; $[2] = t1; if (condition) { t1 =
{x}
; - $structuralCheck($[2], t1, "t1", "Component", "recomputed", "(6:6)"); + _$structuralCheck($[2], t1, "t1", "Component", "recomputed", "(6:6)"); t1 = $[2]; } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-unpruned-dependency.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-unpruned-dependency.expect.md index 28d3e33359..6f8bf2a09f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-unpruned-dependency.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-unpruned-dependency.expect.md @@ -30,7 +30,7 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { $structuralCheck } from "react-compiler-runtime"; +import { $structuralCheck as _$structuralCheck } from "react-compiler-runtime"; import { c as _c } from "react/compiler-runtime"; import { useState } from "react"; // @enableChangeDetectionForDebugging @@ -42,13 +42,13 @@ function Component(props) { let condition = $[0] !== props.x; if (!condition) { let old$t0 = $[1]; - $structuralCheck(old$t0, t0, "t0", "Component", "cached", "(4:4)"); + _$structuralCheck(old$t0, t0, "t0", "Component", "cached", "(4:4)"); } $[0] = props.x; $[1] = t0; if (condition) { t0 = f(props.x); - $structuralCheck($[1], t0, "t0", "Component", "recomputed", "(4:4)"); + _$structuralCheck($[1], t0, "t0", "Component", "recomputed", "(4:4)"); t0 = $[1]; } } @@ -65,7 +65,7 @@ function Component(props) { let condition = $[2] !== w || $[3] !== x; if (!condition) { let old$t1 = $[4]; - $structuralCheck(old$t1, t1, "t1", "Component", "cached", "(7:10)"); + _$structuralCheck(old$t1, t1, "t1", "Component", "cached", "(7:10)"); } $[2] = w; $[3] = x; @@ -77,7 +77,7 @@ function Component(props) { {w} ); - $structuralCheck($[4], t1, "t1", "Component", "recomputed", "(7:10)"); + _$structuralCheck($[4], t1, "t1", "Component", "recomputed", "(7:10)"); t1 = $[4]; } }