Compare commits

...

2 Commits

Author SHA1 Message Date
Joe Savona
43ae8710ca [compiler] Update diagnostics for ValidatePreservedManualMemoization
Uses the new diagnostic infrastructure for this validation, which lets us provide a more targeted message on the text that we highlight (eg "This dependency may be mutated later") separately from the overall error message.
2025-07-24 15:38:22 -07:00
Joe Savona
2283eb9183 [compiler] Improve more error messages
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.
2025-07-24 15:38:22 -07:00
74 changed files with 515 additions and 471 deletions

View File

@@ -59,7 +59,7 @@ export type CompilerDiagnosticDetail =
*/
{
kind: 'error';
loc: SourceLocation;
loc: SourceLocation | null;
message: string;
};
@@ -100,6 +100,12 @@ export class CompilerDiagnostic {
this.options = options;
}
static create(
options: Omit<CompilerDiagnosticOptions, 'details'>,
): CompilerDiagnostic {
return new CompilerDiagnostic({...options, details: []});
}
get category(): CompilerDiagnosticOptions['category'] {
return this.options.category;
}
@@ -113,6 +119,11 @@ export class CompilerDiagnostic {
return this.options.suggestions;
}
withDetail(detail: CompilerDiagnosticDetail): CompilerDiagnostic {
this.options.details.push(detail);
return this;
}
primaryLocation(): SourceLocation | null {
return this.options.details.filter(d => d.kind === 'error')[0]?.loc ?? null;
}
@@ -127,7 +138,7 @@ export class CompilerDiagnostic {
switch (detail.kind) {
case 'error': {
const loc = detail.loc;
if (typeof loc === 'symbol') {
if (loc == null || typeof loc === 'symbol') {
continue;
}
let codeFrame: string;

View File

@@ -9,6 +9,7 @@ import {NodePath, Scope} from '@babel/traverse';
import * as t from '@babel/types';
import invariant from 'invariant';
import {
CompilerDiagnostic,
CompilerError,
CompilerSuggestionOperation,
ErrorSeverity,
@@ -104,12 +105,18 @@ export function lower(
if (param.isIdentifier()) {
const binding = builder.resolveIdentifier(param);
if (binding.kind !== 'Identifier') {
builder.errors.push({
reason: `(BuildHIR::lower) Could not find binding for param \`${param.node.name}\``,
severity: ErrorSeverity.Invariant,
loc: param.node.loc ?? null,
suggestions: null,
});
builder.errors.pushDiagnostic(
CompilerDiagnostic.create({
category: 'Could not find binding',
description: `[BuildHIR] Could not find binding for param \`${param.node.name}\``,
severity: ErrorSeverity.Invariant,
suggestions: null,
}).withDetail({
kind: 'error',
loc: param.node.loc ?? null,
message: 'Could not find binding',
}),
);
return;
}
const place: Place = {
@@ -163,12 +170,18 @@ export function lower(
'Assignment',
);
} else {
builder.errors.push({
reason: `(BuildHIR::lower) Handle ${param.node.type} params`,
severity: ErrorSeverity.Todo,
loc: param.node.loc ?? null,
suggestions: null,
});
builder.errors.pushDiagnostic(
CompilerDiagnostic.create({
category: `Handle ${param.node.type} parameters`,
description: `[BuildHIR] Add support for ${param.node.type} parameters`,
severity: ErrorSeverity.Todo,
suggestions: null,
}).withDetail({
kind: 'error',
loc: param.node.loc ?? null,
message: 'Unsupported parameter type',
}),
);
}
});
@@ -188,13 +201,18 @@ export function lower(
lowerStatement(builder, body);
directives = body.get('directives').map(d => d.node.value.value);
} else {
builder.errors.push({
severity: ErrorSeverity.InvalidJS,
reason: `Unexpected function body kind`,
description: `Expected function body to be an expression or a block statement, got \`${body.type}\``,
loc: body.node.loc ?? null,
suggestions: null,
});
builder.errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.InvalidJS,
category: `Unexpected function body kind`,
description: `Expected function body to be an expression or a block statement, got \`${body.type}\``,
suggestions: null,
}).withDetail({
kind: 'error',
loc: body.node.loc ?? null,
message: 'Expected a block statement or expression',
}),
);
}
if (builder.errors.hasErrors()) {

View File

@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {CompilerError, Effect} from '..';
import {CompilerDiagnostic, CompilerError, Effect, ErrorSeverity} from '..';
import {HIRFunction, IdentifierId, Place} from '../HIR';
import {
eachInstructionLValue,
@@ -28,16 +28,19 @@ export function validateLocalsNotReassignedAfterRender(fn: HIRFunction): void {
false,
);
if (reassignment !== null) {
CompilerError.throwInvalidReact({
reason:
'Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead',
description:
reassignment.identifier.name !== null &&
reassignment.identifier.name.kind === 'named'
? `Variable \`${reassignment.identifier.name.value}\` cannot be reassigned after render`
: '',
loc: reassignment.loc,
});
const errors = new CompilerError();
errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.InvalidReact,
category: 'Cannot reassign a variable after render completes',
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`,
}).withDetail({
kind: 'error',
loc: reassignment.loc,
message: 'Cannot reassign variable after render completes',
}),
);
throw errors;
}
}

View File

@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {CompilerError, Effect, ErrorSeverity} from '..';
import {CompilerDiagnostic, CompilerError, Effect, ErrorSeverity} from '..';
import {
FunctionEffect,
HIRFunction,
@@ -57,16 +57,24 @@ export function validateNoFreezingKnownMutableFunctions(
if (operand.effect === Effect.Freeze) {
const effect = contextMutationEffects.get(operand.identifier.id);
if (effect != null) {
errors.push({
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`,
loc: operand.loc,
severity: ErrorSeverity.InvalidReact,
});
errors.push({
reason: `The function modifies a local variable here`,
loc: effect.loc,
severity: ErrorSeverity.InvalidReact,
});
errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.InvalidReact,
category: 'Cannot modify local variables after render completes',
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`,
})
.withDetail({
kind: 'error',
loc: operand.loc,
message:
'This function may (indirectly) reassign or modify local variables after render',
})
.withDetail({
kind: 'error',
loc: effect.loc,
message: 'This modifies a local variable',
}),
);
}
}
}

View File

@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {CompilerError, ErrorSeverity} from '..';
import {CompilerDiagnostic, CompilerError, ErrorSeverity} from '..';
import {HIRFunction} from '../HIR';
import {getFunctionCallSignature} from '../Inference/InferReferenceEffects';
import {Result} from '../Utils/Result';
@@ -34,17 +34,22 @@ export function validateNoImpureFunctionsInRender(
callee.identifier.type,
);
if (signature != null && signature.impure === true) {
errors.push({
reason:
'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)',
description:
signature.canonicalName != null
? `\`${signature.canonicalName}\` is an impure function whose results may change on every call`
: null,
severity: ErrorSeverity.InvalidReact,
loc: callee.loc,
suggestions: null,
});
errors.pushDiagnostic(
CompilerDiagnostic.create({
category: '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)',
severity: ErrorSeverity.InvalidReact,
suggestions: null,
}).withDetail({
kind: 'error',
loc: callee.loc,
message: 'Cannot call impure function',
}),
);
}
}
}

