diff --git a/compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts b/compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts index e12530a8db5..2e7acac2542 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts @@ -14,52 +14,30 @@ import invariant from 'invariant'; export enum ErrorSeverity { /** - * Invalid JS syntax, or valid syntax that is semantically invalid which may indicate some - * misunderstanding on the user’s part. + * An actionable error that the developer can fix. For example, product code errors should be + * reported as such. */ - InvalidJS = 'InvalidJS', + Error = 'Error', /** - * JS syntax that is not supported and which we do not plan to support. Developers should - * rewrite to use supported forms. + * An error that the developer may not necessarily be able to fix. For example, syntax not + * supported by the compiler does not indicate any fault in the product code. */ - UnsupportedJS = 'UnsupportedJS', + Warning = 'Warning', /** - * Code that breaks the rules of React. + * Not an error. These will not be surfaced in ESLint, but may be surfaced in other ways + * (eg Forgive) where informational hints can be shown. */ - InvalidReact = 'InvalidReact', + Hint = 'Hint', /** - * Incorrect configuration of the compiler. + * These errors will not be reported anywhere. Useful for work in progress validations. */ - InvalidConfig = 'InvalidConfig', - /** - * Code that can reasonably occur and that doesn't break any rules, but is unsafe to preserve - * memoization. - */ - CannotPreserveMemoization = 'CannotPreserveMemoization', - /** - * An API that is known to be incompatible with the compiler. Generally as a result of - * the library using "interior mutability", ie having a value whose referential identity - * stays the same but which provides access to values that can change. For example a - * function that doesn't change but returns different results, or an object that doesn't - * change identity but whose properties change. - */ - IncompatibleLibrary = 'IncompatibleLibrary', - /** - * Unhandled syntax that we don't support yet. - */ - Todo = 'Todo', - /** - * An unexpected internal error in the compiler that indicates critical issues that can panic - * the compiler. - */ - Invariant = 'Invariant', + Off = 'Off', } export type CompilerDiagnosticOptions = { category: ErrorCategory; - severity: ErrorSeverity; reason: string; - description: string; + description: string | null; details: Array; suggestions?: Array | null | undefined; }; @@ -71,7 +49,7 @@ export type CompilerDiagnosticDetail = | { kind: 'error'; loc: SourceLocation | null; - message: string; + message: string | null; } | { kind: 'hint'; @@ -100,9 +78,11 @@ export type CompilerSuggestion = description: string; }; +/** + * @deprecated use {@link CompilerDiagnosticOptions} instead + */ export type CompilerErrorDetailOptions = { category: ErrorCategory; - severity: ErrorSeverity; reason: string; description?: string | null | undefined; loc: SourceLocation | null; @@ -136,8 +116,8 @@ export class CompilerDiagnostic { get description(): CompilerDiagnosticOptions['description'] { return this.options.description; } - get severity(): CompilerDiagnosticOptions['severity'] { - return this.options.severity; + get severity(): ErrorSeverity { + return getRuleForCategory(this.category).severity; } get suggestions(): CompilerDiagnosticOptions['suggestions'] { return this.options.suggestions; @@ -146,8 +126,8 @@ export class CompilerDiagnostic { return this.options.category; } - withDetail(detail: CompilerDiagnosticDetail): CompilerDiagnostic { - this.options.details.push(detail); + withDetails(...details: Array): CompilerDiagnostic { + this.options.details.push(...details); return this; } @@ -161,11 +141,10 @@ export class CompilerDiagnostic { } printErrorMessage(source: string, options: PrintErrorMessageOptions): string { - const buffer = [ - printErrorSummary(this.severity, this.reason), - '\n\n', - this.description, - ]; + const buffer = [printErrorSummary(this.category, this.reason)]; + if (this.description != null) { + buffer.push('\n\n', `${this.description}.`); + } for (const detail of this.options.details) { switch (detail.kind) { case 'error': { @@ -175,9 +154,9 @@ export class CompilerDiagnostic { } let codeFrame: string; try { - codeFrame = printCodeFrame(source, loc, detail.message); + codeFrame = printCodeFrame(source, loc, detail.message ?? ''); } catch (e) { - codeFrame = detail.message; + codeFrame = detail.message ?? ''; } buffer.push('\n\n'); if (loc.filename != null) { @@ -207,7 +186,7 @@ export class CompilerDiagnostic { } toString(): string { - const buffer = [printErrorSummary(this.severity, this.reason)]; + const buffer = [printErrorSummary(this.category, this.reason)]; if (this.description != null) { buffer.push(`. ${this.description}.`); } @@ -219,9 +198,11 @@ export class CompilerDiagnostic { } } -/* +/** * Each bailout or invariant in HIR lowering creates an {@link CompilerErrorDetail}, which is then * aggregated into a single {@link CompilerError} later. + * + * @deprecated use {@link CompilerDiagnostic} instead */ export class CompilerErrorDetail { options: CompilerErrorDetailOptions; @@ -236,8 +217,8 @@ export class CompilerErrorDetail { get description(): CompilerErrorDetailOptions['description'] { return this.options.description; } - get severity(): CompilerErrorDetailOptions['severity'] { - return this.options.severity; + get severity(): ErrorSeverity { + return getRuleForCategory(this.category).severity; } get loc(): CompilerErrorDetailOptions['loc'] { return this.options.loc; @@ -254,7 +235,7 @@ export class CompilerErrorDetail { } printErrorMessage(source: string, options: PrintErrorMessageOptions): string { - const buffer = [printErrorSummary(this.severity, this.reason)]; + const buffer = [printErrorSummary(this.category, this.reason)]; if (this.description != null) { buffer.push(`\n\n${this.description}.`); } @@ -279,7 +260,7 @@ export class CompilerErrorDetail { } toString(): string { - const buffer = [printErrorSummary(this.severity, this.reason)]; + const buffer = [printErrorSummary(this.category, this.reason)]; if (this.description != null) { buffer.push(`. ${this.description}.`); } @@ -291,22 +272,28 @@ export class CompilerErrorDetail { } } +/** + * An aggregate of {@link CompilerDiagnostic}. This allows us to aggregate all issues found by the + * compiler into a single error before we throw. Where possible, prefer to push diagnostics into + * the error aggregate instead of throwing immediately. + */ export class CompilerError extends Error { details: Array = []; + disabledDetails: Array = []; printedMessage: string | null = null; static invariant( condition: unknown, - options: Omit, + options: Omit, ): asserts condition { if (!condition) { const errors = new CompilerError(); - errors.pushErrorDetail( - new CompilerErrorDetail({ - ...options, + errors.pushDiagnostic( + CompilerDiagnostic.create({ + reason: options.reason, + description: options.description, category: ErrorCategory.Invariant, - severity: ErrorSeverity.Invariant, - }), + }).withDetails(...options.details), ); throw errors; } @@ -319,13 +306,12 @@ export class CompilerError extends Error { } static throwTodo( - options: Omit, + options: Omit, ): never { const errors = new CompilerError(); errors.pushErrorDetail( new CompilerErrorDetail({ ...options, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, }), ); @@ -333,40 +319,31 @@ export class CompilerError extends Error { } static throwInvalidJS( - options: Omit, + options: Omit, ): never { const errors = new CompilerError(); errors.pushErrorDetail( new CompilerErrorDetail({ ...options, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, }), ); throw errors; } - static throwInvalidReact( - options: Omit, - ): never { + static throwInvalidReact(options: CompilerErrorDetailOptions): never { const errors = new CompilerError(); - errors.pushErrorDetail( - new CompilerErrorDetail({ - ...options, - severity: ErrorSeverity.InvalidReact, - }), - ); + errors.pushErrorDetail(new CompilerErrorDetail(options)); throw errors; } static throwInvalidConfig( - options: Omit, + options: Omit, ): never { const errors = new CompilerError(); errors.pushErrorDetail( new CompilerErrorDetail({ ...options, - severity: ErrorSeverity.InvalidConfig, category: ErrorCategory.Config, }), ); @@ -383,6 +360,7 @@ export class CompilerError extends Error { super(...args); this.name = 'ReactCompilerError'; this.details = []; + this.disabledDetails = []; } override get message(): string { @@ -423,62 +401,93 @@ export class CompilerError extends Error { merge(other: CompilerError): void { this.details.push(...other.details); + this.disabledDetails.push(...other.disabledDetails); } pushDiagnostic(diagnostic: CompilerDiagnostic): void { - this.details.push(diagnostic); + if (diagnostic.severity === ErrorSeverity.Off) { + this.disabledDetails.push(diagnostic); + } else { + this.details.push(diagnostic); + } } + /** + * @deprecated use {@link pushDiagnostic} instead + */ push(options: CompilerErrorDetailOptions): CompilerErrorDetail { const detail = new CompilerErrorDetail({ category: options.category, reason: options.reason, description: options.description ?? null, - severity: options.severity, suggestions: options.suggestions, loc: typeof options.loc === 'symbol' ? null : options.loc, }); return this.pushErrorDetail(detail); } + /** + * @deprecated use {@link pushDiagnostic} instead + */ pushErrorDetail(detail: CompilerErrorDetail): CompilerErrorDetail { - this.details.push(detail); + if (detail.severity === ErrorSeverity.Off) { + this.disabledDetails.push(detail); + } else { + this.details.push(detail); + } return detail; } - hasErrors(): boolean { + hasAnyErrors(): boolean { return this.details.length > 0; } asResult(): Result { - return this.hasErrors() ? Err(this) : Ok(undefined); - } - - /* - * An error is critical if it means the compiler has entered into a broken state and cannot - * continue safely. Other expected errors such as Todos mean that we can skip over that component - * but otherwise continue compiling the rest of the app. - */ - isCritical(): boolean { - return this.details.some(detail => { - switch (detail.severity) { - case ErrorSeverity.Invariant: - case ErrorSeverity.InvalidJS: - case ErrorSeverity.InvalidReact: - case ErrorSeverity.InvalidConfig: - case ErrorSeverity.UnsupportedJS: - case ErrorSeverity.IncompatibleLibrary: { - return true; - } - case ErrorSeverity.CannotPreserveMemoization: - case ErrorSeverity.Todo: { - return false; - } - default: { - assertExhaustive(detail.severity, 'Unhandled error severity'); - } + return this.hasAnyErrors() ? Err(this) : Ok(undefined); + } + + /** + * Returns true if any of the error details are of severity Error. + */ + hasErrors(): boolean { + for (const detail of this.details) { + if (detail.severity === ErrorSeverity.Error) { + return true; } - }); + } + return false; + } + + /** + * Returns true if there are no Errors and there is at least one Warning. + */ + hasWarning(): boolean { + let res = false; + for (const detail of this.details) { + if (detail.severity === ErrorSeverity.Error) { + return false; + } + if (detail.severity === ErrorSeverity.Warning) { + res = true; + } + } + return res; + } + + hasHints(): boolean { + let res = false; + for (const detail of this.details) { + if (detail.severity === ErrorSeverity.Error) { + return false; + } + if (detail.severity === ErrorSeverity.Warning) { + return false; + } + if (detail.severity === ErrorSeverity.Hint) { + res = true; + } + } + return res; } } @@ -505,115 +514,158 @@ function printCodeFrame( ); } -function printErrorSummary(severity: ErrorSeverity, message: string): string { - let severityCategory: string; - switch (severity) { - case ErrorSeverity.InvalidConfig: - case ErrorSeverity.InvalidJS: - case ErrorSeverity.InvalidReact: - case ErrorSeverity.UnsupportedJS: { - severityCategory = 'Error'; +function printErrorSummary(category: ErrorCategory, message: string): string { + let heading: string; + switch (category) { + case ErrorCategory.AutomaticEffectDependencies: + case ErrorCategory.CapitalizedCalls: + case ErrorCategory.Config: + case ErrorCategory.EffectDerivationsOfState: + case ErrorCategory.EffectSetState: + case ErrorCategory.ErrorBoundaries: + case ErrorCategory.Factories: + case ErrorCategory.FBT: + case ErrorCategory.Fire: + case ErrorCategory.Gating: + case ErrorCategory.Globals: + case ErrorCategory.Hooks: + case ErrorCategory.Immutability: + case ErrorCategory.Purity: + case ErrorCategory.Refs: + case ErrorCategory.RenderSetState: + case ErrorCategory.StaticComponents: + case ErrorCategory.Suppression: + case ErrorCategory.Syntax: + case ErrorCategory.UseMemo: { + heading = 'Error'; break; } - case ErrorSeverity.IncompatibleLibrary: - case ErrorSeverity.CannotPreserveMemoization: { - severityCategory = 'Compilation Skipped'; + case ErrorCategory.EffectDependencies: + case ErrorCategory.IncompatibleLibrary: + case ErrorCategory.PreserveManualMemo: + case ErrorCategory.UnsupportedSyntax: { + heading = 'Compilation Skipped'; break; } - case ErrorSeverity.Invariant: { - severityCategory = 'Invariant'; + case ErrorCategory.Invariant: { + heading = 'Invariant'; break; } - case ErrorSeverity.Todo: { - severityCategory = 'Todo'; + case ErrorCategory.Todo: { + heading = 'Todo'; break; } default: { - assertExhaustive(severity, `Unexpected severity '${severity}'`); + assertExhaustive(category, `Unhandled category '${category}'`); } } - return `${severityCategory}: ${message}`; + return `${heading}: ${message}`; } /** * See getRuleForCategory() for how these map to ESLint rules */ export enum ErrorCategory { - // Checking for valid hooks usage (non conditional, non-first class, non reactive, etc) + /** + * Checking for valid hooks usage (non conditional, non-first class, non reactive, etc) + */ Hooks = 'Hooks', - - // Checking for no capitalized calls (not definitively an error, hence separating) + /** + * Checking for no capitalized calls (not definitively an error, hence separating) + */ CapitalizedCalls = 'CapitalizedCalls', - - // Checking for static components + /** + * Checking for static components + */ StaticComponents = 'StaticComponents', - - // Checking for valid usage of manual memoization + /** + * Checking for valid usage of manual memoization + */ UseMemo = 'UseMemo', - - // Checking for higher order functions acting as factories for components/hooks + /** + * Checking for higher order functions acting as factories for components/hooks + */ Factories = 'Factories', - - // Checks that manual memoization is preserved + /** + * Checks that manual memoization is preserved + */ PreserveManualMemo = 'PreserveManualMemo', - - // Checks for known incompatible libraries + /** + * Checks for known incompatible libraries + */ IncompatibleLibrary = 'IncompatibleLibrary', - - // Checking for no mutations of props, hook arguments, hook return values + /** + * Checking for no mutations of props, hook arguments, hook return values + */ Immutability = 'Immutability', - - // Checking for assignments to globals + /** + * Checking for assignments to globals + */ Globals = 'Globals', - - // Checking for valid usage of refs, ie no access during render + /** + * Checking for valid usage of refs, ie no access during render + */ Refs = 'Refs', - - // Checks for memoized effect deps + /** + * Checks for memoized effect deps + */ EffectDependencies = 'EffectDependencies', - - // Checks for no setState in effect bodies + /** + * Checks for no setState in effect bodies + */ EffectSetState = 'EffectSetState', - EffectDerivationsOfState = 'EffectDerivationsOfState', - - // Validates against try/catch in place of error boundaries + /** + * Validates against try/catch in place of error boundaries + */ ErrorBoundaries = 'ErrorBoundaries', - - // Checking for pure functions + /** + * Checking for pure functions + */ Purity = 'Purity', - - // Validates against setState in render + /** + * Validates against setState in render + */ RenderSetState = 'RenderSetState', - - // Internal invariants + /** + * Internal invariants + */ Invariant = 'Invariant', - - // Todos + /** + * Todos + */ Todo = 'Todo', - - // Syntax errors + /** + * Syntax errors + */ Syntax = 'Syntax', - - // Checks for use of unsupported syntax + /** + * Checks for use of unsupported syntax + */ UnsupportedSyntax = 'UnsupportedSyntax', - - // Config errors + /** + * Config errors + */ Config = 'Config', - - // Gating error + /** + * Gating error + */ Gating = 'Gating', - - // Suppressions + /** + * Suppressions + */ Suppression = 'Suppression', - - // Issues with auto deps + /** + * Issues with auto deps + */ AutomaticEffectDependencies = 'AutomaticEffectDependencies', - - // Issues with `fire` + /** + * Issues with `fire` + */ Fire = 'Fire', - - // fbt-specific issues + /** + * fbt-specific issues + */ FBT = 'FBT', } @@ -621,6 +673,9 @@ export type LintRule = { // Stores the category the rule corresponds to, used to filter errors when reporting category: ErrorCategory; + // Stores the severity of the error, which is used to map to lint levels such as error/warning. + severity: ErrorSeverity; + /** * The "name" of the rule as it will be used by developers to enable/disable, eg * "eslint-disable-nest line " @@ -661,6 +716,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.AutomaticEffectDependencies: { return { category, + severity: ErrorSeverity.Error, name: 'automatic-effect-dependencies', description: 'Verifies that automatic effect dependencies are compiled if opted-in', @@ -670,6 +726,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.CapitalizedCalls: { return { category, + severity: ErrorSeverity.Error, name: 'capitalized-calls', description: 'Validates against calling capitalized functions/methods instead of using JSX', @@ -679,6 +736,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Config: { return { category, + severity: ErrorSeverity.Error, name: 'config', description: 'Validates the compiler configuration options', recommended: true, @@ -687,6 +745,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.EffectDependencies: { return { category, + severity: ErrorSeverity.Error, name: 'memoized-effect-dependencies', description: 'Validates that effect dependencies are memoized', recommended: false, @@ -695,6 +754,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.EffectDerivationsOfState: { return { category, + severity: ErrorSeverity.Error, name: 'no-deriving-state-in-effects', description: 'Validates against deriving values from state in an effect', @@ -704,6 +764,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.EffectSetState: { return { category, + severity: ErrorSeverity.Error, name: 'set-state-in-effect', description: 'Validates against calling setState synchronously in an effect, which can lead to re-renders that degrade performance', @@ -713,6 +774,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.ErrorBoundaries: { return { category, + severity: ErrorSeverity.Error, name: 'error-boundaries', description: 'Validates usage of error boundaries instead of try/catch for errors in child components', @@ -722,6 +784,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Factories: { return { category, + severity: ErrorSeverity.Error, name: 'component-hook-factories', description: 'Validates against higher order functions defining nested components or hooks. ' + @@ -732,6 +795,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.FBT: { return { category, + severity: ErrorSeverity.Error, name: 'fbt', description: 'Validates usage of fbt', recommended: false, @@ -740,6 +804,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Fire: { return { category, + severity: ErrorSeverity.Error, name: 'fire', description: 'Validates usage of `fire`', recommended: false, @@ -748,6 +813,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Gating: { return { category, + severity: ErrorSeverity.Error, name: 'gating', description: 'Validates configuration of [gating mode](https://react.dev/reference/react-compiler/gating)', @@ -757,6 +823,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Globals: { return { category, + severity: ErrorSeverity.Error, name: 'globals', description: 'Validates against assignment/mutation of globals during render, part of ensuring that ' + @@ -767,6 +834,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Hooks: { return { category, + severity: ErrorSeverity.Error, name: 'hooks', description: 'Validates the rules of hooks', /** @@ -780,6 +848,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Immutability: { return { category, + severity: ErrorSeverity.Error, name: 'immutability', description: 'Validates against mutating props, state, and other values that [are immutable](https://react.dev/reference/rules/components-and-hooks-must-be-pure#props-and-state-are-immutable)', @@ -789,6 +858,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Invariant: { return { category, + severity: ErrorSeverity.Error, name: 'invariant', description: 'Internal invariants', recommended: false, @@ -797,6 +867,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.PreserveManualMemo: { return { category, + severity: ErrorSeverity.Error, name: 'preserve-manual-memoization', description: 'Validates that existing manual memoized is preserved by the compiler. ' + @@ -808,6 +879,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Purity: { return { category, + severity: ErrorSeverity.Error, name: 'purity', description: 'Validates that [components/hooks are pure](https://react.dev/reference/rules/components-and-hooks-must-be-pure) by checking that they do not call known-impure functions', @@ -817,6 +889,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Refs: { return { category, + severity: ErrorSeverity.Error, name: 'refs', description: 'Validates correct usage of refs, not reading/writing during render. See the "pitfalls" section in [`useRef()` usage](https://react.dev/reference/react/useRef#usage)', @@ -826,6 +899,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.RenderSetState: { return { category, + severity: ErrorSeverity.Error, name: 'set-state-in-render', description: 'Validates against setting state during render, which can trigger additional renders and potential infinite render loops', @@ -835,6 +909,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.StaticComponents: { return { category, + severity: ErrorSeverity.Error, name: 'static-components', description: 'Validates that components are static, not recreated every render. Components that are recreated dynamically can reset state and trigger excessive re-rendering', @@ -844,6 +919,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Suppression: { return { category, + severity: ErrorSeverity.Error, name: 'rule-suppression', description: 'Validates against suppression of other rules', recommended: false, @@ -852,6 +928,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Syntax: { return { category, + severity: ErrorSeverity.Error, name: 'syntax', description: 'Validates against invalid syntax', recommended: false, @@ -860,6 +937,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Todo: { return { category, + severity: ErrorSeverity.Hint, name: 'todo', description: 'Unimplemented features', recommended: false, @@ -868,6 +946,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.UnsupportedSyntax: { return { category, + severity: ErrorSeverity.Warning, name: 'unsupported-syntax', description: 'Validates against syntax that we do not plan to support in React Compiler', @@ -877,6 +956,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.UseMemo: { return { category, + severity: ErrorSeverity.Error, name: 'use-memo', description: 'Validates usage of the useMemo() hook against common mistakes. See [`useMemo()` docs](https://react.dev/reference/react/useMemo) for more information.', @@ -886,6 +966,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.IncompatibleLibrary: { return { category, + severity: ErrorSeverity.Warning, name: 'incompatible-library', description: 'Validates against usage of libraries which are incompatible with memoization (manual or automatic)', 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 679389277b5..00b61e877fa 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Gating.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Gating.ts @@ -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( @@ -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, 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 9653c49576a..9b0db75912e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts @@ -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, @@ -39,7 +39,6 @@ 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, @@ -47,7 +46,7 @@ export function validateRestrictedImports( } }, }); - if (error.hasErrors()) { + if (error.hasAnyErrors()) { return error; } else { return null; @@ -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, @@ -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, }, ); @@ -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, + }, + ], }, ); } 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 5a9ef9495fa..0d7f2f4a4c7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts @@ -11,7 +11,6 @@ import { CompilerError, CompilerErrorDetail, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import {ExternalFunction, ReactFunctionType} from '../HIR/Environment'; import {CodegenFunction} from '../ReactiveScopes'; @@ -105,7 +104,6 @@ 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, @@ -113,7 +111,7 @@ function findDirectivesDynamicGating( } } } - if (errors.hasErrors()) { + if (errors.hasAnyErrors()) { return Err(errors); } else if (result.length > 1) { const error = new CompilerError(); @@ -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, @@ -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; } @@ -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; @@ -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; } @@ -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, @@ -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, }), @@ -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, }), @@ -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: [ @@ -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, }, ); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts index a0d06f96f0e..509ed729667 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts @@ -12,7 +12,6 @@ import { CompilerError, CompilerSuggestionOperation, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import {assertExhaustive} from '../Utils/utils'; import {GeneratedSource} from '../HIR'; @@ -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) { @@ -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: [ { @@ -198,7 +203,7 @@ export function suppressionsToCompilerError( op: CompilerSuggestionOperation.Remove, }, ], - }).withDetail({ + }).withDetails({ kind: 'error', loc: suppressionRange.disableComment.loc ?? null, message: 'Found React rule suppression', diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/ValidateNoUntransformedReferences.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/ValidateNoUntransformedReferences.ts index beaaff0f79a..f671abbafb0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/ValidateNoUntransformedReferences.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/ValidateNoUntransformedReferences.ts @@ -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'; @@ -20,19 +20,15 @@ import { } from '../CompilerError'; function throwInvalidReact( - options: Omit, + 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( @@ -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: [ { @@ -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', @@ -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); } @@ -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, diff --git a/compiler/packages/babel-plugin-react-compiler/src/Flood/TypeErrors.ts b/compiler/packages/babel-plugin-react-compiler/src/Flood/TypeErrors.ts index fa3f551ff5f..6f6b3d83915 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Flood/TypeErrors.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Flood/TypeErrors.ts @@ -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({ diff --git a/compiler/packages/babel-plugin-react-compiler/src/Flood/Types.ts b/compiler/packages/babel-plugin-react-compiler/src/Flood/Types.ts index 21391b197b7..bfe8f47a58e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Flood/Types.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Flood/Types.ts @@ -152,7 +152,13 @@ export function makeLinearId(id: number): LinearId { CompilerError.invariant(id >= 0 && Number.isInteger(id), { reason: 'Expected LinearId id to be a non-negative integer', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); return id as LinearId; @@ -167,7 +173,13 @@ export function makeTypeParameterId(id: number): TypeParameterId { CompilerError.invariant(id >= 0 && Number.isInteger(id), { reason: 'Expected TypeParameterId to be a non-negative integer', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); return id as TypeParameterId; @@ -191,7 +203,13 @@ export function makeVariableId(id: number): VariableId { CompilerError.invariant(id >= 0 && Number.isInteger(id), { reason: 'Expected VariableId id to be a non-negative integer', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); return id as VariableId; @@ -399,7 +417,14 @@ function convertFlowType(flowType: FlowType, loc: string): ResolvedType { } else { CompilerError.invariant(false, { reason: `Unsupported property kind ${prop.kind}`, - loc: GeneratedSource, + description: null, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }); } } @@ -468,7 +493,14 @@ function convertFlowType(flowType: FlowType, loc: string): ResolvedType { } else { CompilerError.invariant(false, { reason: `Unsupported property kind ${prop.kind}`, - loc: GeneratedSource, + description: null, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }); } } @@ -487,7 +519,14 @@ function convertFlowType(flowType: FlowType, loc: string): ResolvedType { } else { CompilerError.invariant(false, { reason: `Unsupported property kind ${prop.kind}`, - loc: GeneratedSource, + description: null, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }); } } @@ -500,7 +539,14 @@ function convertFlowType(flowType: FlowType, loc: string): ResolvedType { } CompilerError.invariant(false, { reason: `Unsupported class instance type ${flowType.def.type.kind}`, - loc: GeneratedSource, + description: null, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }); } case 'Fun': @@ -559,7 +605,14 @@ function convertFlowType(flowType: FlowType, loc: string): ResolvedType { } else { CompilerError.invariant(false, { reason: `Unsupported component props type ${propsType.type.kind}`, - loc: GeneratedSource, + description: null, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }); } @@ -712,7 +765,14 @@ export class FlowTypeEnv implements ITypeEnv { // TODO: use flow-js only for web environments (e.g. playground) CompilerError.invariant(env.config.flowTypeProvider != null, { reason: 'Expected flowDumpTypes to be defined in environment config', - loc: GeneratedSource, + description: null, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }); let stdout: any; if (source === lastFlowSource) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertConsistentIdentifiers.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertConsistentIdentifiers.ts index 2588ee1f9a8..68562f97b0a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertConsistentIdentifiers.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertConsistentIdentifiers.ts @@ -38,7 +38,13 @@ export function assertConsistentIdentifiers(fn: HIRFunction): void { CompilerError.invariant(instr.lvalue.identifier.name === null, { reason: `Expected all lvalues to be temporaries`, description: `Found named lvalue \`${instr.lvalue.identifier.name}\``, - loc: instr.lvalue.loc, + details: [ + { + kind: 'error', + loc: instr.lvalue.loc, + message: null, + }, + ], suggestions: null, }); CompilerError.invariant(!assignments.has(instr.lvalue.identifier.id), { @@ -46,7 +52,13 @@ export function assertConsistentIdentifiers(fn: HIRFunction): void { description: `Found duplicate assignment of '${printPlace( instr.lvalue, )}'`, - loc: instr.lvalue.loc, + details: [ + { + kind: 'error', + loc: instr.lvalue.loc, + message: null, + }, + ], suggestions: null, }); assignments.add(instr.lvalue.identifier.id); @@ -77,7 +89,13 @@ function validate( CompilerError.invariant(identifier === previous, { reason: `Duplicate identifier object`, description: `Found duplicate identifier object for id ${identifier.id}`, - loc: loc ?? GeneratedSource, + details: [ + { + kind: 'error', + loc: loc ?? GeneratedSource, + message: null, + }, + ], suggestions: null, }); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertTerminalBlocksExist.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertTerminalBlocksExist.ts index e696fddbdeb..f42b5a17f11 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertTerminalBlocksExist.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertTerminalBlocksExist.ts @@ -18,7 +18,13 @@ export function assertTerminalSuccessorsExist(fn: HIRFunction): void { description: `Block bb${successor} does not exist for terminal '${printTerminal( block.terminal, )}'`, - loc: (block.terminal as any).loc ?? GeneratedSource, + details: [ + { + kind: 'error', + loc: (block.terminal as any).loc ?? GeneratedSource, + message: null, + }, + ], suggestions: null, }); return successor; @@ -33,14 +39,26 @@ export function assertTerminalPredsExist(fn: HIRFunction): void { CompilerError.invariant(predBlock != null, { reason: 'Expected predecessor block to exist', description: `Block ${block.id} references non-existent ${pred}`, - loc: GeneratedSource, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }); CompilerError.invariant( [...eachTerminalSuccessor(predBlock.terminal)].includes(block.id), { reason: 'Terminal successor does not reference correct predecessor', description: `Block bb${block.id} has bb${predBlock.id} as a predecessor, but bb${predBlock.id}'s successors do not include bb${block.id}`, - loc: GeneratedSource, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }, ); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidBlockNesting.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidBlockNesting.ts index adfb0510582..bc6956b6461 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidBlockNesting.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidBlockNesting.ts @@ -131,7 +131,13 @@ export function recursivelyTraverseItems( CompilerError.invariant(disjoint || nested, { reason: 'Invalid nesting in program blocks or scopes', description: `Items overlap but are not nested: ${maybeParentRange.start}:${maybeParentRange.end}(${currRange.start}:${currRange.end})`, - loc: GeneratedSource, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }); if (disjoint) { exit(maybeParent, context); diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidMutableRanges.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidMutableRanges.ts index 773986a1b5e..0888f4ae731 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidMutableRanges.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidMutableRanges.ts @@ -57,7 +57,13 @@ function validateMutableRange( { reason: `Invalid mutable range: [${range.start}:${range.end}]`, description: `${printPlace(place)} in ${description}`, - loc: place.loc, + details: [ + { + kind: 'error', + loc: place.loc, + message: null, + }, + ], }, ); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts index 77f2a04e7cf..02607f27b4e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts @@ -13,7 +13,6 @@ import { CompilerError, CompilerSuggestionOperation, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import {Err, Ok, Result} from '../Utils/Result'; import {assertExhaustive, hasNode} from '../Utils/utils'; @@ -108,11 +107,10 @@ export function lower( if (binding.kind !== 'Identifier') { builder.errors.pushDiagnostic( CompilerDiagnostic.create({ - severity: ErrorSeverity.Invariant, category: ErrorCategory.Invariant, reason: 'Could not find binding', - description: `[BuildHIR] Could not find binding for param \`${param.node.name}\`.`, - }).withDetail({ + description: `[BuildHIR] Could not find binding for param \`${param.node.name}\``, + }).withDetails({ kind: 'error', loc: param.node.loc ?? null, message: 'Could not find binding', @@ -173,11 +171,10 @@ export function lower( } else { builder.errors.pushDiagnostic( CompilerDiagnostic.create({ - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, reason: `Handle ${param.node.type} parameters`, - description: `[BuildHIR] Add support for ${param.node.type} parameters.`, - }).withDetail({ + description: `[BuildHIR] Add support for ${param.node.type} parameters`, + }).withDetails({ kind: 'error', loc: param.node.loc ?? null, message: 'Unsupported parameter type', @@ -205,11 +202,10 @@ export function lower( } else { builder.errors.pushDiagnostic( CompilerDiagnostic.create({ - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, reason: `Unexpected function body kind`, - description: `Expected function body to be an expression or a block statement, got \`${body.type}\`.`, - }).withDetail({ + description: `Expected function body to be an expression or a block statement, got \`${body.type}\``, + }).withDetails({ kind: 'error', loc: body.node.loc ?? null, message: 'Expected a block statement or expression', @@ -217,7 +213,7 @@ export function lower( ); } - if (builder.errors.hasErrors()) { + if (builder.errors.hasAnyErrors()) { return Err(builder.errors); } @@ -276,7 +272,6 @@ function lowerStatement( builder.errors.push({ reason: '(BuildHIR::lowerStatement) Support ThrowStatement inside of try/catch', - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: stmt.node.loc ?? null, suggestions: null, @@ -444,7 +439,13 @@ function lowerStatement( reason: 'Expected to find binding for hoisted identifier', description: `Could not find a binding for ${id.node.name}`, suggestions: null, - loc: id.node.loc ?? GeneratedSource, + details: [ + { + kind: 'error', + loc: id.node.loc ?? GeneratedSource, + message: null, + }, + ], }); if (builder.environment.isHoistedIdentifier(binding.identifier)) { // Already hoisted @@ -464,7 +465,6 @@ function lowerStatement( kind = InstructionKind.HoistedFunction; } else if (!binding.path.isVariableDeclarator()) { builder.errors.push({ - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, reason: 'Unsupported declaration type for hoisting', description: `variable "${binding.identifier.name}" declared with ${binding.path.type}`, @@ -474,7 +474,6 @@ function lowerStatement( continue; } else { builder.errors.push({ - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, reason: 'Handle non-const declarations for hoisting', description: `variable "${binding.identifier.name}" declared with ${binding.kind}`, @@ -488,7 +487,14 @@ function lowerStatement( CompilerError.invariant(identifier.kind === 'Identifier', { reason: 'Expected hoisted binding to be a local identifier, not a global', - loc: id.node.loc ?? GeneratedSource, + description: null, + details: [ + { + kind: 'error', + loc: id.node.loc ?? GeneratedSource, + message: null, + }, + ], }); const place: Place = { effect: Effect.Unknown, @@ -555,7 +561,6 @@ function lowerStatement( builder.errors.push({ reason: '(BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement', - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: stmt.node.loc ?? null, suggestions: null, @@ -628,7 +633,6 @@ function lowerStatement( if (test.node == null) { builder.errors.push({ reason: `(BuildHIR::lowerStatement) Handle empty test in ForStatement`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: stmt.node.loc ?? null, suggestions: null, @@ -780,7 +784,6 @@ function lowerStatement( if (hasDefault) { builder.errors.push({ reason: `Expected at most one \`default\` branch in a switch statement, this code should have failed to parse`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: case_.node.loc ?? null, suggestions: null, @@ -853,7 +856,6 @@ function lowerStatement( if (nodeKind === 'var') { builder.errors.push({ reason: `(BuildHIR::lowerStatement) Handle ${nodeKind} kinds in VariableDeclaration`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: stmt.node.loc ?? null, suggestions: null, @@ -882,7 +884,6 @@ function lowerStatement( if (binding.kind !== 'Identifier') { builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Could not find binding for declaration.`, - severity: ErrorSeverity.Invariant, category: ErrorCategory.Invariant, loc: id.node.loc ?? null, suggestions: null, @@ -900,7 +901,6 @@ function lowerStatement( const declRangeStart = declaration.parentPath.node.start!; builder.errors.push({ reason: `Expect \`const\` declaration not to be reassigned`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: id.node.loc ?? null, suggestions: [ @@ -948,7 +948,6 @@ function lowerStatement( builder.errors.push({ reason: `Expected variable declaration to be an identifier if no initializer was provided`, description: `Got a \`${id.type}\``, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: stmt.node.loc ?? null, suggestions: null, @@ -1028,7 +1027,13 @@ function lowerStatement( CompilerError.invariant(stmt.get('id').type === 'Identifier', { reason: 'function declarations must have a name', description: null, - loc: stmt.node.loc ?? null, + details: [ + { + kind: 'error', + loc: stmt.node.loc ?? null, + message: null, + }, + ], suggestions: null, }); const id = stmt.get('id') as NodePath; @@ -1057,7 +1062,6 @@ function lowerStatement( if (stmt.node.await) { builder.errors.push({ reason: `(BuildHIR::lowerStatement) Handle for-await loops`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: stmt.node.loc ?? null, suggestions: null, @@ -1129,7 +1133,13 @@ function lowerStatement( CompilerError.invariant(declarations.length === 1, { reason: `Expected only one declaration in the init of a ForOfStatement, got ${declarations.length}`, description: null, - loc: left.node.loc ?? null, + details: [ + { + kind: 'error', + loc: left.node.loc ?? null, + message: null, + }, + ], suggestions: null, }); const id = declarations[0].get('id'); @@ -1144,8 +1154,15 @@ function lowerStatement( test = lowerValueToTemporary(builder, assign); } else { CompilerError.invariant(left.isLVal(), { - loc: leftLoc, reason: 'Expected ForOf init to be a variable declaration or lval', + description: null, + details: [ + { + kind: 'error', + loc: leftLoc, + message: null, + }, + ], }); const assign = lowerAssignment( builder, @@ -1222,7 +1239,13 @@ function lowerStatement( CompilerError.invariant(declarations.length === 1, { reason: `Expected only one declaration in the init of a ForInStatement, got ${declarations.length}`, description: null, - loc: left.node.loc ?? null, + details: [ + { + kind: 'error', + loc: left.node.loc ?? null, + message: null, + }, + ], suggestions: null, }); const id = declarations[0].get('id'); @@ -1237,8 +1260,15 @@ function lowerStatement( test = lowerValueToTemporary(builder, assign); } else { CompilerError.invariant(left.isLVal(), { - loc: leftLoc, reason: 'Expected ForIn init to be a variable declaration or lval', + description: null, + details: [ + { + kind: 'error', + loc: leftLoc, + message: null, + }, + ], }); const assign = lowerAssignment( builder, @@ -1290,7 +1320,6 @@ function lowerStatement( if (!hasNode(handlerPath)) { builder.errors.push({ reason: `(BuildHIR::lowerStatement) Handle TryStatement without a catch clause`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: stmt.node.loc ?? null, suggestions: null, @@ -1300,7 +1329,6 @@ function lowerStatement( if (hasNode(stmt.get('finalizer'))) { builder.errors.push({ reason: `(BuildHIR::lowerStatement) Handle TryStatement with a finalizer ('finally') clause`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: stmt.node.loc ?? null, suggestions: null, @@ -1394,7 +1422,6 @@ function lowerStatement( builder.errors.push({ reason: `JavaScript 'with' syntax is not supported`, description: `'with' syntax is considered deprecated and removed from JavaScript standards, consider alternatives`, - severity: ErrorSeverity.UnsupportedJS, category: ErrorCategory.UnsupportedSyntax, loc: stmtPath.node.loc ?? null, suggestions: null, @@ -1415,7 +1442,6 @@ function lowerStatement( builder.errors.push({ reason: 'Inline `class` declarations are not supported', description: `Move class declarations outside of components/hooks`, - severity: ErrorSeverity.UnsupportedJS, category: ErrorCategory.UnsupportedSyntax, loc: stmtPath.node.loc ?? null, suggestions: null, @@ -1445,7 +1471,6 @@ function lowerStatement( builder.errors.push({ reason: 'JavaScript `import` and `export` statements may only appear at the top level of a module', - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: stmtPath.node.loc ?? null, suggestions: null, @@ -1461,7 +1486,6 @@ function lowerStatement( builder.errors.push({ reason: 'TypeScript `namespace` statements may only appear at the top level of a module', - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: stmtPath.node.loc ?? null, suggestions: null, @@ -1540,7 +1564,6 @@ function lowerObjectPropertyKey( */ builder.errors.push({ reason: `(BuildHIR::lowerExpression) Expected Identifier, got ${key.type} key in ObjectExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: key.node.loc ?? null, suggestions: null, @@ -1566,7 +1589,6 @@ function lowerObjectPropertyKey( builder.errors.push({ reason: `(BuildHIR::lowerExpression) Expected Identifier, got ${key.type} key in ObjectExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: key.node.loc ?? null, suggestions: null, @@ -1624,7 +1646,6 @@ function lowerExpression( if (!valuePath.isExpression()) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${valuePath.type} values in ObjectExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: valuePath.node.loc ?? null, suggestions: null, @@ -1651,7 +1672,6 @@ function lowerExpression( if (propertyPath.node.kind !== 'method') { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${propertyPath.node.kind} functions in ObjectExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: propertyPath.node.loc ?? null, suggestions: null, @@ -1673,7 +1693,6 @@ function lowerExpression( } else { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${propertyPath.type} properties in ObjectExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: propertyPath.node.loc ?? null, suggestions: null, @@ -1707,7 +1726,6 @@ function lowerExpression( } else { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${element.type} elements in ArrayExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: element.node.loc ?? null, suggestions: null, @@ -1728,7 +1746,6 @@ function lowerExpression( builder.errors.push({ reason: `Expected an expression as the \`new\` expression receiver (v8 intrinsics are not supported)`, description: `Got a \`${calleePath.node.type}\``, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: calleePath.node.loc ?? null, suggestions: null, @@ -1755,7 +1772,6 @@ function lowerExpression( if (!calleePath.isExpression()) { builder.errors.push({ reason: `Expected Expression, got ${calleePath.type} in CallExpression (v8 intrinsics not supported). This error is likely caused by a bug in React Compiler. Please file an issue`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: calleePath.node.loc ?? null, suggestions: null, @@ -1790,7 +1806,6 @@ function lowerExpression( if (!leftPath.isExpression()) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Expected Expression, got ${leftPath.type} lval in BinaryExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: leftPath.node.loc ?? null, suggestions: null, @@ -1803,7 +1818,6 @@ function lowerExpression( if (operator === '|>') { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Pipe operator not supported`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: leftPath.node.loc ?? null, suggestions: null, @@ -1833,7 +1847,6 @@ function lowerExpression( if (last === null) { builder.errors.push({ reason: `Expected sequence expression to have at least one expression`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: expr.node.loc ?? null, suggestions: null, @@ -2046,7 +2059,6 @@ function lowerExpression( builder.errors.push({ reason: `(BuildHIR::lowerExpression) Unsupported syntax on the left side of an AssignmentExpression`, description: `Expected an LVal, got: ${left.type}`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: left.node.loc ?? null, suggestions: null, @@ -2075,7 +2087,6 @@ function lowerExpression( if (binaryOperator == null) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${operator} operators in AssignmentExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: expr.node.loc ?? null, suggestions: null, @@ -2175,7 +2186,6 @@ function lowerExpression( default: { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Expected Identifier or MemberExpression, got ${expr.type} lval in AssignmentExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: expr.node.loc ?? null, suggestions: null, @@ -2215,7 +2225,6 @@ function lowerExpression( if (!attribute.isJSXAttribute()) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${attribute.type} attributes in JSXElement`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: attribute.node.loc ?? null, suggestions: null, @@ -2229,7 +2238,6 @@ function lowerExpression( if (propName.indexOf(':') !== -1) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Unexpected colon in attribute name \`${propName}\``, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: namePath.node.loc ?? null, suggestions: null, @@ -2239,7 +2247,13 @@ function lowerExpression( CompilerError.invariant(namePath.isJSXNamespacedName(), { reason: 'Refinement', description: null, - loc: namePath.node.loc ?? null, + details: [ + { + kind: 'error', + loc: namePath.node.loc ?? null, + message: null, + }, + ], suggestions: null, }); const namespace = namePath.node.namespace.name; @@ -2260,7 +2274,6 @@ function lowerExpression( if (!valueExpr.isJSXExpressionContainer()) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${valueExpr.type} attribute values in JSXElement`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: valueExpr.node?.loc ?? null, suggestions: null, @@ -2271,7 +2284,6 @@ function lowerExpression( if (!expression.isExpression()) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${expression.type} expressions in JSXExpressionContainer within JSXElement`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: valueExpr.node.loc ?? null, suggestions: null, @@ -2295,8 +2307,14 @@ function lowerExpression( // This is already checked in builder.resolveIdentifier CompilerError.invariant(tagIdentifier.kind !== 'Identifier', { reason: `<${tagName}> tags should be module-level imports`, - loc: openingIdentifier.node.loc ?? GeneratedSource, description: null, + details: [ + { + kind: 'error', + loc: openingIdentifier.node.loc ?? GeneratedSource, + message: null, + }, + ], suggestions: null, }); } @@ -2329,8 +2347,7 @@ function lowerExpression( for (const [name, locations] of Object.entries(fbtLocations)) { if (locations.length > 1) { CompilerError.throwDiagnostic({ - severity: ErrorSeverity.Todo, - category: ErrorCategory.FBT, + category: ErrorCategory.Todo, reason: 'Support duplicate fbt tags', description: `Support \`<${tagName}>\` tags with multiple \`<${tagName}:${name}>\` values`, details: locations.map(loc => { @@ -2391,7 +2408,6 @@ function lowerExpression( builder.errors.push({ reason: '(BuildHIR::lowerExpression) Handle tagged template with interpolations', - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -2402,7 +2418,13 @@ function lowerExpression( reason: "there should be only one quasi as we don't support interpolations yet", description: null, - loc: expr.node.loc ?? null, + details: [ + { + kind: 'error', + loc: expr.node.loc ?? null, + message: null, + }, + ], suggestions: null, }); const value = expr.get('quasi').get('quasis').at(0)!.node.value; @@ -2410,7 +2432,6 @@ function lowerExpression( builder.errors.push({ reason: '(BuildHIR::lowerExpression) Handle tagged template where cooked value is different from raw value', - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -2433,7 +2454,6 @@ function lowerExpression( if (subexprs.length !== quasis.length - 1) { builder.errors.push({ reason: `Unexpected quasi and subexpression lengths in template literal`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: exprPath.node.loc ?? null, suggestions: null, @@ -2444,7 +2464,6 @@ function lowerExpression( if (subexprs.some(e => !e.isExpression())) { builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Handle TSType in TemplateLiteral.`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -2487,7 +2506,6 @@ function lowerExpression( } else { builder.errors.push({ reason: `Only object properties can be deleted`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: expr.node.loc ?? null, suggestions: [ @@ -2503,7 +2521,6 @@ function lowerExpression( } else if (expr.node.operator === 'throw') { builder.errors.push({ reason: `Throw expressions are not supported`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: expr.node.loc ?? null, suggestions: [ @@ -2625,7 +2642,6 @@ function lowerExpression( if (!argument.isIdentifier()) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle UpdateExpression with ${argument.type} argument`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -2634,7 +2650,6 @@ function lowerExpression( } else if (builder.isContextIdentifier(argument)) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle UpdateExpression to variables captured within lambdas.`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -2652,10 +2667,9 @@ function lowerExpression( * lowerIdentifierForAssignment should have already reported an error if it returned null, * we check here just in case */ - if (!builder.errors.hasErrors()) { + if (!builder.errors.hasAnyErrors()) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Found an invalid UpdateExpression without a previously reported error`, - severity: ErrorSeverity.Invariant, category: ErrorCategory.Invariant, loc: exprLoc, suggestions: null, @@ -2665,7 +2679,6 @@ function lowerExpression( } else if (lvalue.kind === 'Global') { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Support UpdateExpression where argument is a global`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprLoc, suggestions: null, @@ -2721,7 +2734,6 @@ function lowerExpression( builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle MetaProperty expressions other than import.meta`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -2731,7 +2743,6 @@ function lowerExpression( default: { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${exprPath.type} expressions`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -2811,7 +2822,13 @@ function lowerOptionalMemberExpression( CompilerError.invariant(object !== null, { reason: 'Satisfy type checker', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); @@ -3029,7 +3046,6 @@ function lowerReorderableExpression( if (!isReorderableExpression(builder, expr, true)) { builder.errors.push({ reason: `(BuildHIR::node.lowerReorderableExpression) Expression type \`${expr.type}\` cannot be safely reordered`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: expr.node.loc ?? null, suggestions: null, @@ -3226,7 +3242,6 @@ function lowerArguments( } else { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${argPath.type} arguments in CallExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: argPath.node.loc ?? null, suggestions: null, @@ -3262,7 +3277,6 @@ function lowerMemberExpression( } else { builder.errors.push({ reason: `(BuildHIR::lowerMemberExpression) Handle ${propertyNode.type} property`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: propertyNode.node.loc ?? null, suggestions: null, @@ -3284,7 +3298,6 @@ function lowerMemberExpression( if (!propertyNode.isExpression()) { builder.errors.push({ reason: `(BuildHIR::lowerMemberExpression) Expected Expression, got ${propertyNode.type} property`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: propertyNode.node.loc ?? null, suggestions: null, @@ -3344,7 +3357,6 @@ function lowerJsxElementName( builder.errors.push({ reason: `Expected JSXNamespacedName to have no colons in the namespace or name`, description: `Got \`${namespace}\` : \`${name}\``, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: exprPath.node.loc ?? null, suggestions: null, @@ -3359,7 +3371,6 @@ function lowerJsxElementName( } else { builder.errors.push({ reason: `(BuildHIR::lowerJsxElementName) Handle ${exprPath.type} tags`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -3385,7 +3396,13 @@ function lowerJsxMemberExpression( CompilerError.invariant(object.isJSXIdentifier(), { reason: `TypeScript refinement fail: expected 'JsxIdentifier', got \`${object.node.type}\``, description: null, - loc: object.node.loc ?? null, + details: [ + { + kind: 'error', + loc: object.node.loc ?? null, + message: null, + }, + ], suggestions: null, }); @@ -3427,7 +3444,13 @@ function lowerJsxElement( CompilerError.invariant(expression.isExpression(), { reason: `(BuildHIR::lowerJsxElement) Expected Expression but found ${expression.type}!`, description: null, - loc: expression.node.loc ?? null, + details: [ + { + kind: 'error', + loc: expression.node.loc ?? null, + message: null, + }, + ], suggestions: null, }); return lowerExpressionToTemporary(builder, expression); @@ -3458,7 +3481,6 @@ function lowerJsxElement( } else { builder.errors.push({ reason: `(BuildHIR::lowerJsxElement) Unhandled JsxElement, got: ${exprPath.type}`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -3646,7 +3668,6 @@ function lowerIdentifier( reason: `The 'eval' function is not supported`, description: 'Eval is an anti-pattern in JavaScript, and the code executed cannot be evaluated by React Compiler', - severity: ErrorSeverity.UnsupportedJS, category: ErrorCategory.UnsupportedSyntax, loc: exprPath.node.loc ?? null, suggestions: null, @@ -3703,7 +3724,6 @@ function lowerIdentifierForAssignment( // Else its an internal error bc we couldn't find the binding builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Could not find binding for declaration.`, - severity: ErrorSeverity.Invariant, category: ErrorCategory.Invariant, loc: path.node.loc ?? null, suggestions: null, @@ -3716,7 +3736,6 @@ function lowerIdentifierForAssignment( ) { builder.errors.push({ reason: `Cannot reassign a \`const\` variable`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: path.node.loc ?? null, description: @@ -3774,7 +3793,6 @@ function lowerAssignment( if (kind === InstructionKind.Const && !isHoistedIdentifier) { builder.errors.push({ reason: `Expected \`const\` declaration not to be reassigned`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: lvalue.node.loc ?? null, suggestions: null, @@ -3789,7 +3807,6 @@ function lowerAssignment( ) { builder.errors.push({ reason: `Unexpected context variable kind`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: lvalue.node.loc ?? null, suggestions: null, @@ -3834,7 +3851,13 @@ function lowerAssignment( CompilerError.invariant(kind === InstructionKind.Reassign, { reason: 'MemberExpression may only appear in an assignment expression', description: null, - loc: lvaluePath.node.loc ?? null, + details: [ + { + kind: 'error', + loc: lvaluePath.node.loc ?? null, + message: null, + }, + ], suggestions: null, }); const lvalue = lvaluePath as NodePath; @@ -3861,7 +3884,6 @@ function lowerAssignment( } else { builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Handle ${property.type} properties in MemberExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: property.node.loc ?? null, suggestions: null, @@ -3874,7 +3896,6 @@ function lowerAssignment( builder.errors.push({ reason: '(BuildHIR::lowerAssignment) Expected private name to appear as a non-computed property', - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: property.node.loc ?? null, suggestions: null, @@ -3940,7 +3961,6 @@ function lowerAssignment( continue; } else if (identifier.kind === 'Global') { builder.errors.push({ - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, reason: 'Expected reassignment of globals to enable forceTemporaries', @@ -3980,7 +4000,6 @@ function lowerAssignment( continue; } else if (identifier.kind === 'Global') { builder.errors.push({ - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, reason: 'Expected reassignment of globals to enable forceTemporaries', @@ -4054,7 +4073,6 @@ function lowerAssignment( if (!argument.isIdentifier()) { builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Handle ${argument.node.type} rest element in ObjectPattern`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: argument.node.loc ?? null, suggestions: null, @@ -4086,7 +4104,6 @@ function lowerAssignment( continue; } else if (identifier.kind === 'Global') { builder.errors.push({ - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, reason: 'Expected reassignment of globals to enable forceTemporaries', @@ -4104,7 +4121,6 @@ function lowerAssignment( if (!property.isObjectProperty()) { builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Handle ${property.type} properties in ObjectPattern`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: property.node.loc ?? null, suggestions: null, @@ -4114,7 +4130,6 @@ function lowerAssignment( if (property.node.computed) { builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Handle computed properties in ObjectPattern`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: property.node.loc ?? null, suggestions: null, @@ -4129,7 +4144,6 @@ function lowerAssignment( if (!element.isLVal()) { builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Expected object property value to be an LVal, got: ${element.type}`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: element.node.loc ?? null, suggestions: null, @@ -4152,7 +4166,6 @@ function lowerAssignment( continue; } else if (identifier.kind === 'Global') { builder.errors.push({ - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, reason: 'Expected reassignment of globals to enable forceTemporaries', @@ -4302,7 +4315,6 @@ function lowerAssignment( default: { builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Handle ${lvaluePath.type} assignments`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: lvaluePath.node.loc ?? null, suggestions: null, diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildReactiveScopeTerminalsHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildReactiveScopeTerminalsHIR.ts index 6f69af4b4f2..423c046221c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildReactiveScopeTerminalsHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildReactiveScopeTerminalsHIR.ts @@ -234,7 +234,14 @@ function pushEndScopeTerminal( const fallthroughId = context.fallthroughs.get(scope.id); CompilerError.invariant(fallthroughId != null, { reason: 'Expected scope to exist', - loc: GeneratedSource, + description: null, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }); context.rewrites.push({ kind: 'EndScope', diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts index a11822538f5..f249466431d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts @@ -269,7 +269,14 @@ class PropertyPathRegistry { CompilerError.invariant(reactive === rootNode.fullPath.reactive, { reason: '[HoistablePropertyLoads] Found inconsistencies in `reactive` flag when deduping identifier reads within the same scope', - loc: identifier.loc, + description: null, + details: [ + { + kind: 'error', + loc: identifier.loc, + message: null, + }, + ], }); } return rootNode; @@ -498,7 +505,14 @@ function propagateNonNull( if (node == null) { CompilerError.invariant(false, { reason: `Bad node ${nodeId}, kind: ${direction}`, - loc: GeneratedSource, + description: null, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }); } const neighbors = Array.from( @@ -570,7 +584,14 @@ function propagateNonNull( CompilerError.invariant(i++ < 100, { reason: '[CollectHoistablePropertyLoads] fixed point iteration did not terminate after 100 loops', - loc: GeneratedSource, + description: null, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }); changed = false; @@ -602,7 +623,13 @@ export function assertNonNull, U>( CompilerError.invariant(value != null, { reason: 'Unexpected null', description: source != null ? `(from ${source})` : null, - loc: GeneratedSource, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }); return value; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectOptionalChainDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectOptionalChainDependencies.ts index 75dad4c1bfe..22e2a63964a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectOptionalChainDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectOptionalChainDependencies.ts @@ -186,7 +186,13 @@ function matchOptionalTestBlock( reason: '[OptionalChainDeps] Inconsistent optional chaining property load', description: `Test=${printIdentifier(terminal.test.identifier)} PropertyLoad base=${printIdentifier(propertyLoad.value.object.identifier)}`, - loc: propertyLoad.loc, + details: [ + { + kind: 'error', + loc: propertyLoad.loc, + message: null, + }, + ], }, ); @@ -194,7 +200,14 @@ function matchOptionalTestBlock( storeLocal.value.identifier.id === propertyLoad.lvalue.identifier.id, { reason: '[OptionalChainDeps] Unexpected storeLocal', - loc: propertyLoad.loc, + description: null, + details: [ + { + kind: 'error', + loc: propertyLoad.loc, + message: null, + }, + ], }, ); if ( @@ -211,7 +224,14 @@ function matchOptionalTestBlock( alternate.instructions[1].value.kind === 'StoreLocal', { reason: 'Unexpected alternate structure', - loc: terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: null, + }, + ], }, ); @@ -247,7 +267,14 @@ function traverseOptionalBlock( if (maybeTest.terminal.kind === 'branch') { CompilerError.invariant(optional.terminal.optional, { reason: '[OptionalChainDeps] Expect base case to be always optional', - loc: optional.terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: optional.terminal.loc, + message: null, + }, + ], }); /** * Optional base expressions are currently within value blocks which cannot @@ -285,7 +312,14 @@ function traverseOptionalBlock( maybeTest.instructions.at(-1)!.lvalue.identifier.id, { reason: '[OptionalChainDeps] Unexpected test expression', - loc: maybeTest.terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: maybeTest.terminal.loc, + message: null, + }, + ], }, ); baseObject = { @@ -374,7 +408,14 @@ function traverseOptionalBlock( reason: '[OptionalChainDeps] Unexpected instructions an inner optional block. ' + 'This indicates that the compiler may be incorrectly concatenating two unrelated optional chains', - loc: optional.terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: optional.terminal.loc, + message: null, + }, + ], }); } const matchConsequentResult = matchOptionalTestBlock(test, context.blocks); @@ -387,7 +428,13 @@ function traverseOptionalBlock( { reason: '[OptionalChainDeps] Unexpected optional goto-fallthrough', description: `${matchConsequentResult.consequentGoto} != ${optional.terminal.fallthrough}`, - loc: optional.terminal.loc, + details: [ + { + kind: 'error', + loc: optional.terminal.loc, + message: null, + }, + ], }, ); const load = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/ComputeUnconditionalBlocks.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/ComputeUnconditionalBlocks.ts index 627686b4ecf..e3582c67544 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/ComputeUnconditionalBlocks.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/ComputeUnconditionalBlocks.ts @@ -24,7 +24,14 @@ export function computeUnconditionalBlocks(fn: HIRFunction): Set { CompilerError.invariant(!unconditionalBlocks.has(current), { reason: 'Internal error: non-terminating loop in ComputeUnconditionalBlocks', - loc: null, + description: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); unconditionalBlocks.add(current); diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/DeriveMinimalDependenciesHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/DeriveMinimalDependenciesHIR.ts index 7819ab39b2c..4cdd77f57ff 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/DeriveMinimalDependenciesHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/DeriveMinimalDependenciesHIR.ts @@ -54,7 +54,14 @@ export class ReactiveScopeDependencyTreeHIR { prevAccessType == null || prevAccessType === accessType, { reason: 'Conflicting access types', - loc: GeneratedSource, + description: null, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }, ); let nextNode = currNode.properties.get(path[i].property); @@ -90,7 +97,13 @@ export class ReactiveScopeDependencyTreeHIR { CompilerError.invariant(reactive === rootNode.reactive, { reason: '[DeriveMinimalDependenciesHIR] Conflicting reactive root flag', description: `Identifier ${printIdentifier(identifier)}`, - loc: GeneratedSource, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }); } return rootNode; diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Dominator.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Dominator.ts index 13118621fe5..4cb79d2b370 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Dominator.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Dominator.ts @@ -89,7 +89,13 @@ export class Dominator { CompilerError.invariant(dominator !== undefined, { reason: 'Unknown node', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); return dominator === id ? null : dominator; @@ -130,7 +136,13 @@ export class PostDominator { CompilerError.invariant(dominator !== undefined, { reason: 'Unknown node', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); return dominator === id ? null : dominator; @@ -175,7 +187,13 @@ function computeImmediateDominators(graph: Graph): Map { CompilerError.invariant(newIdom !== null, { reason: `At least one predecessor must have been visited for block ${id}`, description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); 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 421b204e655..e38a49cb56a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -750,7 +750,13 @@ export class Environment { CompilerError.invariant(!this.#globals.has(hookName), { reason: `[Globals] Found existing definition in global registry for custom hook ${hookName}`, description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); this.#globals.set( @@ -783,7 +789,14 @@ export class Environment { CompilerError.invariant(code != null, { reason: 'Expected Environment to be initialized with source code when a Flow type provider is specified', - loc: null, + description: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], }); this.#flowTypeEnvironment.init(this, code); } else { @@ -794,7 +807,14 @@ export class Environment { get typeContext(): FlowTypeEnv { CompilerError.invariant(this.#flowTypeEnvironment != null, { reason: 'Flow type environment not initialized', - loc: null, + description: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], }); return this.#flowTypeEnvironment; } @@ -1044,7 +1064,13 @@ export class Environment { CompilerError.invariant(shape !== undefined, { reason: `[HIR] Forget internal error: cannot resolve shape ${shapeId}`, description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); return shape.properties.get('*') ?? null; @@ -1069,7 +1095,13 @@ export class Environment { CompilerError.invariant(shape !== undefined, { reason: `[HIR] Forget internal error: cannot resolve shape ${shapeId}`, description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); if (typeof property === 'string') { @@ -1094,7 +1126,13 @@ export class Environment { CompilerError.invariant(shape !== undefined, { reason: `[HIR] Forget internal error: cannot resolve shape ${shapeId}`, description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); return shape.functionType; diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/FindContextIdentifiers.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/FindContextIdentifiers.ts index ecc534eb729..f079933c048 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/FindContextIdentifiers.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/FindContextIdentifiers.ts @@ -184,7 +184,13 @@ function handleAssignment( CompilerError.invariant(valuePath.isLVal(), { reason: `[FindContextIdentifiers] Expected object property value to be an LVal, got: ${valuePath.type}`, description: null, - loc: valuePath.node.loc ?? GeneratedSource, + details: [ + { + kind: 'error', + loc: valuePath.node.loc ?? GeneratedSource, + message: null, + }, + ], suggestions: null, }); handleAssignment(currentFn, identifiers, valuePath); @@ -192,7 +198,13 @@ function handleAssignment( CompilerError.invariant(property.isRestElement(), { reason: `[FindContextIdentifiers] Invalid assumptions for babel types.`, description: null, - loc: property.node.loc ?? GeneratedSource, + details: [ + { + kind: 'error', + loc: property.node.loc ?? GeneratedSource, + message: null, + }, + ], suggestions: null, }); handleAssignment(currentFn, identifiers, property); diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index 6b3ba6f94c8..582ef93cf34 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -1314,8 +1314,14 @@ export function makeIdentifierName(name: string): ValidatedIdentifier { } else { CompilerError.invariant(t.isValidIdentifier(name), { reason: `Expected a valid identifier name`, - loc: GeneratedSource, description: `\`${name}\` is not a valid JavaScript identifier`, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], suggestions: null, }); } @@ -1334,8 +1340,14 @@ export function makeIdentifierName(name: string): ValidatedIdentifier { export function promoteTemporary(identifier: Identifier): void { CompilerError.invariant(identifier.name === null, { reason: `Expected a temporary (unnamed) identifier`, - loc: GeneratedSource, description: `Identifier already has a name, \`${identifier.name}\``, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], suggestions: null, }); identifier.name = { @@ -1358,8 +1370,14 @@ export function isPromotedTemporary(name: string): boolean { export function promoteTemporaryJsxTag(identifier: Identifier): void { CompilerError.invariant(identifier.name === null, { reason: `Expected a temporary (unnamed) identifier`, - loc: GeneratedSource, description: `Identifier already has a name, \`${identifier.name}\``, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], suggestions: null, }); identifier.name = { @@ -1527,7 +1545,13 @@ export function isMutableEffect( CompilerError.invariant(false, { reason: 'Unexpected unknown effect', description: null, - loc: location, + details: [ + { + kind: 'error', + loc: location, + message: null, + }, + ], suggestions: null, }); } @@ -1660,7 +1684,13 @@ export function makeBlockId(id: number): BlockId { CompilerError.invariant(id >= 0 && Number.isInteger(id), { reason: 'Expected block id to be a non-negative integer', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); return id as BlockId; @@ -1677,7 +1707,13 @@ export function makeScopeId(id: number): ScopeId { CompilerError.invariant(id >= 0 && Number.isInteger(id), { reason: 'Expected block id to be a non-negative integer', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); return id as ScopeId; @@ -1694,7 +1730,13 @@ export function makeIdentifierId(id: number): IdentifierId { CompilerError.invariant(id >= 0 && Number.isInteger(id), { reason: 'Expected identifier id to be a non-negative integer', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); return id as IdentifierId; @@ -1711,7 +1753,13 @@ export function makeDeclarationId(id: number): DeclarationId { CompilerError.invariant(id >= 0 && Number.isInteger(id), { reason: 'Expected declaration id to be a non-negative integer', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); return id as DeclarationId; @@ -1728,7 +1776,13 @@ export function makeInstructionId(id: number): InstructionId { CompilerError.invariant(id >= 0 && Number.isInteger(id), { reason: 'Expected instruction id to be a non-negative integer', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); return id as InstructionId; diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts index 78c756f812d..d3ecb2abdcd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts @@ -7,7 +7,7 @@ import {Binding, NodePath} from '@babel/traverse'; import * as t from '@babel/types'; -import {CompilerError, ErrorCategory, ErrorSeverity} from '../CompilerError'; +import {CompilerError, ErrorCategory} from '../CompilerError'; import {Environment} from './Environment'; import { BasicBlock, @@ -309,8 +309,7 @@ export default class HIRBuilder { resolveBinding(node: t.Identifier): Identifier { if (node.name === 'fbt') { CompilerError.throwDiagnostic({ - severity: ErrorSeverity.Todo, - category: ErrorCategory.FBT, + category: ErrorCategory.Todo, reason: 'Support local variables named `fbt`', description: 'Local variables named `fbt` may conflict with the fbt plugin and are not yet supported', @@ -325,7 +324,6 @@ export default class HIRBuilder { } if (node.name === 'this') { CompilerError.throwDiagnostic({ - severity: ErrorSeverity.UnsupportedJS, category: ErrorCategory.UnsupportedSyntax, reason: '`this` is not supported syntax', description: @@ -509,7 +507,13 @@ export default class HIRBuilder { { reason: 'Mismatched label', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }, ); @@ -532,7 +536,13 @@ export default class HIRBuilder { { reason: 'Mismatched label', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }, ); @@ -568,7 +578,13 @@ export default class HIRBuilder { { reason: 'Mismatched loops', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }, ); @@ -593,7 +609,13 @@ export default class HIRBuilder { CompilerError.invariant(false, { reason: 'Expected a loop or switch to be in scope', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); } @@ -614,7 +636,13 @@ export default class HIRBuilder { CompilerError.invariant(false, { reason: 'Continue may only refer to a labeled loop', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); } @@ -622,7 +650,13 @@ export default class HIRBuilder { CompilerError.invariant(false, { reason: 'Expected a loop to be in scope', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); } @@ -645,7 +679,13 @@ function _shrink(func: HIR): void { CompilerError.invariant(block != null, { reason: `expected block ${blockId} to exist`, description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); target = getTargetIfIndirection(block); @@ -777,7 +817,13 @@ function getReversePostorderedBlocks(func: HIR): HIR['blocks'] { CompilerError.invariant(block != null, { reason: '[HIRBuilder] Unexpected null block', description: `expected block ${blockId} to exist`, - loc: GeneratedSource, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }); const successors = [...eachTerminalSuccessor(block.terminal)].reverse(); const fallthrough = terminalFallthrough(block.terminal); @@ -833,7 +879,13 @@ export function markInstructionIds(func: HIR): void { CompilerError.invariant(!visited.has(instr), { reason: `${printInstruction(instr)} already visited!`, description: null, - loc: instr.loc, + details: [ + { + kind: 'error', + loc: instr.loc, + message: null, + }, + ], suggestions: null, }); visited.add(instr); @@ -856,7 +908,13 @@ export function markPredecessors(func: HIR): void { CompilerError.invariant(block != null, { reason: 'unexpected missing block', description: `block ${blockId}`, - loc: GeneratedSource, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }); if (prevBlock) { block.preds.add(prevBlock.id); diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/MergeConsecutiveBlocks.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/MergeConsecutiveBlocks.ts index 881e4e93ffc..da8a5a9f192 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/MergeConsecutiveBlocks.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/MergeConsecutiveBlocks.ts @@ -61,7 +61,13 @@ export function mergeConsecutiveBlocks(fn: HIRFunction): void { CompilerError.invariant(predecessor !== undefined, { reason: `Expected predecessor ${predecessorId} to exist`, description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); if (predecessor.terminal.kind !== 'goto' || predecessor.kind !== 'block') { @@ -77,7 +83,13 @@ export function mergeConsecutiveBlocks(fn: HIRFunction): void { CompilerError.invariant(phi.operands.size === 1, { reason: `Found a block with a single predecessor but where a phi has multiple (${phi.operands.size}) operands`, description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); const operand = Array.from(phi.operands.values())[0]!; diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts index 2c626243e70..beaff321e26 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts @@ -119,7 +119,13 @@ function parseAliasingSignatureConfig( CompilerError.invariant(!lifetimes.has(temp), { reason: `Invalid type configuration for module`, description: `Expected aliasing signature to have unique names for receiver, params, rest, returns, and temporaries in module '${moduleName}'`, - loc, + details: [ + { + kind: 'error', + loc, + message: null, + }, + ], }); const place = signatureArgument(lifetimes.size); lifetimes.set(temp, place); @@ -130,7 +136,13 @@ function parseAliasingSignatureConfig( CompilerError.invariant(place != null, { reason: `Invalid type configuration for module`, description: `Expected aliasing signature effects to reference known names from receiver/params/rest/returns/temporaries, but '${temp}' is not a known name in '${moduleName}'`, - loc, + details: [ + { + kind: 'error', + loc, + message: null, + }, + ], }); return place; } @@ -265,7 +277,13 @@ function addShape( CompilerError.invariant(!registry.has(id), { reason: `[ObjectShape] Could not add shape to registry: name ${id} already exists.`, description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); registry.set(id, shape); diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts index a8fb837262e..197e486e8af 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts @@ -596,7 +596,13 @@ export function printInstructionValue(instrValue: ReactiveValue): string { { reason: 'Bad assumption about quasi length.', description: null, - loc: instrValue.loc, + details: [ + { + kind: 'error', + loc: instrValue.loc, + message: null, + }, + ], suggestions: null, }, ); @@ -865,8 +871,15 @@ export function printManualMemoDependency( } else { CompilerError.invariant(val.root.value.identifier.name?.kind === 'named', { reason: 'DepsValidation: expected named local variable in depslist', + description: null, suggestions: null, - loc: val.root.value.loc, + details: [ + { + kind: 'error', + loc: val.root.value.loc, + message: null, + }, + ], }); rootStr = nameOnly ? val.root.value.identifier.name.value diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts index 91b7712b881..bfffd464ead 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts @@ -86,7 +86,14 @@ export function propagateScopeDependenciesHIR(fn: HIRFunction): void { const hoistables = hoistablePropertyLoads.get(scope.id); CompilerError.invariant(hoistables != null, { reason: '[PropagateScopeDependencies] Scope not found in tracked blocks', - loc: GeneratedSource, + description: null, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }); /** * Step 2: Calculate hoistable dependencies. @@ -428,7 +435,14 @@ export class DependencyCollectionContext { const scopedDependencies = this.#dependencies.value; CompilerError.invariant(scopedDependencies != null, { reason: '[PropagateScopeDeps]: Unexpected scope mismatch', - loc: scope.loc, + description: null, + details: [ + { + kind: 'error', + loc: scope.loc, + message: null, + }, + ], }); // Restore context of previous scope diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PruneUnusedLabelsHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PruneUnusedLabelsHIR.ts index f0c488c3e1e..6eedef7bba6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PruneUnusedLabelsHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PruneUnusedLabelsHIR.ts @@ -53,7 +53,14 @@ export function pruneUnusedLabelsHIR(fn: HIRFunction): void { next.phis.size === 0 && fallthrough.phis.size === 0, { reason: 'Unexpected phis when merging label blocks', - loc: label.terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: label.terminal.loc, + message: null, + }, + ], }, ); @@ -64,7 +71,14 @@ export function pruneUnusedLabelsHIR(fn: HIRFunction): void { fallthrough.preds.has(nextId), { reason: 'Unexpected block predecessors when merging label blocks', - loc: label.terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: label.terminal.loc, + message: null, + }, + ], }, ); diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/ScopeDependencyUtils.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/ScopeDependencyUtils.ts index 6e9ff08b862..04afe390b0c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/ScopeDependencyUtils.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/ScopeDependencyUtils.ts @@ -202,8 +202,14 @@ function writeOptionalDependency( CompilerError.invariant(firstOptional !== -1, { reason: '[ScopeDependencyUtils] Internal invariant broken: expected optional path', - loc: dep.identifier.loc, description: null, + details: [ + { + kind: 'error', + loc: dep.identifier.loc, + message: null, + }, + ], suggestions: null, }); if (firstOptional === dep.path.length - 1) { @@ -239,7 +245,13 @@ function writeOptionalDependency( CompilerError.invariant(testIdentifier !== null, { reason: 'Satisfy type checker', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Types.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Types.ts index 53eb8a779d7..cdb1a600c79 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Types.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Types.ts @@ -87,7 +87,13 @@ export function makeTypeId(id: number): TypeId { CompilerError.invariant(id >= 0 && Number.isInteger(id), { reason: 'Expected instruction id to be a non-negative integer', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); return id as TypeId; diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts index 64702c8abcd..af1cffe85fd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts @@ -1233,7 +1233,14 @@ export class ScopeBlockTraversal { CompilerError.invariant(blockInfo.scope.id === top, { reason: 'Expected traversed block fallthrough to match top-most active scope', - loc: block.instructions[0]?.loc ?? block.terminal.id, + description: null, + details: [ + { + kind: 'error', + loc: block.instructions[0]?.loc ?? block.terminal.id, + message: null, + }, + ], }); this.#activeScopes.pop(); } @@ -1247,7 +1254,14 @@ export class ScopeBlockTraversal { !this.blockInfos.has(block.terminal.fallthrough), { reason: 'Expected unique scope blocks and fallthroughs', - loc: block.terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: block.terminal.loc, + message: null, + }, + ], }, ); this.blockInfos.set(block.terminal.block, { diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts index 77a2bdcde59..7c94d81b9bd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts @@ -78,7 +78,14 @@ function lowerWithMutationAliasing(fn: HIRFunction): void { case 'Apply': { CompilerError.invariant(false, { reason: `[AnalyzeFunctions] Expected Apply effects to be replaced with more precise effects`, - loc: effect.function.loc, + description: null, + details: [ + { + kind: 'error', + loc: effect.function.loc, + message: null, + }, + ], }); } case 'Mutate': diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts index 412efcfe7ae..3eaeb5e4aa0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts @@ -5,12 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import { - CompilerDiagnostic, - CompilerError, - ErrorSeverity, - SourceLocation, -} from '..'; +import {CompilerDiagnostic, CompilerError, SourceLocation} from '..'; import {ErrorCategory} from '../CompilerError'; import { CallExpression, @@ -302,11 +297,10 @@ function extractManualMemoizationArgs( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.UseMemo, - severity: ErrorSeverity.InvalidReact, reason: `Expected a callback function to be passed to ${kind}`, description: `Expected a callback function to be passed to ${kind}`, suggestions: null, - }).withDetail({ + }).withDetails({ kind: 'error', loc: instr.value.loc, message: `Expected a callback function to be passed to ${kind}`, @@ -318,11 +312,10 @@ function extractManualMemoizationArgs( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.UseMemo, - severity: ErrorSeverity.InvalidReact, reason: `Unexpected spread argument to ${kind}`, description: `Unexpected spread argument to ${kind}`, suggestions: null, - }).withDetail({ + }).withDetails({ kind: 'error', loc: instr.value.loc, message: `Unexpected spread argument to ${kind}`, @@ -339,11 +332,10 @@ function extractManualMemoizationArgs( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.UseMemo, - severity: ErrorSeverity.InvalidReact, reason: `Expected the dependency list for ${kind} to be an array literal`, description: `Expected the dependency list for ${kind} to be an array literal`, suggestions: null, - }).withDetail({ + }).withDetails({ kind: 'error', loc: depsListPlace.loc, message: `Expected the dependency list for ${kind} to be an array literal`, @@ -358,11 +350,10 @@ function extractManualMemoizationArgs( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.UseMemo, - severity: ErrorSeverity.InvalidReact, reason: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`, description: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`, suggestions: null, - }).withDetail({ + }).withDetails({ kind: 'error', loc: dep.loc, message: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`, @@ -463,16 +454,15 @@ export function dropManualMemoization( if (!hasNonVoidReturn(funcToCheck.loweredFunc.func)) { errors.pushDiagnostic( CompilerDiagnostic.create({ - severity: ErrorSeverity.InvalidReact, category: ErrorCategory.UseMemo, reason: 'useMemo() callbacks must return a value', description: `This ${ manualMemo.loadInstr.value.kind === 'PropertyLoad' ? 'React.useMemo' : 'useMemo' - } callback doesn't return a value. useMemo is for computing and caching values, not for arbitrary side effects.`, + } callback doesn't return a value. useMemo is for computing and caching values, not for arbitrary side effects`, suggestions: null, - }).withDetail({ + }).withDetails({ kind: 'error', loc: instr.value.loc, message: 'useMemo() callbacks must return a value', @@ -505,11 +495,10 @@ export function dropManualMemoization( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.UseMemo, - severity: ErrorSeverity.InvalidReact, reason: `Expected the first argument to be an inline function expression`, description: `Expected the first argument to be an inline function expression`, suggestions: [], - }).withDetail({ + }).withDetails({ kind: 'error', loc: fnPlace.loc, message: `Expected the first argument to be an inline function expression`, @@ -624,7 +613,14 @@ function findOptionalPlaces(fn: HIRFunction): Set { default: { CompilerError.invariant(false, { reason: `Unexpected terminal in optional`, - loc: terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: `Unexpected ${terminal.kind} in optional`, + }, + ], }); } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts index 2997a449dea..999701c3255 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts @@ -438,7 +438,14 @@ function rewriteSplices( { reason: '[InferEffectDependencies] Internal invariant broken: expected block instructions to be sorted', - loc: originalInstrs[cursor].loc, + description: null, + details: [ + { + kind: 'error', + loc: originalInstrs[cursor].loc, + message: null, + }, + ], }, ); currBlock.instructions.push(originalInstrs[cursor]); @@ -447,7 +454,14 @@ function rewriteSplices( CompilerError.invariant(originalInstrs[cursor].id === rewrite.location, { reason: '[InferEffectDependencies] Internal invariant broken: splice location not found', - loc: originalInstrs[cursor].loc, + description: null, + details: [ + { + kind: 'error', + loc: originalInstrs[cursor].loc, + message: null, + }, + ], }); if (rewrite.kind === 'instr') { @@ -467,7 +481,14 @@ function rewriteSplices( { reason: '[InferEffectDependencies] Internal invariant broken: expected entry block to have a fallthrough', - loc: entryBlock.terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: entryBlock.terminal.loc, + message: null, + }, + ], }, ); const originalTerminal = currBlock.terminal; @@ -566,7 +587,14 @@ function inferMinimalDependencies( CompilerError.invariant(hoistableToFnEntry != null, { reason: '[InferEffectDependencies] Internal invariant broken: missing entry block', - loc: fnInstr.loc, + description: null, + details: [ + { + kind: 'error', + loc: fnInstr.loc, + message: null, + }, + ], }); const dependencies = inferDependencies( @@ -622,7 +650,14 @@ function inferDependencies( CompilerError.invariant(resultUnfiltered != null, { reason: '[InferEffectDependencies] Internal invariant broken: missing scope dependencies', - loc: fn.loc, + description: null, + details: [ + { + kind: 'error', + loc: fn.loc, + message: null, + }, + ], }); const fnContext = new Set(fn.context.map(dep => dep.identifier.id)); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts index a0e95932688..8b82e685b0b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts @@ -9,7 +9,6 @@ import { CompilerDiagnostic, CompilerError, Effect, - ErrorSeverity, SourceLocation, ValueKind, } from '..'; @@ -59,7 +58,6 @@ import { printInstruction, printInstructionValue, printPlace, - printSourceLocation, } from '../HIR/PrintHIR'; import {FunctionSignature} from '../HIR/ObjectShape'; import prettyFormat from 'pretty-format'; @@ -136,7 +134,13 @@ export function inferMutationAliasingEffects( reason: 'Expected React component to have not more than two parameters: one for props and for ref', description: null, - loc: fn.loc, + details: [ + { + kind: 'error', + loc: fn.loc, + message: null, + }, + ], suggestions: null, }); const [props, ref] = fn.params; @@ -203,7 +207,13 @@ export function inferMutationAliasingEffects( CompilerError.invariant(false, { reason: `[InferMutationAliasingEffects] Potential infinite loop`, description: `A value, temporary place, or effect was not cached properly`, - loc: fn.loc, + details: [ + { + kind: 'error', + loc: fn.loc, + message: null, + }, + ], }); } for (const [blockId, block] of fn.body.blocks) { @@ -358,7 +368,14 @@ function inferBlock( CompilerError.invariant(state.kind(handlerParam) != null, { reason: 'Expected catch binding to be intialized with a DeclareLocal Catch instruction', - loc: terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: null, + }, + ], }); const effects: Array = []; for (const instr of block.instructions) { @@ -455,10 +472,9 @@ function applySignature( : 'value'; const diagnostic = CompilerDiagnostic.create({ category: ErrorCategory.Immutability, - severity: ErrorSeverity.InvalidReact, reason: 'This value cannot be modified', - description: `${reason}.`, - }).withDetail({ + description: reason, + }).withDetails({ kind: 'error', loc: effect.value.loc, message: `${variable} cannot be modified`, @@ -467,7 +483,7 @@ function applySignature( effect.kind === 'Mutate' && effect.reason?.kind === 'AssignCurrentProperty' ) { - diagnostic.withDetail({ + diagnostic.withDetails({ kind: 'hint', message: `Hint: If this value is a Ref (value returned by \`useRef()\`), rename the variable to end in "Ref".`, }); @@ -509,7 +525,14 @@ function applySignature( ) { CompilerError.invariant(false, { reason: `Expected instruction lvalue to be initialized`, - loc: instruction.loc, + description: null, + details: [ + { + kind: 'error', + loc: instruction.loc, + message: null, + }, + ], }); } return effects.length !== 0 ? effects : null; @@ -538,7 +561,13 @@ function applyEffect( CompilerError.invariant(!initialized.has(effect.into.identifier.id), { reason: `Cannot re-initialize variable within an instruction`, description: `Re-initialized ${printPlace(effect.into)} in ${printAliasingEffect(effect)}`, - loc: effect.into.loc, + details: [ + { + kind: 'error', + loc: effect.into.loc, + message: null, + }, + ], }); initialized.add(effect.into.identifier.id); @@ -577,7 +606,13 @@ function applyEffect( CompilerError.invariant(!initialized.has(effect.into.identifier.id), { reason: `Cannot re-initialize variable within an instruction`, description: `Re-initialized ${printPlace(effect.into)} in ${printAliasingEffect(effect)}`, - loc: effect.into.loc, + details: [ + { + kind: 'error', + loc: effect.into.loc, + message: null, + }, + ], }); initialized.add(effect.into.identifier.id); @@ -637,7 +672,13 @@ function applyEffect( CompilerError.invariant(!initialized.has(effect.into.identifier.id), { reason: `Cannot re-initialize variable within an instruction`, description: `Re-initialized ${printPlace(effect.into)} in ${printAliasingEffect(effect)}`, - loc: effect.into.loc, + details: [ + { + kind: 'error', + loc: effect.into.loc, + message: null, + }, + ], }); initialized.add(effect.into.identifier.id); @@ -711,7 +752,13 @@ function applyEffect( { reason: `Expected destination value to already be initialized within this instruction for Alias effect`, description: `Destination ${printPlace(effect.into)} is not initialized in this instruction`, - loc: effect.into.loc, + details: [ + { + kind: 'error', + loc: effect.into.loc, + message: null, + }, + ], }, ); /* @@ -770,7 +817,13 @@ function applyEffect( CompilerError.invariant(!initialized.has(effect.into.identifier.id), { reason: `Cannot re-initialize variable within an instruction`, description: `Re-initialized ${printPlace(effect.into)} in ${printAliasingEffect(effect)}`, - loc: effect.into.loc, + details: [ + { + kind: 'error', + loc: effect.into.loc, + message: null, + }, + ], }); initialized.add(effect.into.identifier.id); @@ -1040,18 +1093,17 @@ function applyEffect( ); const diagnostic = CompilerDiagnostic.create({ category: ErrorCategory.Immutability, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot access variable before it is declared', - description: `${variable ?? 'This variable'} is accessed before it is declared, which prevents the earlier access from updating when this value changes over time.`, + description: `${variable ?? 'This variable'} is accessed before it is declared, which prevents the earlier access from updating when this value changes over time`, }); if (hoistedAccess != null && hoistedAccess.loc != effect.value.loc) { - diagnostic.withDetail({ + diagnostic.withDetails({ kind: 'error', loc: hoistedAccess.loc, message: `${variable ?? 'variable'} accessed before it is declared`, }); } - diagnostic.withDetail({ + diagnostic.withDetails({ kind: 'error', loc: effect.value.loc, message: `${variable ?? 'variable'} is declared here`, @@ -1080,10 +1132,9 @@ function applyEffect( : 'value'; const diagnostic = CompilerDiagnostic.create({ category: ErrorCategory.Immutability, - severity: ErrorSeverity.InvalidReact, reason: 'This value cannot be modified', - description: `${reason}.`, - }).withDetail({ + description: reason, + }).withDetails({ kind: 'error', loc: effect.value.loc, message: `${variable} cannot be modified`, @@ -1092,7 +1143,7 @@ function applyEffect( effect.kind === 'Mutate' && effect.reason?.kind === 'AssignCurrentProperty' ) { - diagnostic.withDetail({ + diagnostic.withDetails({ kind: 'hint', message: `Hint: If this value is a Ref (value returned by \`useRef()\`), rename the variable to end in "Ref".`, }); @@ -1173,7 +1224,13 @@ class InferenceState { reason: '[InferMutationAliasingEffects] Expected all top-level identifiers to be defined as variables, not values', description: null, - loc: value.loc, + details: [ + { + kind: 'error', + loc: value.loc, + message: null, + }, + ], suggestions: null, }); this.#values.set(value, kind); @@ -1184,7 +1241,13 @@ class InferenceState { CompilerError.invariant(values != null, { reason: `[InferMutationAliasingEffects] Expected value kind to be initialized`, description: `${printPlace(place)}`, - loc: place.loc, + details: [ + { + kind: 'error', + loc: place.loc, + message: 'this is uninitialized', + }, + ], suggestions: null, }); return Array.from(values); @@ -1196,7 +1259,13 @@ class InferenceState { CompilerError.invariant(values != null, { reason: `[InferMutationAliasingEffects] Expected value kind to be initialized`, description: `${printPlace(place)}`, - loc: place.loc, + details: [ + { + kind: 'error', + loc: place.loc, + message: 'this is uninitialized', + }, + ], suggestions: null, }); let mergedKind: AbstractValue | null = null; @@ -1208,7 +1277,13 @@ class InferenceState { CompilerError.invariant(mergedKind !== null, { reason: `[InferMutationAliasingEffects] Expected at least one value`, description: `No value found at \`${printPlace(place)}\``, - loc: place.loc, + details: [ + { + kind: 'error', + loc: place.loc, + message: null, + }, + ], suggestions: null, }); return mergedKind; @@ -1220,7 +1295,13 @@ class InferenceState { CompilerError.invariant(values != null, { reason: `[InferMutationAliasingEffects] Expected value for identifier to be initialized`, description: `${printIdentifier(value.identifier)}`, - loc: value.loc, + details: [ + { + kind: 'error', + loc: value.loc, + message: 'Expected value for identifier to be initialized', + }, + ], suggestions: null, }); this.#variables.set(place.identifier.id, new Set(values)); @@ -1231,7 +1312,13 @@ class InferenceState { CompilerError.invariant(values != null, { reason: `[InferMutationAliasingEffects] Expected value for identifier to be initialized`, description: `${printIdentifier(value.identifier)}`, - loc: value.loc, + details: [ + { + kind: 'error', + loc: value.loc, + message: 'Expected value for identifier to be initialized', + }, + ], suggestions: null, }); const prevValues = this.values(place); @@ -1244,11 +1331,15 @@ class InferenceState { // Defines (initializing or updating) a variable with a specific kind of value. define(place: Place, value: InstructionValue): void { CompilerError.invariant(this.#values.has(value), { - reason: `[InferMutationAliasingEffects] Expected value to be initialized at '${printSourceLocation( - value.loc, - )}'`, + reason: `[InferMutationAliasingEffects] Expected value to be initialized`, description: printInstructionValue(value), - loc: value.loc, + details: [ + { + kind: 'error', + loc: value.loc, + message: 'Expected value for identifier to be initialized', + }, + ], suggestions: null, }); this.#variables.set(place.identifier.id, new Set([value])); @@ -2056,11 +2147,10 @@ function computeSignatureForInstruction( place: value.value, error: CompilerDiagnostic.create({ category: ErrorCategory.Globals, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot reassign variables declared outside of the component/hook', description: `Variable ${variable} is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render)`, - }).withDetail({ + }).withDetails({ kind: 'error', loc: instr.loc, message: `${variable} cannot be reassigned`, @@ -2156,14 +2246,13 @@ function computeEffectsForLegacySignature( place: receiver, error: CompilerDiagnostic.create({ category: ErrorCategory.Purity, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot call impure function during render', description: (signature.canonicalName != null ? `\`${signature.canonicalName}\` is an impure function. ` : '') + 'Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent)', - }).withDetail({ + }).withDetails({ kind: 'error', loc, message: 'Cannot call impure function', @@ -2175,15 +2264,14 @@ function computeEffectsForLegacySignature( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.IncompatibleLibrary, - severity: ErrorSeverity.IncompatibleLibrary, reason: 'Use of incompatible library', description: [ 'This API returns functions which cannot be memoized without leading to stale UI. ' + 'To prevent this, by default React Compiler will skip memoizing this component/hook. ' + 'However, you may see issues if values from this API are passed to other components/hooks that are ' + - 'memoized.', + 'memoized', ].join(''), - }).withDetail({ + }).withDetails({ kind: 'error', loc: receiver.loc, message: signature.knownIncompatible, @@ -2683,7 +2771,13 @@ export function isKnownMutableEffect(effect: Effect): boolean { CompilerError.invariant(false, { reason: 'Unexpected unknown effect', description: null, - loc: GeneratedSource, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], suggestions: null, }); } @@ -2792,7 +2886,13 @@ function mergeValueKinds(a: ValueKind, b: ValueKind): ValueKind { { reason: `Unexpected value kind in mergeValues()`, description: `Found kinds ${a} and ${b}`, - loc: GeneratedSource, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }, ); return ValueKind.Primitive; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingRanges.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingRanges.ts index b53026a4d4b..32f84e1e28b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingRanges.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingRanges.ts @@ -229,7 +229,14 @@ export function inferMutationAliasingRanges( } else { CompilerError.invariant(effect.kind === 'Freeze', { reason: `Unexpected '${effect.kind}' effect for MaybeThrow terminal`, - loc: block.terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: block.terminal.loc, + message: null, + }, + ], }); } } @@ -378,7 +385,14 @@ export function inferMutationAliasingRanges( case 'Apply': { CompilerError.invariant(false, { reason: `[AnalyzeFunctions] Expected Apply effects to be replaced with more precise effects`, - loc: effect.function.loc, + description: null, + details: [ + { + kind: 'error', + loc: effect.function.loc, + message: null, + }, + ], }); } case 'MutateTransitive': @@ -525,7 +539,14 @@ export function inferMutationAliasingRanges( const fromNode = state.nodes.get(from.identifier); CompilerError.invariant(fromNode != null, { reason: `Expected a node to exist for all parameters and context variables`, - loc: into.loc, + description: null, + details: [ + { + kind: 'error', + loc: into.loc, + message: null, + }, + ], }); if (fromNode.lastMutated === mutationIndex) { if (into.identifier.id === fn.returns.identifier.id) { @@ -547,7 +568,7 @@ export function inferMutationAliasingRanges( } } - if (errors.hasErrors() && !isFunctionExpression) { + if (errors.hasAnyErrors() && !isFunctionExpression) { return Err(errors); } return Ok(functionEffects); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReactivePlaces.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReactivePlaces.ts index 19e220b2356..271a76e92c1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReactivePlaces.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReactivePlaces.ts @@ -349,7 +349,13 @@ export function inferReactivePlaces(fn: HIRFunction): void { CompilerError.invariant(false, { reason: 'Unexpected unknown effect', description: null, - loc: operand.loc, + details: [ + { + kind: 'error', + loc: operand.loc, + message: null, + }, + ], suggestions: null, }); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts index 4ad86abbe73..ca2f6e00a5d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts @@ -191,7 +191,14 @@ function evaluatePhi(phi: Phi, constants: Constants): Constant | null { case 'Primitive': { CompilerError.invariant(value.kind === 'Primitive', { reason: 'value kind expected to be Primitive', - loc: null, + description: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); @@ -204,7 +211,14 @@ function evaluatePhi(phi: Phi, constants: Constants): Constant | null { case 'LoadGlobal': { CompilerError.invariant(value.kind === 'LoadGlobal', { reason: 'value kind expected to be LoadGlobal', - loc: null, + description: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts index 3588cf32f9f..8970f2e07ff 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts @@ -709,7 +709,14 @@ function createPropsProperties( const spreadProp = jsxSpreadAttributes[0]; CompilerError.invariant(spreadProp.kind === 'JsxSpreadAttribute', { reason: 'Spread prop attribute must be of kind JSXSpreadAttribute', - loc: instr.loc, + description: null, + details: [ + { + kind: 'error', + loc: instr.loc, + message: null, + }, + ], }); propsProperty = { kind: 'ObjectProperty', diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InstructionReordering.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InstructionReordering.ts index 441ad837780..409c1700272 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InstructionReordering.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InstructionReordering.ts @@ -78,10 +78,17 @@ export function instructionReordering(fn: HIRFunction): void { } CompilerError.invariant(shared.size === 0, { reason: `InstructionReordering: expected all reorderable nodes to have been emitted`, - loc: - [...shared.values()] - .map(node => node.instruction?.loc) - .filter(loc => loc != null)[0] ?? GeneratedSource, + description: null, + details: [ + { + kind: 'error', + loc: + [...shared.values()] + .map(node => node.instruction?.loc) + .filter(loc => loc != null)[0] ?? GeneratedSource, + message: null, + }, + ], }); markInstructionIds(fn.body); } @@ -302,7 +309,13 @@ function reorderBlock( node.reorderability === Reorderability.Reorderable, { reason: `Expected all remaining instructions to be reorderable`, - loc: node.instruction?.loc ?? block.terminal.loc, + details: [ + { + kind: 'error', + loc: node.instruction?.loc ?? block.terminal.loc, + message: null, + }, + ], description: node.instruction != null ? `Instruction [${node.instruction.id}] was not emitted yet but is not reorderable` diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/PruneMaybeThrows.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/PruneMaybeThrows.ts index 9175fbdd1af..ad0b63a1358 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/PruneMaybeThrows.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/PruneMaybeThrows.ts @@ -52,7 +52,13 @@ export function pruneMaybeThrows(fn: HIRFunction): void { const mappedTerminal = terminalMapping.get(predecessor); CompilerError.invariant(mappedTerminal != null, { reason: `Expected non-existing phi operand's predecessor to have been mapped to a new terminal`, - loc: GeneratedSource, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], description: `Could not find mapping for predecessor bb${predecessor} in block bb${ block.id } for phi ${printPlace(phi.place)}`, diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AlignObjectMethodScopes.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AlignObjectMethodScopes.ts index d5b8f99591c..680fb78c40a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AlignObjectMethodScopes.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AlignObjectMethodScopes.ts @@ -41,8 +41,15 @@ function findScopesToMerge(fn: HIRFunction): DisjointSet { { reason: 'Internal error: Expected all ObjectExpressions and ObjectMethods to have non-null scope.', + description: null, suggestions: null, - loc: GeneratedSource, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], }, ); mergeScopesBuilder.union([operandScope, lvalueScope]); diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AlignReactiveScopesToBlockScopesHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AlignReactiveScopesToBlockScopesHIR.ts index e440340bd29..4a562dffdce 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AlignReactiveScopesToBlockScopesHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AlignReactiveScopesToBlockScopesHIR.ts @@ -170,7 +170,14 @@ export function alignReactiveScopesToBlockScopesHIR(fn: HIRFunction): void { CompilerError.invariant(!valueBlockNodes.has(fallthrough), { reason: 'Expect hir blocks to have unique fallthroughs', - loc: terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: null, + }, + ], }); if (node != null) { valueBlockNodes.set(fallthrough, node); @@ -252,7 +259,14 @@ export function alignReactiveScopesToBlockScopesHIR(fn: HIRFunction): void { // Transition from block->value block, derive the outer block range CompilerError.invariant(fallthrough !== null, { reason: `Expected a fallthrough for value block`, - loc: terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: null, + }, + ], }); const fallthroughBlock = fn.body.blocks.get(fallthrough)!; const nextId = diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AssertScopeInstructionsWithinScope.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AssertScopeInstructionsWithinScope.ts index 718e28f6101..ae23280bbd7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AssertScopeInstructionsWithinScope.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AssertScopeInstructionsWithinScope.ts @@ -81,10 +81,16 @@ class CheckInstructionsAgainstScopesVisitor extends ReactiveFunctionVisitor< !this.activeScopes.has(scope.id) ) { CompilerError.invariant(false, { - description: `Instruction [${id}] is part of scope @${scope.id}, but that scope has already completed.`, - loc: place.loc, reason: 'Encountered an instruction that should be part of a scope, but where that scope has already completed', + description: `Instruction [${id}] is part of scope @${scope.id}, but that scope has already completed`, + details: [ + { + kind: 'error', + loc: place.loc, + message: null, + }, + ], suggestions: null, }); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AssertWellFormedBreakTargets.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AssertWellFormedBreakTargets.ts index 9ce9b2f4906..d838fd4bfd4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AssertWellFormedBreakTargets.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AssertWellFormedBreakTargets.ts @@ -28,7 +28,14 @@ class Visitor extends ReactiveFunctionVisitor> { if (terminal.kind === 'break' || terminal.kind === 'continue') { CompilerError.invariant(seenLabels.has(terminal.target), { reason: 'Unexpected break to invalid label', - loc: stmt.terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: stmt.terminal.loc, + message: null, + }, + ], }); } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/BuildReactiveFunction.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/BuildReactiveFunction.ts index 03e06dd0a24..b400bb34987 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/BuildReactiveFunction.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/BuildReactiveFunction.ts @@ -70,7 +70,13 @@ class Driver { CompilerError.invariant(!this.cx.emitted.has(block.id), { reason: `Cannot emit the same block twice: bb${block.id}`, description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); this.cx.emitted.add(block.id); @@ -130,7 +136,14 @@ class Driver { if (this.cx.isScheduled(terminal.consequent)) { CompilerError.invariant(false, { reason: `Unexpected 'if' where the consequent is already scheduled`, - loc: terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: null, + }, + ], }); } else { consequent = this.traverseBlock( @@ -143,7 +156,14 @@ class Driver { if (this.cx.isScheduled(alternateId)) { CompilerError.invariant(false, { reason: `Unexpected 'if' where the alternate is already scheduled`, - loc: terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: null, + }, + ], }); } else { alternate = this.traverseBlock(this.cx.ir.blocks.get(alternateId)!); @@ -196,7 +216,14 @@ class Driver { if (this.cx.isScheduled(case_.block)) { CompilerError.invariant(case_.block === terminal.fallthrough, { reason: `Unexpected 'switch' where a case is already scheduled and block is not the fallthrough`, - loc: terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: null, + }, + ], }); return; } else { @@ -255,7 +282,14 @@ class Driver { } else { CompilerError.invariant(false, { reason: `Unexpected 'do-while' where the loop is already scheduled`, - loc: terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: null, + }, + ], }); } @@ -316,7 +350,14 @@ class Driver { } else { CompilerError.invariant(false, { reason: `Unexpected 'while' where the loop is already scheduled`, - loc: terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: null, + }, + ], }); } @@ -402,7 +443,14 @@ class Driver { } else { CompilerError.invariant(false, { reason: `Unexpected 'for' where the loop is already scheduled`, - loc: terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: null, + }, + ], }); } @@ -500,7 +548,14 @@ class Driver { } else { CompilerError.invariant(false, { reason: `Unexpected 'for-of' where the loop is already scheduled`, - loc: terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: null, + }, + ], }); } @@ -572,7 +627,14 @@ class Driver { } else { CompilerError.invariant(false, { reason: `Unexpected 'for-in' where the loop is already scheduled`, - loc: terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: null, + }, + ], }); } @@ -615,7 +677,14 @@ class Driver { if (this.cx.isScheduled(terminal.alternate)) { CompilerError.invariant(false, { reason: `Unexpected 'branch' where the alternate is already scheduled`, - loc: terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: null, + }, + ], }); } else { alternate = this.traverseBlock( @@ -653,7 +722,14 @@ class Driver { if (this.cx.isScheduled(terminal.block)) { CompilerError.invariant(false, { reason: `Unexpected 'label' where the block is already scheduled`, - loc: terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: null, + }, + ], }); } else { block = this.traverseBlock(this.cx.ir.blocks.get(terminal.block)!); @@ -811,7 +887,14 @@ class Driver { if (this.cx.isScheduled(terminal.block)) { CompilerError.invariant(false, { reason: `Unexpected 'scope' where the block is already scheduled`, - loc: terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: null, + }, + ], }); } else { block = this.traverseBlock(this.cx.ir.blocks.get(terminal.block)!); @@ -837,7 +920,13 @@ class Driver { CompilerError.invariant(false, { reason: 'Unexpected unsupported terminal', description: null, - loc: terminal.loc, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: null, + }, + ], suggestions: null, }); } @@ -874,7 +963,13 @@ class Driver { reason: 'Expected branch block to end in an instruction that sets the test value', description: null, - loc: instr.lvalue.loc, + details: [ + { + kind: 'error', + loc: instr.lvalue.loc, + message: null, + }, + ], suggestions: null, }, ); @@ -906,7 +1001,13 @@ class Driver { CompilerError.invariant(false, { reason: 'Expected goto value block to have at least one instruction', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); } else if (defaultBlock.instructions.length === 1) { @@ -1191,14 +1292,27 @@ class Driver { CompilerError.invariant(false, { reason: 'Expected a break target', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); } if (this.cx.scopeFallthroughs.has(target.block)) { CompilerError.invariant(target.type === 'implicit', { reason: 'Expected reactive scope to implicitly break to fallthrough', - loc, + description: null, + details: [ + { + kind: 'error', + loc, + message: null, + }, + ], }); return null; } @@ -1224,7 +1338,13 @@ class Driver { CompilerError.invariant(target !== null, { reason: `Expected continue target to be scheduled for bb${block}`, description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); @@ -1299,7 +1419,13 @@ class Context { CompilerError.invariant(!this.#scheduled.has(block), { reason: `Break block is already scheduled: bb${block}`, description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); this.#scheduled.add(block); @@ -1318,7 +1444,13 @@ class Context { CompilerError.invariant(!this.#scheduled.has(continueBlock), { reason: `Continue block is already scheduled: bb${continueBlock}`, description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); this.#scheduled.add(continueBlock); @@ -1346,7 +1478,13 @@ class Context { CompilerError.invariant(last !== undefined && last.id === scheduleId, { reason: 'Can only unschedule the last target', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); if (last.type !== 'loop' || last.ownsBlock !== null) { @@ -1421,7 +1559,13 @@ class Context { CompilerError.invariant(false, { reason: 'Expected a break target', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); } 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 c02a41f8f0a..9d6f46c2374 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts @@ -13,7 +13,7 @@ import { pruneUnusedLabels, renameVariables, } from '.'; -import {CompilerError, ErrorCategory, ErrorSeverity} from '../CompilerError'; +import {CompilerError, ErrorCategory} from '../CompilerError'; import {Environment, ExternalFunction} from '../HIR'; import { ArrayPattern, @@ -296,7 +296,14 @@ export function codegenFunction( CompilerError.invariant(globalGating != null, { reason: 'Bad config not caught! Expected at least one of gating or globalGating', - loc: null, + description: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); ifTest = globalGating; @@ -365,7 +372,7 @@ function codegenReactiveFunction( } } - if (cx.errors.hasErrors()) { + if (cx.errors.hasAnyErrors()) { return Err(cx.errors); } @@ -499,10 +506,16 @@ function codegenBlock(cx: Context, block: ReactiveBlock): t.BlockStatement { continue; } CompilerError.invariant(temp.get(key)! === value, { - loc: null, reason: 'Expected temporary value to be unchanged', description: null, suggestions: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], }); } cx.temp = temp; @@ -670,7 +683,13 @@ function codegenReactiveScope( description: `Declaration \`${printIdentifier( identifier, )}\` is unnamed in scope @${scope.id}`, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); @@ -707,7 +726,13 @@ function codegenReactiveScope( CompilerError.invariant(firstOutputIndex !== null, { reason: `Expected scope to have at least one declaration`, description: `Scope '@${scope.id}' has no declarations`, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); testCondition = t.binaryExpression( @@ -730,7 +755,13 @@ function codegenReactiveScope( { reason: `Expected to not have both change detection enabled and memoization disabled`, description: `Incompatible config options`, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], }, ); testCondition = t.logicalExpression( @@ -914,8 +945,14 @@ function codegenReactiveScope( earlyReturnValue.value.name.kind === 'named', { reason: `Expected early return value to be promoted to a named variable`, - loc: earlyReturnValue.loc, description: null, + details: [ + { + kind: 'error', + loc: earlyReturnValue.loc, + message: null, + }, + ], suggestions: null, }, ); @@ -945,7 +982,8 @@ function codegenTerminal( if (terminal.targetKind === 'implicit') { return null; } - return t.breakStatement( + return createBreakStatement( + terminal.loc, terminal.targetKind === 'labeled' ? t.identifier(codegenLabel(terminal.target)) : null, @@ -955,14 +993,16 @@ function codegenTerminal( if (terminal.targetKind === 'implicit') { return null; } - return t.continueStatement( + return createContinueStatement( + terminal.loc, terminal.targetKind === 'labeled' ? t.identifier(codegenLabel(terminal.target)) : null, ); } case 'for': { - return t.forStatement( + return createForStatement( + terminal.loc, codegenForInit(cx, terminal.init), codegenInstructionValueToExpression(cx, terminal.test), terminal.update !== null @@ -975,7 +1015,13 @@ function codegenTerminal( CompilerError.invariant(terminal.init.kind === 'SequenceExpression', { reason: `Expected a sequence expression init for for..in`, description: `Got \`${terminal.init.kind}\` expression instead`, - loc: terminal.init.loc, + details: [ + { + kind: 'error', + loc: terminal.init.loc, + message: null, + }, + ], suggestions: null, }); if (terminal.init.instructions.length !== 2) { @@ -1010,7 +1056,13 @@ function codegenTerminal( CompilerError.invariant(false, { reason: `Expected a StoreLocal or Destructure to be assigned to the collection`, description: `Found ${iterableItem.value.kind}`, - loc: iterableItem.value.loc, + details: [ + { + kind: 'error', + loc: iterableItem.value.loc, + message: null, + }, + ], suggestions: null, }); } @@ -1027,7 +1079,13 @@ function codegenTerminal( reason: 'Destructure should never be Reassign as it would be an Object/ArrayPattern', description: null, - loc: iterableItem.loc, + details: [ + { + kind: 'error', + loc: iterableItem.loc, + message: null, + }, + ], suggestions: null, }); case InstructionKind.Catch: @@ -1038,7 +1096,13 @@ function codegenTerminal( CompilerError.invariant(false, { reason: `Unexpected ${iterableItem.value.lvalue.kind} variable in for..in collection`, description: null, - loc: iterableItem.loc, + details: [ + { + kind: 'error', + loc: iterableItem.loc, + message: null, + }, + ], suggestions: null, }); default: @@ -1047,7 +1111,8 @@ function codegenTerminal( `Unhandled lvalue kind: ${iterableItem.value.lvalue.kind}`, ); } - return t.forInStatement( + return createForInStatement( + terminal.loc, /* * Special handling here since we only want the VariableDeclarators without any inits * This needs to be updated when we handle non-trivial ForOf inits @@ -1067,7 +1132,13 @@ function codegenTerminal( { reason: `Expected a single-expression sequence expression init for for..of`, description: `Got \`${terminal.init.kind}\` expression instead`, - loc: terminal.init.loc, + details: [ + { + kind: 'error', + loc: terminal.init.loc, + message: null, + }, + ], suggestions: null, }, ); @@ -1076,7 +1147,13 @@ function codegenTerminal( CompilerError.invariant(terminal.test.kind === 'SequenceExpression', { reason: `Expected a sequence expression test for for..of`, description: `Got \`${terminal.init.kind}\` expression instead`, - loc: terminal.test.loc, + details: [ + { + kind: 'error', + loc: terminal.test.loc, + message: null, + }, + ], suggestions: null, }); if (terminal.test.instructions.length !== 2) { @@ -1110,7 +1187,13 @@ function codegenTerminal( CompilerError.invariant(false, { reason: `Expected a StoreLocal or Destructure to be assigned to the collection`, description: `Found ${iterableItem.value.kind}`, - loc: iterableItem.value.loc, + details: [ + { + kind: 'error', + loc: iterableItem.value.loc, + message: null, + }, + ], suggestions: null, }); } @@ -1131,7 +1214,13 @@ function codegenTerminal( CompilerError.invariant(false, { reason: `Unexpected ${iterableItem.value.lvalue.kind} variable in for..of collection`, description: null, - loc: iterableItem.loc, + details: [ + { + kind: 'error', + loc: iterableItem.loc, + message: null, + }, + ], suggestions: null, }); default: @@ -1140,7 +1229,8 @@ function codegenTerminal( `Unhandled lvalue kind: ${iterableItem.value.lvalue.kind}`, ); } - return t.forOfStatement( + return createForOfStatement( + terminal.loc, /* * Special handling here since we only want the VariableDeclarators without any inits * This needs to be updated when we handle non-trivial ForOf inits @@ -1162,7 +1252,7 @@ function codegenTerminal( alternate = block; } } - return t.ifStatement(test, consequent, alternate); + return createIfStatement(terminal.loc, test, consequent, alternate); } case 'return': { const value = codegenPlaceToExpression(cx, terminal.value); @@ -1173,7 +1263,8 @@ function codegenTerminal( return t.returnStatement(value); } case 'switch': { - return t.switchStatement( + return createSwitchStatement( + terminal.loc, codegenPlaceToExpression(cx, terminal.test), terminal.cases.map(case_ => { const test = @@ -1186,15 +1277,26 @@ function codegenTerminal( ); } case 'throw': { - return t.throwStatement(codegenPlaceToExpression(cx, terminal.value)); + return createThrowStatement( + terminal.loc, + codegenPlaceToExpression(cx, terminal.value), + ); } case 'do-while': { const test = codegenInstructionValueToExpression(cx, terminal.test); - return t.doWhileStatement(test, codegenBlock(cx, terminal.loop)); + return createDoWhileStatement( + terminal.loc, + test, + codegenBlock(cx, terminal.loop), + ); } case 'while': { const test = codegenInstructionValueToExpression(cx, terminal.test); - return t.whileStatement(test, codegenBlock(cx, terminal.loop)); + return createWhileStatement( + terminal.loc, + test, + codegenBlock(cx, terminal.loop), + ); } case 'label': { return codegenBlock(cx, terminal.block); @@ -1205,7 +1307,8 @@ function codegenTerminal( catchParam = convertIdentifier(terminal.handlerBinding.identifier); cx.temp.set(terminal.handlerBinding.identifier.declarationId, null); } - return t.tryStatement( + return createTryStatement( + terminal.loc, codegenBlock(cx, terminal.block), t.catchClause(catchParam, codegenBlock(cx, terminal.handler)), ); @@ -1272,7 +1375,13 @@ function codegenInstructionNullable( reason: 'Encountered a destructuring operation where some identifiers are already declared (reassignments) but others are not (declarations)', description: null, - loc: instr.loc, + details: [ + { + kind: 'error', + loc: instr.loc, + message: null, + }, + ], suggestions: null, }); } else if (hasReassign) { @@ -1285,7 +1394,13 @@ function codegenInstructionNullable( CompilerError.invariant(instr.lvalue === null, { reason: `Const declaration cannot be referenced as an expression`, description: null, - loc: instr.value.loc, + details: [ + { + kind: 'error', + loc: instr.value.loc, + message: `this is ${kind}`, + }, + ], suggestions: null, }); return createVariableDeclaration(instr.loc, 'const', [ @@ -1296,20 +1411,38 @@ function codegenInstructionNullable( CompilerError.invariant(instr.lvalue === null, { reason: `Function declaration cannot be referenced as an expression`, description: null, - loc: instr.value.loc, + details: [ + { + kind: 'error', + loc: instr.value.loc, + message: `this is ${kind}`, + }, + ], suggestions: null, }); const genLvalue = codegenLValue(cx, lvalue); CompilerError.invariant(genLvalue.type === 'Identifier', { reason: 'Expected an identifier as a function declaration lvalue', description: null, - loc: instr.value.loc, + details: [ + { + kind: 'error', + loc: instr.value.loc, + message: null, + }, + ], suggestions: null, }); CompilerError.invariant(value?.type === 'FunctionExpression', { reason: 'Expected a function as a function declaration value', description: `Got ${value == null ? String(value) : value.type} at ${printInstruction(instr)}`, - loc: instr.value.loc, + details: [ + { + kind: 'error', + loc: instr.value.loc, + message: null, + }, + ], suggestions: null, }); return createFunctionDeclaration( @@ -1325,7 +1458,13 @@ function codegenInstructionNullable( CompilerError.invariant(instr.lvalue === null, { reason: `Const declaration cannot be referenced as an expression`, description: null, - loc: instr.value.loc, + details: [ + { + kind: 'error', + loc: instr.value.loc, + message: 'this is const', + }, + ], suggestions: null, }); return createVariableDeclaration(instr.loc, 'let', [ @@ -1336,7 +1475,13 @@ function codegenInstructionNullable( CompilerError.invariant(value !== null, { reason: 'Expected a value for reassignment', description: null, - loc: instr.value.loc, + details: [ + { + kind: 'error', + loc: instr.value.loc, + message: null, + }, + ], suggestions: null, }); const expr = t.assignmentExpression( @@ -1369,7 +1514,13 @@ function codegenInstructionNullable( CompilerError.invariant(false, { reason: `Expected ${kind} to have been pruned in PruneHoistedContexts`, description: null, - loc: instr.loc, + details: [ + { + kind: 'error', + loc: instr.loc, + message: null, + }, + ], suggestions: null, }); } @@ -1387,7 +1538,14 @@ function codegenInstructionNullable( } else if (instr.value.kind === 'ObjectMethod') { CompilerError.invariant(instr.lvalue, { reason: 'Expected object methods to have a temp lvalue', - loc: null, + description: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); cx.objectMethods.set(instr.lvalue.identifier.id, instr.value); @@ -1434,7 +1592,13 @@ function codegenForInit( (instr.kind === 'let' || instr.kind === 'const'), { reason: 'Expected a variable declaration', - loc: init.loc, + details: [ + { + kind: 'error', + loc: init.loc, + message: null, + }, + ], description: `Got ${instr.type}`, suggestions: null, }, @@ -1447,7 +1611,13 @@ function codegenForInit( }); CompilerError.invariant(declarators.length > 0, { reason: 'Expected a variable declaration', - loc: init.loc, + details: [ + { + kind: 'error', + loc: init.loc, + message: null, + }, + ], description: null, suggestions: null, }); @@ -1543,7 +1713,13 @@ const createExpressionStatement = withLoc(t.expressionStatement); const _createLabelledStatement = withLoc(t.labeledStatement); const createVariableDeclaration = withLoc(t.variableDeclaration); const createFunctionDeclaration = withLoc(t.functionDeclaration); -const _createWhileStatement = withLoc(t.whileStatement); +const createWhileStatement = withLoc(t.whileStatement); +const createDoWhileStatement = withLoc(t.doWhileStatement); +const createSwitchStatement = withLoc(t.switchStatement); +const createIfStatement = withLoc(t.ifStatement); +const createForStatement = withLoc(t.forStatement); +const createForOfStatement = withLoc(t.forOfStatement); +const createForInStatement = withLoc(t.forInStatement); const createTaggedTemplateExpression = withLoc(t.taggedTemplateExpression); const createLogicalExpression = withLoc(t.logicalExpression); const createSequenceExpression = withLoc(t.sequenceExpression); @@ -1558,6 +1734,10 @@ const createJsxText = withLoc(t.jsxText); const createJsxClosingElement = withLoc(t.jsxClosingElement); const createJsxOpeningElement = withLoc(t.jsxOpeningElement); const createStringLiteral = withLoc(t.stringLiteral); +const createThrowStatement = withLoc(t.throwStatement); +const createTryStatement = withLoc(t.tryStatement); +const createBreakStatement = withLoc(t.breakStatement); +const createContinueStatement = withLoc(t.continueStatement); function createHookGuard( guard: ExternalFunction, @@ -1768,7 +1948,13 @@ function codegenInstructionValue( CompilerError.invariant(t.isExpression(optionalValue.callee), { reason: 'v8 intrinsics are validated during lowering', description: null, - loc: optionalValue.callee.loc ?? null, + details: [ + { + kind: 'error', + loc: optionalValue.callee.loc ?? null, + message: null, + }, + ], suggestions: null, }); value = t.optionalCallExpression( @@ -1784,7 +1970,13 @@ function codegenInstructionValue( CompilerError.invariant(t.isExpression(property), { reason: 'Private names are validated during lowering', description: null, - loc: property.loc ?? null, + details: [ + { + kind: 'error', + loc: property.loc ?? null, + message: null, + }, + ], suggestions: null, }); value = t.optionalMemberExpression( @@ -1800,7 +1992,13 @@ function codegenInstructionValue( reason: 'Expected an optional value to resolve to a call expression or member expression', description: `Got a \`${optionalValue.type}\``, - loc: instrValue.loc, + details: [ + { + kind: 'error', + loc: instrValue.loc, + message: null, + }, + ], suggestions: null, }); } @@ -1816,10 +2014,15 @@ function codegenInstructionValue( t.isOptionalMemberExpression(memberExpr), { reason: - '[Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. ' + - `Got a \`${memberExpr.type}\``, + '[Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression', description: null, - loc: memberExpr.loc ?? null, + details: [ + { + kind: 'error', + loc: memberExpr.loc ?? null, + message: `Got: '${memberExpr.type}'`, + }, + ], suggestions: null, }, ); @@ -1833,7 +2036,13 @@ function codegenInstructionValue( '[Codegen] Internal error: Forget should always generate MethodCall::property ' + 'as a MemberExpression of MethodCall::receiver', description: null, - loc: memberExpr.loc ?? null, + details: [ + { + kind: 'error', + loc: memberExpr.loc ?? null, + message: null, + }, + ], suggestions: null, }, ); @@ -1878,7 +2087,14 @@ function codegenInstructionValue( const method = cx.objectMethods.get(property.place.identifier.id); CompilerError.invariant(method, { reason: 'Expected ObjectMethod instruction', - loc: null, + description: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); const loweredFunc = method.loweredFunc; @@ -1949,7 +2165,13 @@ function codegenInstructionValue( CompilerError.invariant(tagValue.type === 'StringLiteral', { reason: `Expected JSX tag to be an identifier or string, got \`${tagValue.type}\``, description: null, - loc: tagValue.loc ?? null, + details: [ + { + kind: 'error', + loc: tagValue.loc ?? null, + message: null, + }, + ], suggestions: null, }); if (tagValue.value.indexOf(':') >= 0) { @@ -1969,7 +2191,13 @@ function codegenInstructionValue( SINGLE_CHILD_FBT_TAGS.has(tagValue.value) ) { CompilerError.invariant(instrValue.children != null, { - loc: instrValue.loc, + details: [ + { + kind: 'error', + loc: instrValue.loc, + message: null, + }, + ], reason: 'Expected fbt element to have children', suggestions: null, description: null, @@ -2184,7 +2412,6 @@ function codegenInstructionValue( reason: `(CodegenReactiveFunction::codegenInstructionValue) Cannot declare variables in a value block, tried to declare '${ (declarator.id as t.Identifier).name }'`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: declarator.loc ?? null, suggestions: null, @@ -2193,7 +2420,6 @@ function codegenInstructionValue( } else { cx.errors.push({ reason: `(CodegenReactiveFunction::codegenInstructionValue) Handle conversion of ${stmt.type} to expression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: stmt.loc ?? null, suggestions: null, @@ -2273,7 +2499,13 @@ function codegenInstructionValue( { reason: `Unexpected StoreLocal in codegenInstructionValue`, description: null, - loc: instrValue.loc, + details: [ + { + kind: 'error', + loc: instrValue.loc, + message: null, + }, + ], suggestions: null, }, ); @@ -2303,7 +2535,13 @@ function codegenInstructionValue( CompilerError.invariant(false, { reason: `Unexpected ${instrValue.kind} in codegenInstructionValue`, description: null, - loc: instrValue.loc, + details: [ + { + kind: 'error', + loc: instrValue.loc, + message: null, + }, + ], suggestions: null, }); } @@ -2314,6 +2552,9 @@ function codegenInstructionValue( ); } } + if (instrValue.loc != null && instrValue.loc != GeneratedSource) { + value.loc = instrValue.loc; + } return value; } @@ -2449,7 +2690,13 @@ function convertMemberExpressionToJsx( CompilerError.invariant(expr.property.type === 'Identifier', { reason: 'Expected JSX member expression property to be a string', description: null, - loc: expr.loc ?? null, + details: [ + { + kind: 'error', + loc: expr.loc ?? null, + message: null, + }, + ], suggestions: null, }); const property = t.jsxIdentifier(expr.property.name); @@ -2460,7 +2707,13 @@ function convertMemberExpressionToJsx( reason: 'Expected JSX member expression to be an identifier or nested member expression', description: null, - loc: expr.object.loc ?? null, + details: [ + { + kind: 'error', + loc: expr.object.loc ?? null, + message: null, + }, + ], suggestions: null, }); const object = convertMemberExpressionToJsx(expr.object); @@ -2484,7 +2737,13 @@ function codegenObjectPropertyKey( CompilerError.invariant(t.isExpression(expr), { reason: 'Expected object property key to be an expression', description: null, - loc: key.name.loc, + details: [ + { + kind: 'error', + loc: key.name.loc, + message: null, + }, + ], suggestions: null, }); return expr; @@ -2631,7 +2890,13 @@ function codegenPlace(cx: Context, place: Place): t.Expression | t.JSXText { description: `Value for '${printPlace( place, )}' was not set in the codegen context`, - loc: place.loc, + details: [ + { + kind: 'error', + loc: place.loc, + message: null, + }, + ], suggestions: null, }); const identifier = convertIdentifier(place.identifier); @@ -2644,7 +2909,13 @@ function convertIdentifier(identifier: Identifier): t.Identifier { identifier.name !== null && identifier.name.kind === 'named', { reason: `Expected temporaries to be promoted to named identifiers in an earlier pass`, - loc: GeneratedSource, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], description: `identifier ${identifier.id} is unnamed`, suggestions: null, }, @@ -2660,7 +2931,14 @@ function compareScopeDependency( a.identifier.name?.kind === 'named' && b.identifier.name?.kind === 'named', { reason: '[Codegen] Expected named identifier for dependency', - loc: a.identifier.loc, + description: null, + details: [ + { + kind: 'error', + loc: a.identifier.loc, + message: null, + }, + ], }, ); const aName = [ @@ -2684,7 +2962,14 @@ function compareScopeDeclaration( a.identifier.name?.kind === 'named' && b.identifier.name?.kind === 'named', { reason: '[Codegen] Expected named identifier for declaration', - loc: a.identifier.loc, + description: null, + details: [ + { + kind: 'error', + loc: a.identifier.loc, + message: null, + }, + ], }, ); const aName = a.identifier.name.value; diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/FlattenScopesWithHooksOrUseHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/FlattenScopesWithHooksOrUseHIR.ts index 103923a2e4d..7f01bde4b27 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/FlattenScopesWithHooksOrUseHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/FlattenScopesWithHooksOrUseHIR.ts @@ -75,7 +75,13 @@ export function flattenScopesWithHooksOrUseHIR(fn: HIRFunction): void { CompilerError.invariant(terminal.kind === 'scope', { reason: `Expected block to have a scope terminal`, description: `Expected block bb${block.id} to end in a scope terminal`, - loc: terminal.loc, + details: [ + { + kind: 'error', + loc: terminal.loc, + message: null, + }, + ], }); const body = fn.body.blocks.get(terminal.block)!; if ( diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts index 0c1fd759bd5..300115c04e4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts @@ -162,7 +162,13 @@ export function inferReactiveScopeVariables(fn: HIRFunction): void { }); CompilerError.invariant(false, { reason: `Invalid mutable range for scope`, - loc: GeneratedSource, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], description: `Scope @${scope.id} has range [${scope.range.start}:${ scope.range.end }] but the valid range is [1:${maxInstruction + 1}]`, diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts index a7acf5d6625..a698e3bd247 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts @@ -159,11 +159,17 @@ class Transform extends ReactiveFunctionTransform = []; function reset(): void { CompilerError.invariant(current !== null, { - loc: null, reason: 'MergeConsecutiveScopes: expected current scope to be non-null if reset()', - suggestions: null, description: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], + suggestions: null, }); if (current.to > current.from + 1) { merged.push(current); @@ -375,10 +381,16 @@ class Transform extends ReactiveFunctionTransform { CompilerError.invariant(lval.identifier.name != null, { reason: 'PromoteInterposedTemporaries: Assignment targets not expected to be temporaries', - loc: instruction.loc, + description: null, + details: [ + { + kind: 'error', + loc: instruction.loc, + message: null, + }, + ], }); } @@ -454,7 +461,13 @@ function promoteIdentifier(identifier: Identifier, state: State): void { reason: 'promoteTemporary: Expected to be called only for temporary variables', description: null, - loc: GeneratedSource, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], suggestions: null, }); if (state.tags.has(identifier.declarationId)) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneHoistedContexts.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneHoistedContexts.ts index ae3ff122a23..489b7aa42e5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneHoistedContexts.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneHoistedContexts.ts @@ -145,7 +145,14 @@ class Visitor extends ReactiveFunctionTransform { if (maybeHoistedFn != null) { CompilerError.invariant(maybeHoistedFn.kind === 'func', { reason: '[PruneHoistedContexts] Unexpected hoisted function', - loc: instruction.loc, + description: null, + details: [ + { + kind: 'error', + loc: instruction.loc, + message: null, + }, + ], }); maybeHoistedFn.definition = instruction.value.lvalue.place; /** diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneInitializationDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneInitializationDependencies.ts index 9ef9d382c28..c8e14be19eb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneInitializationDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneInitializationDependencies.ts @@ -196,7 +196,14 @@ class Visitor extends ReactiveFunctionVisitor { ): void { CompilerError.invariant(state !== 'Create', { reason: "Visiting a terminal statement with state 'Create'", - loc: stmt.terminal.loc, + description: null, + details: [ + { + kind: 'error', + loc: stmt.terminal.loc, + message: null, + }, + ], }); super.visitTerminal(stmt, state); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneNonEscapingScopes.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneNonEscapingScopes.ts index 5735f7e8011..52efb92350c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneNonEscapingScopes.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneNonEscapingScopes.ts @@ -264,7 +264,13 @@ class State { CompilerError.invariant(identifierNode !== undefined, { reason: 'Expected identifier to be initialized', description: `[${id}] operand=${printPlace(place)} for identifier declaration ${identifier}`, - loc: place.loc, + details: [ + { + kind: 'error', + loc: place.loc, + message: null, + }, + ], suggestions: null, }); identifierNode.scopes.add(scope.id); @@ -286,7 +292,13 @@ function computeMemoizedIdentifiers(state: State): Set { CompilerError.invariant(node !== undefined, { reason: `Expected a node for all identifiers, none found for \`${id}\``, description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); if (node.seen) { @@ -328,7 +340,13 @@ function computeMemoizedIdentifiers(state: State): Set { CompilerError.invariant(node !== undefined, { reason: 'Expected a node for all scopes', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); if (node.seen) { @@ -977,7 +995,13 @@ class CollectDependenciesVisitor extends ReactiveFunctionVisitor< CompilerError.invariant(identifierNode !== undefined, { reason: 'Expected identifier to be initialized', description: null, - loc: stmt.terminal.loc, + details: [ + { + kind: 'error', + loc: stmt.terminal.loc, + message: null, + }, + ], suggestions: null, }); for (const scope of scopes) { @@ -1002,7 +1026,13 @@ class CollectDependenciesVisitor extends ReactiveFunctionVisitor< CompilerError.invariant(identifierNode !== undefined, { reason: 'Expected identifier to be initialized', description: null, - loc: reassignment.loc, + details: [ + { + kind: 'error', + loc: reassignment.loc, + message: null, + }, + ], suggestions: null, }); for (const scope of scopes) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/RenameVariables.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/RenameVariables.ts index 5b39055e7d6..f7b76d4258f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/RenameVariables.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/RenameVariables.ts @@ -186,7 +186,13 @@ class Scopes { CompilerError.invariant(last === next, { reason: 'Mismatch push/pop calls', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/SSA/EliminateRedundantPhi.ts b/compiler/packages/babel-plugin-react-compiler/src/SSA/EliminateRedundantPhi.ts index 12c8c0e2e62..afc1f479121 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/SSA/EliminateRedundantPhi.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/SSA/EliminateRedundantPhi.ts @@ -97,7 +97,13 @@ export function eliminateRedundantPhi( CompilerError.invariant(same !== null, { reason: 'Expected phis to be non-empty', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); rewrites.set(phi.place.identifier, same); @@ -149,12 +155,26 @@ export function eliminateRedundantPhi( for (const phi of block.phis) { CompilerError.invariant(!rewrites.has(phi.place.identifier), { reason: '[EliminateRedundantPhis]: rewrite not complete', - loc: phi.place.loc, + description: null, + details: [ + { + kind: 'error', + loc: phi.place.loc, + message: null, + }, + ], }); for (const [, operand] of phi.operands) { CompilerError.invariant(!rewrites.has(operand.identifier), { reason: '[EliminateRedundantPhis]: rewrite not complete', - loc: phi.place.loc, + description: null, + details: [ + { + kind: 'error', + loc: phi.place.loc, + message: null, + }, + ], }); } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/SSA/EnterSSA.ts b/compiler/packages/babel-plugin-react-compiler/src/SSA/EnterSSA.ts index 820f7388dc4..67b8e75eb20 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/SSA/EnterSSA.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/SSA/EnterSSA.ts @@ -70,7 +70,13 @@ class SSABuilder { CompilerError.invariant(this.#current !== null, { reason: 'we need to be in a block to access state!', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); return this.#states.get(this.#current)!; @@ -253,7 +259,13 @@ function enterSSAImpl( CompilerError.invariant(!visitedBlocks.has(block), { reason: `found a cycle! visiting bb${block.id} again`, description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); @@ -266,7 +278,13 @@ function enterSSAImpl( CompilerError.invariant(func.context.length === 0, { reason: `Expected function context to be empty for outer function declarations`, description: null, - loc: func.loc, + details: [ + { + kind: 'error', + loc: func.loc, + message: null, + }, + ], suggestions: null, }); func.params = func.params.map(param => { @@ -295,7 +313,13 @@ function enterSSAImpl( reason: 'Expected function expression entry block to have zero predecessors', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); entry.preds.add(blockId); diff --git a/compiler/packages/babel-plugin-react-compiler/src/SSA/RewriteInstructionKindsBasedOnReassignment.ts b/compiler/packages/babel-plugin-react-compiler/src/SSA/RewriteInstructionKindsBasedOnReassignment.ts index 0af28e0d125..3f1e663b21e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/SSA/RewriteInstructionKindsBasedOnReassignment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/SSA/RewriteInstructionKindsBasedOnReassignment.ts @@ -59,7 +59,13 @@ export function rewriteInstructionKindsBasedOnReassignment( { reason: `Expected variable not to be defined prior to declaration`, description: `${printPlace(lvalue.place)} was already defined`, - loc: lvalue.place.loc, + details: [ + { + kind: 'error', + loc: lvalue.place.loc, + message: null, + }, + ], }, ); declarations.set(lvalue.place.identifier.declarationId, lvalue); @@ -77,7 +83,13 @@ export function rewriteInstructionKindsBasedOnReassignment( { reason: `Expected variable not to be defined prior to declaration`, description: `${printPlace(lvalue.place)} was already defined`, - loc: lvalue.place.loc, + details: [ + { + kind: 'error', + loc: lvalue.place.loc, + message: null, + }, + ], }, ); declarations.set(lvalue.place.identifier.declarationId, lvalue); @@ -101,7 +113,13 @@ export function rewriteInstructionKindsBasedOnReassignment( description: `other places were \`${kind}\` but '${printPlace( place, )}' is const`, - loc: place.loc, + details: [ + { + kind: 'error', + loc: place.loc, + message: 'Expected consistent kind for destructuring', + }, + ], suggestions: null, }, ); @@ -114,7 +132,13 @@ export function rewriteInstructionKindsBasedOnReassignment( CompilerError.invariant(block.kind !== 'value', { reason: `TODO: Handle reassignment in a value block where the original declaration was removed by dead code elimination (DCE)`, description: null, - loc: place.loc, + details: [ + { + kind: 'error', + loc: place.loc, + message: null, + }, + ], suggestions: null, }); declarations.set(place.identifier.declarationId, lvalue); @@ -125,7 +149,13 @@ export function rewriteInstructionKindsBasedOnReassignment( description: `Other places were \`${kind}\` but '${printPlace( place, )}' is const`, - loc: place.loc, + details: [ + { + kind: 'error', + loc: place.loc, + message: 'Expected consistent kind for destructuring', + }, + ], suggestions: null, }, ); @@ -138,7 +168,13 @@ export function rewriteInstructionKindsBasedOnReassignment( description: `Other places were \`${kind}\` but '${printPlace( place, )}' is reassigned`, - loc: place.loc, + details: [ + { + kind: 'error', + loc: place.loc, + message: 'Expected consistent kind for destructuring', + }, + ], suggestions: null, }, ); @@ -150,7 +186,13 @@ export function rewriteInstructionKindsBasedOnReassignment( CompilerError.invariant(kind !== null, { reason: 'Expected at least one operand', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); lvalue.kind = kind; @@ -163,7 +205,13 @@ export function rewriteInstructionKindsBasedOnReassignment( CompilerError.invariant(declaration !== undefined, { reason: `Expected variable to have been defined`, description: `No declaration for ${printPlace(lvalue)}`, - loc: lvalue.loc, + details: [ + { + kind: 'error', + loc: lvalue.loc, + message: null, + }, + ], }); declaration.kind = InstructionKind.Let; break; 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 393f95d94c4..6793df5710b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Transform/TransformFire.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Transform/TransformFire.ts @@ -5,12 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import { - CompilerError, - CompilerErrorDetailOptions, - ErrorSeverity, - SourceLocation, -} from '..'; +import {CompilerError, CompilerErrorDetailOptions, SourceLocation} from '..'; import { ArrayExpression, CallExpression, @@ -133,7 +128,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void { context.pushError({ loc: value.loc, description: null, - severity: ErrorSeverity.Invariant, category: ErrorCategory.Invariant, reason: '[InsertFire] No LoadGlobal found for useEffect call', suggestions: null, @@ -180,7 +174,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void { loc: value.args[1].loc, description: 'You must use an array literal for an effect dependency array when that effect uses `fire()`', - severity: ErrorSeverity.Invariant, category: ErrorCategory.Fire, reason: CANNOT_COMPILE_FIRE, suggestions: null, @@ -191,7 +184,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void { loc: value.args[1].place.loc, description: 'You must use an array literal for an effect dependency array when that effect uses `fire()`', - severity: ErrorSeverity.Invariant, category: ErrorCategory.Fire, reason: CANNOT_COMPILE_FIRE, suggestions: null, @@ -226,7 +218,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void { context.pushError({ loc: value.loc, description: null, - severity: ErrorSeverity.Invariant, category: ErrorCategory.Invariant, reason: '[InsertFire] No loadLocal found for fire call argument', @@ -250,7 +241,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void { loc: value.loc, description: '`fire()` can only receive a function call such as `fire(fn(a,b)). Method calls and other expressions are not allowed', - severity: ErrorSeverity.InvalidReact, category: ErrorCategory.Fire, reason: CANNOT_COMPILE_FIRE, suggestions: null, @@ -269,7 +259,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void { context.pushError({ loc: value.loc, description, - severity: ErrorSeverity.InvalidReact, category: ErrorCategory.Fire, reason: CANNOT_COMPILE_FIRE, suggestions: null, @@ -401,7 +390,6 @@ function ensureNoRemainingCalleeCaptures( description: `All uses of ${calleeName} must be either used with a fire() call in \ this effect or not used with a fire() call at all. ${calleeName} was used with fire() on line \ ${printSourceLocationLine(calleeInfo.fireLoc)} in this effect`, - severity: ErrorSeverity.InvalidReact, category: ErrorCategory.Fire, reason: CANNOT_COMPILE_FIRE, suggestions: null, @@ -420,7 +408,6 @@ function ensureNoMoreFireUses(fn: HIRFunction, context: Context): void { loc: place.identifier.loc, description: 'Cannot use `fire` outside of a useEffect function', category: ErrorCategory.Fire, - severity: ErrorSeverity.Invariant, reason: CANNOT_COMPILE_FIRE, suggestions: null, }); @@ -711,7 +698,7 @@ class Context { } hasErrors(): boolean { - return this.#errors.hasErrors(); + return this.#errors.hasAnyErrors(); } throwIfErrorsFound(): void { diff --git a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts index d3a297e2e51..682195f8df6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts @@ -616,7 +616,13 @@ class Unifier { CompilerError.invariant(type.operands.length > 0, { reason: 'there should be at least one operand', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Utils/DisjointSet.ts b/compiler/packages/babel-plugin-react-compiler/src/Utils/DisjointSet.ts index 566732c2bb9..575a35821e7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Utils/DisjointSet.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Utils/DisjointSet.ts @@ -21,7 +21,13 @@ export default class DisjointSet { CompilerError.invariant(first != null, { reason: 'Expected set to be non-empty', description: null, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); /* diff --git a/compiler/packages/babel-plugin-react-compiler/src/Utils/TestUtils.ts b/compiler/packages/babel-plugin-react-compiler/src/Utils/TestUtils.ts index 5188849f1e9..1c3552d44bf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Utils/TestUtils.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Utils/TestUtils.ts @@ -164,7 +164,13 @@ function parseConfigPragmaEnvironmentForTest( CompilerError.invariant(false, { reason: 'Internal error, could not parse config from pragma string', description: `${fromZodError(config.error)}`, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); } @@ -248,7 +254,13 @@ function parseConfigStringAsJS( CompilerError.invariant(false, { reason: 'Failed to parse config pragma as JavaScript object', description: `Could not parse: ${configString}. Error: ${error}`, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); } @@ -279,7 +291,13 @@ function parseConfigStringAsJS( CompilerError.invariant(false, { reason: 'Invalid environment configuration in config pragma', description: `${fromZodError(validatedEnvironment.error)}`, - loc: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], suggestions: null, }); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateContextVariableLValues.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateContextVariableLValues.ts index b11bb9de1d2..563e3764093 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateContextVariableLValues.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateContextVariableLValues.ts @@ -106,12 +106,19 @@ function visit( } CompilerError.invariant(false, { - reason: `Expected all references to a variable to be consistently local or context references`, - loc: place.loc, + reason: + 'Expected all references to a variable to be consistently local or context references', description: `Identifier ${printPlace( place, - )} is referenced as a ${kind} variable, but was previously referenced as a ${prev} variable`, + )} is referenced as a ${kind} variable, but was previously referenced as a ${prev.kind} variable`, suggestions: null, + details: [ + { + kind: 'error', + loc: place.loc, + message: `this is ${prev.kind}`, + }, + ], }); } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateHooksUsage.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateHooksUsage.ts index af596155253..7259041ec29 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateHooksUsage.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateHooksUsage.ts @@ -10,7 +10,6 @@ import { CompilerError, CompilerErrorDetail, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import {computeUnconditionalBlocks} from '../HIR/ComputeUnconditionalBlocks'; import {isHookName} from '../HIR/Environment'; @@ -129,7 +128,6 @@ export function validateHooksUsage( description: null, reason, loc: place.loc, - severity: ErrorSeverity.InvalidReact, suggestions: null, }), ); @@ -147,7 +145,6 @@ export function validateHooksUsage( reason: 'Hooks may not be referenced as normal values, they must be called. See https://react.dev/reference/rules/react-calls-components-and-hooks#never-pass-around-hooks-as-regular-values', loc: place.loc, - severity: ErrorSeverity.InvalidReact, suggestions: null, }), ); @@ -165,7 +162,6 @@ export function validateHooksUsage( reason: 'Hooks must be the same function on every render, but this value may change over time to a different function. See https://react.dev/reference/rules/react-calls-components-and-hooks#dont-dynamically-use-hooks', loc: place.loc, - severity: ErrorSeverity.InvalidReact, suggestions: null, }), ); @@ -453,7 +449,6 @@ function visitFunctionExpression(errors: CompilerError, fn: HIRFunction): void { errors.pushErrorDetail( new CompilerErrorDetail({ category: ErrorCategory.Hooks, - severity: ErrorSeverity.InvalidReact, reason: 'Hooks must be called at the top level in the body of a function component or custom hook, and may not be called within function expressions. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning)', loc: callee.loc, diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateLocalsNotReassignedAfterRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateLocalsNotReassignedAfterRender.ts index e1ed71049df..77a943905af 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateLocalsNotReassignedAfterRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateLocalsNotReassignedAfterRender.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {CompilerDiagnostic, CompilerError, Effect, ErrorSeverity} from '..'; +import {CompilerDiagnostic, CompilerError, Effect} from '..'; import {ErrorCategory} from '../CompilerError'; import {HIRFunction, IdentifierId, Place} from '../HIR'; import { @@ -38,10 +38,9 @@ export function validateLocalsNotReassignedAfterRender(fn: HIRFunction): void { errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Immutability, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot reassign variable after render completes', - description: `Reassigning ${variable} after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead.`, - }).withDetail({ + description: `Reassigning ${variable} after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead`, + }).withDetails({ kind: 'error', loc: reassignment.loc, message: `Cannot reassign ${variable} after render completes`, @@ -94,11 +93,10 @@ function getContextReassignment( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Immutability, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot reassign variable in async function', description: 'Reassigning a variable in an async function can cause inconsistent behavior on subsequent renders. Consider using state instead', - }).withDetail({ + }).withDetails({ kind: 'error', loc: reassignment.loc, message: `Cannot reassign ${variable}`, @@ -193,7 +191,14 @@ function getContextReassignment( for (const operand of operands) { CompilerError.invariant(operand.effect !== Effect.Unknown, { reason: `Expected effects to be inferred prior to ValidateLocalsNotReassignedAfterRender`, - loc: operand.loc, + description: null, + details: [ + { + kind: 'error', + loc: operand.loc, + message: '', + }, + ], }); const reassignment = reassigningFunctions.get( operand.identifier.id, diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateMemoizedEffectDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateMemoizedEffectDependencies.ts index 186641c3f20..15d0be57fcf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateMemoizedEffectDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateMemoizedEffectDependencies.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {CompilerError, ErrorSeverity} from '..'; +import {CompilerError} from '..'; import {ErrorCategory} from '../CompilerError'; import { Identifier, @@ -113,7 +113,6 @@ class Visitor extends ReactiveFunctionVisitor { reason: 'React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior', description: null, - severity: ErrorSeverity.CannotPreserveMemoization, loc: typeof instruction.loc !== 'symbol' ? instruction.loc : null, suggestions: null, }); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoCapitalizedCalls.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoCapitalizedCalls.ts index d0cf41a13c4..0d0242d25c9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoCapitalizedCalls.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoCapitalizedCalls.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {CompilerError, EnvironmentConfig, ErrorSeverity} from '..'; +import {CompilerError, EnvironmentConfig} from '..'; import {ErrorCategory} from '../CompilerError'; import {HIRFunction, IdentifierId} from '../HIR'; import {DEFAULT_GLOBALS} from '../HIR/Globals'; @@ -59,7 +59,7 @@ export function validateNoCapitalizedCalls( CompilerError.throwInvalidReact({ category: ErrorCategory.CapitalizedCalls, reason, - description: `${calleeName} may be a component.`, + description: `${calleeName} may be a component`, loc: value.loc, suggestions: null, }); @@ -82,9 +82,8 @@ export function validateNoCapitalizedCalls( if (propertyName != null) { errors.push({ category: ErrorCategory.CapitalizedCalls, - severity: ErrorSeverity.InvalidReact, reason, - description: `${propertyName} may be a component.`, + description: `${propertyName} may be a component`, loc: value.loc, suggestions: null, }); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoDerivedComputationsInEffects.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoDerivedComputationsInEffects.ts index f1fa5aec407..8ec7542a9d9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoDerivedComputationsInEffects.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoDerivedComputationsInEffects.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {CompilerError, ErrorSeverity, SourceLocation} from '..'; +import {CompilerError, SourceLocation} from '..'; import {ErrorCategory} from '../CompilerError'; import { ArrayExpression, @@ -83,7 +83,14 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void { const dependencies: Array = deps.elements.map(dep => { CompilerError.invariant(dep.kind === 'Identifier', { reason: `Dependency is checked as a place above`, - loc: value.loc, + description: null, + details: [ + { + kind: 'error', + loc: value.loc, + message: 'this is checked as a place above', + }, + ], }); return locals.get(dep.identifier.id) ?? dep.identifier.id; }); @@ -97,7 +104,7 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void { } } } - if (errors.hasErrors()) { + if (errors.hasAnyErrors()) { throw errors; } } @@ -224,7 +231,6 @@ function validateEffect( reason: 'Values derived from props and state should be calculated during render, not in an effect. (https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state)', description: null, - severity: ErrorSeverity.InvalidReact, loc, suggestions: null, }); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoFreezingKnownMutableFunctions.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoFreezingKnownMutableFunctions.ts index f49a9a0a475..0c5b5a9a319 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoFreezingKnownMutableFunctions.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoFreezingKnownMutableFunctions.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {CompilerDiagnostic, CompilerError, Effect, ErrorSeverity} from '..'; +import {CompilerDiagnostic, CompilerError, Effect} from '..'; import {ErrorCategory} from '../CompilerError'; import { HIRFunction, @@ -66,16 +66,15 @@ export function validateNoFreezingKnownMutableFunctions( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Immutability, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot modify local variables after render completes', - description: `This argument is a function which may reassign or mutate ${variable} after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead.`, + description: `This argument is a function which may reassign or mutate ${variable} after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead`, }) - .withDetail({ + .withDetails({ kind: 'error', loc: operand.loc, message: `This function may (indirectly) reassign or modify ${variable} after render`, }) - .withDetail({ + .withDetails({ kind: 'error', loc: effect.value.loc, message: `This modifies ${variable}`, diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoImpureFunctionsInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoImpureFunctionsInRender.ts index 868352e050e..ca0612d80ce 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoImpureFunctionsInRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoImpureFunctionsInRender.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {CompilerDiagnostic, CompilerError, ErrorSeverity} from '..'; +import {CompilerDiagnostic, CompilerError} from '..'; import {ErrorCategory} from '../CompilerError'; import {HIRFunction} from '../HIR'; import {getFunctionCallSignature} from '../Inference/InferMutationAliasingEffects'; @@ -44,9 +44,8 @@ export function validateNoImpureFunctionsInRender( ? `\`${signature.canonicalName}\` is an impure function. ` : '') + 'Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent)', - severity: ErrorSeverity.InvalidReact, suggestions: null, - }).withDetail({ + }).withDetails({ kind: 'error', loc: callee.loc, message: 'Cannot call impure function', diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoJSXInTryStatement.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoJSXInTryStatement.ts index 158935f9e6e..00ffca556f4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoJSXInTryStatement.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoJSXInTryStatement.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {CompilerDiagnostic, CompilerError, ErrorSeverity} from '..'; +import {CompilerDiagnostic, CompilerError} from '..'; import {ErrorCategory} from '../CompilerError'; import {BlockId, HIRFunction} from '../HIR'; import {Result} from '../Utils/Result'; @@ -38,10 +38,9 @@ export function validateNoJSXInTryStatement( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.ErrorBoundaries, - severity: ErrorSeverity.InvalidReact, reason: 'Avoid constructing JSX within try/catch', description: `React does not immediately render components when JSX is rendered, so any errors from this component will not be caught by the try/catch. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)`, - }).withDetail({ + }).withDetails({ kind: 'error', loc: value.loc, message: 'Avoid constructing JSX within try/catch', diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts index 679d355e321..eb053ac4196 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts @@ -9,7 +9,6 @@ import { CompilerDiagnostic, CompilerError, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import { BlockId, @@ -58,8 +57,14 @@ function makeRefId(id: number): RefId { CompilerError.invariant(id >= 0 && Number.isInteger(id), { reason: 'Expected identifier id to be a non-negative integer', description: null, - loc: null, suggestions: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], }); return id as RefId; } @@ -192,19 +197,40 @@ function tyEqual(a: RefAccessType, b: RefAccessType): boolean { case 'Guard': CompilerError.invariant(b.kind === 'Guard', { reason: 'Expected ref value', - loc: null, + description: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], }); return a.refId === b.refId; case 'RefValue': CompilerError.invariant(b.kind === 'RefValue', { reason: 'Expected ref value', - loc: null, + description: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], }); return a.loc == b.loc; case 'Structure': { CompilerError.invariant(b.kind === 'Structure', { reason: 'Expected structure', - loc: null, + description: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], }); const fnTypesEqual = (a.fn === null && b.fn === null) || @@ -243,7 +269,14 @@ function joinRefAccessTypes(...types: Array): RefAccessType { a.kind === 'Structure' && b.kind === 'Structure', { reason: 'Expected structure', - loc: null, + description: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], }, ); const fn = @@ -470,10 +503,9 @@ function validateNoRefAccessInRenderImpl( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Refs, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot access refs during render', description: ERROR_DESCRIPTION, - }).withDetail({ + }).withDetails({ kind: 'error', loc: callee.loc, message: `This function accesses a ref value`, @@ -703,14 +735,21 @@ function validateNoRefAccessInRenderImpl( } } - if (errors.hasErrors()) { + if (errors.hasAnyErrors()) { return Err(errors); } } CompilerError.invariant(!env.hasChanged(), { reason: 'Ref type environment did not converge', - loc: null, + description: null, + details: [ + { + kind: 'error', + loc: null, + message: null, + }, + ], }); return Ok( @@ -734,10 +773,9 @@ function guardCheck(errors: CompilerError, operand: Place, env: Env): void { errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Refs, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot access refs during render', description: ERROR_DESCRIPTION, - }).withDetail({ + }).withDetails({ kind: 'error', loc: operand.loc, message: `Cannot access ref value during render`, @@ -759,10 +797,9 @@ function validateNoRefValueAccess( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Refs, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot access refs during render', description: ERROR_DESCRIPTION, - }).withDetail({ + }).withDetails({ kind: 'error', loc: (type.kind === 'RefValue' && type.loc) || operand.loc, message: `Cannot access ref value during render`, @@ -786,10 +823,9 @@ function validateNoRefPassedToFunction( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Refs, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot access refs during render', description: ERROR_DESCRIPTION, - }).withDetail({ + }).withDetails({ kind: 'error', loc: (type.kind === 'RefValue' && type.loc) || loc, message: `Passing a ref to a function may read its value during render`, @@ -809,10 +845,9 @@ function validateNoRefUpdate( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Refs, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot access refs during render', description: ERROR_DESCRIPTION, - }).withDetail({ + }).withDetails({ kind: 'error', loc: (type.kind === 'RefValue' && type.loc) || loc, message: `Cannot update ref during render`, @@ -831,10 +866,9 @@ function validateNoDirectRefValueAccess( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Refs, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot access refs during render', description: ERROR_DESCRIPTION, - }).withDetail({ + }).withDetails({ kind: 'error', loc: type.loc ?? operand.loc, message: `Cannot access ref value during render`, diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInEffects.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInEffects.ts index 4a24098a9fe..19c2e7bc5b9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInEffects.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInEffects.ts @@ -9,7 +9,6 @@ import { CompilerDiagnostic, CompilerError, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import { HIRFunction, @@ -107,9 +106,8 @@ export function validateNoSetStateInEffects( '* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\n' + 'Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. ' + '(https://react.dev/learn/you-might-not-need-an-effect)', - severity: ErrorSeverity.InvalidReact, suggestions: null, - }).withDetail({ + }).withDetails({ kind: 'error', loc: setState.loc, message: diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInRender.ts index 2ee9ab64b7e..a1a05b2e63c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInRender.ts @@ -9,7 +9,6 @@ import { CompilerDiagnostic, CompilerError, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import {HIRFunction, IdentifierId, isSetStateType} from '../HIR'; import {computeUnconditionalBlocks} from '../HIR/ComputeUnconditionalBlocks'; @@ -103,7 +102,14 @@ function validateNoSetStateInRenderImpl( case 'StartMemoize': { CompilerError.invariant(activeManualMemoId === null, { reason: 'Unexpected nested StartMemoize instructions', - loc: instr.value.loc, + description: null, + details: [ + { + kind: 'error', + loc: instr.value.loc, + message: null, + }, + ], }); activeManualMemoId = instr.value.manualMemoId; break; @@ -114,7 +120,14 @@ function validateNoSetStateInRenderImpl( { reason: 'Expected FinishMemoize to align with previous StartMemoize instruction', - loc: instr.value.loc, + description: null, + details: [ + { + kind: 'error', + loc: instr.value.loc, + message: null, + }, + ], }, ); activeManualMemoId = null; @@ -134,9 +147,8 @@ function validateNoSetStateInRenderImpl( 'Calling setState from useMemo may trigger an infinite loop', description: 'Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState)', - severity: ErrorSeverity.InvalidReact, suggestions: null, - }).withDetail({ + }).withDetails({ kind: 'error', loc: callee.loc, message: 'Found setState() within useMemo()', @@ -150,9 +162,8 @@ function validateNoSetStateInRenderImpl( 'Calling setState during render may trigger an infinite loop', description: 'Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)', - severity: ErrorSeverity.InvalidReact, suggestions: null, - }).withDetail({ + }).withDetails({ kind: 'error', loc: callee.loc, message: 'Found setState() in render', diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts index 624cf382b7d..49d8a85a96b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts @@ -9,7 +9,6 @@ import { CompilerDiagnostic, CompilerError, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import { DeclarationId, @@ -246,7 +245,14 @@ function validateInferredDep( CompilerError.invariant(dep.identifier.name?.kind === 'named', { reason: 'ValidatePreservedManualMemoization: expected scope dependency to be named', - loc: GeneratedSource, + description: null, + details: [ + { + kind: 'error', + loc: GeneratedSource, + message: null, + }, + ], suggestions: null, }); normalizedDep = { @@ -283,7 +289,6 @@ function validateInferredDep( errorState.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.PreserveManualMemo, - severity: ErrorSeverity.CannotPreserveMemoization, reason: 'Existing memoization could not be preserved', description: [ 'React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. ', @@ -299,13 +304,13 @@ function validateInferredDep( errorDiagnostic ? getCompareDependencyResultDescription(errorDiagnostic) : 'Inferred dependency not present in source' - }.` + }` : '', ] .join('') .trim(), suggestions: null, - }).withDetail({ + }).withDetails({ kind: 'error', loc: memoLocation, message: 'Could not preserve existing manual memoization', @@ -497,7 +502,13 @@ class Visitor extends ReactiveFunctionVisitor { CompilerError.invariant(state.manualMemoState == null, { reason: 'Unexpected nested StartMemoize instructions', description: `Bad manual memoization ids: ${state.manualMemoState?.manualMemoId}, ${value.manualMemoId}`, - loc: value.loc, + details: [ + { + kind: 'error', + loc: value.loc, + message: null, + }, + ], suggestions: null, }); @@ -537,13 +548,12 @@ class Visitor extends ReactiveFunctionVisitor { state.errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.PreserveManualMemo, - severity: ErrorSeverity.CannotPreserveMemoization, reason: 'Existing memoization could not be preserved', description: [ 'React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. ', - 'This dependency may be mutated later, which could cause the value to change unexpectedly.', + 'This dependency may be mutated later, which could cause the value to change unexpectedly', ].join(''), - }).withDetail({ + }).withDetails({ kind: 'error', loc, message: 'This dependency may be modified later', @@ -559,7 +569,13 @@ class Visitor extends ReactiveFunctionVisitor { { reason: 'Unexpected mismatch between StartMemoize and FinishMemoize', description: `Encountered StartMemoize id=${state.manualMemoState?.manualMemoId} followed by FinishMemoize id=${value.manualMemoId}`, - loc: value.loc, + details: [ + { + kind: 'error', + loc: value.loc, + message: null, + }, + ], suggestions: null, }, ); @@ -585,17 +601,16 @@ class Visitor extends ReactiveFunctionVisitor { state.errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.PreserveManualMemo, - severity: ErrorSeverity.CannotPreserveMemoization, reason: 'Existing memoization could not be preserved', description: [ - 'React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output. ', + 'React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output', DEBUG ? `${printIdentifier(identifier)} was not memoized.` : '', ] .join('') .trim(), - }).withDetail({ + }).withDetails({ kind: 'error', loc, message: 'Could not preserve existing memoization', diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateStaticComponents.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateStaticComponents.ts index 375b8e8f011..484f825ac18 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateStaticComponents.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateStaticComponents.ts @@ -9,7 +9,6 @@ import { CompilerDiagnostic, CompilerError, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import {HIRFunction, IdentifierId, SourceLocation} from '../HIR'; import {Result} from '../Utils/Result'; @@ -67,16 +66,15 @@ export function validateStaticComponents( error.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.StaticComponents, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot create components during render', - description: `Components created during render will reset their state each time they are created. Declare components outside of render. `, + description: `Components created during render will reset their state each time they are created. Declare components outside of render`, }) - .withDetail({ + .withDetails({ kind: 'error', loc: value.tag.loc, message: 'This component is created during render', }) - .withDetail({ + .withDetails({ kind: 'error', loc: location, message: 'The component is created during render here', diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateUseMemo.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateUseMemo.ts index 3146bbea38a..de74af93b6d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateUseMemo.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateUseMemo.ts @@ -9,7 +9,6 @@ import { CompilerDiagnostic, CompilerError, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import {FunctionExpression, HIRFunction, IdentifierId} from '../HIR'; import {Result} from '../Utils/Result'; @@ -76,12 +75,11 @@ export function validateUseMemo(fn: HIRFunction): Result { errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.UseMemo, - severity: ErrorSeverity.InvalidReact, reason: 'useMemo() callbacks may not accept parameters', description: - 'useMemo() callbacks are called by React to cache calculations across re-renders. They should not take parameters. Instead, directly reference the props, state, or local variables needed for the computation.', + 'useMemo() callbacks are called by React to cache calculations across re-renders. They should not take parameters. Instead, directly reference the props, state, or local variables needed for the computation', suggestions: null, - }).withDetail({ + }).withDetails({ kind: 'error', loc, message: 'Callbacks with parameters are not supported', @@ -93,13 +91,12 @@ export function validateUseMemo(fn: HIRFunction): Result { errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.UseMemo, - severity: ErrorSeverity.InvalidReact, reason: 'useMemo() callbacks may not be async or generator functions', description: - 'useMemo() callbacks are called once and must synchronously return a value.', + 'useMemo() callbacks are called once and must synchronously return a value', suggestions: null, - }).withDetail({ + }).withDetails({ kind: 'error', loc: body.loc, message: 'Async and generator functions are not supported', diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/Logger-test.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/Logger-test.ts index 096b723554f..ca386fb2402 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/Logger-test.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/Logger-test.ts @@ -56,7 +56,7 @@ it('logs failed compilation', () => { expect(event.kind).toEqual('CompileError'); invariant(event.kind === 'CompileError', 'typescript be smarter'); - expect(event.detail.severity).toEqual('InvalidReact'); + expect(event.detail.severity).toEqual('Error'); //@ts-ignore const {start, end, identifierName} = event.detail.primaryLocation() as t.SourceLocation; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/align-scopes-nested-block-structure.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/align-scopes-nested-block-structure.expect.md index f0dc8853882..3cad136ff11 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/align-scopes-nested-block-structure.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/align-scopes-nested-block-structure.expect.md @@ -129,6 +129,7 @@ function useFoo(t0) { t1 = null; break bb0; } + if (cond2) { mutate(s); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/align-scopes-reactive-scope-overlaps-label.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/align-scopes-reactive-scope-overlaps-label.expect.md index f2b1273a8f2..dc39126da45 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/align-scopes-reactive-scope-overlaps-label.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/align-scopes-reactive-scope-overlaps-label.expect.md @@ -43,6 +43,7 @@ function useFoo(t0) { if ($[0] !== cond || $[1] !== value) { bb0: { items = []; + if (cond) { break bb0; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/align-scopes-trycatch-nested-overlapping-range.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/align-scopes-trycatch-nested-overlapping-range.expect.md index 38d8a230680..2cb15a99ea5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/align-scopes-trycatch-nested-overlapping-range.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/align-scopes-trycatch-nested-overlapping-range.expect.md @@ -39,6 +39,7 @@ function Foo() { if (cond) { thing = makeObject_Primitives(); } + if (CONST_TRUE) { mutate(thing); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/assignment-in-nested-if.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/assignment-in-nested-if.expect.md index 583e2fcb2c9..c26d7652fed 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/assignment-in-nested-if.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/assignment-in-nested-if.expect.md @@ -23,6 +23,7 @@ import { c as _c } from "react/compiler-runtime"; function useBar(props) { const $ = _c(1); let z; + if (props.a) { if (props.b) { let t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-param-mutate.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-param-mutate.expect.md index 9e4709616d5..9d3623b849a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-param-mutate.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-param-mutate.expect.md @@ -67,6 +67,7 @@ function getNativeLogFunction(level) { ) { logLevel = LOG_LEVELS.warn; } + if (global.__inspectorLog) { global.__inspectorLog( INSPECTOR_LEVELS[logLevel], @@ -75,6 +76,7 @@ function getNativeLogFunction(level) { INSPECTOR_FRAMES_TO_SKIP, ); } + if (groupStack.length) { str = groupFormat("", str); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.expect.md index b7371108d58..223823621d0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.expect.md @@ -47,9 +47,7 @@ function useKeyCommand() { }; const moveLeft = { handler: handleKey("left") }; - const moveRight = { handler: handleKey("right") }; - t0 = [moveLeft, moveRight]; $[0] = t0; } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/chained-assignment-context-variable.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/chained-assignment-context-variable.expect.md index 13b0af22b9d..796b75b2ddb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/chained-assignment-context-variable.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/chained-assignment-context-variable.expect.md @@ -33,7 +33,6 @@ function Component() { let y; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { y = x = {}; - const foo = () => { x = makeArray(); }; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-on-mutable.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-on-mutable.expect.md index fa8348c2009..f855f2231d0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-on-mutable.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-on-mutable.expect.md @@ -44,6 +44,7 @@ function ComponentA(props) { if (b) { a.push(props.p0); } + if (props.p1) { b.push(props.p2); } @@ -68,6 +69,7 @@ function ComponentB(props) { if (mayMutate(b)) { a.push(props.p0); } + if (props.p1) { b.push(props.p2); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-set-state-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-set-state-in-render.expect.md index 8aad7d5be14..5c74ec25b85 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-set-state-in-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-set-state-in-render.expect.md @@ -34,6 +34,7 @@ function Component(props) { const foo = () => { setX(1); }; + if (props.cond) { setX(2); foo(); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-prop-to-object-method.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-prop-to-object-method.expect.md index 4b12ad07a6a..cc5633a7b3f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-prop-to-object-method.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-prop-to-object-method.expect.md @@ -36,7 +36,6 @@ function Foo() { return identity(1); }, }; - t0 = x.foo(); $[0] = t0; } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-template-literal.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-template-literal.expect.md index 0f01fa0a769..6f13b0cd489 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-template-literal.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-template-literal.expect.md @@ -79,7 +79,6 @@ function foo() { value={[ true, true, - "a\nb", "\n", "a1b", diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-unary-number.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-unary-number.expect.md index 074c3214810..b52ea1b51b4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-unary-number.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-unary-number.expect.md @@ -48,7 +48,6 @@ function foo() { true, -Infinity, -NaN, - -1 * NaN, -1 * Infinity, -1 * -Infinity, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constructor.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constructor.expect.md index bfa6c830712..6a01460e009 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constructor.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constructor.expect.md @@ -28,6 +28,7 @@ function Component(props) { const a = []; const b = {}; new Foo(a, b); + new Foo(b); t0 =
; $[0] = t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/context-variable-reassigned-objectmethod.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/context-variable-reassigned-objectmethod.expect.md index ae574c4dfc9..cdd0269d5cf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/context-variable-reassigned-objectmethod.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/context-variable-reassigned-objectmethod.expect.md @@ -43,7 +43,6 @@ function Component(t0) { } }, }; - invoke(obj.method, cond); $[0] = cond; $[1] = x; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/debugger.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/debugger.expect.md index db648a63904..b1eddc5d439 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/debugger.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/debugger.expect.md @@ -27,6 +27,7 @@ export const FIXTURE_ENTRYPOINT = { ```javascript function Component(props) { debugger; + if (props.cond) { debugger; } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/delete-computed-property.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/delete-computed-property.expect.md index be22ae06867..02be1a0ca47 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/delete-computed-property.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/delete-computed-property.expect.md @@ -26,6 +26,7 @@ function Component(props) { let x; if ($[0] !== props.a || $[1] !== props.b) { x = { a: props.a, b: props.b }; + delete x["b"]; $[0] = props.a; $[1] = props.b; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dependencies-outputs.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dependencies-outputs.expect.md index f0f9911c07e..70eeecdda95 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dependencies-outputs.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dependencies-outputs.expect.md @@ -46,6 +46,7 @@ function foo(a, b) { if (x.length) { y.push(x); } + if (b) { y.push(b); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dependencies.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dependencies.expect.md index cea8ae72d93..783ad41fd4f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dependencies.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dependencies.expect.md @@ -46,6 +46,7 @@ function foo(x, y, z) { } else { items2 = $[2]; } + if (y) { items.push(x); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dont-merge-if-dep-is-inner-declaration-of-previous-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dont-merge-if-dep-is-inner-declaration-of-previous-scope.expect.md index ce5bfda6440..58013c15608 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dont-merge-if-dep-is-inner-declaration-of-previous-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dont-merge-if-dep-is-inner-declaration-of-previous-scope.expect.md @@ -57,6 +57,7 @@ function Component(t0) { let y; if ($[0] !== a || $[1] !== b || $[2] !== c) { x = []; + if (a) { let t1; if ($[5] !== b) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.expect.md index 986fb8a5b26..deb87c9d8a0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.expect.md @@ -24,9 +24,9 @@ function useThing(fn) { ``` Found 1 error: -Error: `this` is not supported syntax +Compilation Skipped: `this` is not supported syntax -React Compiler does not support compiling functions that use `this` +React Compiler does not support compiling functions that use `this`. error.reserved-words.ts:8:28 6 | diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.assign-global-in-component-tag-function.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.assign-global-in-component-tag-function.expect.md index ce42e651259..b7b707b3e74 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.assign-global-in-component-tag-function.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.assign-global-in-component-tag-function.expect.md @@ -19,7 +19,7 @@ Found 1 error: Error: Cannot reassign variables declared outside of the component/hook -Variable `someGlobal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) +Variable `someGlobal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render). error.assign-global-in-component-tag-function.ts:3:4 1 | function Component() { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.assign-global-in-jsx-children.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.assign-global-in-jsx-children.expect.md index ee57ea6eb0c..1f5ac0c83df 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.assign-global-in-jsx-children.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.assign-global-in-jsx-children.expect.md @@ -22,7 +22,7 @@ Found 1 error: Error: Cannot reassign variables declared outside of the component/hook -Variable `someGlobal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) +Variable `someGlobal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render). error.assign-global-in-jsx-children.ts:3:4 1 | function Component() { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bailout-on-flow-suppression.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bailout-on-flow-suppression.expect.md index 6e522e16669..fe0ade4b91e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bailout-on-flow-suppression.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bailout-on-flow-suppression.expect.md @@ -20,7 +20,7 @@ Found 1 error: Error: React Compiler has skipped optimizing this component because one or more React rule violations were reported by Flow -React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression `$FlowFixMe[react-rule-hook]` +React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression `$FlowFixMe[react-rule-hook]`. error.bailout-on-flow-suppression.ts:4:2 2 | diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bailout-on-suppression-of-custom-rule.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bailout-on-suppression-of-custom-rule.expect.md index 3221f97731d..ed9f73a0163 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bailout-on-suppression-of-custom-rule.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bailout-on-suppression-of-custom-rule.expect.md @@ -23,7 +23,7 @@ Found 2 errors: Error: React Compiler has skipped optimizing this component because one or more React ESLint rules were disabled -React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression `eslint-disable my-app/react-rule` +React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression `eslint-disable my-app/react-rule`. error.bailout-on-suppression-of-custom-rule.ts:3:0 1 | // @eslintSuppressionRules:["my-app","react-rule"] @@ -36,7 +36,7 @@ error.bailout-on-suppression-of-custom-rule.ts:3:0 Error: React Compiler has skipped optimizing this component because one or more React ESLint rules were disabled -React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression `eslint-disable-next-line my-app/react-rule` +React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression `eslint-disable-next-line my-app/react-rule`. error.bailout-on-suppression-of-custom-rule.ts:7:2 5 | 'use forget'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-infer-mutation-aliasing-effects.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-infer-mutation-aliasing-effects.expect.md index a1c64e50483..8968351e78e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-infer-mutation-aliasing-effects.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-infer-mutation-aliasing-effects.expect.md @@ -37,7 +37,7 @@ error.bug-infer-mutation-aliasing-effects.ts:10:22 8 | function thunk(action) { 9 | if (typeof action === 'function') { > 10 | return action(thunk, () => stateRef.current, extraArg); - | ^^^^^ [InferMutationAliasingEffects] Expected value kind to be initialized + | ^^^^^ this is uninitialized 11 | } else { 12 | dispatch(action); 13 | return undefined; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-codegen-methodcall.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-codegen-methodcall.expect.md index 4ea831de875..cd311c6f219 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-codegen-methodcall.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-codegen-methodcall.expect.md @@ -16,13 +16,13 @@ const YearsAndMonthsSince = () => { ``` Found 1 error: -Invariant: [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. Got a `Identifier` +Invariant: [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression error.bug-invariant-codegen-methodcall.ts:3:17 1 | const YearsAndMonthsSince = () => { 2 | const diff = foo(); > 3 | const months = Math.floor(diff.bar()); - | ^^^^^^^^^^ [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. Got a `Identifier` + | ^^^^^^^^^^ Got: 'Identifier' 4 | return <>{months}; 5 | }; 6 | diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-local-or-context-references.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-local-or-context-references.expect.md index bbf753f9650..bca2e693074 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-local-or-context-references.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-local-or-context-references.expect.md @@ -31,13 +31,13 @@ Found 1 error: Invariant: Expected all references to a variable to be consistently local or context references -Identifier err$7 is referenced as a context variable, but was previously referenced as a [object Object] variable. +Identifier err$7 is referenced as a context variable, but was previously referenced as a local variable. error.bug-invariant-local-or-context-references.ts:15:13 13 | setState(_prevState => ({ 14 | loading: false, > 15 | error: err, - | ^^^ Expected all references to a variable to be consistently local or context references + | ^^^ this is local 16 | })); 17 | } 18 | }; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unexpected-terminal-in-optional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unexpected-terminal-in-optional.expect.md index 743d2b9071e..30b95149263 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unexpected-terminal-in-optional.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unexpected-terminal-in-optional.expect.md @@ -25,7 +25,7 @@ error.bug-invariant-unexpected-terminal-in-optional.ts:3:16 1 | const Foo = ({json}) => { 2 | try { > 3 | const foo = JSON.parse(json)?.foo; - | ^^^^ Unexpected terminal in optional + | ^^^^ Unexpected maybe-throw in optional 4 | return {foo}; 5 | } catch { 6 | return null; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.call-args-destructuring-asignment-complex.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.call-args-destructuring-asignment-complex.expect.md index 624bc8b0b57..8b936ff0d92 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.call-args-destructuring-asignment-complex.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.call-args-destructuring-asignment-complex.expect.md @@ -22,7 +22,7 @@ error.call-args-destructuring-asignment-complex.ts:3:9 1 | function Component(props) { 2 | let x = makeObject(); > 3 | x.foo(([[x]] = makeObject())); - | ^^^^^ Const declaration cannot be referenced as an expression + | ^^^^^ this is Const 4 | return x; 5 | } 6 | diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capitalized-function-call-aliased.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capitalized-function-call-aliased.expect.md index 499f2dd8739..60964064765 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capitalized-function-call-aliased.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capitalized-function-call-aliased.expect.md @@ -18,7 +18,7 @@ Found 1 error: Error: Capitalized functions are reserved for components, which must be invoked with JSX. If this is a component, render it with JSX. Otherwise, ensure that it has no hook calls and rename it to begin with a lowercase letter. Alternatively, if you know for a fact that this function is not a component, you can allowlist it via the compiler config -Bar may be a component.. +Bar may be a component. error.capitalized-function-call-aliased.ts:4:2 2 | function Foo() { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capitalized-function-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capitalized-function-call.expect.md index a89efa7c451..59db7442a36 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capitalized-function-call.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capitalized-function-call.expect.md @@ -19,7 +19,7 @@ Found 1 error: Error: Capitalized functions are reserved for components, which must be invoked with JSX. If this is a component, render it with JSX. Otherwise, ensure that it has no hook calls and rename it to begin with a lowercase letter. Alternatively, if you know for a fact that this function is not a component, you can allowlist it via the compiler config -SomeFunc may be a component.. +SomeFunc may be a component. error.capitalized-function-call.ts:3:12 1 | // @validateNoCapitalizedCalls diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capitalized-method-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capitalized-method-call.expect.md index c957e5bf7a5..f55721caa10 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capitalized-method-call.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capitalized-method-call.expect.md @@ -19,7 +19,7 @@ Found 1 error: Error: Capitalized functions are reserved for components, which must be invoked with JSX. If this is a component, render it with JSX. Otherwise, ensure that it has no hook calls and rename it to begin with a lowercase letter. Alternatively, if you know for a fact that this function is not a component, you can allowlist it via the compiler config -SomeFunc may be a component.. +SomeFunc may be a component. error.capitalized-method-call.ts:3:12 1 | // @validateNoCapitalizedCalls diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-mutation.expect.md index cb2256a187f..a3b2ace512f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-mutation.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-mutation.expect.md @@ -36,7 +36,7 @@ Found 2 errors: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.capture-ref-for-mutation.ts:12:13 10 | }; @@ -49,7 +49,7 @@ error.capture-ref-for-mutation.ts:12:13 Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.capture-ref-for-mutation.ts:15:13 13 | }; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-ref-value.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-ref-value.expect.md index 36949c65042..cf9a6a5b4c1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-ref-value.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-ref-value.expect.md @@ -24,7 +24,7 @@ Found 2 errors: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.hook-ref-value.ts:5:23 3 | function Component(props) { @@ -37,7 +37,7 @@ error.hook-ref-value.ts:5:23 Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.hook-ref-value.ts:5:23 3 | function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-during-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-during-render.expect.md index 989e68efd88..94a9a984c2b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-during-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-during-render.expect.md @@ -19,7 +19,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-access-ref-during-render.ts:4:16 2 | function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-in-reducer-init.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-in-reducer-init.expect.md index 29fe24a2202..647cf28f7b3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-in-reducer-init.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-in-reducer-init.expect.md @@ -30,7 +30,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-access-ref-in-reducer-init.ts:8:4 6 | (state, action) => state + action, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-in-reducer.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-in-reducer.expect.md index f23560b4f69..33fcd6d188c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-in-reducer.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-in-reducer.expect.md @@ -26,7 +26,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-access-ref-in-reducer.ts:5:29 3 | function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-in-render-mutate-object-with-ref-function.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-in-render-mutate-object-with-ref-function.expect.md index a70fcf39b3d..73cead6affc 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-in-render-mutate-object-with-ref-function.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-in-render-mutate-object-with-ref-function.expect.md @@ -22,7 +22,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-access-ref-in-render-mutate-object-with-ref-function.ts:7:19 5 | const object = {}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-in-state-initializer.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-in-state-initializer.expect.md index dd6a64d9db7..a10db96463d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-in-state-initializer.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-in-state-initializer.expect.md @@ -26,7 +26,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-access-ref-in-state-initializer.ts:5:27 3 | function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-aliased-ref-in-callback-invoked-during-render-.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-aliased-ref-in-callback-invoked-during-render-.expect.md index 3aa52375339..09a64d4bab2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-aliased-ref-in-callback-invoked-during-render-.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-aliased-ref-in-callback-invoked-during-render-.expect.md @@ -23,7 +23,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-aliased-ref-in-callback-invoked-during-render-.ts:9:33 7 | return ; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-assign-current-inferred-ref-during-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-assign-current-inferred-ref-during-render.expect.md index 4f4ed63550d..293596a5403 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-assign-current-inferred-ref-during-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-assign-current-inferred-ref-during-render.expect.md @@ -22,7 +22,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). 4 | component Example() { 5 | const fooRef = makeObject_Primitives(); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-conditional-setState-in-useMemo.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-conditional-setState-in-useMemo.expect.md index c99dfc1e195..e4a94249623 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-conditional-setState-in-useMemo.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-conditional-setState-in-useMemo.expect.md @@ -26,7 +26,7 @@ Found 2 errors: Error: Calling setState from useMemo may trigger an infinite loop -Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState) +Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState). error.invalid-conditional-setState-in-useMemo.ts:7:6 5 | useMemo(() => { @@ -39,7 +39,7 @@ error.invalid-conditional-setState-in-useMemo.ts:7:6 Error: Calling setState from useMemo may trigger an infinite loop -Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState) +Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState). error.invalid-conditional-setState-in-useMemo.ts:8:6 6 | if (cond) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-destructure-assignment-to-global.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-destructure-assignment-to-global.expect.md index 4b49c5f6530..7565ae35466 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-destructure-assignment-to-global.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-destructure-assignment-to-global.expect.md @@ -17,7 +17,7 @@ Found 1 error: Error: Cannot reassign variables declared outside of the component/hook -Variable `x` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) +Variable `x` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render). error.invalid-destructure-assignment-to-global.ts:2:3 1 | function useFoo(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-destructure-to-local-global-variables.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-destructure-to-local-global-variables.expect.md index 6da3b558bda..fedb1d5f3b1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-destructure-to-local-global-variables.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-destructure-to-local-global-variables.expect.md @@ -19,7 +19,7 @@ Found 1 error: Error: Cannot reassign variables declared outside of the component/hook -Variable `b` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) +Variable `b` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render). error.invalid-destructure-to-local-global-variables.ts:3:6 1 | function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-disallow-mutating-ref-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-disallow-mutating-ref-in-render.expect.md index 9f19d10b9d4..c43bb5dcd9b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-disallow-mutating-ref-in-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-disallow-mutating-ref-in-render.expect.md @@ -20,7 +20,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-disallow-mutating-ref-in-render.ts:4:2 2 | function Component() { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-disallow-mutating-refs-in-render-transitive.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-disallow-mutating-refs-in-render-transitive.expect.md index 740a0519d5c..c8b70edcc41 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-disallow-mutating-refs-in-render-transitive.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-disallow-mutating-refs-in-render-transitive.expect.md @@ -25,7 +25,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-disallow-mutating-refs-in-render-transitive.ts:9:2 7 | }; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-eval-unsupported.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-eval-unsupported.expect.md index d01aeeb1d48..d766bc03b21 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-eval-unsupported.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-eval-unsupported.expect.md @@ -15,7 +15,7 @@ function Component(props) { ``` Found 1 error: -Error: The 'eval' function is not supported +Compilation Skipped: The 'eval' function is not supported Eval is an anti-pattern in JavaScript, and the code executed cannot be evaluated by React Compiler. diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-global-reassignment-indirect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-global-reassignment-indirect.expect.md index 8e8b7917d77..c8331d43afb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-global-reassignment-indirect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-global-reassignment-indirect.expect.md @@ -39,7 +39,7 @@ Found 1 error: Error: Cannot reassign variables declared outside of the component/hook -Variable `someGlobal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) +Variable `someGlobal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render). error.invalid-global-reassignment-indirect.ts:9:4 7 | diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-impure-functions-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-impure-functions-in-render.expect.md index 3155d64329c..255da7389b3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-impure-functions-in-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-impure-functions-in-render.expect.md @@ -21,7 +21,7 @@ Found 3 errors: Error: Cannot call impure function during render -`Date.now` is an impure function. Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent) +`Date.now` is an impure function. Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). error.invalid-impure-functions-in-render.ts:4:15 2 | @@ -34,7 +34,7 @@ error.invalid-impure-functions-in-render.ts:4:15 Error: Cannot call impure function during render -`performance.now` is an impure function. Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent) +`performance.now` is an impure function. Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). error.invalid-impure-functions-in-render.ts:5:14 3 | function Component() { @@ -47,7 +47,7 @@ error.invalid-impure-functions-in-render.ts:5:14 Error: Cannot call impure function during render -`Math.random` is an impure function. Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent) +`Math.random` is an impure function. Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). error.invalid-impure-functions-in-render.ts:6:15 4 | const date = Date.now(); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-pass-ref-to-function.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-pass-ref-to-function.expect.md index 79c2a2e4f6c..eaa140eb90b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-pass-ref-to-function.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-pass-ref-to-function.expect.md @@ -19,7 +19,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-pass-ref-to-function.ts:4:16 2 | function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-read-ref-prop-in-render-destructure.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-read-ref-prop-in-render-destructure.expect.md index 5521300e292..cca903de74c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-read-ref-prop-in-render-destructure.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-read-ref-prop-in-render-destructure.expect.md @@ -18,7 +18,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-read-ref-prop-in-render-destructure.ts:3:16 1 | // @validateRefAccessDuringRender @compilationMode:"infer" diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-read-ref-prop-in-render-property-load.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-read-ref-prop-in-render-property-load.expect.md index 11d95823d46..49b8e5d199f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-read-ref-prop-in-render-property-load.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-read-ref-prop-in-render-property-load.expect.md @@ -18,7 +18,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-read-ref-prop-in-render-property-load.ts:3:16 1 | // @validateRefAccessDuringRender @compilationMode:"infer" diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-reassign-local-variable-in-async-callback.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-reassign-local-variable-in-async-callback.expect.md index aa9c0bffe4f..4e397afd6a0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-reassign-local-variable-in-async-callback.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-reassign-local-variable-in-async-callback.expect.md @@ -29,7 +29,7 @@ Found 1 error: Error: Cannot reassign variable in async function -Reassigning a variable in an async function can cause inconsistent behavior on subsequent renders. Consider using state instead +Reassigning a variable in an async function can cause inconsistent behavior on subsequent renders. Consider using state instead. error.invalid-reassign-local-variable-in-async-callback.ts:8:6 6 | // after render, so this should error regardless of where this ends up diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-ref-in-callback-invoked-during-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-ref-in-callback-invoked-during-render.expect.md index 414ee9d536a..df1e771fa25 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-ref-in-callback-invoked-during-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-ref-in-callback-invoked-during-render.expect.md @@ -22,7 +22,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-ref-in-callback-invoked-during-render.ts:8:33 6 | return ; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-ref-value-as-props.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-ref-value-as-props.expect.md index 2bbde91d8f1..d581232b3a4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-ref-value-as-props.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-ref-value-as-props.expect.md @@ -18,7 +18,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-ref-value-as-props.ts:4:19 2 | function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-set-and-read-ref-during-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-set-and-read-ref-during-render.expect.md index 296b9f0831b..387dff27bf0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-set-and-read-ref-during-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-set-and-read-ref-during-render.expect.md @@ -19,7 +19,7 @@ Found 2 errors: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-set-and-read-ref-during-render.ts:4:2 2 | function Component(props) { @@ -32,7 +32,7 @@ error.invalid-set-and-read-ref-during-render.ts:4:2 Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-set-and-read-ref-during-render.ts:5:9 3 | const ref = useRef(null); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-set-and-read-ref-nested-property-during-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-set-and-read-ref-nested-property-during-render.expect.md index ff57f3d171a..8ef0e223a86 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-set-and-read-ref-nested-property-during-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-set-and-read-ref-nested-property-during-render.expect.md @@ -19,7 +19,7 @@ Found 2 errors: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-set-and-read-ref-nested-property-during-render.ts:4:2 2 | function Component(props) { @@ -32,7 +32,7 @@ error.invalid-set-and-read-ref-nested-property-during-render.ts:4:2 Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-set-and-read-ref-nested-property-during-render.ts:5:9 3 | const ref = useRef({inner: null}); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-setState-in-useMemo-indirect-useCallback.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-setState-in-useMemo-indirect-useCallback.expect.md index 48188548fc0..e284a9367fb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-setState-in-useMemo-indirect-useCallback.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-setState-in-useMemo-indirect-useCallback.expect.md @@ -30,7 +30,7 @@ Found 1 error: Error: Calling setState from useMemo may trigger an infinite loop -Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState) +Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState). error.invalid-setState-in-useMemo-indirect-useCallback.ts:13:4 11 | diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-setState-in-useMemo.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-setState-in-useMemo.expect.md index 16a9386f4da..04d82e429f8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-setState-in-useMemo.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-setState-in-useMemo.expect.md @@ -24,7 +24,7 @@ Found 2 errors: Error: Calling setState from useMemo may trigger an infinite loop -Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState) +Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState). error.invalid-setState-in-useMemo.ts:6:4 4 | @@ -37,7 +37,7 @@ error.invalid-setState-in-useMemo.ts:6:4 Error: Calling setState from useMemo may trigger an infinite loop -Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState) +Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState). error.invalid-setState-in-useMemo.ts:7:4 5 | useMemo(() => { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-sketchy-code-use-forget.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-sketchy-code-use-forget.expect.md index 96be8584be2..be22558e3c7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-sketchy-code-use-forget.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-sketchy-code-use-forget.expect.md @@ -21,7 +21,7 @@ Found 2 errors: Error: React Compiler has skipped optimizing this component because one or more React ESLint rules were disabled -React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression `eslint-disable react-hooks/rules-of-hooks` +React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression `eslint-disable react-hooks/rules-of-hooks`. error.invalid-sketchy-code-use-forget.ts:1:0 > 1 | /* eslint-disable react-hooks/rules-of-hooks */ @@ -32,7 +32,7 @@ error.invalid-sketchy-code-use-forget.ts:1:0 Error: React Compiler has skipped optimizing this component because one or more React ESLint rules were disabled -React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression `eslint-disable-next-line react-hooks/rules-of-hooks` +React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression `eslint-disable-next-line react-hooks/rules-of-hooks`. error.invalid-sketchy-code-use-forget.ts:5:2 3 | 'use forget'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-unclosed-eslint-suppression.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-unclosed-eslint-suppression.expect.md index e19cee75326..9b7883f6172 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-unclosed-eslint-suppression.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-unclosed-eslint-suppression.expect.md @@ -40,7 +40,7 @@ Found 1 error: Error: React Compiler has skipped optimizing this component because one or more React ESLint rules were disabled -React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression `eslint-disable react-hooks/rules-of-hooks` +React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression `eslint-disable react-hooks/rules-of-hooks`. error.invalid-unclosed-eslint-suppression.ts:2:0 1 | // Note: Everything below this is sketchy diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-unconditional-set-state-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-unconditional-set-state-in-render.expect.md index c4adc4c9bfb..78deea83904 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-unconditional-set-state-in-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-unconditional-set-state-in-render.expect.md @@ -23,7 +23,7 @@ Found 2 errors: Error: Calling setState during render may trigger an infinite loop -Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState) +Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState). error.invalid-unconditional-set-state-in-render.ts:6:2 4 | const aliased = setX; @@ -36,7 +36,7 @@ error.invalid-unconditional-set-state-in-render.ts:6:2 Error: Calling setState during render may trigger an infinite loop -Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState) +Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState). error.invalid-unconditional-set-state-in-render.ts:7:2 5 | diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-use-ref-added-to-dep-without-type-info.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-use-ref-added-to-dep-without-type-info.expect.md index f41ae64ce75..53bf66b1ee5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-use-ref-added-to-dep-without-type-info.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-use-ref-added-to-dep-without-type-info.expect.md @@ -26,7 +26,7 @@ Found 2 errors: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-use-ref-added-to-dep-without-type-info.ts:10:21 8 | // however, this is an instance of accessing a ref during render and is disallowed @@ -39,7 +39,7 @@ error.invalid-use-ref-added-to-dep-without-type-info.ts:10:21 Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-use-ref-added-to-dep-without-type-info.ts:12:28 10 | const x = {a, val: val.ref.current}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-write-but-dont-read-ref-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-write-but-dont-read-ref-in-render.expect.md index abce1ed3445..94223bb898c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-write-but-dont-read-ref-in-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-write-but-dont-read-ref-in-render.expect.md @@ -21,7 +21,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-write-but-dont-read-ref-in-render.ts:5:2 3 | const ref = useRef(null); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-write-ref-prop-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-write-ref-prop-in-render.expect.md index 0e76607498a..f8d44926094 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-write-ref-prop-in-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-write-ref-prop-in-render.expect.md @@ -19,7 +19,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.invalid-write-ref-prop-in-render.ts:4:2 2 | function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.nested-component-in-normal-function.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.nested-component-in-normal-function.expect.md index 14d86ffe825..69ce796faed 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.nested-component-in-normal-function.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.nested-component-in-normal-function.expect.md @@ -31,7 +31,7 @@ Found 1 error: Error: Components and hooks cannot be created dynamically -The function `Wrapper` appears to be a React component, but it's defined inside `getInput`. Components and Hooks should always be declared at module scope +The function `Wrapper` appears to be a React component, but it's defined inside `getInput`. Components and Hooks should always be declared at module scope. error.nested-component-in-normal-function.ts:2:16 1 | // @validateNoDynamicallyCreatedComponentsOrHooks diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.nested-hook-in-normal-function.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.nested-hook-in-normal-function.expect.md index 0ab2b977561..652fc2feb00 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.nested-hook-in-normal-function.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.nested-hook-in-normal-function.expect.md @@ -35,7 +35,7 @@ Found 1 error: Error: Components and hooks cannot be created dynamically -The function `useConfiguredState` appears to be a React hook, but it's defined inside `createCustomHook`. Components and Hooks should always be declared at module scope +The function `useConfiguredState` appears to be a React hook, but it's defined inside `createCustomHook`. Components and Hooks should always be declared at module scope. error.nested-hook-in-normal-function.ts:4:9 2 | import {useState} from 'react'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.reassign-global-fn-arg.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.reassign-global-fn-arg.expect.md index 2c409ea5b50..db088bbd0b9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.reassign-global-fn-arg.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.reassign-global-fn-arg.expect.md @@ -28,7 +28,7 @@ Found 1 error: Error: Cannot reassign variables declared outside of the component/hook -Variable `b` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) +Variable `b` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render). error.reassign-global-fn-arg.ts:5:4 3 | export default function MyApp() { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.reassignment-to-global-indirect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.reassignment-to-global-indirect.expect.md index 8835f19ad10..a223997bb55 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.reassignment-to-global-indirect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.reassignment-to-global-indirect.expect.md @@ -21,7 +21,7 @@ Found 2 errors: Error: Cannot reassign variables declared outside of the component/hook -Variable `someUnknownGlobal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) +Variable `someUnknownGlobal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render). error.reassignment-to-global-indirect.ts:4:4 2 | const foo = () => { @@ -34,7 +34,7 @@ error.reassignment-to-global-indirect.ts:4:4 Error: Cannot reassign variables declared outside of the component/hook -Variable `moduleLocal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) +Variable `moduleLocal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render). error.reassignment-to-global-indirect.ts:5:4 3 | // Cannot assign to globals diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.reassignment-to-global.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.reassignment-to-global.expect.md index 4d259dd8d4c..0a374fd39ff 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.reassignment-to-global.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.reassignment-to-global.expect.md @@ -18,7 +18,7 @@ Found 2 errors: Error: Cannot reassign variables declared outside of the component/hook -Variable `someUnknownGlobal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) +Variable `someUnknownGlobal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render). error.reassignment-to-global.ts:3:2 1 | function Component() { @@ -31,7 +31,7 @@ error.reassignment-to-global.ts:3:2 Error: Cannot reassign variables declared outside of the component/hook -Variable `moduleLocal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) +Variable `moduleLocal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render). error.reassignment-to-global.ts:4:2 2 | // Cannot assign to globals diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-arbitrary.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-arbitrary.expect.md index 2a725592815..17625298cd7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-arbitrary.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-arbitrary.expect.md @@ -29,7 +29,7 @@ Found 2 errors: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). 6 | component C() { 7 | const r = useRef(DEFAULT_VALUE); @@ -41,7 +41,7 @@ React refs are values that are not needed for rendering. Refs should only be acc Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). 7 | const r = useRef(DEFAULT_VALUE); 8 | if (r.current == DEFAULT_VALUE) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call-2.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call-2.expect.md index f3b292f6585..3a6d0b0f7a4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call-2.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call-2.expect.md @@ -27,7 +27,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). 5 | const r = useRef(null); 6 | if (r.current == null) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call.expect.md index d57c3ee010a..d9f3ac3aad8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call.expect.md @@ -27,7 +27,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). 5 | const r = useRef(null); 6 | if (r.current == null) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-linear.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-linear.expect.md index 211dee52c80..7c6e6d5d58a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-linear.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-linear.expect.md @@ -28,7 +28,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). 6 | if (r.current == null) { 7 | r.current = 42; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-nonif.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-nonif.expect.md index 6388f01ee23..aaa86f91415 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-nonif.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-nonif.expect.md @@ -28,7 +28,7 @@ Found 2 errors: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). 4 | component C() { 5 | const r = useRef(null); @@ -40,7 +40,7 @@ React refs are values that are not needed for rendering. Refs should only be acc Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). 5 | const r = useRef(null); 6 | const guard = r.current == null; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-other.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-other.expect.md index 4103eaa2913..e1bda188909 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-other.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-other.expect.md @@ -28,7 +28,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). 6 | const r2 = useRef(null); 7 | if (r.current == null) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access-2.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access-2.expect.md index f04df650ad5..e30d6103a20 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access-2.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access-2.expect.md @@ -28,7 +28,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). 7 | r.current = 1; 8 | } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access.expect.md index b432538f61c..f8d08dda477 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access.expect.md @@ -28,7 +28,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). 7 | r.current = 1; 8 | } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-optional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-optional.expect.md index 80609e0338d..94e4b0fc46f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-optional.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-optional.expect.md @@ -24,7 +24,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.ref-optional.ts:5:9 3 | function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.sketchy-code-exhaustive-deps.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.sketchy-code-exhaustive-deps.expect.md index 9c87cafff18..92c0d5ab1a0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.sketchy-code-exhaustive-deps.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.sketchy-code-exhaustive-deps.expect.md @@ -24,7 +24,7 @@ Found 1 error: Error: React Compiler has skipped optimizing this component because one or more React ESLint rules were disabled -React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression `eslint-disable-next-line react-hooks/exhaustive-deps` +React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression `eslint-disable-next-line react-hooks/exhaustive-deps`. error.sketchy-code-exhaustive-deps.ts:6:7 4 | () => { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.sketchy-code-rules-of-hooks.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.sketchy-code-rules-of-hooks.expect.md index 7077b733b0d..2e95c637897 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.sketchy-code-rules-of-hooks.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.sketchy-code-rules-of-hooks.expect.md @@ -25,7 +25,7 @@ Found 1 error: Error: React Compiler has skipped optimizing this component because one or more React ESLint rules were disabled -React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression `eslint-disable react-hooks/rules-of-hooks` +React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression `eslint-disable react-hooks/rules-of-hooks`. error.sketchy-code-rules-of-hooks.ts:1:0 > 1 | /* eslint-disable react-hooks/rules-of-hooks */ diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md index a4d3525757b..32db5b2e7ca 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md @@ -92,7 +92,7 @@ error.todo-kitchensink.ts:3:2 5 | class Bar { 6 | #secretSauce = 42; -Error: Inline `class` declarations are not supported +Compilation Skipped: Inline `class` declarations are not supported Move class declarations outside of components/hooks. diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-nested-method-calls-lower-property-load-into-temporary.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-nested-method-calls-lower-property-load-into-temporary.expect.md index 67d6c4f4e05..e6968dcf13f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-nested-method-calls-lower-property-load-into-temporary.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-nested-method-calls-lower-property-load-into-temporary.expect.md @@ -24,13 +24,13 @@ export const FIXTURE_ENTRYPOINT = { ``` Found 1 error: -Invariant: [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. Got a `Identifier` +Invariant: [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression error.todo-nested-method-calls-lower-property-load-into-temporary.ts:6:14 4 | function Component({}) { 5 | const items = makeArray(0, 1, 2, null, 4, false, 6); > 6 | const max = Math.max(2, items.push(5), ...other); - | ^^^^^^^^ [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. Got a `Identifier` + | ^^^^^^^^ Got: 'Identifier' 7 | return max; 8 | } 9 | diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md index 8b2bc0b2b6d..32595c07b52 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md @@ -29,7 +29,7 @@ error.todo-repro-named-function-with-shadowed-local-same-name.ts:9:9 7 | return hasErrors; 8 | } > 9 | return hasErrors(); - | ^^^^^^^^^ [InferMutationAliasingEffects] Expected value kind to be initialized + | ^^^^^^^^^ this is uninitialized 10 | } 11 | ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.expect.md index fb472f683b6..a0c492120a3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.expect.md @@ -35,7 +35,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.ts:14:2 12 | diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-after-loop-break.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-after-loop-break.expect.md index 3a5990e1624..8ccb4f2dee7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-after-loop-break.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-after-loop-break.expect.md @@ -26,7 +26,7 @@ Found 1 error: Error: Calling setState during render may trigger an infinite loop -Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState) +Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState). error.unconditional-set-state-in-render-after-loop-break.ts:11:2 9 | } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-after-loop.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-after-loop.expect.md index c2beb3424a1..df805b4795f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-after-loop.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-after-loop.expect.md @@ -21,7 +21,7 @@ Found 1 error: Error: Calling setState during render may trigger an infinite loop -Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState) +Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState). error.unconditional-set-state-in-render-after-loop.ts:6:2 4 | for (const _ of props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-with-loop-throw.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-with-loop-throw.expect.md index faef4dd5995..313b2ed0e4a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-with-loop-throw.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-with-loop-throw.expect.md @@ -26,7 +26,7 @@ Found 1 error: Error: Calling setState during render may trigger an infinite loop -Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState) +Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState). error.unconditional-set-state-in-render-with-loop-throw.ts:11:2 9 | } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-lambda.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-lambda.expect.md index 9d9c741f7ae..1c89b5c9f21 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-lambda.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-lambda.expect.md @@ -24,7 +24,7 @@ Found 1 error: Error: Calling setState during render may trigger an infinite loop -Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState) +Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState). error.unconditional-set-state-lambda.ts:8:2 6 | setX(1); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-nested-function-expressions.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-nested-function-expressions.expect.md index 07dd0b0a17e..fceed8b192f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-nested-function-expressions.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-nested-function-expressions.expect.md @@ -32,7 +32,7 @@ Found 1 error: Error: Calling setState during render may trigger an infinite loop -Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState) +Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState). error.unconditional-set-state-nested-function-expressions.ts:16:2 14 | bar(); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.update-global-should-bailout.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.update-global-should-bailout.expect.md index 8432be198b6..439ada4b631 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.update-global-should-bailout.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.update-global-should-bailout.expect.md @@ -23,7 +23,7 @@ Found 1 error: Error: Cannot reassign variables declared outside of the component/hook -Variable `renderCount` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) +Variable `renderCount` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render). error.update-global-should-bailout.ts:3:2 1 | let renderCount = 0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md index f93e9875655..ba5a7407773 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md @@ -38,7 +38,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.ts:17:2 15 | ref.current.inner = null; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-set-ref-nested-property-dont-preserve-memoization.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-set-ref-nested-property-dont-preserve-memoization.expect.md index 74822389a5a..b40b0bbf226 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-set-ref-nested-property-dont-preserve-memoization.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-set-ref-nested-property-dont-preserve-memoization.expect.md @@ -34,7 +34,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.useCallback-set-ref-nested-property-dont-preserve-memoization.ts:13:2 11 | }); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useMemo-non-literal-depslist.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useMemo-non-literal-depslist.expect.md index 188814ee02c..e135d7d5754 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useMemo-non-literal-depslist.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useMemo-non-literal-depslist.expect.md @@ -32,7 +32,7 @@ Found 1 error: Error: Expected the dependency list for useMemo to be an array literal -Expected the dependency list for useMemo to be an array literal +Expected the dependency list for useMemo to be an array literal. error.useMemo-non-literal-depslist.ts:10:4 8 | return text.toUpperCase(); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-mutate-ref-arg-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-mutate-ref-arg-in-render.expect.md index 06378fe0d03..1d5a4a2284c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-mutate-ref-arg-in-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.validate-mutate-ref-arg-in-render.expect.md @@ -24,7 +24,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.validate-mutate-ref-arg-in-render.ts:3:14 1 | // @validateRefAccessDuringRender:true diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/extend-scopes-if.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/extend-scopes-if.expect.md index bbdc90d7b1a..2cc97eac7f5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/extend-scopes-if.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/extend-scopes-if.expect.md @@ -48,6 +48,7 @@ function foo(a, b, c) { } else { x = $[3]; } + if (x.length) { return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-fbt-as-local.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-fbt-as-local.expect.md index 2e75e457826..bb86d3bc42e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-fbt-as-local.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-fbt-as-local.expect.md @@ -54,7 +54,7 @@ Found 1 error: Todo: Support local variables named `fbt` -Local variables named `fbt` may conflict with the fbt plugin and are not yet supported +Local variables named `fbt` may conflict with the fbt plugin and are not yet supported. error.todo-fbt-as-local.ts:18:19 16 | diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-fbt-unknown-enum-value.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-fbt-unknown-enum-value.expect.md index 6251105d1c2..3999d17d515 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-fbt-unknown-enum-value.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-fbt-unknown-enum-value.expect.md @@ -23,7 +23,7 @@ Found 1 error: Todo: Support duplicate fbt tags -Support `` tags with multiple `` values +Support `` tags with multiple `` values. error.todo-fbt-unknown-enum-value.ts:6:7 4 | return ( diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-locally-require-fbt.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-locally-require-fbt.expect.md index 1dbe86dc3a3..62605e5896c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-locally-require-fbt.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-locally-require-fbt.expect.md @@ -18,7 +18,7 @@ Found 1 error: Todo: Support local variables named `fbt` -Local variables named `fbt` may conflict with the fbt plugin and are not yet supported +Local variables named `fbt` may conflict with the fbt plugin and are not yet supported. error.todo-locally-require-fbt.ts:2:8 1 | function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-multiple-fbt-plural.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-multiple-fbt-plural.expect.md index 71c1ef2c83d..275f0ef0670 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-multiple-fbt-plural.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-multiple-fbt-plural.expect.md @@ -57,7 +57,7 @@ Found 1 error: Todo: Support duplicate fbt tags -Support `` tags with multiple `` values +Support `` tags with multiple `` values. error.todo-multiple-fbt-plural.ts:29:7 27 | return ( diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-multiple-variable-declarations-in-initializer.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-multiple-variable-declarations-in-initializer.expect.md index 9c12109185e..faafa79faa5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-multiple-variable-declarations-in-initializer.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-multiple-variable-declarations-in-initializer.expect.md @@ -28,6 +28,7 @@ function Component(props) { let items; if ($[0] !== props.items) { items = []; + for (let i = 0, length = props.items.length; i < length; i++) { items.push(props.items[i]); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-of-capture-item-of-local-collection-mutate-later-value-initially-null.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-of-capture-item-of-local-collection-mutate-later-value-initially-null.expect.md index 43ccfc1cb72..c21bc3fd382 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-of-capture-item-of-local-collection-mutate-later-value-initially-null.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-of-capture-item-of-local-collection-mutate-later-value-initially-null.expect.md @@ -39,6 +39,7 @@ function Component(props) { for (const x of items) { lastItem = x; } + if (lastItem != null) { lastItem.a = lastItem.a + 1; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-of-capture-item-of-local-collection-mutate-later.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-of-capture-item-of-local-collection-mutate-later.expect.md index a20f1fcbc58..413f810c8a4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-of-capture-item-of-local-collection-mutate-later.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-of-capture-item-of-local-collection-mutate-later.expect.md @@ -39,6 +39,7 @@ function Component(props) { for (const x of items) { lastItem = x; } + if (lastItem != null) { lastItem.a = lastItem.a + 1; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-captures-value-later-frozen-jsx.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-captures-value-later-frozen-jsx.expect.md index 2da6b1d1364..3bc3d03e3a0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-captures-value-later-frozen-jsx.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-captures-value-later-frozen-jsx.expect.md @@ -41,6 +41,7 @@ function Component(props) { t1 = $[1]; } const onChange = t1; + if (props.cond) { } let t2; 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 5eaa593fa1c..4f31c280775 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 @@ -69,6 +69,7 @@ const Foo = isForgetEnabled_Fixtures() 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/dynamic-gating-bailout-nopanic.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-bailout-nopanic.expect.md index bb0172c56f8..4c5461f6f34 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-bailout-nopanic.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-bailout-nopanic.expect.md @@ -58,7 +58,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":206},"end":{"line":16,"column":1,"index":433},"filename":"dynamic-gating-bailout-nopanic.ts"},"detail":{"options":{"category":"PreserveManualMemo","severity":"CannotPreserveMemoization","reason":"Existing memoization could not be preserved","description":"React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `value`, but the source dependencies were []. Inferred dependency not present in source.","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":9,"column":31,"index":288},"end":{"line":9,"column":52,"index":309},"filename":"dynamic-gating-bailout-nopanic.ts"},"message":"Could not preserve existing manual memoization"}]}}} +{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":206},"end":{"line":16,"column":1,"index":433},"filename":"dynamic-gating-bailout-nopanic.ts"},"detail":{"options":{"category":"PreserveManualMemo","reason":"Existing memoization could not be preserved","description":"React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `value`, but the source dependencies were []. Inferred dependency not present in source","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":9,"column":31,"index":288},"end":{"line":9,"column":52,"index":309},"filename":"dynamic-gating-bailout-nopanic.ts"},"message":"Could not preserve existing manual memoization"}]}}} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-invalid-multiple.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-invalid-multiple.expect.md index 7f8f1d43310..4650588cc47 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-invalid-multiple.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-invalid-multiple.expect.md @@ -38,7 +38,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"kind":"CompileError","fnLoc":{"start":{"line":3,"column":0,"index":86},"end":{"line":7,"column":1,"index":190},"filename":"dynamic-gating-invalid-multiple.ts"},"detail":{"options":{"category":"Gating","reason":"Multiple dynamic gating directives found","description":"Expected a single directive but found [use memo if(getTrue), use memo if(getFalse)]","severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":4,"column":2,"index":105},"end":{"line":4,"column":25,"index":128},"filename":"dynamic-gating-invalid-multiple.ts"}}}} +{"kind":"CompileError","fnLoc":{"start":{"line":3,"column":0,"index":86},"end":{"line":7,"column":1,"index":190},"filename":"dynamic-gating-invalid-multiple.ts"},"detail":{"options":{"category":"Gating","reason":"Multiple dynamic gating directives found","description":"Expected a single directive but found [use memo if(getTrue), use memo if(getFalse)]","suggestions":null,"loc":{"start":{"line":4,"column":2,"index":105},"end":{"line":4,"column":25,"index":128},"filename":"dynamic-gating-invalid-multiple.ts"}}}} ``` ### Eval output 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 8665addb8a2..2a0d3a598ec 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 @@ -63,6 +63,7 @@ const Foo = isForgetEnabled_Fixtures() ? function Foo(props) { "use forget"; const $ = _c(3); + if (props.bar < 0) { return props.children; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-object-method.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-object-method.expect.md index c55eb49e64e..df1797fc85b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-object-method.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-object-method.expect.md @@ -35,7 +35,6 @@ function hoisting() { return bar(); }, }; - const bar = _temp; t0 = x.foo(); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/iife-return-modified-later-phi.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/iife-return-modified-later-phi.expect.md index 22f967883b0..a3b3b843a9d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/iife-return-modified-later-phi.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/iife-return-modified-later-phi.expect.md @@ -30,6 +30,7 @@ function Component(props) { let items; if ($[0] !== props.a || $[1] !== props.cond) { let t0; + if (props.cond) { t0 = []; } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.todo-syntax.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.todo-syntax.expect.md index 57ccade29dd..38d10ee0d1b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.todo-syntax.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.todo-syntax.expect.md @@ -36,7 +36,7 @@ Found 1 error: Error: Cannot infer dependencies of this effect. This will break your build! -To resolve, either pass a dependency array or fix reported compiler bailout diagnostics. Todo: (BuildHIR::lowerStatement) Handle TryStatement without a catch clause (13:6) +To resolve, either pass a dependency array or fix reported compiler bailout diagnostics Todo: (BuildHIR::lowerStatement) Handle TryStatement without a catch clause (13:6). error.todo-syntax.ts:11:2 9 | function Component({prop1}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-optional-chain.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-optional-chain.expect.md index 14bd646bb15..4606d49f37f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-optional-chain.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-optional-chain.expect.md @@ -48,7 +48,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":149},"end":{"line":12,"column":1,"index":404},"filename":"mutate-after-useeffect-optional-chain.ts"},"detail":{"options":{"category":"Immutability","severity":"InvalidReact","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect().","details":[{"kind":"error","loc":{"start":{"line":10,"column":2,"index":365},"end":{"line":10,"column":5,"index":368},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}} +{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":149},"end":{"line":12,"column":1,"index":404},"filename":"mutate-after-useeffect-optional-chain.ts"},"detail":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect()","details":[{"kind":"error","loc":{"start":{"line":10,"column":2,"index":365},"end":{"line":10,"column":5,"index":368},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}} {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":9,"column":2,"index":314},"end":{"line":9,"column":49,"index":361},"filename":"mutate-after-useeffect-optional-chain.ts"},"decorations":[{"start":{"line":9,"column":24,"index":336},"end":{"line":9,"column":27,"index":339},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"}]} {"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":149},"end":{"line":12,"column":1,"index":404},"filename":"mutate-after-useeffect-optional-chain.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-ref-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-ref-access.expect.md index 2f930964acd..ea5a887b8bf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-ref-access.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-ref-access.expect.md @@ -47,7 +47,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":158},"end":{"line":11,"column":1,"index":331},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"options":{"category":"Refs","severity":"InvalidReact","reason":"Cannot access refs during render","description":"React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":289},"end":{"line":9,"column":16,"index":303},"filename":"mutate-after-useeffect-ref-access.ts"},"message":"Cannot update ref during render"}]}}} +{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":158},"end":{"line":11,"column":1,"index":331},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"options":{"category":"Refs","reason":"Cannot access refs during render","description":"React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":289},"end":{"line":9,"column":16,"index":303},"filename":"mutate-after-useeffect-ref-access.ts"},"message":"Cannot update ref during render"}]}}} {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":237},"end":{"line":8,"column":50,"index":285},"filename":"mutate-after-useeffect-ref-access.ts"},"decorations":[{"start":{"line":8,"column":24,"index":259},"end":{"line":8,"column":30,"index":265},"filename":"mutate-after-useeffect-ref-access.ts","identifierName":"arrRef"}]} {"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":158},"end":{"line":11,"column":1,"index":331},"filename":"mutate-after-useeffect-ref-access.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect.expect.md index 9a8a2a78e06..71cd9fb6208 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect.expect.md @@ -47,7 +47,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":111},"end":{"line":11,"column":1,"index":242},"filename":"mutate-after-useeffect.ts"},"detail":{"options":{"category":"Immutability","severity":"InvalidReact","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect().","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":214},"end":{"line":9,"column":5,"index":217},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}} +{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":111},"end":{"line":11,"column":1,"index":242},"filename":"mutate-after-useeffect.ts"},"detail":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect()","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":214},"end":{"line":9,"column":5,"index":217},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}} {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":6,"column":2,"index":159},"end":{"line":8,"column":14,"index":210},"filename":"mutate-after-useeffect.ts"},"decorations":[{"start":{"line":7,"column":4,"index":181},"end":{"line":7,"column":7,"index":184},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":4,"index":181},"end":{"line":7,"column":7,"index":184},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":13,"index":190},"end":{"line":7,"column":16,"index":193},"filename":"mutate-after-useeffect.ts","identifierName":"foo"}]} {"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":111},"end":{"line":11,"column":1,"index":242},"filename":"mutate-after-useeffect.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/no-emit/retry-no-emit.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/no-emit/retry-no-emit.expect.md index 7ecd65382cc..55a6aa5c46d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/no-emit/retry-no-emit.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/no-emit/retry-no-emit.expect.md @@ -54,7 +54,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":195},"end":{"line":14,"column":1,"index":409},"filename":"retry-no-emit.ts"},"detail":{"options":{"category":"Immutability","severity":"InvalidReact","reason":"This value cannot be modified","description":"Modifying a value previously passed as an argument to a hook is not allowed. Consider moving the modification before calling the hook.","details":[{"kind":"error","loc":{"start":{"line":12,"column":2,"index":372},"end":{"line":12,"column":6,"index":376},"filename":"retry-no-emit.ts","identifierName":"arr2"},"message":"value cannot be modified"}]}}} +{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":195},"end":{"line":14,"column":1,"index":409},"filename":"retry-no-emit.ts"},"detail":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value previously passed as an argument to a hook is not allowed. Consider moving the modification before calling the hook","details":[{"kind":"error","loc":{"start":{"line":12,"column":2,"index":372},"end":{"line":12,"column":6,"index":376},"filename":"retry-no-emit.ts","identifierName":"arr2"},"message":"value cannot be modified"}]}}} {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":248},"end":{"line":8,"column":46,"index":292},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":8,"column":31,"index":277},"end":{"line":8,"column":34,"index":280},"filename":"retry-no-emit.ts","identifierName":"arr"}]} {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":11,"column":2,"index":316},"end":{"line":11,"column":54,"index":368},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":11,"column":25,"index":339},"end":{"line":11,"column":29,"index":343},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":11,"column":25,"index":339},"end":{"line":11,"column":29,"index":343},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":11,"column":35,"index":349},"end":{"line":11,"column":42,"index":356},"filename":"retry-no-emit.ts","identifierName":"propVal"}]} {"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":195},"end":{"line":14,"column":1,"index":409},"filename":"retry-no-emit.ts"},"fnName":"Foo","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md index 8101ddb0723..69a68daa232 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md @@ -390,6 +390,7 @@ function ConditionalJsx(t0) { t1 = $[0]; } let content = t1; + if (shouldWrap) { const t2 = content; let t3; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.expect.md index 5c7c4360e7c..5eaa1fd5040 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.expect.md @@ -65,7 +65,7 @@ function Component(props) { ## Logs ``` -{"kind":"CompileError","detail":{"options":{"category":"ErrorBoundaries","severity":"InvalidReact","reason":"Avoid constructing JSX within try/catch","description":"React does not immediately render components when JSX is rendered, so any errors from this component will not be caught by the try/catch. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)","details":[{"kind":"error","loc":{"start":{"line":11,"column":11,"index":222},"end":{"line":11,"column":32,"index":243},"filename":"invalid-jsx-in-catch-in-outer-try-with-catch.ts"},"message":"Avoid constructing JSX within try/catch"}]}},"fnLoc":null} +{"kind":"CompileError","detail":{"options":{"category":"ErrorBoundaries","reason":"Avoid constructing JSX within try/catch","description":"React does not immediately render components when JSX is rendered, so any errors from this component will not be caught by the try/catch. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)","details":[{"kind":"error","loc":{"start":{"line":11,"column":11,"index":222},"end":{"line":11,"column":32,"index":243},"filename":"invalid-jsx-in-catch-in-outer-try-with-catch.ts"},"message":"Avoid constructing JSX within try/catch"}]}},"fnLoc":null} {"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":91},"end":{"line":17,"column":1,"index":298},"filename":"invalid-jsx-in-catch-in-outer-try-with-catch.ts"},"fnName":"Component","memoSlots":4,"memoBlocks":2,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.expect.md index 88d4849b4f6..323aedd869d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.expect.md @@ -42,7 +42,7 @@ function Component(props) { ## Logs ``` -{"kind":"CompileError","detail":{"options":{"category":"ErrorBoundaries","severity":"InvalidReact","reason":"Avoid constructing JSX within try/catch","description":"React does not immediately render components when JSX is rendered, so any errors from this component will not be caught by the try/catch. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)","details":[{"kind":"error","loc":{"start":{"line":5,"column":9,"index":104},"end":{"line":5,"column":16,"index":111},"filename":"invalid-jsx-in-try-with-catch.ts"},"message":"Avoid constructing JSX within try/catch"}]}},"fnLoc":null} +{"kind":"CompileError","detail":{"options":{"category":"ErrorBoundaries","reason":"Avoid constructing JSX within try/catch","description":"React does not immediately render components when JSX is rendered, so any errors from this component will not be caught by the try/catch. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)","details":[{"kind":"error","loc":{"start":{"line":5,"column":9,"index":104},"end":{"line":5,"column":16,"index":111},"filename":"invalid-jsx-in-try-with-catch.ts"},"message":"Avoid constructing JSX within try/catch"}]}},"fnLoc":null} {"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":49},"end":{"line":10,"column":1,"index":160},"filename":"invalid-jsx-in-try-with-catch.ts"},"fnName":"Component","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.expect.md index 9107c896cc0..6e5762f3c88 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.expect.md @@ -65,7 +65,7 @@ function _temp(s) { ## Logs ``` -{"kind":"CompileError","detail":{"options":{"category":"EffectSetState","reason":"Calling setState synchronously within an effect can trigger cascading renders","description":"Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:\n* Update external systems with the latest state from React.\n* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\nCalling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect)","severity":"InvalidReact","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":13,"column":4,"index":265},"end":{"line":13,"column":5,"index":266},"filename":"invalid-setState-in-useEffect-transitive.ts","identifierName":"g"},"message":"Avoid calling setState() directly within an effect"}]}},"fnLoc":null} +{"kind":"CompileError","detail":{"options":{"category":"EffectSetState","reason":"Calling setState synchronously within an effect can trigger cascading renders","description":"Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:\n* Update external systems with the latest state from React.\n* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\nCalling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect)","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":13,"column":4,"index":265},"end":{"line":13,"column":5,"index":266},"filename":"invalid-setState-in-useEffect-transitive.ts","identifierName":"g"},"message":"Avoid calling setState() directly within an effect"}]}},"fnLoc":null} {"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":92},"end":{"line":16,"column":1,"index":293},"filename":"invalid-setState-in-useEffect-transitive.ts"},"fnName":"Component","memoSlots":2,"memoBlocks":2,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.expect.md index cb5203c8816..3c3a5a8053a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.expect.md @@ -45,7 +45,7 @@ function _temp(s) { ## Logs ``` -{"kind":"CompileError","detail":{"options":{"category":"EffectSetState","reason":"Calling setState synchronously within an effect can trigger cascading renders","description":"Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:\n* Update external systems with the latest state from React.\n* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\nCalling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect)","severity":"InvalidReact","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":7,"column":4,"index":180},"end":{"line":7,"column":12,"index":188},"filename":"invalid-setState-in-useEffect.ts","identifierName":"setState"},"message":"Avoid calling setState() directly within an effect"}]}},"fnLoc":null} +{"kind":"CompileError","detail":{"options":{"category":"EffectSetState","reason":"Calling setState synchronously within an effect can trigger cascading renders","description":"Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:\n* Update external systems with the latest state from React.\n* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\nCalling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect)","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":7,"column":4,"index":180},"end":{"line":7,"column":12,"index":188},"filename":"invalid-setState-in-useEffect.ts","identifierName":"setState"},"message":"Avoid calling setState() directly within an effect"}]}},"fnLoc":null} {"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":92},"end":{"line":10,"column":1,"index":225},"filename":"invalid-setState-in-useEffect.ts"},"fnName":"Component","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-local-memberexpr-tag-conditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-local-memberexpr-tag-conditional.expect.md index f13d3a05981..c8cf3f23991 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-local-memberexpr-tag-conditional.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-local-memberexpr-tag-conditional.expect.md @@ -27,6 +27,7 @@ import * as SharedRuntime from "shared-runtime"; function useFoo(t0) { const $ = _c(1); const { cond } = t0; + if (cond) { let t1; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merge-consecutive-nested-scopes.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merge-consecutive-nested-scopes.expect.md index 2a7e8f8b012..e1b723b1b0e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merge-consecutive-nested-scopes.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merge-consecutive-nested-scopes.expect.md @@ -30,6 +30,7 @@ const { getNumber } = require("shared-runtime"); function Component(props) { const $ = _c(1); let x; + if (props.cond) { let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/module-scoped-bindings.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/module-scoped-bindings.expect.md index 3962fcc607c..8e96f49417b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/module-scoped-bindings.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/module-scoped-bindings.expect.md @@ -75,7 +75,6 @@ function Component() { if ($[0] !== state) { t0 = [ React, - state, CONST, NON_REASSIGNED_LET, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutable-lifetime-loops.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutable-lifetime-loops.expect.md index 7bea9f20faf..4b76d62482e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutable-lifetime-loops.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutable-lifetime-loops.expect.md @@ -94,12 +94,16 @@ function testFunction(props) { break; } } + if (a) { } + if (b) { } + if (c) { } + if (d) { } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutable-lifetime-with-aliasing.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutable-lifetime-with-aliasing.expect.md index 0a5cb1960d0..2dffce2ce27 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutable-lifetime-with-aliasing.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutable-lifetime-with-aliasing.expect.md @@ -78,14 +78,19 @@ function Component(props) { x = {}; x.b = b; const y = mutate(x, d); + if (a) { } + if (b) { } + if (c) { } + if (d) { } + if (y) { } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutable-liverange-loop.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutable-liverange-loop.expect.md index 62501bfb6fb..b28a96361b8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutable-liverange-loop.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutable-liverange-loop.expect.md @@ -51,12 +51,16 @@ function Component(props) { break; } } + if (a) { } + if (b) { } + if (c) { } + if (d) { } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capture-backedge-phi-with-later-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capture-backedge-phi-with-later-mutation.expect.md index df9b5e58f8b..a77dad5fe77 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capture-backedge-phi-with-later-mutation.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/capture-backedge-phi-with-later-mutation.expect.md @@ -53,8 +53,10 @@ function Component(t0) { let z; if ($[0] !== prop1 || $[1] !== prop2) { let x = [{ value: prop1 }]; + while (x.length < 2) { arrayPush(x, { value: prop2 }); + if (x[0].value === prop1) { x = [{ value: prop2 }]; const y = x; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-impure-functions-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-impure-functions-in-render.expect.md index a9782a3b9e6..1241971d827 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-impure-functions-in-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-impure-functions-in-render.expect.md @@ -21,7 +21,7 @@ Found 3 errors: Error: Cannot call impure function during render -`Date.now` is an impure function. Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent) +`Date.now` is an impure function. Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). error.invalid-impure-functions-in-render.ts:4:15 2 | @@ -34,7 +34,7 @@ error.invalid-impure-functions-in-render.ts:4:15 Error: Cannot call impure function during render -`performance.now` is an impure function. Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent) +`performance.now` is an impure function. Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). error.invalid-impure-functions-in-render.ts:5:14 3 | function Component() { @@ -47,7 +47,7 @@ error.invalid-impure-functions-in-render.ts:5:14 Error: Cannot call impure function during render -`Math.random` is an impure function. Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent) +`Math.random` is an impure function. Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent). error.invalid-impure-functions-in-render.ts:6:15 4 | const date = Date.now(); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global-indirect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global-indirect.expect.md index 41ed513912f..9d106cd4f4e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global-indirect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global-indirect.expect.md @@ -22,7 +22,7 @@ Found 2 errors: Error: Cannot reassign variables declared outside of the component/hook -Variable `someUnknownGlobal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) +Variable `someUnknownGlobal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render). error.reassignment-to-global-indirect.ts:5:4 3 | const foo = () => { @@ -35,7 +35,7 @@ error.reassignment-to-global-indirect.ts:5:4 Error: Cannot reassign variables declared outside of the component/hook -Variable `moduleLocal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) +Variable `moduleLocal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render). error.reassignment-to-global-indirect.ts:6:4 4 | // Cannot assign to globals diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global.expect.md index 6089255fd5e..01ff6085213 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.reassignment-to-global.expect.md @@ -19,7 +19,7 @@ Found 2 errors: Error: Cannot reassign variables declared outside of the component/hook -Variable `someUnknownGlobal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) +Variable `someUnknownGlobal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render). error.reassignment-to-global.ts:4:2 2 | function Component() { @@ -32,7 +32,7 @@ error.reassignment-to-global.ts:4:2 Error: Cannot reassign variables declared outside of the component/hook -Variable `moduleLocal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) +Variable `moduleLocal` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render). error.reassignment-to-global.ts:5:2 3 | // Cannot assign to globals diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md index 092c895cc98..44f358caade 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md @@ -30,7 +30,7 @@ error.todo-repro-named-function-with-shadowed-local-same-name.ts:10:9 8 | return hasErrors; 9 | } > 10 | return hasErrors(); - | ^^^^^^^^^ [InferMutationAliasingEffects] Expected value kind to be initialized + | ^^^^^^^^^ this is uninitialized 11 | } 12 | ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/iife-return-modified-later-phi.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/iife-return-modified-later-phi.expect.md index 22f967883b0..a3b3b843a9d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/iife-return-modified-later-phi.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/iife-return-modified-later-phi.expect.md @@ -30,6 +30,7 @@ function Component(props) { let items; if ($[0] !== props.a || $[1] !== props.cond) { let t0; + if (props.cond) { t0 = []; } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.expect.md index 6a9b4d98e28..edc266b9f33 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.expect.md @@ -48,7 +48,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":181},"end":{"line":12,"column":1,"index":436},"filename":"mutate-after-useeffect-optional-chain.ts"},"detail":{"options":{"category":"Immutability","severity":"InvalidReact","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect().","details":[{"kind":"error","loc":{"start":{"line":10,"column":2,"index":397},"end":{"line":10,"column":5,"index":400},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}} +{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":181},"end":{"line":12,"column":1,"index":436},"filename":"mutate-after-useeffect-optional-chain.ts"},"detail":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect()","details":[{"kind":"error","loc":{"start":{"line":10,"column":2,"index":397},"end":{"line":10,"column":5,"index":400},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}} {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":9,"column":2,"index":346},"end":{"line":9,"column":49,"index":393},"filename":"mutate-after-useeffect-optional-chain.ts"},"decorations":[{"start":{"line":9,"column":24,"index":368},"end":{"line":9,"column":27,"index":371},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"}]} {"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":181},"end":{"line":12,"column":1,"index":436},"filename":"mutate-after-useeffect-optional-chain.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.expect.md index 00473c8eec7..acf9c28cabd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.expect.md @@ -47,7 +47,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":190},"end":{"line":11,"column":1,"index":363},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"options":{"category":"Refs","severity":"InvalidReact","reason":"Cannot access refs during render","description":"React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":321},"end":{"line":9,"column":16,"index":335},"filename":"mutate-after-useeffect-ref-access.ts"},"message":"Cannot update ref during render"}]}}} +{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":190},"end":{"line":11,"column":1,"index":363},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"options":{"category":"Refs","reason":"Cannot access refs during render","description":"React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":321},"end":{"line":9,"column":16,"index":335},"filename":"mutate-after-useeffect-ref-access.ts"},"message":"Cannot update ref during render"}]}}} {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":269},"end":{"line":8,"column":50,"index":317},"filename":"mutate-after-useeffect-ref-access.ts"},"decorations":[{"start":{"line":8,"column":24,"index":291},"end":{"line":8,"column":30,"index":297},"filename":"mutate-after-useeffect-ref-access.ts","identifierName":"arrRef"}]} {"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":190},"end":{"line":11,"column":1,"index":363},"filename":"mutate-after-useeffect-ref-access.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.expect.md index 825bc4a1df0..93e7f1e0609 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.expect.md @@ -47,7 +47,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":143},"end":{"line":11,"column":1,"index":274},"filename":"mutate-after-useeffect.ts"},"detail":{"options":{"category":"Immutability","severity":"InvalidReact","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect().","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":246},"end":{"line":9,"column":5,"index":249},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}} +{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":143},"end":{"line":11,"column":1,"index":274},"filename":"mutate-after-useeffect.ts"},"detail":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect()","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":246},"end":{"line":9,"column":5,"index":249},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}} {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":6,"column":2,"index":191},"end":{"line":8,"column":14,"index":242},"filename":"mutate-after-useeffect.ts"},"decorations":[{"start":{"line":7,"column":4,"index":213},"end":{"line":7,"column":7,"index":216},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":4,"index":213},"end":{"line":7,"column":7,"index":216},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":13,"index":222},"end":{"line":7,"column":16,"index":225},"filename":"mutate-after-useeffect.ts","identifierName":"foo"}]} {"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":143},"end":{"line":11,"column":1,"index":274},"filename":"mutate-after-useeffect.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-key-object-mutated-later.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-key-object-mutated-later.expect.md index 5c73ce6d77a..f9f881c72af 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-key-object-mutated-later.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-key-object-mutated-later.expect.md @@ -33,7 +33,6 @@ function Component(props) { if ($[0] !== props.value) { const key = {}; context = { [key]: identity([props.value]) }; - mutate(key); $[0] = props.value; $[1] = context; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-member.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-member.expect.md index 1ef3ed157f9..b899212b5ba 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-member.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/object-expression-computed-member.expect.md @@ -44,7 +44,6 @@ function Component(props) { t2 = $[3]; } context = t2; - mutate(key); $[0] = props.value; $[1] = context; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/repro-compiler-infinite-loop.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/repro-compiler-infinite-loop.expect.md index dfc4ed98830..a402713f869 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/repro-compiler-infinite-loop.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/repro-compiler-infinite-loop.expect.md @@ -32,6 +32,7 @@ import fbt from "fbt"; function Component() { const $ = _c(1); const sections = Object.keys(items); + for (let i = 0; i < sections.length; i = i + 3, i) { chunks.push(sections.slice(i, i + 3).map(_temp)); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.expect.md index 7d490de8c6a..9529a5c31de 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.expect.md @@ -54,7 +54,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":227},"end":{"line":14,"column":1,"index":441},"filename":"retry-no-emit.ts"},"detail":{"options":{"category":"Immutability","severity":"InvalidReact","reason":"This value cannot be modified","description":"Modifying a value previously passed as an argument to a hook is not allowed. Consider moving the modification before calling the hook.","details":[{"kind":"error","loc":{"start":{"line":12,"column":2,"index":404},"end":{"line":12,"column":6,"index":408},"filename":"retry-no-emit.ts","identifierName":"arr2"},"message":"value cannot be modified"}]}}} +{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":227},"end":{"line":14,"column":1,"index":441},"filename":"retry-no-emit.ts"},"detail":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value previously passed as an argument to a hook is not allowed. Consider moving the modification before calling the hook","details":[{"kind":"error","loc":{"start":{"line":12,"column":2,"index":404},"end":{"line":12,"column":6,"index":408},"filename":"retry-no-emit.ts","identifierName":"arr2"},"message":"value cannot be modified"}]}}} {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":280},"end":{"line":8,"column":46,"index":324},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":8,"column":31,"index":309},"end":{"line":8,"column":34,"index":312},"filename":"retry-no-emit.ts","identifierName":"arr"}]} {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":11,"column":2,"index":348},"end":{"line":11,"column":54,"index":400},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":11,"column":25,"index":371},"end":{"line":11,"column":29,"index":375},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":11,"column":25,"index":371},"end":{"line":11,"column":29,"index":375},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":11,"column":35,"index":381},"end":{"line":11,"column":42,"index":388},"filename":"retry-no-emit.ts","identifierName":"propVal"}]} {"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":227},"end":{"line":14,"column":1,"index":441},"filename":"retry-no-emit.ts"},"fnName":"Foo","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-depslist-assignment.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-depslist-assignment.expect.md index d37762bbac5..cc65670080b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-depslist-assignment.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/useCallback-reordering-depslist-assignment.expect.md @@ -51,7 +51,6 @@ function useFoo(arr1, arr2) { if ($[2] !== arr2 || $[3] !== x) { let y; t1 = () => ({ y }); - (y = x.concat(arr2)), y; $[2] = arr2; $[3] = x; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nonmutating-capture-in-unsplittable-memo-block.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nonmutating-capture-in-unsplittable-memo-block.expect.md index a3403e6c8d8..deedcb7fec1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nonmutating-capture-in-unsplittable-memo-block.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nonmutating-capture-in-unsplittable-memo-block.expect.md @@ -89,6 +89,7 @@ function useFoo(t0) { y = $[2]; z = $[3]; } + if (z[0] !== y) { throw new Error("oh no!"); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-object-mutated-later.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-object-mutated-later.expect.md index f187c8c79d3..dfd6649095b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-object-mutated-later.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-object-mutated-later.expect.md @@ -32,7 +32,6 @@ function Component(props) { if ($[0] !== props.value) { const key = {}; context = { [key]: identity([props.value]) }; - mutate(key); $[0] = props.value; $[1] = context; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-member.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-member.expect.md index 01d91de8d4f..8d1615f65c6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-member.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-member.expect.md @@ -43,7 +43,6 @@ function Component(props) { t2 = $[3]; } context = t2; - mutate(key); $[0] = props.value; $[1] = context; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-maybe-alias.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-maybe-alias.expect.md index 3ddb046c5a1..74c0dcdc14f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-maybe-alias.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-maybe-alias.expect.md @@ -38,13 +38,11 @@ function useHook(props) { return props; }, }; - const y = { getY() { return "y"; }, }; - t0 = setProperty(x, y); $[0] = props; $[1] = t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-shorthand-3.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-shorthand-3.expect.md index 37668c07ebd..886eb119d36 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-shorthand-3.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-shorthand-3.expect.md @@ -39,7 +39,6 @@ function useHook(a) { return x; }, }; - t0 = obj.method(); $[0] = a; $[1] = t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-shorthand-aliased-mutate-after.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-shorthand-aliased-mutate-after.expect.md index b139e23f6dd..1674c16e88b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-shorthand-aliased-mutate-after.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-shorthand-aliased-mutate-after.expect.md @@ -37,7 +37,6 @@ function useHook(t0) { return value; }, }; - mutate(x); $[0] = value; $[1] = obj; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-shorthand-mutated-after.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-shorthand-mutated-after.expect.md index ce6a28dc3a2..9c73dd6f992 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-shorthand-mutated-after.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-shorthand-mutated-after.expect.md @@ -37,7 +37,6 @@ function useHook(t0) { return x; }, }; - mutate(obj); $[0] = value; $[1] = obj; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-shorthand.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-shorthand.expect.md index 55ba27cfa35..ebfa1d8d316 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-shorthand.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-method-shorthand.expect.md @@ -31,7 +31,6 @@ function Component() { return 1; }, }; - t0 = obj.method(); $[0] = t0; } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.expect.md index 54184be0f3f..b5babb37cdf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.expect.md @@ -48,9 +48,7 @@ function useKeyCommand() { }; const moveLeft = { handler: handleKey("left") }; - const moveRight = { handler: handleKey("right") }; - t0 = [moveLeft, moveRight]; $[0] = t0; } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/overlapping-scopes-interleaved-by-terminal.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/overlapping-scopes-interleaved-by-terminal.expect.md index 2c1093f3cea..894dea7ce89 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/overlapping-scopes-interleaved-by-terminal.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/overlapping-scopes-interleaved-by-terminal.expect.md @@ -27,6 +27,7 @@ export const FIXTURE_ENTRYPOINT = { function foo(a, b, c) { const x = []; const y = []; + if (x) { } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-mutable-ref-not-preserved.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-mutable-ref-not-preserved.expect.md index 82bce339519..77f104cab0c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-mutable-ref-not-preserved.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-mutable-ref-not-preserved.expect.md @@ -27,7 +27,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). error.maybe-mutable-ref-not-preserved.ts:8:33 6 | function useFoo() { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-with-refs.flow.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-with-refs.flow.expect.md index 19ffca8af61..0269b22a1f2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-with-refs.flow.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-with-refs.flow.expect.md @@ -23,7 +23,7 @@ Found 1 error: Error: Cannot access refs during render -React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef) +React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef). 5 | const localRef = useFooRef(); 6 | const mergedRef = useMemo(() => { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.validate-useMemo-named-function.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.validate-useMemo-named-function.expect.md index 27af59e175d..d14bbccb599 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.validate-useMemo-named-function.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.validate-useMemo-named-function.expect.md @@ -24,7 +24,7 @@ Found 1 error: Error: Expected the first argument to be an inline function expression -Expected the first argument to be an inline function expression +Expected the first argument to be an inline function expression. error.validate-useMemo-named-function.ts:9:20 7 | // for now. diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/maybe-invalid-useMemo-no-memoblock-sideeffect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/maybe-invalid-useMemo-no-memoblock-sideeffect.expect.md index b1a65cab02e..50d812fde56 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/maybe-invalid-useMemo-no-memoblock-sideeffect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/maybe-invalid-useMemo-no-memoblock-sideeffect.expect.md @@ -36,6 +36,7 @@ import { useMemo } from "react"; // (i.e. inferred non-mutable or non-escaping values don't get memoized) function useFoo(t0) { const { minWidth, styles, setStyles } = t0; + if (styles.width > minWidth) { setStyles(styles); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/prune-nonescaping-useMemo-mult-returns-primitive.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/prune-nonescaping-useMemo-mult-returns-primitive.expect.md index 8850f869d07..27fdecd79fa 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/prune-nonescaping-useMemo-mult-returns-primitive.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/prune-nonescaping-useMemo-mult-returns-primitive.expect.md @@ -34,6 +34,7 @@ import { identity } from "shared-runtime"; function useFoo(cond) { let t0; + if (cond) { t0 = 2; } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/prune-nonescaping-useMemo-mult-returns.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/prune-nonescaping-useMemo-mult-returns.expect.md index af959b9865b..cddc2dd86b9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/prune-nonescaping-useMemo-mult-returns.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/prune-nonescaping-useMemo-mult-returns.expect.md @@ -34,6 +34,7 @@ import { identity } from "shared-runtime"; function useFoo(cond) { let t0; + if (cond) { t0 = identity(10); } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-nonescaping.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-nonescaping.expect.md index ddf7d32dc45..bc9d4341e3a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-nonescaping.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-nonescaping.expect.md @@ -41,6 +41,7 @@ function Component(t0) { const { entity, children } = t0; const showMessage = () => entity != null; + if (!showMessage()) { return children; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-reordering-depslist-assignment.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-reordering-depslist-assignment.expect.md index f7ebdf0ca59..086ef4f58d6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-reordering-depslist-assignment.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-reordering-depslist-assignment.expect.md @@ -50,7 +50,6 @@ function useFoo(arr1, arr2) { if ($[2] !== arr2 || $[3] !== x) { let y; t1 = () => ({ y }); - (y = x.concat(arr2)), y; $[2] = arr2; $[3] = x; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.expect.md index 17ff728051d..7e0d9d2e64e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.expect.md @@ -45,6 +45,7 @@ function ComponentA(props) { if (b) { a.push(props.p0); } + if (props.p1) { b.push(props.p2); } @@ -69,6 +70,7 @@ function ComponentB(props) { if (mayMutate(b)) { a.push(props.p0); } + if (props.p1) { b.push(props.p2); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.expect.md index 2a3da8b195a..6d88e411c0d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.expect.md @@ -31,6 +31,7 @@ function Component(props) { let items; if ($[0] !== props.a || $[1] !== props.cond) { let t0; + if (props.cond) { t0 = []; } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-object-method-uncond-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-object-method-uncond-access.expect.md index 1c01c96b837..c8b9a5dddb7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-object-method-uncond-access.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-object-method-uncond-access.expect.md @@ -40,7 +40,6 @@ function useFoo(t0) { return identity(a.b.c); }, }; - t1 = ; $[0] = a; $[1] = t1; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/switch-non-final-default.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/switch-non-final-default.expect.md index fee31c9fafb..ed00e248ede 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/switch-non-final-default.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/switch-non-final-default.expect.md @@ -61,7 +61,6 @@ function Component(props) { y = x; } } - t0 = ; $[0] = props.p0; $[1] = props.p2; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/switch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/switch.expect.md index 62906680155..c86cba7cc88 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/switch.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/switch.expect.md @@ -34,6 +34,7 @@ function Component(props) { let y; if ($[0] !== props.p0 || $[1] !== props.p2 || $[2] !== props.p3) { const x = []; + switch (props.p0) { case true: { x.push(props.p2); @@ -43,7 +44,6 @@ function Component(props) { y = x; } } - t0 = ; $[0] = props.p0; $[1] = props.p2; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/useMemo-multiple-if-else.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/useMemo-multiple-if-else.expect.md index 4ce8ef58028..1d4761e447b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/useMemo-multiple-if-else.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/useMemo-multiple-if-else.expect.md @@ -47,6 +47,7 @@ function Component(props) { if (props.cond) { y.push(props.a); } + if (props.cond2) { t0 = y; break bb0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-dependency-fixpoint.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-dependency-fixpoint.expect.md index f93956ad29e..1c936618833 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-dependency-fixpoint.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-dependency-fixpoint.expect.md @@ -33,6 +33,7 @@ function Component(props) { const $ = _c(2); let x = 0; let y = 0; + while (x === 0) { x = y; y = props.value; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassignment-conditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassignment-conditional.expect.md index 9358d39cf44..4baca5ad6d4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassignment-conditional.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassignment-conditional.expect.md @@ -29,6 +29,7 @@ function Component(props) { let x = []; x.push(props.p0); const y = x; + if (props.p1) { let t1; if ($[4] === Symbol.for("react.memo_cache_sentinel")) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rename-source-variables-nested-object-method.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rename-source-variables-nested-object-method.expect.md index e406f3a7d7d..01130cc3a37 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rename-source-variables-nested-object-method.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rename-source-variables-nested-object-method.expect.md @@ -59,7 +59,6 @@ function useFoo(props) { return b; }, }; - t1 = a.foo().bar(); $0[0] = props; $0[1] = t1; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-backedge-reference-effect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-backedge-reference-effect.expect.md index cc33cfc0846..1dc8a1f01a8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-backedge-reference-effect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-backedge-reference-effect.expect.md @@ -43,6 +43,7 @@ function Foo(t0) { { const arr = []; + for (const selectedUser of userIds) { arr.push(selectedUser); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-false-positive-ref-validation-in-use-effect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-false-positive-ref-validation-in-use-effect.expect.md index 3896e6a2f2e..fd7f195a54f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-false-positive-ref-validation-in-use-effect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-false-positive-ref-validation-in-use-effect.expect.md @@ -49,7 +49,6 @@ function Component() { if ($[0] !== params) { t0 = (partialParams) => { const nextParams = { ...params, ...partialParams }; - nextParams.param = "value"; console.log(nextParams); }; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-invalid-reactivity-value-block.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-invalid-reactivity-value-block.expect.md index 1ad6f6a0477..211f48f7d7a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-invalid-reactivity-value-block.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-invalid-reactivity-value-block.expect.md @@ -82,6 +82,7 @@ function Foo() { const result = t1; useNoAlias(result, obj); + if (shouldCaptureObj && result[0] !== obj) { throw new Error("Unexpected"); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-mutate-ref-in-function-passed-to-hook.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-mutate-ref-in-function-passed-to-hook.expect.md index d8431d5bcac..03bca61ad1e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-mutate-ref-in-function-passed-to-hook.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-mutate-ref-in-function-passed-to-hook.expect.md @@ -52,6 +52,7 @@ function Example() { if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = function updateStyles() { const foo = fooRef.current; + if (barRef.current == null || foo == null) { return; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.expect.md index 6a9225eb772..407a9744250 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.expect.md @@ -67,7 +67,6 @@ function Component(props) { const key = {}; const tmp = (mutate(key), key); const context = { [tmp]: identity([props.value]) }; - mutate(key); t0 = [context, key]; $[0] = props.value; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-renaming-conflicting-decls.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-renaming-conflicting-decls.expect.md index 4f2b711d89a..85d345fbf7d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-renaming-conflicting-decls.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-renaming-conflicting-decls.expect.md @@ -72,7 +72,6 @@ function Component(props) { let t2; if ($[3] !== t0) { const linkProps = { url: t0 }; - const x = {}; let t3; let t4; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-slow-validate-preserve-memo.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-slow-validate-preserve-memo.expect.md index ab409b366d9..3238f43c073 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-slow-validate-preserve-memo.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-slow-validate-preserve-memo.expect.md @@ -40,11 +40,7 @@ function useTest(t0) { t1 = Builder.makeBuilder(isNull, "hello world") ?.push("1", 2) ?.push(3, { a: 4, b: 5, c: data }) - ?.push( - 6, - - data, - ) + ?.push(6, data) ?.push(7, "8") ?.push("8", Builder.makeBuilder(!isNull)?.push(9).vals)?.vals; $[0] = data; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-unreachable-code-early-return-in-useMemo.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-unreachable-code-early-return-in-useMemo.expect.md index 496d80d52b0..a1af1285ec8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-unreachable-code-early-return-in-useMemo.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-unreachable-code-early-return-in-useMemo.expect.md @@ -53,6 +53,7 @@ function Component(t0) { t1 = null; break bb0; } + try { let t3; if ($[0] !== value) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/return-ref-callback-structure.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/return-ref-callback-structure.expect.md index 95976383cbf..56dffd3c8d6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/return-ref-callback-structure.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/return-ref-callback-structure.expect.md @@ -44,6 +44,7 @@ function Foo(t0) { t1 = $[0]; } const s = t1; + if (cond) { let t2; if ($[1] === Symbol.for("react.memo_cache_sentinel")) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/rules-of-hooks-93dc5d5e538a.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/rules-of-hooks-93dc5d5e538a.expect.md index 626091be1e2..701d0a89bf9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/rules-of-hooks-93dc5d5e538a.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/rules-of-hooks-93dc5d5e538a.expect.md @@ -20,6 +20,7 @@ function RegressionTest() { // Valid because the loop doesn't change the order of hooks calls. function RegressionTest() { const res = []; + for (let i = 0; i !== 10 && true; ++i) { res.push(i); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/rules-of-hooks-c1e8c7f4c191.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/rules-of-hooks-c1e8c7f4c191.expect.md index 7761022d620..23705106a3e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/rules-of-hooks-c1e8c7f4c191.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/rules-of-hooks-c1e8c7f4c191.expect.md @@ -148,82 +148,121 @@ function MyComponent() { function MyComponent() { if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } + if (c) { } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-6949b255e7eb.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-6949b255e7eb.expect.md index 20c93fd9ac1..bc22e25e136 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-6949b255e7eb.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/todo.bail.rules-of-hooks-6949b255e7eb.expect.md @@ -97,6 +97,7 @@ const SomeName = () => { (FILLER ?? FILLER, FILLER) ?? FILLER; useSomeHook(); + if (anyConditionCanEvenBeFalse) { return null; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.expect.md index c0cac509c88..b6895fc396d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.expect.md @@ -50,7 +50,7 @@ function Example(props) { ## Logs ``` -{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","severity":"InvalidReact","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render. ","details":[{"kind":"error","loc":{"start":{"line":9,"column":10,"index":202},"end":{"line":9,"column":19,"index":211},"filename":"invalid-conditionally-assigned-dynamically-constructed-component-in-render.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":5,"column":16,"index":124},"end":{"line":5,"column":33,"index":141},"filename":"invalid-conditionally-assigned-dynamically-constructed-component-in-render.ts"},"message":"The component is created during render here"}]}},"fnLoc":null} +{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render","details":[{"kind":"error","loc":{"start":{"line":9,"column":10,"index":202},"end":{"line":9,"column":19,"index":211},"filename":"invalid-conditionally-assigned-dynamically-constructed-component-in-render.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":5,"column":16,"index":124},"end":{"line":5,"column":33,"index":141},"filename":"invalid-conditionally-assigned-dynamically-constructed-component-in-render.ts"},"message":"The component is created during render here"}]}},"fnLoc":null} {"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":45},"end":{"line":10,"column":1,"index":217},"filename":"invalid-conditionally-assigned-dynamically-constructed-component-in-render.ts"},"fnName":"Example","memoSlots":3,"memoBlocks":2,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.expect.md index 337997caa59..3d9f1f76f96 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.expect.md @@ -32,7 +32,7 @@ function Example(props) { ## Logs ``` -{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","severity":"InvalidReact","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render. ","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":120},"end":{"line":4,"column":19,"index":129},"filename":"invalid-dynamically-construct-component-in-render.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":91},"end":{"line":3,"column":37,"index":108},"filename":"invalid-dynamically-construct-component-in-render.ts"},"message":"The component is created during render here"}]}},"fnLoc":null} +{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":120},"end":{"line":4,"column":19,"index":129},"filename":"invalid-dynamically-construct-component-in-render.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":91},"end":{"line":3,"column":37,"index":108},"filename":"invalid-dynamically-construct-component-in-render.ts"},"message":"The component is created during render here"}]}},"fnLoc":null} {"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":45},"end":{"line":5,"column":1,"index":135},"filename":"invalid-dynamically-construct-component-in-render.ts"},"fnName":"Example","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.expect.md index 019beccdc86..2939a27a881 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.expect.md @@ -37,7 +37,7 @@ function Example(props) { ## Logs ``` -{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","severity":"InvalidReact","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render. ","details":[{"kind":"error","loc":{"start":{"line":6,"column":10,"index":130},"end":{"line":6,"column":19,"index":139},"filename":"invalid-dynamically-constructed-component-function.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":2,"index":73},"end":{"line":5,"column":3,"index":119},"filename":"invalid-dynamically-constructed-component-function.ts"},"message":"The component is created during render here"}]}},"fnLoc":null} +{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render","details":[{"kind":"error","loc":{"start":{"line":6,"column":10,"index":130},"end":{"line":6,"column":19,"index":139},"filename":"invalid-dynamically-constructed-component-function.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":2,"index":73},"end":{"line":5,"column":3,"index":119},"filename":"invalid-dynamically-constructed-component-function.ts"},"message":"The component is created during render here"}]}},"fnLoc":null} {"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":45},"end":{"line":7,"column":1,"index":145},"filename":"invalid-dynamically-constructed-component-function.ts"},"fnName":"Example","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.expect.md index f673b277798..860490581b1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.expect.md @@ -41,7 +41,7 @@ function Example(props) { ## Logs ``` -{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","severity":"InvalidReact","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render. ","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":118},"end":{"line":4,"column":19,"index":127},"filename":"invalid-dynamically-constructed-component-method-call.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":91},"end":{"line":3,"column":35,"index":106},"filename":"invalid-dynamically-constructed-component-method-call.ts"},"message":"The component is created during render here"}]}},"fnLoc":null} +{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":118},"end":{"line":4,"column":19,"index":127},"filename":"invalid-dynamically-constructed-component-method-call.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":91},"end":{"line":3,"column":35,"index":106},"filename":"invalid-dynamically-constructed-component-method-call.ts"},"message":"The component is created during render here"}]}},"fnLoc":null} {"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":45},"end":{"line":5,"column":1,"index":133},"filename":"invalid-dynamically-constructed-component-method-call.ts"},"fnName":"Example","memoSlots":4,"memoBlocks":2,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.expect.md index a44cf6a9f0e..8dbcf0f108a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.expect.md @@ -32,7 +32,7 @@ function Example(props) { ## Logs ``` -{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","severity":"InvalidReact","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render. ","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":125},"end":{"line":4,"column":19,"index":134},"filename":"invalid-dynamically-constructed-component-new.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":91},"end":{"line":3,"column":42,"index":113},"filename":"invalid-dynamically-constructed-component-new.ts"},"message":"The component is created during render here"}]}},"fnLoc":null} +{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":125},"end":{"line":4,"column":19,"index":134},"filename":"invalid-dynamically-constructed-component-new.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":91},"end":{"line":3,"column":42,"index":113},"filename":"invalid-dynamically-constructed-component-new.ts"},"message":"The component is created during render here"}]}},"fnLoc":null} {"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":45},"end":{"line":5,"column":1,"index":140},"filename":"invalid-dynamically-constructed-component-new.ts"},"fnName":"Example","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch-non-final-default.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch-non-final-default.expect.md index 804acfce19b..2822ee39eb6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch-non-final-default.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch-non-final-default.expect.md @@ -60,7 +60,6 @@ function Component(props) { y = x; } } - t0 = ; $[0] = props.p0; $[1] = props.p2; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch.expect.md index 33a7ae31930..7d6fc359147 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch.expect.md @@ -33,6 +33,7 @@ function Component(props) { let y; if ($[0] !== props.p0 || $[1] !== props.p2 || $[2] !== props.p3) { const x = []; + switch (props.p0) { case true: { x.push(props.p2); @@ -42,7 +43,6 @@ function Component(props) { y = x; } } - t0 = ; $[0] = props.p0; $[1] = props.p2; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-function-expression-captures-value-later-frozen.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-function-expression-captures-value-later-frozen.expect.md index 9f356bff589..cc89c1967be 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-function-expression-captures-value-later-frozen.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-function-expression-captures-value-later-frozen.expect.md @@ -32,6 +32,7 @@ function Component(props) { const onChange = (e) => { maybeMutate(x, e.target.value); }; + if (props.cond) { } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.todo-syntax.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.todo-syntax.expect.md index 006d2a49c02..e823939d3ff 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.todo-syntax.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.todo-syntax.expect.md @@ -33,7 +33,7 @@ Found 1 error: Error: [Fire] Untransformed reference to compiler-required feature. - Todo: (BuildHIR::lowerStatement) Handle TryStatement without a catch clause (11:4) +Either remove this `fire` call or ensure it is successfully transformed by the compiler Todo: (BuildHIR::lowerStatement) Handle TryStatement without a catch clause (11:4). error.todo-syntax.ts:18:4 16 | }; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.untransformed-fire-reference.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.untransformed-fire-reference.expect.md index 8481ed2c576..751c9ec21c9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.untransformed-fire-reference.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.untransformed-fire-reference.expect.md @@ -17,7 +17,7 @@ Found 1 error: Error: [Fire] Untransformed reference to compiler-required feature. - null +Either remove this `fire` call or ensure it is successfully transformed by the compiler. error.untransformed-fire-reference.ts:4:12 2 | import {fire} from 'react'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.use-no-memo.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.use-no-memo.expect.md index f84686bc36b..38a27d84780 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.use-no-memo.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/error.use-no-memo.expect.md @@ -34,7 +34,7 @@ Found 1 error: Error: [Fire] Untransformed reference to compiler-required feature. - null +Either remove this `fire` call or ensure it is successfully transformed by the compiler. error.use-no-memo.ts:15:4 13 | }; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/infer-deps-on-retry.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/infer-deps-on-retry.expect.md index 29201225afb..3caeef386f6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/infer-deps-on-retry.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/bailout-retry/infer-deps-on-retry.expect.md @@ -46,6 +46,7 @@ function useFoo(t0) { () => { log(derived); }, + [derived], [derived], ); 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 2c81d693b12..0b0be812791 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 @@ -39,6 +39,7 @@ import { Stringify } from "shared-runtime"; */ function Component(props) { const foo = _temp; + if (props.cond) { const t0 = useFire(foo); useEffect(() => { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-outside-effect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-outside-effect.expect.md index 81c36a362cf..cdb0726f2e1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-outside-effect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-outside-effect.expect.md @@ -26,7 +26,7 @@ function Component({props, bar}) { ``` Found 2 errors: -Invariant: Cannot compile `fire` +Error: Cannot compile `fire` Cannot use `fire` outside of a useEffect function. @@ -39,7 +39,7 @@ error.invalid-outside-effect.ts:8:2 10 | useCallback(() => { 11 | fire(foo(props)); -Invariant: Cannot compile `fire` +Error: Cannot compile `fire` Cannot use `fire` outside of a useEffect function. diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-no-array-literal.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-no-array-literal.expect.md index 96cea9c08f0..d82f1ee1b22 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-no-array-literal.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-no-array-literal.expect.md @@ -27,7 +27,7 @@ function Component(props) { ``` Found 1 error: -Invariant: Cannot compile `fire` +Error: Cannot compile `fire` You must use an array literal for an effect dependency array when that effect uses `fire()`. diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-spread.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-spread.expect.md index 4dc5336ebe0..a8418136302 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-spread.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-spread.expect.md @@ -30,7 +30,7 @@ function Component(props) { ``` Found 1 error: -Invariant: Cannot compile `fire` +Error: Cannot compile `fire` You must use an array literal for an effect dependency array when that effect uses `fire()`. diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-object-method-returns-caught-value.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-object-method-returns-caught-value.expect.md index b760716a0c7..388ab73746f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-object-method-returns-caught-value.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-object-method-returns-caught-value.expect.md @@ -44,7 +44,6 @@ function Component(props) { } }, }; - t0 = object.foo(); $[0] = props; $[1] = t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-object-method.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-object-method.expect.md index 80cde3265a3..45f525eb156 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-object-method.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-object-method.expect.md @@ -39,7 +39,6 @@ function Component(props) { } }, }; - t0 = object.foo(); $[0] = t0; } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unlabeled-break-within-label-loop.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unlabeled-break-within-label-loop.expect.md index 5675c77d2cd..1bb02c3ee7d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unlabeled-break-within-label-loop.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unlabeled-break-within-label-loop.expect.md @@ -35,6 +35,7 @@ function useHook(end) { log = []; for (let i = 0; i < end + 1; i++) { log.push(`${i} @A`); + if (i === end) { break; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unlabeled-break-within-label-switch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unlabeled-break-within-label-switch.expect.md index a990ee04e57..e95538ff52f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unlabeled-break-within-label-switch.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unlabeled-break-within-label-switch.expect.md @@ -41,6 +41,7 @@ function useHook(cond) { bb0: switch (CONST_STRING0) { case CONST_STRING0: { log.push("@A"); + if (cond) { break bb0; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-effect-cleanup-reassigns.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-effect-cleanup-reassigns.expect.md index 7a6d6334273..a2da26811f6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-effect-cleanup-reassigns.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-effect-cleanup-reassigns.expect.md @@ -65,12 +65,16 @@ function Component(t0) { if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t1 = () => { let cleanedUp = false; - setTimeout(() => { - if (!cleanedUp) { - cleanedUp = true; - setCleanupCount(_temp); - } - }, 0); + setTimeout( + () => { + if (!cleanedUp) { + cleanedUp = true; + setCleanupCount(_temp); + } + }, + + 0, + ); return () => { if (!cleanedUp) { cleanedUp = true; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useImperativeHandle-ref-mutate.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useImperativeHandle-ref-mutate.expect.md index 30d96038d43..d8f1a9ff20d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useImperativeHandle-ref-mutate.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useImperativeHandle-ref-mutate.expect.md @@ -43,7 +43,6 @@ function Component(t0) { const precomputed = prop + ref2.current; return { foo: () => prop + ref2.current + precomputed }; }; - t2 = [prop]; $[0] = prop; $[1] = t1; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useMemo-multiple-if-else.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useMemo-multiple-if-else.expect.md index 7f4b8af9650..bf110b75dc8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useMemo-multiple-if-else.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useMemo-multiple-if-else.expect.md @@ -46,6 +46,7 @@ function Component(props) { if (props.cond) { y.push(props.a); } + if (props.cond2) { t0 = y; break bb0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useMemo-switch-return.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useMemo-switch-return.expect.md index 278063c8561..652e675cfd1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useMemo-switch-return.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useMemo-switch-return.expect.md @@ -50,7 +50,6 @@ function Component(props) { y = props.y; } } - t0 = y; } const x = t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/validate-no-set-state-in-render-uncalled-function-with-mutable-range-is-valid.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/validate-no-set-state-in-render-uncalled-function-with-mutable-range-is-valid.expect.md index c7459eb6434..d44f098f897 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/validate-no-set-state-in-render-uncalled-function-with-mutable-range-is-valid.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/validate-no-set-state-in-render-uncalled-function-with-mutable-range-is-valid.expect.md @@ -50,6 +50,7 @@ function Component(props) { t0 = $[1]; } const onSubmit = t0; + switch (currentStep) { case 0: { let t1; diff --git a/compiler/packages/eslint-plugin-react-compiler/__tests__/ImpureFunctionCallsRule-test.ts b/compiler/packages/eslint-plugin-react-compiler/__tests__/ImpureFunctionCallsRule-test.ts index a745397078a..f89b049d100 100644 --- a/compiler/packages/eslint-plugin-react-compiler/__tests__/ImpureFunctionCallsRule-test.ts +++ b/compiler/packages/eslint-plugin-react-compiler/__tests__/ImpureFunctionCallsRule-test.ts @@ -14,7 +14,7 @@ import {allRules} from '../src/rules/ReactCompilerRule'; testRule( 'no impure function calls rule', - allRules[getRuleForCategory(ErrorCategory.Purity).name], + allRules[getRuleForCategory(ErrorCategory.Purity).name].rule, { valid: [], invalid: [ diff --git a/compiler/packages/eslint-plugin-react-compiler/__tests__/InvalidHooksRule-test.ts b/compiler/packages/eslint-plugin-react-compiler/__tests__/InvalidHooksRule-test.ts index 0ba165011c6..1fd88935575 100644 --- a/compiler/packages/eslint-plugin-react-compiler/__tests__/InvalidHooksRule-test.ts +++ b/compiler/packages/eslint-plugin-react-compiler/__tests__/InvalidHooksRule-test.ts @@ -14,7 +14,7 @@ import {allRules} from '../src/rules/ReactCompilerRule'; testRule( 'rules-of-hooks', - allRules[getRuleForCategory(ErrorCategory.Hooks).name], + allRules[getRuleForCategory(ErrorCategory.Hooks).name].rule, { valid: [ { diff --git a/compiler/packages/eslint-plugin-react-compiler/__tests__/NoAmbiguousJsxRule-test.ts b/compiler/packages/eslint-plugin-react-compiler/__tests__/NoAmbiguousJsxRule-test.ts index 9a09f4c4e05..bb6f4b93b88 100644 --- a/compiler/packages/eslint-plugin-react-compiler/__tests__/NoAmbiguousJsxRule-test.ts +++ b/compiler/packages/eslint-plugin-react-compiler/__tests__/NoAmbiguousJsxRule-test.ts @@ -14,7 +14,7 @@ import {allRules} from '../src/rules/ReactCompilerRule'; testRule( 'no ambiguous JSX rule', - allRules[getRuleForCategory(ErrorCategory.ErrorBoundaries).name], + allRules[getRuleForCategory(ErrorCategory.ErrorBoundaries).name].rule, { valid: [], invalid: [ diff --git a/compiler/packages/eslint-plugin-react-compiler/__tests__/NoCapitalizedCallsRule-test.ts b/compiler/packages/eslint-plugin-react-compiler/__tests__/NoCapitalizedCallsRule-test.ts index c361670e974..5b45a70fa1d 100644 --- a/compiler/packages/eslint-plugin-react-compiler/__tests__/NoCapitalizedCallsRule-test.ts +++ b/compiler/packages/eslint-plugin-react-compiler/__tests__/NoCapitalizedCallsRule-test.ts @@ -13,7 +13,7 @@ import {allRules} from '../src/rules/ReactCompilerRule'; testRule( 'no-capitalized-calls', - allRules[getRuleForCategory(ErrorCategory.CapitalizedCalls).name], + allRules[getRuleForCategory(ErrorCategory.CapitalizedCalls).name].rule, { valid: [], invalid: [ diff --git a/compiler/packages/eslint-plugin-react-compiler/__tests__/NoRefAccessInRender-tests.ts b/compiler/packages/eslint-plugin-react-compiler/__tests__/NoRefAccessInRender-tests.ts index 9042980a807..9953c8c2136 100644 --- a/compiler/packages/eslint-plugin-react-compiler/__tests__/NoRefAccessInRender-tests.ts +++ b/compiler/packages/eslint-plugin-react-compiler/__tests__/NoRefAccessInRender-tests.ts @@ -14,7 +14,7 @@ import {allRules} from '../src/rules/ReactCompilerRule'; testRule( 'no ref access in render rule', - allRules[getRuleForCategory(ErrorCategory.Refs).name], + allRules[getRuleForCategory(ErrorCategory.Refs).name].rule, { valid: [], invalid: [ diff --git a/compiler/packages/eslint-plugin-react-compiler/__tests__/shared-utils.ts b/compiler/packages/eslint-plugin-react-compiler/__tests__/shared-utils.ts index 2ab24581d8d..b0523f522c9 100644 --- a/compiler/packages/eslint-plugin-react-compiler/__tests__/shared-utils.ts +++ b/compiler/packages/eslint-plugin-react-compiler/__tests__/shared-utils.ts @@ -61,10 +61,10 @@ export const TestRecommendedRules: Rule.RuleModule = { schema: [{type: 'object', additionalProperties: true}], }, create(context) { - for (const rule of Object.values( + for (const ruleConfig of Object.values( configs.recommended.plugins['react-compiler'].rules, )) { - const listener = rule.create(context); + const listener = ruleConfig.rule.create(context); if (Object.entries(listener).length !== 0) { throw new Error('TODO: handle rules that return listeners to eslint'); } diff --git a/compiler/packages/eslint-plugin-react-compiler/src/index.ts b/compiler/packages/eslint-plugin-react-compiler/src/index.ts index 1a339e83310..9d49b16c57e 100644 --- a/compiler/packages/eslint-plugin-react-compiler/src/index.ts +++ b/compiler/packages/eslint-plugin-react-compiler/src/index.ts @@ -5,7 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -import {allRules, recommendedRules} from './rules/ReactCompilerRule'; +import {type Linter} from 'eslint'; +import { + allRules, + mapErrorSeverityToESlint, + recommendedRules, +} from './rules/ReactCompilerRule'; const meta = { name: 'eslint-plugin-react-compiler', @@ -19,11 +24,13 @@ const configs = { }, }, rules: Object.fromEntries( - Object.keys(recommendedRules).map(ruleName => [ - 'react-compiler/' + ruleName, - 'error', - ]), - ) as Record, + Object.entries(recommendedRules).map(([name, ruleConfig]) => { + return [ + 'react-compiler/' + name, + mapErrorSeverityToESlint(ruleConfig.severity), + ]; + }), + ) as Record, }, }; diff --git a/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts b/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts index d2e8fdd42e0..3eb6dfa0c71 100644 --- a/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts +++ b/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts @@ -11,9 +11,10 @@ import { CompilerErrorDetailOptions, CompilerSuggestionOperation, } from 'babel-plugin-react-compiler/src'; -import type {Rule} from 'eslint'; +import type {Linter, Rule} from 'eslint'; import runReactCompiler, {RunCacheEntry} from '../shared/RunReactCompiler'; import { + ErrorSeverity, LintRules, type LintRule, } from 'babel-plugin-react-compiler/src/CompilerError'; @@ -192,26 +193,54 @@ export const NoUnusedDirectivesRule: Rule.RuleModule = { }, }; -type RulesObject = {[name: string]: Rule.RuleModule}; +type RulesConfig = { + [name: string]: {rule: Rule.RuleModule; severity: ErrorSeverity}; +}; -export const allRules: RulesObject = LintRules.reduce( +export const allRules: RulesConfig = LintRules.reduce( (acc, rule) => { - acc[rule.name] = makeRule(rule); + acc[rule.name] = {rule: makeRule(rule), severity: rule.severity}; return acc; }, { - 'no-unused-directives': NoUnusedDirectivesRule, - } as RulesObject, + 'no-unused-directives': { + rule: NoUnusedDirectivesRule, + severity: ErrorSeverity.Error, + }, + } as RulesConfig, ); -export const recommendedRules: RulesObject = LintRules.filter( +export const recommendedRules: RulesConfig = LintRules.filter( rule => rule.recommended, ).reduce( (acc, rule) => { - acc[rule.name] = makeRule(rule); + acc[rule.name] = {rule: makeRule(rule), severity: rule.severity}; return acc; }, { - 'no-unused-directives': NoUnusedDirectivesRule, - } as RulesObject, + 'no-unused-directives': { + rule: NoUnusedDirectivesRule, + severity: ErrorSeverity.Error, + }, + } as RulesConfig, ); + +export function mapErrorSeverityToESlint( + severity: ErrorSeverity, +): Linter.StringSeverity { + switch (severity) { + case ErrorSeverity.Error: { + return 'error'; + } + case ErrorSeverity.Warning: { + return 'warn'; + } + case ErrorSeverity.Hint: + case ErrorSeverity.Off: { + return 'off'; + } + default: { + assertExhaustive(severity, `Unhandled severity: ${severity}`); + } + } +} diff --git a/compiler/scripts/build-eslint-docs.js b/compiler/scripts/build-eslint-docs.js index d8d59096d9e..f4e411590e8 100644 --- a/compiler/scripts/build-eslint-docs.js +++ b/compiler/scripts/build-eslint-docs.js @@ -19,12 +19,14 @@ const combinedRules = [ ]; const printed = combinedRules - .filter(rule => rule.recommended) - .map(rule => { + .filter( + ruleConfig => ruleConfig.rule.recommended && ruleConfig.severity !== 'Off' + ) + .map(ruleConfig => { return ` -## \`react-hooks/${rule.name}\` +## \`react-hooks/${ruleConfig.rule.name}\` -${rule.description} +${ruleConfig.rule.description} `.trim(); }) .join('\n\n'); diff --git a/packages/eslint-plugin-react-hooks/__tests__/ReactCompilerRuleTypescript-test.ts b/packages/eslint-plugin-react-hooks/__tests__/ReactCompilerRuleTypescript-test.ts index d9385bdba43..1da7be666af 100644 --- a/packages/eslint-plugin-react-hooks/__tests__/ReactCompilerRuleTypescript-test.ts +++ b/packages/eslint-plugin-react-hooks/__tests__/ReactCompilerRuleTypescript-test.ts @@ -74,4 +74,4 @@ const tests: CompilerTestCases = { const eslintTester = new ESLintTesterV8({ parser: require.resolve('@typescript-eslint/parser-v5'), }); -eslintTester.run('react-compiler', allRules['immutability'], tests); +eslintTester.run('react-compiler', allRules['immutability'].rule, tests); diff --git a/packages/eslint-plugin-react-hooks/src/index.ts b/packages/eslint-plugin-react-hooks/src/index.ts index 462c3104a70..65cb030d006 100644 --- a/packages/eslint-plugin-react-hooks/src/index.ts +++ b/packages/eslint-plugin-react-hooks/src/index.ts @@ -7,22 +7,34 @@ import type {Linter, Rule} from 'eslint'; import ExhaustiveDeps from './rules/ExhaustiveDeps'; -import {allRules, recommendedRules} from './shared/ReactCompiler'; +import { + allRules, + mapErrorSeverityToESlint, + recommendedRules, +} from './shared/ReactCompiler'; import RulesOfHooks from './rules/RulesOfHooks'; // All rules const rules = { 'exhaustive-deps': ExhaustiveDeps, 'rules-of-hooks': RulesOfHooks, - ...allRules, + ...Object.fromEntries( + Object.entries(allRules).map(([name, config]) => [name, config.rule]) + ), } satisfies Record; // Config rules const ruleConfigs = { 'react-hooks/rules-of-hooks': 'error', 'react-hooks/exhaustive-deps': 'warn', + // Compiler rules ...Object.fromEntries( - Object.keys(recommendedRules).map(name => ['react-hooks/' + name, 'error']), + Object.entries(recommendedRules).map(([name, ruleConfig]) => { + return [ + 'react-hooks/' + name, + mapErrorSeverityToESlint(ruleConfig.severity), + ]; + }), ), } satisfies Linter.RulesRecord; diff --git a/packages/eslint-plugin-react-hooks/src/shared/ReactCompiler.ts b/packages/eslint-plugin-react-hooks/src/shared/ReactCompiler.ts index f006b797817..dec46457cce 100644 --- a/packages/eslint-plugin-react-hooks/src/shared/ReactCompiler.ts +++ b/packages/eslint-plugin-react-hooks/src/shared/ReactCompiler.ts @@ -13,8 +13,9 @@ import { CompilerSuggestionOperation, LintRules, type LintRule, + ErrorSeverity, } from 'babel-plugin-react-compiler'; -import type {Rule} from 'eslint'; +import {type Linter, type Rule} from 'eslint'; import runReactCompiler, {RunCacheEntry} from './RunReactCompiler'; function assertExhaustive(_: never, errorMsg: string): never { @@ -191,26 +192,54 @@ export const NoUnusedDirectivesRule: Rule.RuleModule = { }, }; -type RulesObject = {[name: string]: Rule.RuleModule}; +type RulesConfig = { + [name: string]: {rule: Rule.RuleModule; severity: ErrorSeverity}; +}; -export const allRules: RulesObject = LintRules.reduce( +export const allRules: RulesConfig = LintRules.reduce( (acc, rule) => { - acc[rule.name] = makeRule(rule); + acc[rule.name] = {rule: makeRule(rule), severity: rule.severity}; return acc; }, { - 'no-unused-directives': NoUnusedDirectivesRule, - } as RulesObject, + 'no-unused-directives': { + rule: NoUnusedDirectivesRule, + severity: ErrorSeverity.Error, + }, + } as RulesConfig, ); -export const recommendedRules: RulesObject = LintRules.filter( +export const recommendedRules: RulesConfig = LintRules.filter( rule => rule.recommended, ).reduce( (acc, rule) => { - acc[rule.name] = makeRule(rule); + acc[rule.name] = {rule: makeRule(rule), severity: rule.severity}; return acc; }, { - 'no-unused-directives': NoUnusedDirectivesRule, - } as RulesObject, + 'no-unused-directives': { + rule: NoUnusedDirectivesRule, + severity: ErrorSeverity.Error, + }, + } as RulesConfig, ); + +export function mapErrorSeverityToESlint( + severity: ErrorSeverity, +): Linter.StringSeverity { + switch (severity) { + case ErrorSeverity.Error: { + return 'error'; + } + case ErrorSeverity.Warning: { + return 'warn'; + } + case ErrorSeverity.Hint: + case ErrorSeverity.Off: { + return 'off'; + } + default: { + assertExhaustive(severity, `Unhandled severity: ${severity}`); + } + } +} diff --git a/packages/react-devtools-shared/src/__tests__/utils-test.js b/packages/react-devtools-shared/src/__tests__/utils-test.js index dcffd2a228b..9b9e82102cc 100644 --- a/packages/react-devtools-shared/src/__tests__/utils-test.js +++ b/packages/react-devtools-shared/src/__tests__/utils-test.js @@ -421,6 +421,26 @@ function f() { } await expect(run('http://test/c.mjs')).resolves.toStrictEqual(result); await expect(run('http://test/d.mjs')).resolves.toStrictEqual(result); }); + + it('should not throw for invalid base URL with relative source map', async () => { + const fs2 = { + 'bundle.js': `${source}bundle.js.map`, + }; + const fetch2 = async url => fs2[url] || null; + const run = url => symbolicateSource(fetch2, url, 1, 1); + await expect(run('bundle.js')).resolves.toBe(null); + }); + + it('should resolve absolute source map even if base URL is invalid', async () => { + const fs3 = { + 'invalid-base.js': `${source}http://test/a.mjs.map`, + 'http://test/a.mts': `export function f() {}`, + 'http://test/a.mjs.map': `{"version":3,"file":"a.mjs","sourceRoot":"","sources":["a.mts"],"names":[],"mappings":";;AAAA,cAAsB;AAAtB,SAAgB,CAAC,KAAI,CAAC"}`, + }; + const fetch3 = async url => fs3[url] || null; + const run = url => symbolicateSource(fetch3, url, 4, 10); + await expect(run('invalid-base.js')).resolves.toStrictEqual(result); + }); }); describe('formatConsoleArguments', () => { diff --git a/packages/react-devtools-shared/src/symbolicateSource.js b/packages/react-devtools-shared/src/symbolicateSource.js index 267e291e120..092b1f8187a 100644 --- a/packages/react-devtools-shared/src/symbolicateSource.js +++ b/packages/react-devtools-shared/src/symbolicateSource.js @@ -75,7 +75,18 @@ export async function symbolicateSource( resourceLine.length, ); - const sourceMapURL = new URL(sourceMapAt, sourceURL).toString(); + // Compute the absolute source map URL. If the base URL is invalid, gracefully bail. + let sourceMapURL; + try { + sourceMapURL = new URL(sourceMapAt, sourceURL).toString(); + } catch (e) { + // Fallback: try if sourceMapAt is already an absolute URL; otherwise give up. + try { + sourceMapURL = new URL(sourceMapAt).toString(); + } catch (_e) { + return null; + } + } const sourceMap = await fetchFileWithCaching(sourceMapURL).catch( () => null, );