@samitouri / QOS-React / commits / 72848027a5

[compiler] Improve more error messages (#33758)

This PR uses the new diagnostic type for most of the error messages produced in our explicit validation passes (`Validation/` directory). One of the validations produced multiple errors as a hack to showing multiple related locations, which we can now consolidate into a single diagnostic. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33758). * #33981 * #33777 * #33767 * #33765 * #33760 * #33759 * __->__ #33758

Joseph Savona committed Jul 24, 2025 at 15:39 UTC 72848027a5525d7beebeccb0a485f4f211a1a101
41 files changed +324 -262
compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts
+13 -2
@@ -59,7 +59,7 @@ export type CompilerDiagnosticDetail =
59 */
60 {
61 kind: 'error';
62 - loc: SourceLocation;
62 + loc: SourceLocation | null;
63 message: string;
64 };
65
@@ -100,6 +100,12 @@ export class CompilerDiagnostic {
100 this.options = options;
101 }
102
103 + static create(
104 + options: Omit<CompilerDiagnosticOptions, 'details'>,
105 + ): CompilerDiagnostic {
106 + return new CompilerDiagnostic({...options, details: []});
107 + }
108 +
109 get category(): CompilerDiagnosticOptions['category'] {
110 return this.options.category;
111 }
@@ -113,6 +119,11 @@ export class CompilerDiagnostic {
119 return this.options.suggestions;
120 }
121
122 + withDetail(detail: CompilerDiagnosticDetail): CompilerDiagnostic {
123 + this.options.details.push(detail);
124 + return this;
125 + }
126 +
127 primaryLocation(): SourceLocation | null {
128 return this.options.details.filter(d => d.kind === 'error')[0]?.loc ?? null;
129 }
@@ -127,7 +138,7 @@ export class CompilerDiagnostic {
138 switch (detail.kind) {
139 case 'error': {
140 const loc = detail.loc;
130 - if (typeof loc === 'symbol') {
141 + if (loc == null || typeof loc === 'symbol') {
142 continue;
143 }
144 let codeFrame: string;
compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts
+37 -19
@@ -9,6 +9,7 @@ import {NodePath, Scope} from '@babel/traverse';
9 import * as t from '@babel/types';
10 import invariant from 'invariant';
11 import {
12 + CompilerDiagnostic,
13 CompilerError,
14 CompilerSuggestionOperation,
15 ErrorSeverity,
@@ -104,12 +105,18 @@ export function lower(
105 if (param.isIdentifier()) {
106 const binding = builder.resolveIdentifier(param);
107 if (binding.kind !== 'Identifier') {
107 - builder.errors.push({
108 - reason: `(BuildHIR::lower) Could not find binding for param \`${param.node.name}\``,
109 - severity: ErrorSeverity.Invariant,
110 - loc: param.node.loc ?? null,
111 - suggestions: null,
112 - });
108 + builder.errors.pushDiagnostic(
109 + CompilerDiagnostic.create({
110 + category: 'Could not find binding',
111 + description: `[BuildHIR] Could not find binding for param \`${param.node.name}\``,
112 + severity: ErrorSeverity.Invariant,
113 + suggestions: null,
114 + }).withDetail({
115 + kind: 'error',
116 + loc: param.node.loc ?? null,
117 + message: 'Could not find binding',
118 + }),
119 + );
120 return;
121 }
122 const place: Place = {
@@ -163,12 +170,18 @@ export function lower(
170 'Assignment',
171 );
172 } else {
166 - builder.errors.push({
167 - reason: `(BuildHIR::lower) Handle ${param.node.type} params`,
168 - severity: ErrorSeverity.Todo,
169 - loc: param.node.loc ?? null,
170 - suggestions: null,
171 - });
173 + builder.errors.pushDiagnostic(
174 + CompilerDiagnostic.create({
175 + category: `Handle ${param.node.type} parameters`,
176 + description: `[BuildHIR] Add support for ${param.node.type} parameters`,
177 + severity: ErrorSeverity.Todo,
178 + suggestions: null,
179 + }).withDetail({
180 + kind: 'error',
181 + loc: param.node.loc ?? null,
182 + message: 'Unsupported parameter type',
183 + }),
184 + );
185 }
186 });
187
@@ -188,13 +201,18 @@ export function lower(
201 lowerStatement(builder, body);
202 directives = body.get('directives').map(d => d.node.value.value);
203 } else {
191 - builder.errors.push({
192 - severity: ErrorSeverity.InvalidJS,
193 - reason: `Unexpected function body kind`,
194 - description: `Expected function body to be an expression or a block statement, got \`${body.type}\``,
195 - loc: body.node.loc ?? null,
196 - suggestions: null,
197 - });
204 + builder.errors.pushDiagnostic(
205 + CompilerDiagnostic.create({
206 + severity: ErrorSeverity.InvalidJS,
207 + category: `Unexpected function body kind`,
208 + description: `Expected function body to be an expression or a block statement, got \`${body.type}\``,
209 + suggestions: null,
210 + }).withDetail({
211 + kind: 'error',
212 + loc: body.node.loc ?? null,
213 + message: 'Expected a block statement or expression',
214 + }),
215 + );
216 }
217
218 if (builder.errors.hasErrors()) {
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateLocalsNotReassignedAfterRender.ts
+14 -11
@@ -5,7 +5,7 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {CompilerError, Effect} from '..';
8 +import {CompilerDiagnostic, CompilerError, Effect, ErrorSeverity} from '..';
9 import {HIRFunction, IdentifierId, Place} from '../HIR';
10 import {
11 eachInstructionLValue,
@@ -28,16 +28,19 @@ export function validateLocalsNotReassignedAfterRender(fn: HIRFunction): void {
28 false,
29 );
30 if (reassignment !== null) {
31 - CompilerError.throwInvalidReact({
32 - reason:
33 - 'Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead',
34 - description:
35 - reassignment.identifier.name !== null &&
36 - reassignment.identifier.name.kind === 'named'
37 - ? `Variable \`${reassignment.identifier.name.value}\` cannot be reassigned after render`
38 - : '',
39 - loc: reassignment.loc,
40 - });
31 + const errors = new CompilerError();
32 + errors.pushDiagnostic(
33 + CompilerDiagnostic.create({
34 + severity: ErrorSeverity.InvalidReact,
35 + category: 'Cannot reassign a variable after render completes',
36 + description: `Reassigning ${reassignment.identifier.name != null && reassignment.identifier.name.kind === 'named' ? `variable \`${reassignment.identifier.name.value}\`` : 'a variable'} after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead`,
37 + }).withDetail({
38 + kind: 'error',
39 + loc: reassignment.loc,
40 + message: 'Cannot reassign variable after render completes',
41 + }),
42 + );
43 + throw errors;
44 }
45 }
46
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoFreezingKnownMutableFunctions.ts
+19 -11
@@ -5,7 +5,7 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {CompilerError, Effect, ErrorSeverity} from '..';
8 +import {CompilerDiagnostic, CompilerError, Effect, ErrorSeverity} from '..';
9 import {
10 FunctionEffect,
11 HIRFunction,
@@ -57,16 +57,24 @@ export function validateNoFreezingKnownMutableFunctions(
57 if (operand.effect === Effect.Freeze) {
58 const effect = contextMutationEffects.get(operand.identifier.id);
59 if (effect != null) {
60 - errors.push({
61 - reason: `This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead`,
62 - loc: operand.loc,
63 - severity: ErrorSeverity.InvalidReact,
64 - });
65 - errors.push({
66 - reason: `The function modifies a local variable here`,
67 - loc: effect.loc,
68 - severity: ErrorSeverity.InvalidReact,
69 - });
60 + errors.pushDiagnostic(
61 + CompilerDiagnostic.create({
62 + severity: ErrorSeverity.InvalidReact,
63 + category: 'Cannot modify local variables after render completes',
64 + description: `This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead`,
65 + })
66 + .withDetail({
67 + kind: 'error',
68 + loc: operand.loc,
69 + message:
70 + 'This function may (indirectly) reassign or modify local variables after render',
71 + })
72 + .withDetail({
73 + kind: 'error',
74 + loc: effect.loc,
75 + message: 'This modifies a local variable',
76 + }),
77 + );
78 }
79 }
80 }
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoImpureFunctionsInRender.ts
+17 -12
@@ -5,7 +5,7 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {CompilerError, ErrorSeverity} from '..';
8 +import {CompilerDiagnostic, CompilerError, ErrorSeverity} from '..';
9 import {HIRFunction} from '../HIR';
10 import {getFunctionCallSignature} from '../Inference/InferReferenceEffects';
11 import {Result} from '../Utils/Result';
@@ -34,17 +34,22 @@ export function validateNoImpureFunctionsInRender(
34 callee.identifier.type,
35 );
36 if (signature != null && signature.impure === true) {
37 - errors.push({
38 - reason:
39 - 'Calling an impure function can produce unstable results. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent)',
40 - description:
41 - signature.canonicalName != null
42 - ? `\`${signature.canonicalName}\` is an impure function whose results may change on every call`
43 - : null,
44 - severity: ErrorSeverity.InvalidReact,
45 - loc: callee.loc,
46 - suggestions: null,
47 - });
37 + errors.pushDiagnostic(
38 + CompilerDiagnostic.create({
39 + category: 'Cannot call impure function during render',
40 + description:
41 + (signature.canonicalName != null
42 + ? `\`${signature.canonicalName}\` is an impure function. `
43 + : '') +
44 + '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)',
45 + severity: ErrorSeverity.InvalidReact,
46 + suggestions: null,
47 + }).withDetail({
48 + kind: 'error',
49 + loc: callee.loc,
50 + message: 'Cannot call impure function',
51 + }),
52 + );
53 }
54 }
55 }
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoJSXInTryStatement.ts
+12 -6
@@ -5,7 +5,7 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {CompilerError, ErrorSeverity} from '..';
8 +import {CompilerDiagnostic, CompilerError, ErrorSeverity} from '..';
9 import {BlockId, HIRFunction} from '../HIR';
10 import {Result} from '../Utils/Result';
11 import {retainWhere} from '../Utils/utils';
@@ -34,11 +34,17 @@ export function validateNoJSXInTryStatement(
34 switch (value.kind) {
35 case 'JsxExpression':
36 case 'JsxFragment': {
37 - errors.push({
38 - severity: ErrorSeverity.InvalidReact,
39 - reason: `Unexpected JSX element within a try statement. 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)`,
40 - loc: value.loc,
41 - });
37 + errors.pushDiagnostic(
38 + CompilerDiagnostic.create({
39 + severity: ErrorSeverity.InvalidReact,
40 + category: 'Avoid constructing JSX within try/catch',
41 + 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)`,
42 + }).withDetail({
43 + kind: 'error',
44 + loc: value.loc,
45 + message: 'Avoid constructing JSX within try/catch',
46 + }),
47 + );
48 break;
49 }
50 }
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInEffects.ts
+20 -9
@@ -5,7 +5,11 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {CompilerError, ErrorSeverity} from '../CompilerError';
8 +import {
9 + CompilerDiagnostic,
10 + CompilerError,
11 + ErrorSeverity,
12 +} from '../CompilerError';
13 import {
14 HIRFunction,
15 IdentifierId,
@@ -90,14 +94,21 @@ export function validateNoSetStateInEffects(
94 if (arg !== undefined && arg.kind === 'Identifier') {
95 const setState = setStateFunctions.get(arg.identifier.id);
96 if (setState !== undefined) {
93 - errors.push({
94 - reason:
95 - 'Calling setState directly within a useEffect causes cascading renders and is not recommended. Consider alternatives to useEffect. (https://react.dev/learn/you-might-not-need-an-effect)',
96 - description: null,
97 - severity: ErrorSeverity.InvalidReact,
98 - loc: setState.loc,
99 - suggestions: null,
100 - });
97 + errors.pushDiagnostic(
98 + CompilerDiagnostic.create({
99 + category:
100 + 'Calling setState within an effect can trigger cascading renders',
101 + description:
102 + 'Calling setState directly within a useEffect causes cascading renders that can hurt performance, and is not recommended. Consider alternatives to useEffect. (https://react.dev/learn/you-might-not-need-an-effect)',
103 + severity: ErrorSeverity.InvalidReact,
104 + suggestions: null,
105 + }).withDetail({
106 + kind: 'error',
107 + loc: setState.loc,
108 + message:
109 + 'Avoid calling setState() in the top-level of an effect',
110 + }),
111 + );
112 }
113 }
114 }
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInRender.ts
+33 -17
@@ -5,7 +5,11 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {CompilerError, ErrorSeverity} from '../CompilerError';
8 +import {
9 + CompilerDiagnostic,
10 + CompilerError,
11 + ErrorSeverity,
12 +} from '../CompilerError';
13 import {HIRFunction, IdentifierId, isSetStateType} from '../HIR';
14 import {computeUnconditionalBlocks} from '../HIR/ComputeUnconditionalBlocks';
15 import {eachInstructionValueOperand} from '../HIR/visitors';
@@ -122,23 +126,35 @@ function validateNoSetStateInRenderImpl(
126 unconditionalSetStateFunctions.has(callee.identifier.id)
127 ) {
128 if (activeManualMemoId !== null) {
125 - errors.push({
126 - reason:
127 - 'Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)',
128 - description: null,
129 - severity: ErrorSeverity.InvalidReact,
130 - loc: callee.loc,
131 - suggestions: null,
132 - });
129 + errors.pushDiagnostic(
130 + CompilerDiagnostic.create({
131 + category:
132 + 'Calling setState from useMemo may trigger an infinite loop',
133 + description:
134 + '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)',
135 + severity: ErrorSeverity.InvalidReact,
136 + suggestions: null,
137 + }).withDetail({
138 + kind: 'error',
139 + loc: callee.loc,
140 + message: 'Found setState() within useMemo()',
141 + }),
142 + );
143 } else if (unconditionalBlocks.has(block.id)) {
134 - errors.push({
135 - reason:
136 - 'This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)',
137 - description: null,
138 - severity: ErrorSeverity.InvalidReact,
139 - loc: callee.loc,
140 - suggestions: null,
141 - });
144 + errors.pushDiagnostic(
145 + CompilerDiagnostic.create({
146 + category:
147 + 'Calling setState during render may trigger an infinite loop',
148 + description:
149 + 'Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)',
150 + severity: ErrorSeverity.InvalidReact,
151 + suggestions: null,
152 + }).withDetail({
153 + kind: 'error',
154 + loc: callee.loc,
155 + message: 'Found setState() within useMemo()',
156 + }),
157 + );
158 }
159 }
160 break;
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateUseMemo.ts
+37 -16
@@ -5,7 +5,11 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {CompilerError, ErrorSeverity} from '..';
8 +import {
9 + CompilerDiagnostic,
10 + CompilerError,
11 + ErrorSeverity,
12 +} from '../CompilerError';
13 import {FunctionExpression, HIRFunction, IdentifierId} from '../HIR';
14 import {Result} from '../Utils/Result';
15
@@ -63,24 +67,41 @@ export function validateUseMemo(fn: HIRFunction): Result<void, CompilerError> {
67 }
68
69 if (body.loweredFunc.func.params.length > 0) {
66 - errors.push({
67 - severity: ErrorSeverity.InvalidReact,
68 - reason: 'useMemo callbacks may not accept any arguments',
69 - description: null,
70 - loc: body.loc,
71 - suggestions: null,
72 - });
70 + const firstParam = body.loweredFunc.func.params[0];
71 + const loc =
72 + firstParam.kind === 'Identifier'
73 + ? firstParam.loc
74 + : firstParam.place.loc;
75 + errors.pushDiagnostic(
76 + CompilerDiagnostic.create({
77 + severity: ErrorSeverity.InvalidReact,
78 + category: 'useMemo() callbacks may not accept parameters',
79 + description:
80 + '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.',
81 + suggestions: null,
82 + }).withDetail({
83 + kind: 'error',
84 + loc,
85 + message: '',
86 + }),
87 + );
88 }
89
90 if (body.loweredFunc.func.async || body.loweredFunc.func.generator) {
76 - errors.push({
77 - severity: ErrorSeverity.InvalidReact,
78 - reason:
79 - 'useMemo callbacks may not be async or generator functions',
80 - description: null,
81 - loc: body.loc,
82 - suggestions: null,
83 - });
91 + errors.pushDiagnostic(
92 + CompilerDiagnostic.create({
93 + severity: ErrorSeverity.InvalidReact,
94 + category:
95 + 'useMemo callbacks may not be async or generator functions',
96 + description:
97 + 'useMemo() callbacks are called once and must synchronously return a value',
98 + suggestions: null,
99 + }).withDetail({
100 + kind: 'error',
101 + loc: body.loc,
102 + message: 'Async and generator functions are not supported',
103 + }),
104 + );
105 }
106
107 break;
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-old-inference-false-positive-ref-validation-in-use-effect.expect.md
+6 -9
@@ -36,8 +36,10 @@ function Component() {
36 ## Error
37
38 ```
39 -Found 2 errors:
40 -Error: This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
39 +Found 1 error:
40 +Error: Cannot modify local variables after render completes
41 +
42 +This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
43
44 error.bug-old-inference-false-positive-ref-validation-in-use-effect.ts:20:12
45 18 | );
@@ -51,24 +53,19 @@ error.bug-old-inference-false-positive-ref-validation-in-use-effect.ts:20:12
53 > 23 | }
54 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
55 > 24 | }, [update]);
54 - | ^^^^ This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
56 + | ^^^^ This function may (indirectly) reassign or modify local variables after render
57 25 |
58 26 | return 'ok';
59 27 | }
60
59 -
60 -Error: The function modifies a local variable here
61 -
61 error.bug-old-inference-false-positive-ref-validation-in-use-effect.ts:14:6
62 12 | ...partialParams,
63 13 | };
64 > 14 | nextParams.param = 'value';
66 - | ^^^^^^^^^^ The function modifies a local variable here
65 + | ^^^^^^^^^^ This modifies a local variable
66 15 | console.log(nextParams);
67 16 | },
68 17 | [params]
70 -
71 -
69 ```
70
71
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.context-variable-only-chained-assign.expect.md
+3 -5
@@ -29,20 +29,18 @@ export const FIXTURE_ENTRYPOINT = {
29
30 ```
31 Found 1 error:
32 -Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
32 +Error: Cannot reassign a variable after render completes
33
34 -Variable `x` cannot be reassigned after render.
34 +Reassigning variable `x` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
35
36 error.context-variable-only-chained-assign.ts:10:19
37 8 | };
38 9 | const fn2 = () => {
39 > 10 | const copy2 = (x = 4);
40 - | ^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
40 + | ^ Cannot reassign variable after render completes
41 11 | return [invoke(fn1), copy2, identity(copy2)];
42 12 | };
43 13 | return invoke(fn2);
44 -
45 -
44 ```
45
46
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.declare-reassign-variable-in-function-declaration.expect.md
+3 -5
@@ -18,20 +18,18 @@ function Component() {
18
19 ```
20 Found 1 error:
21 -Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
21 +Error: Cannot reassign a variable after render completes
22
23 -Variable `x` cannot be reassigned after render.
23 +Reassigning variable `x` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
24
25 error.declare-reassign-variable-in-function-declaration.ts:4:4
26 2 | let x = null;
27 3 | function foo() {
28 > 4 | x = 9;
29 - | ^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
29 + | ^ Cannot reassign variable after render completes
30 5 | }
31 6 | const y = bar(foo);
32 7 | return <Child y={y} />;
33 -
34 -
33 ```
34
35
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.function-expression-references-variable-its-assigned-to.expect.md
+3 -5
@@ -16,20 +16,18 @@ function Component() {
16
17 ```
18 Found 1 error:
19 -Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
19 +Error: Cannot reassign a variable after render completes
20
21 -Variable `callback` cannot be reassigned after render.
21 +Reassigning variable `callback` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
22
23 error.function-expression-references-variable-its-assigned-to.ts:3:4
24 1 | function Component() {
25 2 | let callback = () => {
26 > 3 | callback = null;
27 - | ^^^^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
27 + | ^^^^^^^^ Cannot reassign variable after render completes
28 4 | };
29 5 | return <div onClick={callback} />;
30 6 | }
31 -
32 -
31 ```
32
33
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-ReactUseMemo-async-callback.expect.md
+3 -3
@@ -18,6 +18,8 @@ function component(a, b) {
18 Found 1 error:
19 Error: useMemo callbacks may not be async or generator functions
20
21 +useMemo() callbacks are called once and must synchronously return a value
22 +
23 error.invalid-ReactUseMemo-async-callback.ts:2:24
24 1 | function component(a, b) {
25 > 2 | let x = React.useMemo(async () => {
@@ -25,12 +27,10 @@ error.invalid-ReactUseMemo-async-callback.ts:2:24
27 > 3 | await a;
28 | ^^^^^^^^^^^^
29 > 4 | }, []);
28 - | ^^^^ useMemo callbacks may not be async or generator functions
30 + | ^^^^ Async and generator functions are not supported
31 5 | return x;
32 6 | }
33 7 |
32 -
33 -
34 ```
35
36
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-conditional-setState-in-useMemo.expect.md
+7 -7
@@ -23,30 +23,30 @@ function Component({item, cond}) {
23
24 ```
25 Found 2 errors:
26 -Error: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
26 +Error: Calling setState from useMemo may trigger an infinite loop
27 +
28 +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)
29
30 error.invalid-conditional-setState-in-useMemo.ts:7:6
31 5 | useMemo(() => {
32 6 | if (cond) {
33 > 7 | setPrevItem(item);
32 - | ^^^^^^^^^^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
34 + | ^^^^^^^^^^^ Found setState() within useMemo()
35 8 | setState(0);
36 9 | }
37 10 | }, [cond, key, init]);
38 +Error: Calling setState from useMemo may trigger an infinite loop
39
37 -
38 -Error: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
40 +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)
41
42 error.invalid-conditional-setState-in-useMemo.ts:8:6
43 6 | if (cond) {
44 7 | setPrevItem(item);
45 > 8 | setState(0);
44 - | ^^^^^^^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
46 + | ^^^^^^^^ Found setState() within useMemo()
47 9 | }
48 10 | }, [cond, key, init]);
49 11 |
48 -
49 -
50 ```
51
52
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-hook-function-argument-mutates-local-variable.expect.md
+6 -9
@@ -17,8 +17,10 @@ function useFoo() {
17 ## Error
18
19 ```
20 -Found 2 errors:
21 -Error: This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
20 +Found 1 error:
21 +Error: Cannot modify local variables after render completes
22 +
23 +This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
24
25 error.invalid-hook-function-argument-mutates-local-variable.ts:5:10
26 3 | function useFoo() {
@@ -28,23 +30,18 @@ error.invalid-hook-function-argument-mutates-local-variable.ts:5:10
30 > 6 | cache.set('key', 'value');
31 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
32 > 7 | });
31 - | ^^^^ This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
33 + | ^^^^ This function may (indirectly) reassign or modify local variables after render
34 8 | }
35 9 |
36
35 -
36 -Error: The function modifies a local variable here
37 -
37 error.invalid-hook-function-argument-mutates-local-variable.ts:6:4
38 4 | const cache = new Map();
39 5 | useHook(() => {
40 > 6 | cache.set('key', 'value');
42 - | ^^^^^ The function modifies a local variable here
41 + | ^^^^^ This modifies a local variable
42 7 | });
43 8 | }
44 9 |
46 -
47 -
45 ```
46
47
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-nested-function-reassign-local-variable-in-effect.expect.md
+3 -5
@@ -47,20 +47,18 @@ function Component() {
47
48 ```
49 Found 1 error:
50 -Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
50 +Error: Cannot reassign a variable after render completes
51
52 -Variable `local` cannot be reassigned after render.
52 +Reassigning variable `local` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
53
54 error.invalid-nested-function-reassign-local-variable-in-effect.ts:7:6
55 5 | // Create the reassignment function inside another function, then return it
56 6 | const reassignLocal = newValue => {
57 > 7 | local = newValue;
58 - | ^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
58 + | ^^^^^ Cannot reassign variable after render completes
59 8 | };
60 9 | return reassignLocal;
61 10 | };
62 -
63 -
62 ```
63
64
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-pass-mutable-function-as-prop.expect.md
+6 -9
@@ -17,30 +17,27 @@ function Component() {
17 ## Error
18
19 ```
20 -Found 2 errors:
21 -Error: This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
20 +Found 1 error:
21 +Error: Cannot modify local variables after render completes
22 +
23 +This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
24
25 error.invalid-pass-mutable-function-as-prop.ts:7:18
26 5 | cache.set('key', 'value');
27 6 | };
28 > 7 | return <Foo fn={fn} />;
27 - | ^^ This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
29 + | ^^ This function may (indirectly) reassign or modify local variables after render
30 8 | }
31 9 |
32
31 -
32 -Error: The function modifies a local variable here
33 -
33 error.invalid-pass-mutable-function-as-prop.ts:5:4
34 3 | const cache = new Map();
35 4 | const fn = () => {
36 > 5 | cache.set('key', 'value');
38 - | ^^^^^ The function modifies a local variable here
37 + | ^^^^^ This modifies a local variable
38 6 | };
39 7 | return <Foo fn={fn} />;
40 8 | }
42 -
43 -
41 ```
42
43
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-reassign-local-in-hook-return-value.expect.md
+3 -5
@@ -16,20 +16,18 @@ function useFoo() {
16
17 ```
18 Found 1 error:
19 -Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
19 +Error: Cannot reassign a variable after render completes
20
21 -Variable `x` cannot be reassigned after render.
21 +Reassigning variable `x` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
22
23 error.invalid-reassign-local-in-hook-return-value.ts:4:4
24 2 | let x = 0;
25 3 | return value => {
26 > 4 | x = value;
27 - | ^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
27 + | ^ Cannot reassign variable after render completes
28 5 | };
29 6 | }
30 7 |
31 -
32 -
31 ```
32
33
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-reassign-local-variable-in-effect.expect.md
+3 -5
@@ -48,20 +48,18 @@ function Component() {
48
49 ```
50 Found 1 error:
51 -Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
51 +Error: Cannot reassign a variable after render completes
52
53 -Variable `local` cannot be reassigned after render.
53 +Reassigning variable `local` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
54
55 error.invalid-reassign-local-variable-in-effect.ts:7:4
56 5 |
57 6 | const reassignLocal = newValue => {
58 > 7 | local = newValue;
59 - | ^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
59 + | ^^^^^ Cannot reassign variable after render completes
60 8 | };
61 9 |
62 10 | const onMount = newValue => {
63 -
64 -
63 ```
64
65
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-reassign-local-variable-in-hook-argument.expect.md
+3 -5
@@ -49,20 +49,18 @@ function Component() {
49
50 ```
51 Found 1 error:
52 -Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
52 +Error: Cannot reassign a variable after render completes
53
54 -Variable `local` cannot be reassigned after render.
54 +Reassigning variable `local` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
55
56 error.invalid-reassign-local-variable-in-hook-argument.ts:8:4
57 6 |
58 7 | const reassignLocal = newValue => {
59 > 8 | local = newValue;
60 - | ^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
60 + | ^^^^^ Cannot reassign variable after render completes
61 9 | };
62 10 |
63 11 | const callback = newValue => {
64 -
65 -
64 ```
65
66
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-reassign-local-variable-in-jsx-callback.expect.md
+3 -5
@@ -42,20 +42,18 @@ function Component() {
42
43 ```
44 Found 1 error:
45 -Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
45 +Error: Cannot reassign a variable after render completes
46
47 -Variable `local` cannot be reassigned after render.
47 +Reassigning variable `local` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
48
49 error.invalid-reassign-local-variable-in-jsx-callback.ts:5:4
50 3 |
51 4 | const reassignLocal = newValue => {
52 > 5 | local = newValue;
53 - | ^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
53 + | ^^^^^ Cannot reassign variable after render completes
54 6 | };
55 7 |
56 8 | const onClick = newValue => {
57 -
58 -
57 ```
58
59
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-return-mutable-function-from-hook.expect.md
+6 -9
@@ -19,8 +19,10 @@ function useFoo() {
19 ## Error
20
21 ```
22 -Found 2 errors:
23 -Error: This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
22 +Found 1 error:
23 +Error: Cannot modify local variables after render completes
24 +
25 +This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
26
27 error.invalid-return-mutable-function-from-hook.ts:7:9
28 5 | useHook(); // for inference to kick in
@@ -30,23 +32,18 @@ error.invalid-return-mutable-function-from-hook.ts:7:9
32 > 8 | cache.set('key', 'value');
33 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34 > 9 | };
33 - | ^^^^ This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
35 + | ^^^^ This function may (indirectly) reassign or modify local variables after render
36 10 | }
37 11 |
38
37 -
38 -Error: The function modifies a local variable here
39 -
39 error.invalid-return-mutable-function-from-hook.ts:8:4
40 6 | const cache = new Map();
41 7 | return () => {
42 > 8 | cache.set('key', 'value');
44 - | ^^^^^ The function modifies a local variable here
43 + | ^^^^^ This modifies a local variable
44 9 | };
45 10 | }
46 11 |
48 -
49 -
47 ```
48
49
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-setState-in-useMemo-indirect-useCallback.expect.md
+4 -4
@@ -27,18 +27,18 @@ function useKeyedState({key, init}) {
27
28 ```
29 Found 1 error:
30 -Error: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
30 +Error: Calling setState from useMemo may trigger an infinite loop
31 +
32 +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)
33
34 error.invalid-setState-in-useMemo-indirect-useCallback.ts:13:4
35 11 |
36 12 | useMemo(() => {
37 > 13 | fn();
36 - | ^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
38 + | ^^ Found setState() within useMemo()
39 14 | }, [key, init]);
40 15 |
41 16 | return state;
40 -
41 -
42 ```
43
44
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-setState-in-useMemo.expect.md
+7 -7
@@ -21,30 +21,30 @@ function useKeyedState({key, init}) {
21
22 ```
23 Found 2 errors:
24 -Error: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
24 +Error: Calling setState from useMemo may trigger an infinite loop
25 +
26 +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)
27
28 error.invalid-setState-in-useMemo.ts:6:4
29 4 |
30 5 | useMemo(() => {
31 > 6 | setPrevKey(key);
30 - | ^^^^^^^^^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
32 + | ^^^^^^^^^^ Found setState() within useMemo()
33 7 | setState(init);
34 8 | }, [key, init]);
35 9 |
36 +Error: Calling setState from useMemo may trigger an infinite loop
37
35 -
36 -Error: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
38 +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)
39
40 error.invalid-setState-in-useMemo.ts:7:4
41 5 | useMemo(() => {
42 6 | setPrevKey(key);
43 > 7 | setState(init);
42 - | ^^^^^^^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
44 + | ^^^^^^^^ Found setState() within useMemo()
45 8 | }, [key, init]);
46 9 |
47 10 | return state;
46 -
47 -
48 ```
49
50
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-uncalled-function-capturing-mutable-values-memoizes-with-captures-values.expect.md
+6 -9
@@ -47,8 +47,10 @@ hook useMemoMap<TInput: interface {}, TOutput>(
47 ## Error
48
49 ```
50 -Found 2 errors:
51 -Error: This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
50 +Found 1 error:
51 +Error: Cannot modify local variables after render completes
52 +
53 +This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
54
55 undefined:21:9
56 19 | map: TInput => TOutput
@@ -86,23 +88,18 @@ undefined:21:9
88 > 36 | };
89 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
90 > 37 | }, [map]);
89 - | ^^^^^^^^^^^^ This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
91 + | ^^^^^^^^^^^^ This function may (indirectly) reassign or modify local variables after render
92 38 | }
93 39 |
94
93 -
94 -Error: The function modifies a local variable here
95 -
95 undefined:33:8
96 31 | if (output == null) {
97 32 | output = map(input);
98 > 33 | cache.set(input, output);
100 - | ^^^^^ The function modifies a local variable here
99 + | ^^^^^ This modifies a local variable
100 34 | }
101 35 | return output;
102 36 | };
104 -
105 -
103 ```
104
105
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-unconditional-set-state-in-render.expect.md
+7 -7
@@ -20,30 +20,30 @@ function Component(props) {
20
21 ```
22 Found 2 errors:
23 -Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
23 +Error: Calling setState during render may trigger an infinite loop
24 +
25 +Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)
26
27 error.invalid-unconditional-set-state-in-render.ts:6:2
28 4 | const aliased = setX;
29 5 |
30 > 6 | setX(1);
29 - | ^^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
31 + | ^^^^ Found setState() within useMemo()
32 7 | aliased(2);
33 8 |
34 9 | return x;
35 +Error: Calling setState during render may trigger an infinite loop
36
34 -
35 -Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
37 +Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)
38
39 error.invalid-unconditional-set-state-in-render.ts:7:2
40 5 |
41 6 | setX(1);
42 > 7 | aliased(2);
41 - | ^^^^^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
43 + | ^^^^^^^ Found setState() within useMemo()
44 8 |
45 9 | return x;
46 10 | }
45 -
46 -
47 ```
48
49
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-useMemo-async-callback.expect.md
+3 -3
@@ -18,6 +18,8 @@ function component(a, b) {
18 Found 1 error:
19 Error: useMemo callbacks may not be async or generator functions
20
21 +useMemo() callbacks are called once and must synchronously return a value
22 +
23 error.invalid-useMemo-async-callback.ts:2:18
24 1 | function component(a, b) {
25 > 2 | let x = useMemo(async () => {
@@ -25,12 +27,10 @@ error.invalid-useMemo-async-callback.ts:2:18
27 > 3 | await a;
28 | ^^^^^^^^^^^^
29 > 4 | }, []);
28 - | ^^^^ useMemo callbacks may not be async or generator functions
30 + | ^^^^ Async and generator functions are not supported
31 5 | return x;
32 6 | }
33 7 |
32 -
33 -
34 ```
35
36
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-useMemo-callback-args.expect.md
+4 -4
@@ -14,17 +14,17 @@ function component(a, b) {
14
15 ```
16 Found 1 error:
17 -Error: useMemo callbacks may not accept any arguments
17 +Error: useMemo() callbacks may not accept parameters
18 +
19 +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.
20
21 error.invalid-useMemo-callback-args.ts:2:18
22 1 | function component(a, b) {
23 > 2 | let x = useMemo(c => a, []);
22 - | ^^^^^^ useMemo callbacks may not accept any arguments
24 + | ^
25 3 | return x;
26 4 | }
27 5 |
26 -
27 -
28 ```
29
30
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.mutable-range-shared-inner-outer-function.expect.md
+3 -5
@@ -33,20 +33,18 @@ export const FIXTURE_ENTRYPOINT = {
33
34 ```
35 Found 1 error:
36 -Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
36 +Error: Cannot reassign a variable after render completes
37
38 -Variable `a` cannot be reassigned after render.
38 +Reassigning variable `a` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
39
40 error.mutable-range-shared-inner-outer-function.ts:8:6
41 6 | const f = () => {
42 7 | if (cond) {
43 > 8 | a = {};
44 - | ^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
44 + | ^ Cannot reassign variable after render completes
45 9 | b = [];
46 10 | } else {
47 11 | a = {};
48 -
49 -
48 ```
49
50
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-function-expression-references-later-variable-declaration.expect.md
+3 -5
@@ -18,20 +18,18 @@ function Component() {
18
19 ```
20 Found 1 error:
21 -Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
21 +Error: Cannot reassign a variable after render completes
22
23 -Variable `onClick` cannot be reassigned after render.
23 +Reassigning variable `onClick` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
24
25 error.todo-function-expression-references-later-variable-declaration.ts:3:4
26 1 | function Component() {
27 2 | let callback = () => {
28 > 3 | onClick = () => {};
29 - | ^^^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
29 + | ^^^^^^^ Cannot reassign variable after render completes
30 4 | };
31 5 | let onClick;
32 6 |
33 -
34 -
33 ```
34
35
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-after-loop-break.expect.md
+4 -4
@@ -23,18 +23,18 @@ function Component(props) {
23
24 ```
25 Found 1 error:
26 -Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
26 +Error: Calling setState during render may trigger an infinite loop
27 +
28 +Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)
29
30 error.unconditional-set-state-in-render-after-loop-break.ts:11:2
31 9 | }
32 10 | }
33 > 11 | setState(true);
32 - | ^^^^^^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
34 + | ^^^^^^^^ Found setState() within useMemo()
35 12 | return state;
36 13 | }
37 14 |
36 -
37 -
38 ```
39
40
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-after-loop.expect.md
+4 -4
@@ -18,18 +18,18 @@ function Component(props) {
18
19 ```
20 Found 1 error:
21 -Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
21 +Error: Calling setState during render may trigger an infinite loop
22 +
23 +Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)
24
25 error.unconditional-set-state-in-render-after-loop.ts:6:2
26 4 | for (const _ of props) {
27 5 | }
28 > 6 | setState(true);
27 - | ^^^^^^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
29 + | ^^^^^^^^ Found setState() within useMemo()
30 7 | return state;
31 8 | }
32 9 |
31 -
32 -
33 ```
34
35
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-with-loop-throw.expect.md
+4 -4
@@ -23,18 +23,18 @@ function Component(props) {
23
24 ```
25 Found 1 error:
26 -Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
26 +Error: Calling setState during render may trigger an infinite loop
27 +
28 +Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)
29
30 error.unconditional-set-state-in-render-with-loop-throw.ts:11:2
31 9 | }
32 10 | }
33 > 11 | setState(true);
32 - | ^^^^^^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
34 + | ^^^^^^^^ Found setState() within useMemo()
35 12 | return state;
36 13 | }
37 14 |
36 -
37 -
38 ```
39
40
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-lambda.expect.md
+4 -4
@@ -21,18 +21,18 @@ function Component(props) {
21
22 ```
23 Found 1 error:
24 -Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
24 +Error: Calling setState during render may trigger an infinite loop
25 +
26 +Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)
27
28 error.unconditional-set-state-lambda.ts:8:2
29 6 | setX(1);
30 7 | };
31 > 8 | foo();
30 - | ^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
32 + | ^^^ Found setState() within useMemo()
33 9 |
34 10 | return [x];
35 11 | }
34 -
35 -
36 ```
37
38
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-nested-function-expressions.expect.md
+4 -4
@@ -29,18 +29,18 @@ function Component(props) {
29
30 ```
31 Found 1 error:
32 -Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
32 +Error: Calling setState during render may trigger an infinite loop
33 +
34 +Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)
35
36 error.unconditional-set-state-nested-function-expressions.ts:16:2
37 14 | bar();
38 15 | };
39 > 16 | baz();
38 - | ^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
40 + | ^^^ Found setState() within useMemo()
41 17 |
42 18 | return [x];
43 19 | }
42 -
43 -
44 ```
45
46
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.expect.md
+1 -1
@@ -65,7 +65,7 @@ function Component(props) {
65 ## Logs
66
67 ```
68 -{"kind":"CompileError","detail":{"options":{"reason":"Unexpected JSX element within a try statement. 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)","description":null,"severity":"InvalidReact","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"}}},"fnLoc":null}
68 +{"kind":"CompileError","detail":{"options":{"severity":"InvalidReact","category":"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}
69 {"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}
70 ```
71
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.expect.md
+1 -1
@@ -42,7 +42,7 @@ function Component(props) {
42 ## Logs
43
44 ```
45 -{"kind":"CompileError","detail":{"options":{"reason":"Unexpected JSX element within a try statement. 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)","description":null,"severity":"InvalidReact","loc":{"start":{"line":5,"column":9,"index":104},"end":{"line":5,"column":16,"index":111},"filename":"invalid-jsx-in-try-with-catch.ts"}}},"fnLoc":null}
45 +{"kind":"CompileError","detail":{"options":{"severity":"InvalidReact","category":"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}
46 {"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}
47 ```
48
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.expect.md
+1 -1
@@ -65,7 +65,7 @@ function _temp(s) {
65 ## Logs
66
67 ```
68 -{"kind":"CompileError","detail":{"options":{"reason":"Calling setState directly within a useEffect causes cascading renders and is not recommended. Consider alternatives to useEffect. (https://react.dev/learn/you-might-not-need-an-effect)","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":13,"column":4,"index":265},"end":{"line":13,"column":5,"index":266},"filename":"invalid-setState-in-useEffect-transitive.ts","identifierName":"g"}}},"fnLoc":null}
68 +{"kind":"CompileError","detail":{"options":{"category":"Calling setState within an effect can trigger cascading renders","description":"Calling setState directly within a useEffect causes cascading renders that can hurt performance, and is not recommended. Consider alternatives to useEffect. (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() in the top-level of an effect"}]}},"fnLoc":null}
69 {"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}
70 ```
71
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.expect.md
+1 -1
@@ -45,7 +45,7 @@ function _temp(s) {
45 ## Logs
46
47 ```
48 -{"kind":"CompileError","detail":{"options":{"reason":"Calling setState directly within a useEffect causes cascading renders and is not recommended. Consider alternatives to useEffect. (https://react.dev/learn/you-might-not-need-an-effect)","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":7,"column":4,"index":180},"end":{"line":7,"column":12,"index":188},"filename":"invalid-setState-in-useEffect.ts","identifierName":"setState"}}},"fnLoc":null}
48 +{"kind":"CompileError","detail":{"options":{"category":"Calling setState within an effect can trigger cascading renders","description":"Calling setState directly within a useEffect causes cascading renders that can hurt performance, and is not recommended. Consider alternatives to useEffect. (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() in the top-level of an effect"}]}},"fnLoc":null}
49 {"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}
50 ```
51
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-reassign-local-variable-in-jsx-callback.expect.md
+3 -5
@@ -43,20 +43,18 @@ function Component() {
43
44 ```
45 Found 1 error:
46 -Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
46 +Error: Cannot reassign a variable after render completes
47
48 -Variable `local` cannot be reassigned after render.
48 +Reassigning variable `local` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
49
50 error.invalid-reassign-local-variable-in-jsx-callback.ts:6:4
51 4 |
52 5 | const reassignLocal = newValue => {
53 > 6 | local = newValue;
54 - | ^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
54 + | ^^^^^ Cannot reassign variable after render completes
55 7 | };
56 8 |
57 9 | const onClick = newValue => {
58 -
59 -
58 ```
59
60
\ No newline at end of file