View File

@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {CompilerError, ErrorSeverity} from '..';
import {CompilerDiagnostic, CompilerError, ErrorSeverity} from '..';
import {BlockId, HIRFunction} from '../HIR';
import {Result} from '../Utils/Result';
import {retainWhere} from '../Utils/utils';
@@ -34,11 +34,17 @@ export function validateNoJSXInTryStatement(
switch (value.kind) {
case 'JsxExpression':
case 'JsxFragment': {
errors.push({
severity: ErrorSeverity.InvalidReact,
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)`,
loc: value.loc,
});
errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.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)`,
}).withDetail({
kind: 'error',
loc: value.loc,
message: 'Avoid constructing JSX within try/catch',
}),
);
break;
}
}

View File

@@ -5,7 +5,11 @@
* LICENSE file in the root directory of this source tree.
*/
import {CompilerError, ErrorSeverity} from '../CompilerError';
import {
CompilerDiagnostic,
CompilerError,
ErrorSeverity,
} from '../CompilerError';
import {
HIRFunction,
IdentifierId,
@@ -90,14 +94,21 @@ export function validateNoSetStateInEffects(
if (arg !== undefined && arg.kind === 'Identifier') {
const setState = setStateFunctions.get(arg.identifier.id);
if (setState !== undefined) {
errors.push({
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: ErrorSeverity.InvalidReact,
loc: setState.loc,
suggestions: null,
});
errors.pushDiagnostic(
CompilerDiagnostic.create({
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: ErrorSeverity.InvalidReact,
suggestions: null,
}).withDetail({
kind: 'error',
loc: setState.loc,
message:
'Avoid calling setState() in the top-level of an effect',
}),
);
}
}
}

View File

@@ -5,7 +5,11 @@
* LICENSE file in the root directory of this source tree.
*/
import {CompilerError, ErrorSeverity} from '../CompilerError';
import {
CompilerDiagnostic,
CompilerError,
ErrorSeverity,
} from '../CompilerError';
import {HIRFunction, IdentifierId, isSetStateType} from '../HIR';
import {computeUnconditionalBlocks} from '../HIR/ComputeUnconditionalBlocks';
import {eachInstructionValueOperand} from '../HIR/visitors';
@@ -122,23 +126,35 @@ function validateNoSetStateInRenderImpl(
unconditionalSetStateFunctions.has(callee.identifier.id)
) {
if (activeManualMemoId !== null) {
errors.push({
reason:
'Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)',
description: null,
severity: ErrorSeverity.InvalidReact,
loc: callee.loc,
suggestions: null,
});
errors.pushDiagnostic(
CompilerDiagnostic.create({
category:
'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({
kind: 'error',
loc: callee.loc,
message: 'Found setState() within useMemo()',
}),
);
} else if (unconditionalBlocks.has(block.id)) {
errors.push({
reason:
'This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)',
description: null,
severity: ErrorSeverity.InvalidReact,
loc: callee.loc,
suggestions: null,
});
errors.pushDiagnostic(
CompilerDiagnostic.create({
category:
'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({
kind: 'error',
loc: callee.loc,
message: 'Found setState() within useMemo()',
}),
);
}
}
break;

View File

@@ -5,7 +5,11 @@
* LICENSE file in the root directory of this source tree.
*/
import {CompilerError, ErrorSeverity} from '../CompilerError';
import {
CompilerDiagnostic,
CompilerError,
ErrorSeverity,
} from '../CompilerError';
import {
DeclarationId,
Effect,
@@ -275,27 +279,37 @@ function validateInferredDep(
errorDiagnostic = merge(errorDiagnostic ?? compareResult, compareResult);
}
}
errorState.push({
severity: ErrorSeverity.CannotPreserveMemoization,
reason:
'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',
description:
DEBUG ||
// If the dependency is a named variable then we can report it. Otherwise only print in debug mode
(dep.identifier.name != null && dep.identifier.name.kind === 'named')
? `The inferred dependency was \`${prettyPrintScopeDependency(
dep,
)}\`, but the source dependencies were [${validDepsInMemoBlock
.map(dep => printManualMemoDependency(dep, true))
.join(', ')}]. ${
errorDiagnostic
? getCompareDependencyResultDescription(errorDiagnostic)
: 'Inferred dependency not present in source'
}`
: null,
loc: memoLocation,
suggestions: null,
});
errorState.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.CannotPreserveMemoization,
category:
'Compilation skipped because 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. ',
DEBUG ||
// If the dependency is a named variable then we can report it. Otherwise only print in debug mode
(dep.identifier.name != null && dep.identifier.name.kind === 'named')
? `The inferred dependency was \`${prettyPrintScopeDependency(
dep,
)}\`, but the source dependencies were [${validDepsInMemoBlock
.map(dep => printManualMemoDependency(dep, true))
.join(', ')}]. ${
errorDiagnostic
? getCompareDependencyResultDescription(errorDiagnostic)
: 'Inferred dependency not present in source'
}.`
: '',
]
.join('')
.trim(),
suggestions: null,
}).withDetail({
kind: 'error',
loc: memoLocation,
message: 'Could not preserve existing manual memoization',
}),
);
}
class Visitor extends ReactiveFunctionVisitor<VisitorState> {
@@ -519,14 +533,21 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
!this.scopes.has(identifier.scope.id) &&
!this.prunedScopes.has(identifier.scope.id)
) {
state.errors.push({
reason:
'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',
description: null,
severity: ErrorSeverity.CannotPreserveMemoization,
loc,
suggestions: null,
});
state.errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.CannotPreserveMemoization,
category:
'Compilation skipped because 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.',
].join(''),
}).withDetail({
kind: 'error',
loc,
message: 'This dependency may be modified later',
}),
);
}
}
}
@@ -560,16 +581,25 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
for (const identifier of decls) {
if (isUnmemoized(identifier, this.scopes)) {
state.errors.push({
reason:
'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.',
description: DEBUG
? `${printIdentifier(identifier)} was not memoized`
: null,
severity: ErrorSeverity.CannotPreserveMemoization,
loc,
suggestions: null,
});
state.errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.CannotPreserveMemoization,
category:
'Compilation skipped because 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. ',
DEBUG
? `${printIdentifier(identifier)} was not memoized.`
: '',
]
.join('')
.trim(),
}).withDetail({
kind: 'error',
loc,
message: 'Could not preserve existing memoization',
}),
);
}
}
}

