[compiler][be] Clean up compilation skipping logic in Program

ghstack-source-id: fe2c81de9d4f41a787c690b722cbcff55eb18ac3
Pull Request resolved: https://github.com/facebook/react/pull/30642
This commit is contained in:
Mofei Zhang
2024-08-08 15:41:38 -07:00
parent 0fb03c4952
commit 3871fdadaa

View File

@@ -13,6 +13,7 @@ import {
ErrorSeverity,
} from '../CompilerError';
import {
EnvironmentConfig,
ExternalFunction,
ReactFunctionType,
parseEnvironmentConfig,
@@ -276,41 +277,27 @@ export function compileProgram(
program: NodePath<t.Program>,
pass: CompilerPass,
): void {
if (pass.opts.sources) {
if (pass.filename === null) {
const error = new CompilerError();
error.pushErrorDetail(
new CompilerErrorDetail({
reason: `Expected a filename but found none.`,
description:
"When the 'sources' config options is specified, the React compiler will only compile files with a name",
severity: ErrorSeverity.InvalidConfig,
loc: null,
}),
);
handleError(error, pass, null);
return;
}
if (!isFilePartOfSources(pass.opts.sources, pass.filename)) {
return;
}
}
// Top level "use no forget", skip this file entirely
if (
findDirectiveDisablingMemoization(program.node.directives, pass.opts) !=
null
) {
if (shouldSkipCompilation(program, pass)) {
return;
}
const environment = parseEnvironmentConfig(pass.opts.environment ?? {});
/*
* TODO(lauren): Remove pass.opts.environment nullcheck once PluginOptions
* is validated
*/
const environmentResult = parseEnvironmentConfig(pass.opts.environment ?? {});
if (environmentResult.isErr()) {
CompilerError.throwInvalidConfig({
reason:
'Error in validating environment config. This is an advanced setting and not meant to be used directly',
description: environmentResult.unwrapErr().toString(),
suggestions: null,
loc: null,
});
}
const environment = environmentResult.unwrap();
const useMemoCacheIdentifier = program.scope.generateUidIdentifier('c');
const moduleName = pass.opts.runtimeModule ?? 'react/compiler-runtime';
if (hasMemoCacheFunctionImport(program, moduleName)) {
return;
}
/*
* Record lint errors and critical errors as depending on Forget's config,
@@ -332,7 +319,7 @@ export function compileProgram(
const compiledFns: Array<CompileResult> = [];
const traverseFunction = (fn: BabelFn, pass: CompilerPass): void => {
const fnType = getReactFunctionType(fn, pass);
const fnType = getReactFunctionType(fn, pass, environment);
if (fnType === null || ALREADY_COMPILED.has(fn.node)) {
return;
}
@@ -403,24 +390,9 @@ export function compileProgram(
let compiledFn: CodegenFunction;
try {
/*
* TODO(lauren): Remove pass.opts.environment nullcheck once PluginOptions
* is validated
*/
if (environment.isErr()) {
CompilerError.throwInvalidConfig({
reason:
'Error in validating environment config. This is an advanced setting and not meant to be used directly',
description: environment.unwrapErr().toString(),
suggestions: null,
loc: null,
});
}
const config = environment.unwrap();
compiledFn = compileFn(
fn,
config,
environment,
fnType,
useMemoCacheIdentifier.name,
pass.opts.logger,
@@ -514,43 +486,29 @@ export function compileProgram(
externalFunctions.push(gating);
}
const lowerContextAccess = pass.opts.environment?.lowerContextAccess;
const lowerContextAccess = environment.lowerContextAccess;
if (lowerContextAccess && hasLoweredContextAccess) {
externalFunctions.push(tryParseExternalFunction(lowerContextAccess));
externalFunctions.push(lowerContextAccess);
}
const enableEmitInstrumentForget =
pass.opts.environment?.enableEmitInstrumentForget;
const enableEmitInstrumentForget = environment.enableEmitInstrumentForget;
if (enableEmitInstrumentForget != null) {
externalFunctions.push(
tryParseExternalFunction(enableEmitInstrumentForget.fn),
);
externalFunctions.push(enableEmitInstrumentForget.fn);
if (enableEmitInstrumentForget.gating != null) {
externalFunctions.push(
tryParseExternalFunction(enableEmitInstrumentForget.gating),
);
externalFunctions.push(enableEmitInstrumentForget.gating);
}
}
if (pass.opts.environment?.enableEmitFreeze != null) {
const enableEmitFreeze = tryParseExternalFunction(
pass.opts.environment.enableEmitFreeze,
);
externalFunctions.push(enableEmitFreeze);
if (environment.enableEmitFreeze != null) {
externalFunctions.push(environment.enableEmitFreeze);
}
if (pass.opts.environment?.enableEmitHookGuards != null) {
const enableEmitHookGuards = tryParseExternalFunction(
pass.opts.environment.enableEmitHookGuards,
);
externalFunctions.push(enableEmitHookGuards);
if (environment.enableEmitHookGuards != null) {
externalFunctions.push(environment.enableEmitHookGuards);
}
if (pass.opts.environment?.enableChangeDetectionForDebugging != null) {
const enableChangeDetectionForDebugging = tryParseExternalFunction(
pass.opts.environment.enableChangeDetectionForDebugging,
);
externalFunctions.push(enableChangeDetectionForDebugging);
if (environment.enableChangeDetectionForDebugging != null) {
externalFunctions.push(environment.enableChangeDetectionForDebugging);
}
} catch (err) {
handleError(err, pass, null);
@@ -593,11 +551,65 @@ export function compileProgram(
}
}
function shouldSkipCompilation(
program: NodePath<t.Program>,
pass: CompilerPass,
): boolean {
if (pass.opts.sources) {
if (pass.filename === null) {
const error = new CompilerError();
error.pushErrorDetail(
new CompilerErrorDetail({
reason: `Expected a filename but found none.`,
description:
"When the 'sources' config options is specified, the React compiler will only compile files with a name",
severity: ErrorSeverity.InvalidConfig,
loc: null,
}),
);
handleError(error, pass, null);
return true;
}
if (!isFilePartOfSources(pass.opts.sources, pass.filename)) {
return true;
}
}
// Top level "use no forget", skip this file entirely
const useNoForget = findDirectiveDisablingMemoization(
program.node.directives,
pass.opts,
);
if (useNoForget != null) {
pass.opts.logger?.logEvent(pass.filename, {
kind: 'CompileError',
fnLoc: null,
detail: {
severity: ErrorSeverity.Todo,
reason: 'Skipped due to "use no forget" directive.',
loc: useNoForget.loc ?? null,
suggestions: null,
},
});
return true;
}
const moduleName = pass.opts.runtimeModule ?? 'react/compiler-runtime';
if (hasMemoCacheFunctionImport(program, moduleName)) {
return true;
}
return false;
}
function getReactFunctionType(
fn: BabelFn,
pass: CompilerPass,
/**
* TODO(mofeiZ): remove once we validate PluginOptions with Zod
*/
environment: EnvironmentConfig,
): ReactFunctionType | null {
const hookPattern = pass.opts.environment?.hookPattern ?? null;
const hookPattern = environment.hookPattern;
if (fn.node.body.type === 'BlockStatement') {
// Opt-outs disable compilation regardless of mode
const useNoForget = findDirectiveDisablingMemoization(