[compiler][be] Clean up compilation skipping logic in Program
ghstack-source-id: fe2c81de9d4f41a787c690b722cbcff55eb18ac3 Pull Request resolved: https://github.com/facebook/react/pull/30642
Mofei Zhang committed
Aug 8, 2024 at 15:41 UTC
3871fdadaa6ff98ba3039c3976e8aac6038f69a9
1 file changed
+85
-73
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts
+85
-73
@@ -13,6 +13,7 @@ import {
13
ErrorSeverity,
14
} from '../CompilerError';
15
import {
16
+ EnvironmentConfig,
17
ExternalFunction,
18
ReactFunctionType,
19
parseEnvironmentConfig,
@@ -276,41 +277,27 @@ export function compileProgram(
277
program: NodePath<t.Program>,
278
pass: CompilerPass,
279
): void {
279
- if (pass.opts.sources) {
280
- if (pass.filename === null) {
281
- const error = new CompilerError();
282
- error.pushErrorDetail(
283
- new CompilerErrorDetail({
284
- reason: `Expected a filename but found none.`,
285
- description:
286
- "When the 'sources' config options is specified, the React compiler will only compile files with a name",
287
- severity: ErrorSeverity.InvalidConfig,
288
- loc: null,
289
- }),
290
- );
291
- handleError(error, pass, null);
292
- return;
293
- }
294
-
295
- if (!isFilePartOfSources(pass.opts.sources, pass.filename)) {
296
- return;
297
- }
298
- }
299
-
300
- // Top level "use no forget", skip this file entirely
301
- if (
302
- findDirectiveDisablingMemoization(program.node.directives, pass.opts) !=
303
- null
304
- ) {
280
+ if (shouldSkipCompilation(program, pass)) {
281
return;
282
}
283
308
- const environment = parseEnvironmentConfig(pass.opts.environment ?? {});
284
+ /*
285
+ * TODO(lauren): Remove pass.opts.environment nullcheck once PluginOptions
286
+ * is validated
287
+ */
288
+ const environmentResult = parseEnvironmentConfig(pass.opts.environment ?? {});
289
+ if (environmentResult.isErr()) {
290
+ CompilerError.throwInvalidConfig({
291
+ reason:
292
+ 'Error in validating environment config. This is an advanced setting and not meant to be used directly',
293
+ description: environmentResult.unwrapErr().toString(),
294
+ suggestions: null,
295
+ loc: null,
296
+ });
297
+ }
298
+ const environment = environmentResult.unwrap();
299
const useMemoCacheIdentifier = program.scope.generateUidIdentifier('c');
300
const moduleName = pass.opts.runtimeModule ?? 'react/compiler-runtime';
311
- if (hasMemoCacheFunctionImport(program, moduleName)) {
312
- return;
313
- }
301
302
/*
303
* Record lint errors and critical errors as depending on Forget's config,
@@ -332,7 +319,7 @@ export function compileProgram(
319
const compiledFns: Array<CompileResult> = [];
320
321
const traverseFunction = (fn: BabelFn, pass: CompilerPass): void => {
335
- const fnType = getReactFunctionType(fn, pass);
322
+ const fnType = getReactFunctionType(fn, pass, environment);
323
if (fnType === null || ALREADY_COMPILED.has(fn.node)) {
324
return;
325
}
@@ -403,24 +390,9 @@ export function compileProgram(
390
391
let compiledFn: CodegenFunction;
392
try {
406
- /*
407
- * TODO(lauren): Remove pass.opts.environment nullcheck once PluginOptions
408
- * is validated
409
- */
410
- if (environment.isErr()) {
411
- CompilerError.throwInvalidConfig({
412
- reason:
413
- 'Error in validating environment config. This is an advanced setting and not meant to be used directly',
414
- description: environment.unwrapErr().toString(),
415
- suggestions: null,
416
- loc: null,
417
- });
418
- }
419
- const config = environment.unwrap();
420
-
393
compiledFn = compileFn(
394
fn,
423
- config,
395
+ environment,
396
fnType,
397
useMemoCacheIdentifier.name,
398
pass.opts.logger,
@@ -514,43 +486,29 @@ export function compileProgram(
486
externalFunctions.push(gating);
487
}
488
517
- const lowerContextAccess = pass.opts.environment?.lowerContextAccess;
489
+ const lowerContextAccess = environment.lowerContextAccess;
490
if (lowerContextAccess && hasLoweredContextAccess) {
519
- externalFunctions.push(tryParseExternalFunction(lowerContextAccess));
491
+ externalFunctions.push(lowerContextAccess);
492
}
493
522
- const enableEmitInstrumentForget =
523
- pass.opts.environment?.enableEmitInstrumentForget;
494
+ const enableEmitInstrumentForget = environment.enableEmitInstrumentForget;
495
if (enableEmitInstrumentForget != null) {
525
- externalFunctions.push(
526
- tryParseExternalFunction(enableEmitInstrumentForget.fn),
527
- );
496
+ externalFunctions.push(enableEmitInstrumentForget.fn);
497
if (enableEmitInstrumentForget.gating != null) {
529
- externalFunctions.push(
530
- tryParseExternalFunction(enableEmitInstrumentForget.gating),
531
- );
498
+ externalFunctions.push(enableEmitInstrumentForget.gating);
499
}
500
}
501
535
- if (pass.opts.environment?.enableEmitFreeze != null) {
536
- const enableEmitFreeze = tryParseExternalFunction(
537
- pass.opts.environment.enableEmitFreeze,
538
- );
539
- externalFunctions.push(enableEmitFreeze);
502
+ if (environment.enableEmitFreeze != null) {
503
+ externalFunctions.push(environment.enableEmitFreeze);
504
}
505
542
- if (pass.opts.environment?.enableEmitHookGuards != null) {
543
- const enableEmitHookGuards = tryParseExternalFunction(
544
- pass.opts.environment.enableEmitHookGuards,
545
- );
546
- externalFunctions.push(enableEmitHookGuards);
506
+ if (environment.enableEmitHookGuards != null) {
507
+ externalFunctions.push(environment.enableEmitHookGuards);
508
}
509
549
- if (pass.opts.environment?.enableChangeDetectionForDebugging != null) {
550
- const enableChangeDetectionForDebugging = tryParseExternalFunction(
551
- pass.opts.environment.enableChangeDetectionForDebugging,
552
- );
553
- externalFunctions.push(enableChangeDetectionForDebugging);
510
+ if (environment.enableChangeDetectionForDebugging != null) {
511
+ externalFunctions.push(environment.enableChangeDetectionForDebugging);
512
}
513
} catch (err) {
514
handleError(err, pass, null);
@@ -593,11 +551,65 @@ export function compileProgram(
551
}
552
}
553
554
+function shouldSkipCompilation(
555
+ program: NodePath<t.Program>,
556
+ pass: CompilerPass,
557
+): boolean {
558
+ if (pass.opts.sources) {
559
+ if (pass.filename === null) {
560
+ const error = new CompilerError();
561
+ error.pushErrorDetail(
562
+ new CompilerErrorDetail({
563
+ reason: `Expected a filename but found none.`,
564
+ description:
565
+ "When the 'sources' config options is specified, the React compiler will only compile files with a name",
566
+ severity: ErrorSeverity.InvalidConfig,
567
+ loc: null,
568
+ }),
569
+ );
570
+ handleError(error, pass, null);
571
+ return true;
572
+ }
573
+
574
+ if (!isFilePartOfSources(pass.opts.sources, pass.filename)) {
575
+ return true;
576
+ }
577
+ }
578
+
579
+ // Top level "use no forget", skip this file entirely
580
+ const useNoForget = findDirectiveDisablingMemoization(
581
+ program.node.directives,
582
+ pass.opts,
583
+ );
584
+ if (useNoForget != null) {
585
+ pass.opts.logger?.logEvent(pass.filename, {
586
+ kind: 'CompileError',
587
+ fnLoc: null,
588
+ detail: {
589
+ severity: ErrorSeverity.Todo,
590
+ reason: 'Skipped due to "use no forget" directive.',
591
+ loc: useNoForget.loc ?? null,
592
+ suggestions: null,
593
+ },
594
+ });
595
+ return true;
596
+ }
597
+ const moduleName = pass.opts.runtimeModule ?? 'react/compiler-runtime';
598
+ if (hasMemoCacheFunctionImport(program, moduleName)) {
599
+ return true;
600
+ }
601
+ return false;
602
+}
603
+
604
function getReactFunctionType(
605
fn: BabelFn,
606
pass: CompilerPass,
607
+ /**
608
+ * TODO(mofeiZ): remove once we validate PluginOptions with Zod
609
+ */
610
+ environment: EnvironmentConfig,
611
): ReactFunctionType | null {
600
- const hookPattern = pass.opts.environment?.hookPattern ?? null;
612
+ const hookPattern = environment.hookPattern;
613
if (fn.node.body.type === 'BlockStatement') {
614
// Opt-outs disable compilation regardless of mode
615
const useNoForget = findDirectiveDisablingMemoization(