View File

@@ -5,7 +5,11 @@
* LICENSE file in the root directory of this source tree.
*/
import {CompilerError, ErrorSeverity} from '..';
import {
CompilerDiagnostic,
CompilerError,
ErrorSeverity,
} from '../CompilerError';
import {FunctionExpression, HIRFunction, IdentifierId} from '../HIR';
import {Result} from '../Utils/Result';
@@ -63,24 +67,41 @@ export function validateUseMemo(fn: HIRFunction): Result<void, CompilerError> {
}
if (body.loweredFunc.func.params.length > 0) {
errors.push({
severity: ErrorSeverity.InvalidReact,
reason: 'useMemo callbacks may not accept any arguments',
description: null,
loc: body.loc,
suggestions: null,
});
const firstParam = body.loweredFunc.func.params[0];
const loc =
firstParam.kind === 'Identifier'
? firstParam.loc
: firstParam.place.loc;
errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.InvalidReact,
category: '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.',
suggestions: null,
}).withDetail({
kind: 'error',
loc,
message: '',
}),
);
}
if (body.loweredFunc.func.async || body.loweredFunc.func.generator) {
errors.push({
severity: ErrorSeverity.InvalidReact,
reason:
'useMemo callbacks may not be async or generator functions',
description: null,
loc: body.loc,
suggestions: null,
});
errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.InvalidReact,
category:
'useMemo callbacks may not be async or generator functions',
description:
'useMemo() callbacks are called once and must synchronously return a value',
suggestions: null,
}).withDetail({
kind: 'error',
loc: body.loc,
message: 'Async and generator functions are not supported',
}),
);
}
break;

View File

@@ -36,8 +36,10 @@ function Component() {
## Error
```
Found 2 errors:
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
Found 1 error:
Error: Cannot modify local variables after render completes
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
error.bug-old-inference-false-positive-ref-validation-in-use-effect.ts:20:12
18 | );
@@ -51,24 +53,19 @@ error.bug-old-inference-false-positive-ref-validation-in-use-effect.ts:20:12
> 23 | }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 24 | }, [update]);
| ^^^^ 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
| ^^^^ This function may (indirectly) reassign or modify local variables after render
25 |
26 | return 'ok';
27 | }
Error: The function modifies a local variable here
error.bug-old-inference-false-positive-ref-validation-in-use-effect.ts:14:6
12 | ...partialParams,
13 | };
> 14 | nextParams.param = 'value';
| ^^^^^^^^^^ The function modifies a local variable here
| ^^^^^^^^^^ This modifies a local variable
15 | console.log(nextParams);
16 | },
17 | [params]
```

View File

@@ -29,20 +29,18 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
Error: Cannot reassign a variable after render completes
Variable `x` cannot be reassigned after render.
Reassigning variable `x` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
error.context-variable-only-chained-assign.ts:10:19
8 | };
9 | const fn2 = () => {
> 10 | const copy2 = (x = 4);
| ^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
| ^ Cannot reassign variable after render completes
11 | return [invoke(fn1), copy2, identity(copy2)];
12 | };
13 | return invoke(fn2);
```

View File

@@ -18,20 +18,18 @@ function Component() {
```
Found 1 error:
Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
Error: Cannot reassign a variable after render completes
Variable `x` cannot be reassigned after render.
Reassigning variable `x` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
error.declare-reassign-variable-in-function-declaration.ts:4:4
2 | let x = null;
3 | function foo() {
> 4 | x = 9;
| ^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
| ^ Cannot reassign variable after render completes
5 | }
6 | const y = bar(foo);
7 | return <Child y={y} />;
```

View File

@@ -16,20 +16,18 @@ function Component() {
```
Found 1 error:
Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
Error: Cannot reassign a variable after render completes
Variable `callback` cannot be reassigned after render.
Reassigning variable `callback` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
error.function-expression-references-variable-its-assigned-to.ts:3:4
1 | function Component() {
2 | let callback = () => {
> 3 | callback = null;
| ^^^^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
| ^^^^^^^^ Cannot reassign variable after render completes
4 | };
5 | return <div onClick={callback} />;
6 | }
```

View File

@@ -25,9 +25,9 @@ function Component(props) {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `props.items`, but the source dependencies were [props?.items, props.cond]. Inferred different dependency than source.
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 `props.items`, but the source dependencies were [props?.items, props.cond]. Inferred different dependency than source.
error.hoist-optional-member-expression-with-conditional-optional.ts:4:23
2 | import {ValidateMemoization} from 'shared-runtime';
@@ -47,12 +47,10 @@ error.hoist-optional-member-expression-with-conditional-optional.ts:4:23
> 10 | return x;
| ^^^^^^^^^^^^^^^^^
> 11 | }, [props?.items, props.cond]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
12 | return (
13 | <ValidateMemoization inputs={[props?.items, props.cond]} output={data} />
14 | );
```

View File

@@ -25,9 +25,9 @@ function Component(props) {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `props.items`, but the source dependencies were [props?.items, props.cond]. Inferred different dependency than source.
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 `props.items`, but the source dependencies were [props?.items, props.cond]. Inferred different dependency than source.
error.hoist-optional-member-expression-with-conditional.ts:4:23
2 | import {ValidateMemoization} from 'shared-runtime';
@@ -47,12 +47,10 @@ error.hoist-optional-member-expression-with-conditional.ts:4:23
> 10 | return x;
| ^^^^^^^^^^^^^^^^^
> 11 | }, [props?.items, props.cond]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
12 | return (
13 | <ValidateMemoization inputs={[props?.items, props.cond]} output={data} />
14 | );
```

View File

@@ -18,6 +18,8 @@ function component(a, b) {
Found 1 error:
Error: useMemo callbacks may not be async or generator functions
useMemo() callbacks are called once and must synchronously return a value
error.invalid-ReactUseMemo-async-callback.ts:2:24
1 | function component(a, b) {
> 2 | let x = React.useMemo(async () => {
@@ -25,12 +27,10 @@ error.invalid-ReactUseMemo-async-callback.ts:2:24
> 3 | await a;
| ^^^^^^^^^^^^
> 4 | }, []);
| ^^^^ useMemo callbacks may not be async or generator functions
| ^^^^ Async and generator functions are not supported
5 | return x;
6 | }
7 |
```

View File

