[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
}
```
This commit is contained in:
Mofei Zhang
2025-03-18 17:32:37 -04:00
parent 86d5ac0882
commit 508dd4c2fc
66 changed files with 875 additions and 271 deletions
@@ -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,
@@ -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<t.FunctionDeclaration>,
compiled: t.FunctionDeclaration,
gating: NonNullable<PluginOptions['gating']>,
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<PluginOptions['gating']>,
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),
);
@@ -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<t.Program>,
@@ -44,45 +45,36 @@ export function validateRestrictedImports(
export function addImportsToProgram(
path: NodePath<t.Program>,
importList: Array<ExternalFunction>,
importList: Array<ImportedExternalFunction>,
): void {
const identifiers: Set<string> = new Set();
const sortedImports: Map<string, Array<string>> = new Map();
for (const {importSpecifierName, source} of importList) {
/*
* Codegen currently does not rename import specifiers, so we do additional
* validation here
const sortedImports: Map<string, Array<ImportedExternalFunction>> = 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<t.ImportDeclaration> = [];
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)));
@@ -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,
@@ -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<t.Program>,
options: PluginOptions,
): Result<
{
importedIdentifierNames: ImportedUids;
importedFunctions: Array<ImportedExternalFunction>;
},
CompilerError
> {
const environment = options.environment;
const importedFunctions: Array<ImportedExternalFunction> = [];
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<CompileResult>;
} = 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<ExternalFunction> = [];
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') {
@@ -84,6 +84,8 @@ export const InstrumentationSchema = z
);
export type ExternalFunction = z.infer<typeof ExternalFunctionSchema>;
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;
@@ -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<IdentifierId, CallExpression> = new Map();
const contextKeys: Map<IdentifierId, Array<string>> = 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,
};
@@ -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<t.Statement> = [];
const changeDetectionStatements: Array<t.Statement> = [];
const idempotenceDetectionStatements: Array<t.Statement> = [];
@@ -1513,16 +1514,14 @@ const createJsxOpeningElement = withLoc(t.jsxOpeningElement);
const createStringLiteral = withLoc(t.stringLiteral);
function createHookGuard(
guard: ExternalFunction,
guardFnName: string,
stmts: Array<t.Statement>,
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<t.Expression | t.SpreadElement>,
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,
@@ -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,
};
@@ -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];
}
}
@@ -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];
}
@@ -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];
}
@@ -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) {
@@ -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 (
<div style={shouldInstrument} other={_shouldInstrument}>
{props.bar}
</div>
);
}
function Foo(props) {
'use forget';
return <Foo>{props.bar}</Foo>;
}
```
## 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 = (
<div style={shouldInstrument} other={_shouldInstrument}>
{props.bar}
</div>
);
$[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 = <Foo>{props.bar}</Foo>;
$[0] = props.bar;
$[1] = t0;
} else {
t0 = $[1];
}
return t0;
}
```
### Eval output
(kind: exception) Fixture not implemented
@@ -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 (
<div style={shouldInstrument} other={_shouldInstrument}>
{props.bar}
</div>
);
}
function Foo(props) {
'use forget';
return <Foo>{props.bar}</Foo>;
}
@@ -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
@@ -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
@@ -0,0 +1,4 @@
// @enableEmitFreeze @instrumentForget
function useFoo(props) {
return foo(props.x, __DEV__);
}
@@ -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]
```
@@ -0,0 +1,6 @@
// @enableEmitFreeze @instrumentForget
function useFoo(props) {
const __DEV__ = 'conflicting global';
console.log(__DEV__);
return foo(props.x);
}
@@ -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);
}
}
@@ -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;
@@ -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 <Bar>{props.noForget}</Bar>;
}
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;
@@ -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;
@@ -0,0 +1,62 @@
## Input
```javascript
// @gating
export const isForgetEnabled_Fixtures = () => {
'use no forget';
return false;
};
export function Bar(props) {
'use forget';
return <div>{props.bar}</div>;
}
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 = <div>{props.bar}</div>;
$[0] = props.bar;
$[1] = t0;
} else {
t0 = $[1];
}
return t0;
}
: function Bar(props) {
"use forget";
return <div>{props.bar}</div>;
};
export const FIXTURE_ENTRYPOINT = {
fn: eval("Bar"),
params: [{ bar: 2 }],
};
```
### Eval output
(kind: ok) <div>2</div>
@@ -0,0 +1,16 @@
// @gating
export const isForgetEnabled_Fixtures = () => {
'use no forget';
return false;
};
export function Bar(props) {
'use forget';
return <div>{props.bar}</div>;
}
export const FIXTURE_ENTRYPOINT = {
fn: eval('Bar'),
params: [{bar: 2}],
};
@@ -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;
@@ -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();
@@ -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;
@@ -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 <Bar>{props.noForget}</Bar>;
}
const Foo = isForgetEnabled_Fixtures()
const Foo = _isForgetEnabled_Fixtures()
? function Foo(props) {
"use forget";
const $ = _c(2);
@@ -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 <Bar>{props.noForget}</Bar>;
}
const Foo = isForgetEnabled_Fixtures()
const Foo = _isForgetEnabled_Fixtures()
? function Foo(props) {
"use forget";
const $ = _c(3);
@@ -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 <Bar>{props.noForget}</Bar>;
}
export const Foo = isForgetEnabled_Fixtures()
export const Foo = _isForgetEnabled_Fixtures()
? function Foo(props) {
"use forget";
const $ = _c(2);
@@ -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 <Bar>{props.noForget}</Bar>;
}
const Foo = isForgetEnabled_Fixtures()
const Foo = _isForgetEnabled_Fixtures()
? function Foo(props) {
"use forget";
const $ = _c(2);
@@ -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;
@@ -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);
@@ -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<typeof Component>;
const Component = isForgetEnabled_Fixtures()
const Component = _isForgetEnabled_Fixtures()
? function Component(t0) {
const $ = _c(2);
const { value } = t0;
@@ -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;
@@ -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: [],
};
@@ -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) => <Stringify error={error}></Stringify>;
export default isForgetEnabled_Fixtures()
export default _isForgetEnabled_Fixtures()
? (props) => {
const $ = _c(1);
let t0;
@@ -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) => <Stringify error={error}></Stringify>;
export const Renderer = isForgetEnabled_Fixtures()
export const Renderer = _isForgetEnabled_Fixtures()
? (props) => {
const $ = _c(1);
let t0;
@@ -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) => <Stringify error={error}></Stringify>;
const Renderer = isForgetEnabled_Fixtures()
const Renderer = _isForgetEnabled_Fixtures()
? (props) => {
const $ = _c(1);
let t0;
@@ -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()
}
: () => <div>hello world 1!</div>;
const MemoOne = React.memo(Foo);
Foo = isForgetEnabled_Fixtures()
Foo = _isForgetEnabled_Fixtures()
? () => {
const $ = _c(1);
let t0;
@@ -0,0 +1,66 @@
## Input
```javascript
// @lowerContextAccess @enableEmitHookGuards
function App() {
const {foo} = useContext(MyContext);
const {bar} = useContext(MyContext);
return <Bar foo={foo} bar={bar} />;
}
```
## 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 = <Bar foo={foo} bar={bar} />;
$[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
@@ -0,0 +1,6 @@
// @lowerContextAccess @enableEmitHookGuards
function App() {
const {foo} = useContext(MyContext);
const {bar} = useContext(MyContext);
return <Bar foo={foo} bar={bar} />;
}
@@ -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 = <Bar foo={foo} bar={bar} />;
@@ -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 = <Bar foo={foo} bar={bar} />;
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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();
@@ -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 = () => {
@@ -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);
});
@@ -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 = () => {
@@ -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 = () => {
@@ -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 = () => {
@@ -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
@@ -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;
}
@@ -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 = () => {
@@ -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 = () => {
@@ -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) {
@@ -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 = () => {
@@ -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 = <div>{x}</div>;
$structuralCheck($[3], t1, "t1", "Component", "recomputed", "(11:11)");
_$structuralCheck($[3], t1, "t1", "Component", "recomputed", "(11:11)");
t1 = $[3];
}
}
@@ -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 = <div>{x}</div>;
$structuralCheck($[2], t1, "t1", "Component", "recomputed", "(6:6)");
_$structuralCheck($[2], t1, "t1", "Component", "recomputed", "(6:6)");
t1 = $[2];
}
}
@@ -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}
</div>
);
$structuralCheck($[4], t1, "t1", "Component", "recomputed", "(7:10)");
_$structuralCheck($[4], t1, "t1", "Component", "recomputed", "(7:10)");
t1 = $[4];
}
}