Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
425 changes: 253 additions & 172 deletions compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,26 @@ function insertAdditionalFunctionDeclaration(
CompilerError.invariant(originalFnName != null && compiled.id != null, {
reason:
'Expected function declarations that are referenced elsewhere to have a named identifier',
loc: fnPath.node.loc ?? null,
description: null,
details: [
{
kind: 'error',
loc: fnPath.node.loc ?? null,
message: null,
},
],
});
CompilerError.invariant(originalFnParams.length === compiledParams.length, {
reason:
'Expected React Compiler optimized function declarations to have the same number of parameters as source',
loc: fnPath.node.loc ?? null,
description: null,
details: [
{
kind: 'error',
loc: fnPath.node.loc ?? null,
message: null,
},
],
});

const gatingCondition = t.identifier(
Expand Down Expand Up @@ -140,7 +154,13 @@ export function insertGatedFunctionDeclaration(
CompilerError.invariant(compiled.type === 'FunctionDeclaration', {
reason: 'Expected compiled node type to match input type',
description: `Got ${compiled.type} but expected FunctionDeclaration`,
loc: fnPath.node.loc ?? null,
details: [
{
kind: 'error',
loc: fnPath.node.loc ?? null,
message: null,
},
],
});
insertAdditionalFunctionDeclaration(
fnPath,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {NodePath} from '@babel/core';
import * as t from '@babel/types';
import {Scope as BabelScope} from '@babel/traverse';

import {CompilerError, ErrorCategory, ErrorSeverity} from '../CompilerError';
import {CompilerError, ErrorCategory} from '../CompilerError';
import {
EnvironmentConfig,
GeneratedSource,
Expand Down Expand Up @@ -39,15 +39,14 @@ export function validateRestrictedImports(
if (restrictedImports.has(importDeclPath.node.source.value)) {
error.push({
category: ErrorCategory.Todo,
severity: ErrorSeverity.Todo,
reason: 'Bailing out due to blocklisted import',
description: `Import from module ${importDeclPath.node.source.value}`,
loc: importDeclPath.node.loc ?? null,
});
}
},
});
if (error.hasErrors()) {
if (error.hasAnyErrors()) {
return error;
} else {
return null;
Expand Down Expand Up @@ -207,7 +206,6 @@ export class ProgramContext {
const error = new CompilerError();
error.push({
category: ErrorCategory.Todo,
severity: ErrorSeverity.Todo,
reason: 'Encountered conflicting global in generated program',
description: `Conflict from local binding ${name}`,
loc: scope.getBinding(name)?.path.node.loc ?? null,
Expand Down Expand Up @@ -258,8 +256,14 @@ export function addImportsToProgram(
{
reason:
'Encountered conflicting import specifiers in generated program',
description: `Conflict from import ${loweredImport.module}:(${loweredImport.imported} as ${loweredImport.name}).`,
loc: GeneratedSource,
description: `Conflict from import ${loweredImport.module}:(${loweredImport.imported} as ${loweredImport.name})`,
details: [
{
kind: 'error',
loc: GeneratedSource,
message: null,
},
],
suggestions: null,
},
);
Expand All @@ -270,7 +274,13 @@ export function addImportsToProgram(
reason:
'Found inconsistent import specifier. This is an internal bug.',
description: `Expected import ${moduleName}:${specifierName} but found ${loweredImport.module}:${loweredImport.imported}`,
loc: GeneratedSource,
details: [
{
kind: 'error',
loc: GeneratedSource,
message: null,
},
],
},
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
CompilerError,
CompilerErrorDetail,
ErrorCategory,
ErrorSeverity,
} from '../CompilerError';
import {ExternalFunction, ReactFunctionType} from '../HIR/Environment';
import {CodegenFunction} from '../ReactiveScopes';
Expand Down Expand Up @@ -105,15 +104,14 @@ function findDirectivesDynamicGating(
errors.push({
reason: `Dynamic gating directive is not a valid JavaScript identifier`,
description: `Found '${directive.value.value}'`,
severity: ErrorSeverity.InvalidReact,
category: ErrorCategory.Gating,
loc: directive.loc ?? null,
suggestions: null,
});
}
}
}
if (errors.hasErrors()) {
if (errors.hasAnyErrors()) {
return Err(errors);
} else if (result.length > 1) {
const error = new CompilerError();
Expand All @@ -122,7 +120,6 @@ function findDirectivesDynamicGating(
description: `Expected a single directive but found [${result
.map(r => r.directive.value.value)
.join(', ')}]`,
severity: ErrorSeverity.InvalidReact,
category: ErrorCategory.Gating,
loc: result[0].directive.loc ?? null,
suggestions: null,
Expand All @@ -141,15 +138,13 @@ function findDirectivesDynamicGating(
}
}

function isCriticalError(err: unknown): boolean {
return !(err instanceof CompilerError) || err.isCritical();
function isError(err: unknown): boolean {
return !(err instanceof CompilerError) || err.hasErrors();
}

function isConfigError(err: unknown): boolean {
if (err instanceof CompilerError) {
return err.details.some(
detail => detail.severity === ErrorSeverity.InvalidConfig,
);
return err.details.some(detail => detail.category === ErrorCategory.Config);
}
return false;
}
Expand Down Expand Up @@ -214,8 +209,7 @@ function handleError(
logError(err, context, fnLoc);
if (
context.opts.panicThreshold === 'all_errors' ||
(context.opts.panicThreshold === 'critical_errors' &&
isCriticalError(err)) ||
(context.opts.panicThreshold === 'critical_errors' && isError(err)) ||
isConfigError(err) // Always throws regardless of panic threshold
) {
throw err;
Expand Down Expand Up @@ -316,7 +310,13 @@ function insertNewOutlinedFunctionNode(
CompilerError.invariant(insertedFuncDecl.isFunctionDeclaration(), {
reason: 'Expected inserted function declaration',
description: `Got: ${insertedFuncDecl}`,
loc: insertedFuncDecl.node?.loc ?? null,
details: [
{
kind: 'error',
loc: insertedFuncDecl.node?.loc ?? null,
message: null,
},
],
});
return insertedFuncDecl;
}
Expand Down Expand Up @@ -425,7 +425,14 @@ export function compileProgram(
for (const outlined of compiled.outlined) {
CompilerError.invariant(outlined.fn.outlined.length === 0, {
reason: 'Unexpected nested outlined functions',
loc: outlined.fn.loc,
description: null,
details: [
{
kind: 'error',
loc: outlined.fn.loc,
message: null,
},
],
});
const fn = insertNewOutlinedFunctionNode(
program,
Expand Down Expand Up @@ -458,7 +465,6 @@ export function compileProgram(
new CompilerErrorDetail({
reason:
'Unexpected compiled functions when module scope opt-out is present',
severity: ErrorSeverity.Invariant,
category: ErrorCategory.Invariant,
loc: null,
}),
Expand Down Expand Up @@ -827,7 +833,6 @@ function shouldSkipCompilation(
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,
category: ErrorCategory.Config,
loc: null,
}),
Expand Down Expand Up @@ -890,7 +895,6 @@ function validateNoDynamicallyCreatedComponentsOrHooks(
if (nestedFnType === 'Component' || nestedFnType === 'Hook') {
CompilerError.throwDiagnostic({
category: ErrorCategory.Factories,
severity: ErrorSeverity.InvalidReact,
reason: `Components and hooks cannot be created dynamically`,
description: `The function \`${nestedName}\` appears to be a React ${nestedFnType.toLowerCase()}, but it's defined inside \`${parentName}\`. Components and Hooks should always be declared at module scope`,
details: [
Expand Down Expand Up @@ -1416,7 +1420,13 @@ export function getReactCompilerRuntimeModule(
{
reason: 'Expected target to already be validated',
description: null,
loc: null,
details: [
{
kind: 'error',
loc: null,
message: null,
},
],
suggestions: null,
},
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
CompilerError,
CompilerSuggestionOperation,
ErrorCategory,
ErrorSeverity,
} from '../CompilerError';
import {assertExhaustive} from '../Utils/utils';
import {GeneratedSource} from '../HIR';
Expand Down Expand Up @@ -153,7 +152,14 @@ export function suppressionsToCompilerError(
): CompilerError {
CompilerError.invariant(suppressionRanges.length !== 0, {
reason: `Expected at least suppression comment source range`,
loc: GeneratedSource,
description: null,
details: [
{
kind: 'error',
loc: GeneratedSource,
message: null,
},
],
});
const error = new CompilerError();
for (const suppressionRange of suppressionRanges) {
Expand Down Expand Up @@ -186,7 +192,6 @@ export function suppressionsToCompilerError(
CompilerDiagnostic.create({
reason: reason,
description: `React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression \`${suppressionRange.disableComment.value.trim()}\``,
severity: ErrorSeverity.InvalidReact,
category: ErrorCategory.Suppression,
suggestions: [
{
Expand All @@ -198,7 +203,7 @@ export function suppressionsToCompilerError(
op: CompilerSuggestionOperation.Remove,
},
],
}).withDetail({
}).withDetails({
kind: 'error',
loc: suppressionRange.disableComment.loc ?? null,
message: 'Found React rule suppression',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import {NodePath} from '@babel/core';
import * as t from '@babel/types';

import {CompilerError, EnvironmentConfig, ErrorSeverity, Logger} from '..';
import {CompilerError, EnvironmentConfig, Logger} from '..';
import {getOrInsertWith} from '../Utils/utils';
import {Environment, GeneratedSource} from '../HIR';
import {DEFAULT_EXPORT} from '../HIR/Environment';
Expand All @@ -20,19 +20,15 @@ import {
} from '../CompilerError';

function throwInvalidReact(
options: Omit<CompilerDiagnosticOptions, 'severity'>,
options: CompilerDiagnosticOptions,
{logger, filename}: TraversalState,
): never {
const detail: CompilerDiagnosticOptions = {
severity: ErrorSeverity.InvalidReact,
...options,
};
logger?.logEvent(filename, {
kind: 'CompileError',
fnLoc: null,
detail: new CompilerDiagnostic(detail),
detail: new CompilerDiagnostic(options),
});
CompilerError.throwDiagnostic(detail);
CompilerError.throwDiagnostic(options);
}

function isAutodepsSigil(
Expand Down Expand Up @@ -100,7 +96,7 @@ function assertValidEffectImportReference(
reason:
'Cannot infer dependencies of this effect. This will break your build!',
description:
'To resolve, either pass a dependency array or fix reported compiler bailout diagnostics.' +
'To resolve, either pass a dependency array or fix reported compiler bailout diagnostics' +
(maybeErrorDiagnostic ? ` ${maybeErrorDiagnostic}` : ''),
details: [
{
Expand Down Expand Up @@ -132,9 +128,7 @@ function assertValidFireImportReference(
reason: '[Fire] Untransformed reference to compiler-required feature.',
description:
'Either remove this `fire` call or ensure it is successfully transformed by the compiler' +
maybeErrorDiagnostic
? ` ${maybeErrorDiagnostic}`
: '',
(maybeErrorDiagnostic != null ? ` ${maybeErrorDiagnostic}` : ''),
details: [
{
kind: 'error',
Expand Down Expand Up @@ -221,7 +215,14 @@ function validateImportSpecifier(
const binding = local.scope.getBinding(local.node.name);
CompilerError.invariant(binding != null, {
reason: 'Expected binding to be found for import specifier',
loc: local.node.loc ?? null,
description: null,
details: [
{
kind: 'error',
loc: local.node.loc ?? null,
message: null,
},
],
});
checkFn(binding.referencePaths, state);
}
Expand All @@ -241,7 +242,14 @@ function validateNamespacedImport(

CompilerError.invariant(binding != null, {
reason: 'Expected binding to be found for import specifier',
loc: local.node.loc ?? null,
description: null,
details: [
{
kind: 'error',
loc: local.node.loc ?? null,
message: null,
},
],
});
const filteredReferences = new Map<
CheckInvalidReferenceFn,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,14 @@ export function raiseUnificationErrors(
if (errs.length === 0) {
CompilerError.invariant(false, {
reason: 'Should not have array of zero errors',
loc,
description: null,
details: [
{
kind: 'error',
loc,
message: null,
},
],
});
} else if (errs.length === 1) {
CompilerError.throwInvalidJS({
Expand Down
Loading
Loading