@@ -23,30 +23,30 @@ function Component({item, cond}) {
```
Found 2 errors:
Error: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
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)
error.invalid-conditional-setState-in-useMemo.ts:7:6
5 | useMemo(() => {
6 | if (cond) {
> 7 | setPrevItem(item);
| ^^^^^^^^^^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
| ^^^^^^^^^^^ Found setState() within useMemo()
8 | setState(0);
9 | }
10 | }, [cond, key, init]);
Error: Calling setState from useMemo may trigger an infinite loop
Error: Calling setState from useMemo may trigger an infinite loop. (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) {
7 | setPrevItem(item);
> 8 | setState(0);
| ^^^^^^^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
| ^^^^^^^^ Found setState() within useMemo()
9 | }
10 | }, [cond, key, init]);
11 |
```

View File

@@ -17,8 +17,10 @@ function useFoo() {
## Error
```
Found 2 errors:
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
Found 1 error:
Error: Cannot modify local variables after render completes
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
error.invalid-hook-function-argument-mutates-local-variable.ts:5:10
3 | function useFoo() {
@@ -28,23 +30,18 @@ error.invalid-hook-function-argument-mutates-local-variable.ts:5:10
> 6 | cache.set('key', 'value');
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 7 | });
| ^^^^ 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
| ^^^^ This function may (indirectly) reassign or modify local variables after render
8 | }
9 |
Error: The function modifies a local variable here
error.invalid-hook-function-argument-mutates-local-variable.ts:6:4
4 | const cache = new Map();
5 | useHook(() => {
> 6 | cache.set('key', 'value');
| ^^^^^ The function modifies a local variable here
| ^^^^^ This modifies a local variable
7 | });
8 | }
9 |
```

View File

@@ -47,20 +47,18 @@ function Component() {
```
Found 1 error:
Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
Error: Cannot reassign a variable after render completes
Variable `local` cannot be reassigned after render.
Reassigning variable `local` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
error.invalid-nested-function-reassign-local-variable-in-effect.ts:7:6
5 | // Create the reassignment function inside another function, then return it
6 | const reassignLocal = newValue => {
> 7 | local = newValue;
| ^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
| ^^^^^ Cannot reassign variable after render completes
8 | };
9 | return reassignLocal;
10 | };
```

View File

@@ -19,9 +19,9 @@ function Component(props) {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `props.items.edges.nodes`, but the source dependencies were [props.items?.edges?.nodes]. Inferred different dependency than source.
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 `props.items.edges.nodes`, but the source dependencies were [props.items?.edges?.nodes]. Inferred different dependency than source.
error.invalid-optional-member-expression-as-memo-dep-non-optional-in-body.ts:3:23
1 | // @validatePreserveExistingMemoizationGuarantees
@@ -35,12 +35,10 @@ error.invalid-optional-member-expression-as-memo-dep-non-optional-in-body.ts:3:2
> 6 | // deps are optional
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 7 | }, [props.items?.edges?.nodes]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
8 | return <Foo data={data} />;
9 | }
10 |
```

View File

@@ -17,30 +17,27 @@ function Component() {
## Error
```
Found 2 errors:
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
Found 1 error:
Error: Cannot modify local variables after render completes
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
error.invalid-pass-mutable-function-as-prop.ts:7:18
5 | cache.set('key', 'value');
6 | };
> 7 | return <Foo fn={fn} />;
| ^^ 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
| ^^ This function may (indirectly) reassign or modify local variables after render
8 | }
9 |
Error: The function modifies a local variable here
error.invalid-pass-mutable-function-as-prop.ts:5:4
3 | const cache = new Map();
4 | const fn = () => {
> 5 | cache.set('key', 'value');
| ^^^^^ The function modifies a local variable here
| ^^^^^ This modifies a local variable
6 | };
7 | return <Foo fn={fn} />;
8 | }
```

View File

@@ -16,20 +16,18 @@ function useFoo() {
```
Found 1 error:
Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
Error: Cannot reassign a variable after render completes
Variable `x` cannot be reassigned after render.
Reassigning variable `x` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
error.invalid-reassign-local-in-hook-return-value.ts:4:4
2 | let x = 0;
3 | return value => {
> 4 | x = value;
| ^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
| ^ Cannot reassign variable after render completes
5 | };
6 | }
7 |
```

View File

@@ -48,20 +48,18 @@ function Component() {
```
Found 1 error:
Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
Error: Cannot reassign a variable after render completes
Variable `local` cannot be reassigned after render.
Reassigning variable `local` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
error.invalid-reassign-local-variable-in-effect.ts:7:4
5 |
6 | const reassignLocal = newValue => {
> 7 | local = newValue;
| ^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
| ^^^^^ Cannot reassign variable after render completes
8 | };
9 |
10 | const onMount = newValue => {
```

View File

@@ -49,20 +49,18 @@ function Component() {
```
Found 1 error:
Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
Error: Cannot reassign a variable after render completes
Variable `local` cannot be reassigned after render.
Reassigning variable `local` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
error.invalid-reassign-local-variable-in-hook-argument.ts:8:4
6 |
7 | const reassignLocal = newValue => {
> 8 | local = newValue;
| ^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
| ^^^^^ Cannot reassign variable after render completes
9 | };
10 |
11 | const callback = newValue => {
```

View File

@@ -42,20 +42,18 @@ function Component() {
```
Found 1 error:
Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
Error: Cannot reassign a variable after render completes
Variable `local` cannot be reassigned after render.
Reassigning variable `local` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
error.invalid-reassign-local-variable-in-jsx-callback.ts:5:4
3 |
4 | const reassignLocal = newValue => {
> 5 | local = newValue;
| ^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
| ^^^^^ Cannot reassign variable after render completes
6 | };
7 |
8 | const onClick = newValue => {
```

View File

@@ -19,8 +19,10 @@ function useFoo() {
## Error
```
Found 2 errors:
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
Found 1 error:
Error: Cannot modify local variables after render completes
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
error.invalid-return-mutable-function-from-hook.ts:7:9
5 | useHook(); // for inference to kick in
@@ -30,23 +32,18 @@ error.invalid-return-mutable-function-from-hook.ts:7:9
> 8 | cache.set('key', 'value');
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 9 | };
| ^^^^ 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
| ^^^^ This function may (indirectly) reassign or modify local variables after render
10 | }
11 |
Error: The function modifies a local variable here
error.invalid-return-mutable-function-from-hook.ts:8:4
6 | const cache = new Map();
7 | return () => {
> 8 | cache.set('key', 'value');
| ^^^^^ The function modifies a local variable here
| ^^^^^ This modifies a local variable
9 | };
10 | }
11 |
```

View File

@@ -27,18 +27,18 @@ function useKeyedState({key, init}) {
```
Found 1 error:
Error: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
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)
error.invalid-setState-in-useMemo-indirect-useCallback.ts:13:4
11 |
12 | useMemo(() => {
> 13 | fn();
| ^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
| ^^ Found setState() within useMemo()
14 | }, [key, init]);
15 |
16 | return state;
```

View File

@@ -21,30 +21,30 @@ function useKeyedState({key, init}) {
```
Found 2 errors:
Error: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
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)
error.invalid-setState-in-useMemo.ts:6:4
4 |
5 | useMemo(() => {
> 6 | setPrevKey(key);
| ^^^^^^^^^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
| ^^^^^^^^^^ Found setState() within useMemo()
7 | setState(init);
8 | }, [key, init]);
9 |
Error: Calling setState from useMemo may trigger an infinite loop
Error: Calling setState from useMemo may trigger an infinite loop. (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(() => {
6 | setPrevKey(key);
> 7 | setState(init);
| ^^^^^^^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
| ^^^^^^^^ Found setState() within useMemo()
8 | }, [key, init]);
9 |
10 | return state;
```

View File

@@ -47,8 +47,10 @@ hook useMemoMap<TInput: interface {}, TOutput>(
## Error
```
Found 2 errors:
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
Found 1 error:
Error: Cannot modify local variables after render completes
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
undefined:21:9
19 | map: TInput => TOutput
@@ -86,23 +88,18 @@ undefined:21:9
> 36 | };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 37 | }, [map]);
| ^^^^^^^^^^^^ 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
| ^^^^^^^^^^^^ This function may (indirectly) reassign or modify local variables after render
38 | }
39 |
Error: The function modifies a local variable here
undefined:33:8
31 | if (output == null) {
32 | output = map(input);
> 33 | cache.set(input, output);
| ^^^^^ The function modifies a local variable here
| ^^^^^ This modifies a local variable
34 | }
35 | return output;
36 | };
```

View File

@@ -20,30 +20,30 @@ function Component(props) {
```
Found 2 errors:
Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
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)
error.invalid-unconditional-set-state-in-render.ts:6:2
4 | const aliased = setX;
5 |
> 6 | setX(1);
| ^^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
| ^^^^ Found setState() within useMemo()
7 | aliased(2);
8 |
9 | return x;
Error: Calling setState during render may trigger an infinite loop
Error: This is an unconditional set state during render, which will trigger an infinite loop. (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 |
6 | setX(1);
> 7 | aliased(2);
| ^^^^^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
| ^^^^^^^ Found setState() within useMemo()
8 |
9 | return x;
10 | }
```

View File

@@ -18,6 +18,8 @@ function component(a, b) {
Found 1 error:
Error: useMemo callbacks may not be async or generator functions
useMemo() callbacks are called once and must synchronously return a value
error.invalid-useMemo-async-callback.ts:2:18
1 | function component(a, b) {
> 2 | let x = useMemo(async () => {
@@ -25,12 +27,10 @@ error.invalid-useMemo-async-callback.ts:2:18
> 3 | await a;
| ^^^^^^^^^^^^
> 4 | }, []);
| ^^^^ useMemo callbacks may not be async or generator functions
| ^^^^ Async and generator functions are not supported
5 | return x;
6 | }
7 |
```

View File

@@ -14,17 +14,17 @@ function component(a, b) {
```
Found 1 error:
Error: useMemo callbacks may not accept any arguments
Error: useMemo() callbacks may not accept parameters
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.
error.invalid-useMemo-callback-args.ts:2:18
1 | function component(a, b) {
> 2 | let x = useMemo(c => a, []);
| ^^^^^^ useMemo callbacks may not accept any arguments
| ^
3 | return x;
4 | }
5 |
```

View File

@@ -33,20 +33,18 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
Error: Cannot reassign a variable after render completes
Variable `a` cannot be reassigned after render.
Reassigning variable `a` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
error.mutable-range-shared-inner-outer-function.ts:8:6
6 | const f = () => {
7 | if (cond) {
> 8 | a = {};
| ^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
| ^ Cannot reassign variable after render completes
9 | b = [];
10 | } else {
11 | a = {};
```

View File

@@ -32,9 +32,9 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `Ref.current`, but the source dependencies were []. Inferred dependency not present in source.
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 `Ref.current`, but the source dependencies were []. Inferred dependency not present in source.
error.ref-like-name-not-Ref.ts:11:30
9 | const Ref = useCustomRef();
@@ -44,12 +44,10 @@ error.ref-like-name-not-Ref.ts:11:30
> 12 | Ref.current?.click();
| ^^^^^^^^^^^^^^^^^^^^^^^^^
> 13 | }, []);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
14 |
15 | return <button onClick={onClick} />;
16 | }
```

View File

@@ -32,9 +32,9 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `notaref.current`, but the source dependencies were []. Inferred dependency not present in source.
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 `notaref.current`, but the source dependencies were []. Inferred dependency not present in source.
error.ref-like-name-not-a-ref.ts:11:30
9 | const notaref = useCustomRef();
@@ -44,12 +44,10 @@ error.ref-like-name-not-a-ref.ts:11:30
> 12 | notaref.current?.click();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 13 | }, []);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
14 |
15 | return <button onClick={onClick} />;
16 | }
```

View File

@@ -18,20 +18,18 @@ function Component() {
```
Found 1 error:
Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
Error: Cannot reassign a variable after render completes
Variable `onClick` cannot be reassigned after render.
Reassigning variable `onClick` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
error.todo-function-expression-references-later-variable-declaration.ts:3:4
1 | function Component() {
2 | let callback = () => {
> 3 | onClick = () => {};
| ^^^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
| ^^^^^^^ Cannot reassign variable after render completes
4 | };
5 | let onClick;
6 |
```

View File

@@ -43,18 +43,18 @@ component Component() {
```
Found 1 error:
Memoization: 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.
Memoization: Compilation skipped because existing memoization could not be preserved
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.
undefined:18:20
16 | // We infer that getIsEnabled returns a mutable value, such that
17 | // isEnabled is mutable
> 18 | const isEnabled = useMemo(() => getIsEnabled(), [getIsEnabled]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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.
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Could not preserve existing memoization
19 |
20 | // We then infer getLoggingData as capturing that mutable value,
21 | // so any calls to this function are then inferred as extending
```

View File

@@ -53,7 +53,9 @@ component Component(id) {
```
Found 3 errors:
Memoization: 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.
Memoization: Compilation skipped because existing memoization could not be preserved
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.
undefined:11:18
9 | const [index, setIndex] = useState(0);
@@ -69,25 +71,25 @@ undefined:11:18
> 15 | };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 16 | }, [index, items]);
| ^^^^^^^^^^^^^^^^^^^^^ 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.
| ^^^^^^^^^^^^^^^^^^^^^ Could not preserve existing memoization
17 |
18 | const setCurrentIndex = useCallback(
19 | (index: number) => {
Memoization: Compilation skipped because existing memoization could not be preserved
Memoization: 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
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.
undefined:28:12
26 | setIndex(index);
27 | },
> 28 | [index, logData, items]
| ^^^^^^^ 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 modified later
29 | );
30 |
31 | if (prevId !== id) {
Memoization: Compilation skipped because existing memoization could not be preserved
Memoization: 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.
undefined:19:4
17 |
@@ -109,12 +111,10 @@ undefined:19:4
> 26 | setIndex(index);
| ^^^^^^^^^^^^^^^^^^^^^^
> 27 | },
| ^^^^^^ 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.
| ^^^^^^ Could not preserve existing memoization
28 | [index, logData, items]
29 | );
30 |
```

View File

@@ -51,18 +51,18 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Memoization: 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.
Memoization: Compilation skipped because existing memoization could not be preserved
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.
error.todo-repro-unmemoized-callback-captured-in-context-variable.ts:11:12
9 | const a = useHook();
10 | // Because b is also part of that same mutable range, it can't be memoized either
> 11 | const b = useMemo(() => ({}), []);
| ^^^^^^^^^^^^^^^^^^^^^^^ 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.
| ^^^^^^^^^^^^^^^^^^^^^^^ Could not preserve existing memoization
12 |
13 | // Conditional assignment without a subsequent mutation normally doesn't create a mutable
14 | // range, but in this case we're reassigning a context variable
```

View File

@@ -23,18 +23,18 @@ function Component(props) {
```
Found 1 error:
Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
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)
error.unconditional-set-state-in-render-after-loop-break.ts:11:2
9 | }
10 | }
> 11 | setState(true);
| ^^^^^^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
| ^^^^^^^^ Found setState() within useMemo()
12 | return state;
13 | }
14 |
```

View File

@@ -18,18 +18,18 @@ function Component(props) {
```
Found 1 error:
Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
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)
error.unconditional-set-state-in-render-after-loop.ts:6:2
4 | for (const _ of props) {
5 | }
> 6 | setState(true);
| ^^^^^^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
| ^^^^^^^^ Found setState() within useMemo()
7 | return state;
8 | }
9 |
```

View File

@@ -23,18 +23,18 @@ function Component(props) {
```
Found 1 error:
Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
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)
error.unconditional-set-state-in-render-with-loop-throw.ts:11:2
9 | }
10 | }
> 11 | setState(true);
| ^^^^^^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
| ^^^^^^^^ Found setState() within useMemo()
12 | return state;
13 | }
14 |
```

View File

@@ -21,18 +21,18 @@ function Component(props) {
```
Found 1 error:
Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
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)
error.unconditional-set-state-lambda.ts:8:2
6 | setX(1);
7 | };
> 8 | foo();
| ^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
| ^^^ Found setState() within useMemo()
9 |
10 | return [x];
11 | }
```

View File

@@ -29,18 +29,18 @@ function Component(props) {
```
Found 1 error:
Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
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)
error.unconditional-set-state-nested-function-expressions.ts:16:2
14 | bar();
15 | };
> 16 | baz();
| ^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
| ^^^ Found setState() within useMemo()
17 |
18 | return [x];
19 | }
```

View File

@@ -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":{"reason":"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","description":"The inferred dependency was `value`, but the source dependencies were []. Inferred dependency not present in source","severity":"CannotPreserveMemoization","suggestions":null,"loc":{"start":{"line":9,"column":31,"index":288},"end":{"line":9,"column":52,"index":309},"filename":"dynamic-gating-bailout-nopanic.ts"}}}}
{"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":{"severity":"CannotPreserveMemoization","category":"Compilation skipped because 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

View File

@@ -65,7 +65,7 @@ function Component(props) {
## Logs
```
{"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}
{"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}
{"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}
```

View File

@@ -42,7 +42,7 @@ function Component(props) {
## Logs
```
{"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}
{"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}
{"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}
```

View File

@@ -65,7 +65,7 @@ function _temp(s) {
## Logs
```
{"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}
{"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}
{"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}
```

View File

@@ -45,7 +45,7 @@ function _temp(s) {
## Logs
```
{"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}
{"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}
{"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}
```

View File

@@ -43,20 +43,18 @@ function Component() {
```
Found 1 error:
Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
Error: Cannot reassign a variable after render completes
Variable `local` cannot be reassigned after render.
Reassigning variable `local` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
error.invalid-reassign-local-variable-in-jsx-callback.ts:6:4
4 |
5 | const reassignLocal = newValue => {
> 6 | local = newValue;
| ^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
| ^^^^^ Cannot reassign variable after render completes
7 | };
8 |
9 | const onClick = newValue => {
```

View File

@@ -30,30 +30,30 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 2 errors:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
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.
error.invalid-useCallback-captures-reassigned-context.ts:11:37
9 |
10 | // makeArray() is captured, but depsList contains [props]
> 11 | const cb = useCallback(() => [x], [x]);
| ^ 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 modified later
12 |
13 | x = makeArray();
14 |
Memoization: Compilation skipped because existing memoization could not be preserved
Memoization: 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.
error.invalid-useCallback-captures-reassigned-context.ts:11:25
9 |
10 | // makeArray() is captured, but depsList contains [props]
> 11 | const cb = useCallback(() => [x], [x]);
| ^^^^^^^^^ 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.
| ^^^^^^^^^ Could not preserve existing memoization
12 |
13 | x = makeArray();
14 |
```

View File

@@ -31,18 +31,18 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Memoization: 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.
Memoization: Compilation skipped because existing memoization could not be preserved
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.
error.false-positive-useMemo-dropped-infer-always-invalidating.ts:15:9
13 | x.push(props);
14 |
> 15 | return useMemo(() => [x], [x]);
| ^^^^^^^^^^^^^^^^^^^^^^^ 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.
| ^^^^^^^^^^^^^^^^^^^^^^^ Could not preserve existing memoization
16 | }
17 |
18 | export const FIXTURE_ENTRYPOINT = {
```

View File

@@ -30,18 +30,18 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
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.
error.false-positive-useMemo-infer-mutate-deps.ts:14:6
12 | return useMemo(() => {
13 | return identity(val);
> 14 | }, [val]);
| ^^^ 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 modified later
15 | }
16 |
17 | export const FIXTURE_ENTRYPOINT = {
```

View File

@@ -41,18 +41,18 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
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.
error.false-positive-useMemo-overlap-scopes.ts:23:9
21 | const result = useMemo(() => {
22 | return [Math.max(x[1], a)];
> 23 | }, [a, x]);
| ^ 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 modified later
24 | arrayPush(y, 3);
25 | return {result, y};
26 | }
```

View File

@@ -27,9 +27,9 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `propB`, but the source dependencies were [propA, propB.x.y]. Inferred less specific property than source.
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 `propB`, but the source dependencies were [propA, propB.x.y]. Inferred less specific property than source.
error.hoist-useCallback-conditional-access-own-scope.ts:5:21
3 |
@@ -47,12 +47,10 @@ error.hoist-useCallback-conditional-access-own-scope.ts:5:21
> 10 | }
| ^^^^^^^^^^^^^^^^
> 11 | }, [propA, propB.x.y]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
12 | }
13 |
14 | export const FIXTURE_ENTRYPOINT = {
```

View File

@@ -30,9 +30,9 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 2 errors:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `propA`, but the source dependencies were [propA.a, propB.x.y]. Inferred less specific property than source.
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 `propA`, but the source dependencies were [propA.a, propB.x.y]. Inferred less specific property than source.
error.hoist-useCallback-infer-conditional-value-block.ts:6:21
4 |
@@ -54,15 +54,13 @@ error.hoist-useCallback-infer-conditional-value-block.ts:6:21
> 13 | }
| ^^^^^^^^^^^^^^^^^
> 14 | }, [propA.a, propB.x.y]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
15 | }
16 |
17 | export const FIXTURE_ENTRYPOINT = {
Memoization: Compilation skipped because existing memoization could not be preserved
Memoization: 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 `propB`, but the source dependencies were [propA.a, propB.x.y]. Inferred less specific property than source.
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 `propB`, but the source dependencies were [propA.a, propB.x.y]. Inferred less specific property than source.
error.hoist-useCallback-infer-conditional-value-block.ts:6:21
4 |
@@ -84,12 +82,10 @@ error.hoist-useCallback-infer-conditional-value-block.ts:6:21
> 13 | }
| ^^^^^^^^^^^^^^^^^
> 14 | }, [propA.a, propB.x.y]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
15 | }
16 |
17 | export const FIXTURE_ENTRYPOINT = {
```

View File

@@ -31,30 +31,30 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 2 errors:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
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.
error.invalid-useCallback-captures-reassigned-context.ts:12:37
10 |
11 | // makeArray() is captured, but depsList contains [props]
> 12 | const cb = useCallback(() => [x], [x]);
| ^ 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 modified later
13 |
14 | x = makeArray();
15 |
Memoization: Compilation skipped because existing memoization could not be preserved
Memoization: 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.
error.invalid-useCallback-captures-reassigned-context.ts:12:25
10 |
11 | // makeArray() is captured, but depsList contains [props]
> 12 | const cb = useCallback(() => [x], [x]);
| ^^^^^^^^^ 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.
| ^^^^^^^^^ Could not preserve existing memoization
13 |
14 | x = makeArray();
15 |
```

View File

@@ -18,9 +18,9 @@ function useHook(maybeRef) {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `maybeRef.current`, but the source dependencies were [maybeRef]. Differences in ref.current access.
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 `maybeRef.current`, but the source dependencies were [maybeRef]. Differences in ref.current access.
error.maybe-invalid-useCallback-read-maybeRef.ts:5:21
3 |
@@ -30,11 +30,9 @@ error.maybe-invalid-useCallback-read-maybeRef.ts:5:21
> 6 | return [maybeRef.current];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 7 | }, [maybeRef]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
8 | }
9 |
```

View File

@@ -18,9 +18,9 @@ function useHook(maybeRef, shouldRead) {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `maybeRef.current`, but the source dependencies were [shouldRead, maybeRef]. Differences in ref.current access.
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 `maybeRef.current`, but the source dependencies were [shouldRead, maybeRef]. Differences in ref.current access.
error.maybe-invalid-useMemo-read-maybeRef.ts:5:17
3 |
@@ -30,11 +30,9 @@ error.maybe-invalid-useMemo-read-maybeRef.ts:5:17
> 6 | return () => [maybeRef.current];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 7 | }, [shouldRead, maybeRef]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
8 | }
9 |
```

View File

@@ -29,9 +29,9 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `ref`, but the source dependencies were []. Inferred dependency not present in source.
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 `ref`, but the source dependencies were []. Inferred dependency not present in source.
error.preserve-use-memo-ref-missing-reactive.ts:9:21
7 | const ref = cond ? ref1 : ref2;
@@ -45,12 +45,10 @@ error.preserve-use-memo-ref-missing-reactive.ts:9:21
> 12 | }
| ^^^^^^^^^^^^^^^^^^^^^^
> 13 | }, []);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
14 | }
15 |
16 | export const FIXTURE_ENTRYPOINT = {
```

View File

@@ -29,18 +29,18 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Memoization: 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.
Memoization: Compilation skipped because existing memoization could not be preserved
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.
error.todo-useCallback-captures-invalidating-value.ts:13:21
11 | x.push(props);
12 |
> 13 | return useCallback(() => [x], [x]);
| ^^^^^^^^^ 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.
| ^^^^^^^^^ Could not preserve existing memoization
14 | }
15 |
16 | export const FIXTURE_ENTRYPOINT = {
```

View File

@@ -20,19 +20,17 @@ function useHook(x) {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `aliasedX`, but the source dependencies were [x, aliasedProp]. Inferred different dependency than source.
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 `aliasedX`, but the source dependencies were [x, aliasedProp]. Inferred different dependency than source.
error.useCallback-aliased-var.ts:9:21
7 | const aliasedProp = x.y.z;
8 |
> 9 | return useCallback(() => [aliasedX, x.y.z], [x, aliasedProp]);
| ^^^^^^^^^^^^^^^^^^^^^^^ 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
| ^^^^^^^^^^^^^^^^^^^^^^^ Could not preserve existing manual memoization
10 | }
11 |
```

View File

@@ -26,9 +26,9 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `propB?.x.y`, but the source dependencies were [propA, propB.x.y]. Inferred different dependency than source.
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 `propB?.x.y`, but the source dependencies were [propA, propB.x.y]. Inferred different dependency than source.
error.useCallback-conditional-access-noAlloc.ts:5:21
3 |
@@ -44,12 +44,10 @@ error.useCallback-conditional-access-noAlloc.ts:5:21
> 9 | };
| ^^^^^^^^^^^^
> 10 | }, [propA, propB.x.y]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
11 | }
12 |
13 | export const FIXTURE_ENTRYPOINT = {
```

View File

@@ -25,9 +25,9 @@ function Component({propA, propB}) {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `propB`, but the source dependencies were [propA?.a, propB.x.y]. Inferred less specific property than source.
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 `propB`, but the source dependencies were [propA?.a, propB.x.y]. Inferred less specific property than source.
error.useCallback-infer-less-specific-conditional-access.ts:6:21
4 |
@@ -49,11 +49,9 @@ error.useCallback-infer-less-specific-conditional-access.ts:6:21
> 13 | }
| ^^^^^^^^^^^^^^^^^
> 14 | }, [propA?.a, propB.x.y]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
15 | }
16 |
```

View File

@@ -18,9 +18,9 @@ function Component({propA}) {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `propA`, but the source dependencies were [propA.x]. Inferred less specific property than source.
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 `propA`, but the source dependencies were [propA.x]. Inferred less specific property than source.
error.useCallback-property-call-dep.ts:5:21
3 |
@@ -30,11 +30,9 @@ error.useCallback-property-call-dep.ts:5:21
> 6 | return propA.x();
| ^^^^^^^^^^^^^^^^^^^^^
> 7 | }, [propA.x]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
8 | }
9 |
```

View File

@@ -20,19 +20,17 @@ function useHook(x) {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `x`, but the source dependencies were [aliasedX, aliasedProp]. Inferred different dependency than source.
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 `x`, but the source dependencies were [aliasedX, aliasedProp]. Inferred different dependency than source.
error.useMemo-aliased-var.ts:9:17
7 | const aliasedProp = x.y.z;
8 |
> 9 | return useMemo(() => [x, x.y.z], [aliasedX, aliasedProp]);
| ^^^^^^^^^^^^^^^^ 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
| ^^^^^^^^^^^^^^^^ Could not preserve existing manual memoization
10 | }
11 |
```

View File

@@ -25,9 +25,9 @@ function Component({propA, propB}) {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `propB`, but the source dependencies were [propA?.a, propB.x.y]. Inferred less specific property than source.
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 `propB`, but the source dependencies were [propA?.a, propB.x.y]. Inferred less specific property than source.
error.useMemo-infer-less-specific-conditional-access.ts:6:17
4 |
@@ -49,11 +49,9 @@ error.useMemo-infer-less-specific-conditional-access.ts:6:17
> 13 | }
| ^^^^^^^^^^^^^^^^^
> 14 | }, [propA?.a, propB.x.y]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
15 | }
16 |
```

View File

@@ -25,9 +25,9 @@ function Component({propA, propB}) {
```
Found 2 errors:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `propA`, but the source dependencies were [propA.a, propB.x.y]. Inferred less specific property than source.
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 `propA`, but the source dependencies were [propA.a, propB.x.y]. Inferred less specific property than source.
error.useMemo-infer-less-specific-conditional-value-block.ts:6:17
4 |
@@ -49,14 +49,12 @@ error.useMemo-infer-less-specific-conditional-value-block.ts:6:17
> 13 | }
| ^^^^^^^^^^^^^^^^^
> 14 | }, [propA.a, propB.x.y]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
15 | }
16 |
Memoization: Compilation skipped because existing memoization could not be preserved
Memoization: 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 `propB`, but the source dependencies were [propA.a, propB.x.y]. Inferred less specific property than source.
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 `propB`, but the source dependencies were [propA.a, propB.x.y]. Inferred less specific property than source.
error.useMemo-infer-less-specific-conditional-value-block.ts:6:17
4 |
@@ -78,11 +76,9 @@ error.useMemo-infer-less-specific-conditional-value-block.ts:6:17
> 13 | }
| ^^^^^^^^^^^^^^^^^
> 14 | }, [propA.a, propB.x.y]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
15 | }
16 |
```

View File

@@ -20,9 +20,9 @@ function Component({propA}) {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `propA`, but the source dependencies were [propA.x]. Inferred less specific property than source.
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 `propA`, but the source dependencies were [propA.x]. Inferred less specific property than source.
error.useMemo-property-call-chained-object.ts:5:17
3 |
@@ -36,11 +36,9 @@ error.useMemo-property-call-chained-object.ts:5:17
> 8 | };
| ^^^^^^^^^^^^
> 9 | }, [propA.x]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
10 | }
11 |
```

View File

@@ -18,9 +18,9 @@ function Component({propA}) {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `propA`, but the source dependencies were [propA.x]. Inferred less specific property than source.
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 `propA`, but the source dependencies were [propA.x]. Inferred less specific property than source.
error.useMemo-property-call-dep.ts:5:17
3 |
@@ -30,11 +30,9 @@ error.useMemo-property-call-dep.ts:5:17
> 6 | return propA.x();
| ^^^^^^^^^^^^^^^^^^^^^
> 7 | }, [propA.x]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
8 | }
9 |
```

View File

@@ -31,9 +31,9 @@ function useFoo(input1) {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `input1`, but the source dependencies were [y]. Inferred different dependency than source.
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 `input1`, but the source dependencies were [y]. Inferred different dependency than source.
error.useMemo-unrelated-mutation-in-depslist.ts:16:27
14 | const x = {};
@@ -43,12 +43,10 @@ error.useMemo-unrelated-mutation-in-depslist.ts:16:27
> 17 | return [y];
| ^^^^^^^^^^^^^^^
> 18 | }, [(mutate(x), y)]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
19 |
20 | return [x, memoized];
21 | }
```

View File

@@ -25,9 +25,9 @@ function Component(props) {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `props.items`, but the source dependencies were [props?.items, props.cond]. Inferred different dependency than source.
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 `props.items`, but the source dependencies were [props?.items, props.cond]. Inferred different dependency than source.
error.todo-optional-member-expression-with-conditional-optional.ts:4:23
2 | import {ValidateMemoization} from 'shared-runtime';
@@ -47,12 +47,10 @@ error.todo-optional-member-expression-with-conditional-optional.ts:4:23
> 10 | return x;
| ^^^^^^^^^^^^^^^^^
> 11 | }, [props?.items, props.cond]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
12 | return (
13 | <ValidateMemoization inputs={[props?.items, props.cond]} output={data} />
14 | );
```

View File

@@ -25,9 +25,9 @@ function Component(props) {
```
Found 1 error:
Memoization: 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
Memoization: Compilation skipped because existing memoization could not be preserved
The inferred dependency was `props.items`, but the source dependencies were [props?.items, props.cond]. Inferred different dependency than source.
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 `props.items`, but the source dependencies were [props?.items, props.cond]. Inferred different dependency than source.
error.todo-optional-member-expression-with-conditional.ts:4:23
2 | import {ValidateMemoization} from 'shared-runtime';
@@ -47,12 +47,10 @@ error.todo-optional-member-expression-with-conditional.ts:4:23
> 10 | return x;
| ^^^^^^^^^^^^^^^^^
> 11 | }, [props?.items, props.cond]);
| ^^^^ 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
| ^^^^ Could not preserve existing manual memoization
12 | return (
13 | <ValidateMemoization inputs={[props?.items, props.cond]} output={data} />
14 | );
```