Compare commits

..

3 Commits

Author SHA1 Message Date
Joe Savona
2649d102b8 [compiler][wip] Improve diagnostic infra
Work in progress, i'm experimenting with revamping our diagnostic infra. Starting with a better format for representing errors, with an ability to point ot multiple locations, along with better printing of errors. Of course, Babel still controls the printing in the majority case so this still needs more work.
2025-07-24 14:48:36 -07:00
Joe Savona
1517c63a78 [compiler] Enable additional lints by default
Enable more validations to help catch bad patterns, but only in the linter. These rules are already enabled by default in the compiler _if_ violations could produce unsafe output.
2025-07-24 14:43:03 -07:00
Joe Savona
5fbe88ab40 [compiler] Validate against setState in all effect types 2025-07-24 14:43:03 -07:00
83 changed files with 497 additions and 809 deletions

View File

@@ -59,7 +59,7 @@ export type CompilerDiagnosticDetail =
*/
{
kind: 'error';
loc: SourceLocation | null;
loc: SourceLocation;
message: string;
};
@@ -100,12 +100,6 @@ 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;
}
@@ -119,11 +113,6 @@ 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;
}
@@ -138,7 +127,7 @@ export class CompilerDiagnostic {
switch (detail.kind) {
case 'error': {
const loc = detail.loc;
if (loc == null || typeof loc === 'symbol') {
if (typeof loc === 'symbol') {
continue;
}
let codeFrame: string;

View File

@@ -9,7 +9,6 @@ import {NodePath, Scope} from '@babel/traverse';
import * as t from '@babel/types';
import invariant from 'invariant';
import {
CompilerDiagnostic,
CompilerError,
CompilerSuggestionOperation,
ErrorSeverity,
@@ -105,18 +104,12 @@ export function lower(
if (param.isIdentifier()) {
const binding = builder.resolveIdentifier(param);
if (binding.kind !== 'Identifier') {
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',
}),
);
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,
});
return;
}
const place: Place = {
@@ -170,18 +163,12 @@ export function lower(
'Assignment',
);
} else {
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',
}),
);
builder.errors.push({
reason: `(BuildHIR::lower) Handle ${param.node.type} params`,
severity: ErrorSeverity.Todo,
loc: param.node.loc ?? null,
suggestions: null,
});
}
});
@@ -201,18 +188,13 @@ export function lower(
lowerStatement(builder, body);
directives = body.get('directives').map(d => d.node.value.value);
} else {
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',
}),
);
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,
});
}
if (builder.errors.hasErrors()) {

View File

@@ -345,51 +345,6 @@ export function* eachPatternOperand(pattern: Pattern): Iterable<Place> {
}
}
export function* eachPatternItem(
pattern: Pattern,
): Iterable<Place | SpreadPattern> {
switch (pattern.kind) {
case 'ArrayPattern': {
for (const item of pattern.items) {
if (item.kind === 'Identifier') {
yield item;
} else if (item.kind === 'Spread') {
yield item;
} else if (item.kind === 'Hole') {
continue;
} else {
assertExhaustive(
item,
`Unexpected item kind \`${(item as any).kind}\``,
);
}
}
break;
}
case 'ObjectPattern': {
for (const property of pattern.properties) {
if (property.kind === 'ObjectProperty') {
yield property.place;
} else if (property.kind === 'Spread') {
yield property;
} else {
assertExhaustive(
property,
`Unexpected item kind \`${(property as any).kind}\``,
);
}
}
break;
}
default: {
assertExhaustive(
pattern,
`Unexpected pattern kind \`${(pattern as any).kind}\``,
);
}
}
}
export function mapInstructionLValues(
instr: Instruction,
fn: (place: Place) => Place,

View File

@@ -36,8 +36,8 @@ import {
ValueReason,
} from '../HIR';
import {
eachInstructionValueLValue,
eachInstructionValueOperand,
eachPatternItem,
eachTerminalOperand,
eachTerminalSuccessor,
} from '../HIR/visitors';
@@ -1864,34 +1864,19 @@ function computeSignatureForInstruction(
break;
}
case 'Destructure': {
for (const patternItem of eachPatternItem(value.lvalue.pattern)) {
const place =
patternItem.kind === 'Identifier' ? patternItem : patternItem.place;
if (isPrimitiveType(place.identifier)) {
for (const patternLValue of eachInstructionValueLValue(value)) {
if (isPrimitiveType(patternLValue.identifier)) {
effects.push({
kind: 'Create',
into: place,
into: patternLValue,
value: ValueKind.Primitive,
reason: ValueReason.Other,
});
} else if (patternItem.kind === 'Identifier') {
} else {
effects.push({
kind: 'CreateFrom',
from: value.value,
into: place,
});
} else {
// Spread creates a new object/array that captures from the RValue
effects.push({
kind: 'Create',
into: place,
reason: ValueReason.Other,
value: ValueKind.Mutable,
});
effects.push({
kind: 'Capture',
from: value.value,
into: place,
into: patternLValue,
});
}
}

View File

@@ -360,12 +360,6 @@ function* generateInstructionTypes(
value: makePropertyLiteral(propertyName),
},
});
} else if (item.kind === 'Spread') {
// Array pattern spread always creates an array
yield equation(item.place.identifier.type, {
kind: 'Object',
shapeId: BuiltInArrayId,
});
} else {
break;
}

View File

@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {CompilerDiagnostic, CompilerError, Effect, ErrorSeverity} from '..';
import {CompilerError, Effect} from '..';
import {HIRFunction, IdentifierId, Place} from '../HIR';
import {
eachInstructionLValue,
@@ -28,19 +28,16 @@ export function validateLocalsNotReassignedAfterRender(fn: HIRFunction): void {
false,
);
if (reassignment !== null) {
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;
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,
});
}
}

View File

@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {CompilerDiagnostic, CompilerError, Effect, ErrorSeverity} from '..';
import {CompilerError, Effect, ErrorSeverity} from '..';
import {
FunctionEffect,
HIRFunction,
@@ -57,24 +57,16 @@ export function validateNoFreezingKnownMutableFunctions(
if (operand.effect === Effect.Freeze) {
const effect = contextMutationEffects.get(operand.identifier.id);
if (effect != null) {
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',
}),
);
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,
});
}
}
}

View File

@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {CompilerDiagnostic, CompilerError, ErrorSeverity} from '..';
import {CompilerError, ErrorSeverity} from '..';
import {HIRFunction} from '../HIR';
import {getFunctionCallSignature} from '../Inference/InferReferenceEffects';
import {Result} from '../Utils/Result';
@@ -34,22 +34,17 @@ export function validateNoImpureFunctionsInRender(
callee.identifier.type,
);
if (signature != null && signature.impure === true) {
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',
}),
);
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,
});
}
}
}

View File

@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {CompilerDiagnostic, CompilerError, ErrorSeverity} from '..';
import {CompilerError, ErrorSeverity} from '..';
import {BlockId, HIRFunction} from '../HIR';
import {Result} from '../Utils/Result';
import {retainWhere} from '../Utils/utils';
@@ -34,17 +34,11 @@ export function validateNoJSXInTryStatement(
switch (value.kind) {
case 'JsxExpression':
case 'JsxFragment': {
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',
}),
);
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,
});
break;
}
}

View File

@@ -5,11 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {
CompilerDiagnostic,
CompilerError,
ErrorSeverity,
} from '../CompilerError';
import {CompilerError, ErrorSeverity} from '../CompilerError';
import {
HIRFunction,
IdentifierId,
@@ -94,21 +90,14 @@ export function validateNoSetStateInEffects(
if (arg !== undefined && arg.kind === 'Identifier') {
const setState = setStateFunctions.get(arg.identifier.id);
if (setState !== undefined) {
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',
}),
);
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,
});
}
}
}

View File

@@ -5,11 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {
CompilerDiagnostic,
CompilerError,
ErrorSeverity,
} from '../CompilerError';
import {CompilerError, ErrorSeverity} from '../CompilerError';
import {HIRFunction, IdentifierId, isSetStateType} from '../HIR';
import {computeUnconditionalBlocks} from '../HIR/ComputeUnconditionalBlocks';
import {eachInstructionValueOperand} from '../HIR/visitors';
@@ -126,35 +122,23 @@ function validateNoSetStateInRenderImpl(
unconditionalSetStateFunctions.has(callee.identifier.id)
) {
if (activeManualMemoId !== 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()',
}),
);
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,
});
} else if (unconditionalBlocks.has(block.id)) {
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()',
}),
);
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,
});
}
}
break;

View File

@@ -5,11 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {
CompilerDiagnostic,
CompilerError,
ErrorSeverity,
} from '../CompilerError';
import {CompilerError, ErrorSeverity} from '../CompilerError';
import {
DeclarationId,
Effect,
@@ -279,37 +275,27 @@ function validateInferredDep(
errorDiagnostic = merge(errorDiagnostic ?? compareResult, compareResult);
}
}
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',
}),
);
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,
});
}
class Visitor extends ReactiveFunctionVisitor<VisitorState> {
@@ -533,21 +519,14 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
!this.scopes.has(identifier.scope.id) &&
!this.prunedScopes.has(identifier.scope.id)
) {
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',
}),
);
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,
});
}
}
}
@@ -581,25 +560,16 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
for (const identifier of decls) {
if (isUnmemoized(identifier, this.scopes)) {
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',
}),
);
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,
});
}
}
}

View File

@@ -5,11 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {
CompilerDiagnostic,
CompilerError,
ErrorSeverity,
} from '../CompilerError';
import {CompilerError, ErrorSeverity} from '..';
import {FunctionExpression, HIRFunction, IdentifierId} from '../HIR';
import {Result} from '../Utils/Result';
@@ -67,41 +63,24 @@ export function validateUseMemo(fn: HIRFunction): Result<void, CompilerError> {
}
if (body.loweredFunc.func.params.length > 0) {
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: '',
}),
);
errors.push({
severity: ErrorSeverity.InvalidReact,
reason: 'useMemo callbacks may not accept any arguments',
description: null,
loc: body.loc,
suggestions: null,
});
}
if (body.loweredFunc.func.async || body.loweredFunc.func.generator) {
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',
}),
);
errors.push({
severity: ErrorSeverity.InvalidReact,
reason:
'useMemo callbacks may not be async or generator functions',
description: null,
loc: body.loc,
suggestions: null,
});
}
break;

View File

@@ -1,104 +0,0 @@
## Input
```javascript
// @validatePreserveExistingMemoizationGuarantees
import {useMemo} from 'react';
import {makeObject_Primitives, ValidateMemoization} from 'shared-runtime';
function Component(props) {
// Should memoize independently
const x = useMemo(() => makeObject_Primitives(), []);
const rest = useMemo(() => {
const [_, ...rest] = props.array;
// Should be inferred as Array.proto.push which doesn't mutate input
rest.push(x);
return rest;
});
return (
<>
<ValidateMemoization inputs={[]} output={x} />
<ValidateMemoization inputs={[props.array]} output={rest} />
</>
);
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{array: [0, 1, 2]}],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees
import { useMemo } from "react";
import { makeObject_Primitives, ValidateMemoization } from "shared-runtime";
function Component(props) {
const $ = _c(9);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = makeObject_Primitives();
$[0] = t0;
} else {
t0 = $[0];
}
const x = t0;
let rest;
if ($[1] !== props.array) {
[, ...rest] = props.array;
rest.push(x);
$[1] = props.array;
$[2] = rest;
} else {
rest = $[2];
}
const rest_0 = rest;
let t1;
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
t1 = <ValidateMemoization inputs={[]} output={x} />;
$[3] = t1;
} else {
t1 = $[3];
}
let t2;
if ($[4] !== props.array) {
t2 = [props.array];
$[4] = props.array;
$[5] = t2;
} else {
t2 = $[5];
}
let t3;
if ($[6] !== rest_0 || $[7] !== t2) {
t3 = (
<>
{t1}
<ValidateMemoization inputs={t2} output={rest_0} />
</>
);
$[6] = rest_0;
$[7] = t2;
$[8] = t3;
} else {
t3 = $[8];
}
return t3;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{ array: [0, 1, 2] }],
};
```
### Eval output
(kind: ok) <div>{"inputs":[],"output":{"a":0,"b":"value1","c":true}}</div><div>{"inputs":[[0,1,2]],"output":[1,2,{"a":0,"b":"value1","c":true}]}</div>

View File

@@ -1,28 +0,0 @@
// @validatePreserveExistingMemoizationGuarantees
import {useMemo} from 'react';
import {makeObject_Primitives, ValidateMemoization} from 'shared-runtime';
function Component(props) {
// Should memoize independently
const x = useMemo(() => makeObject_Primitives(), []);
const rest = useMemo(() => {
const [_, ...rest] = props.array;
// Should be inferred as Array.proto.push which doesn't mutate input
rest.push(x);
return rest;
});
return (
<>
<ValidateMemoization inputs={[]} output={x} />
<ValidateMemoization inputs={[props.array]} output={rest} />
</>
);
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{array: [0, 1, 2]}],
};

View File

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

View File

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

View File

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

View File

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

View File

@@ -25,9 +25,9 @@ function Component(props) {
```
Found 1 error:
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
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.
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,10 +47,12 @@ error.hoist-optional-member-expression-with-conditional-optional.ts:4:23
> 10 | return x;
| ^^^^^^^^^^^^^^^^^
> 11 | }, [props?.items, props.cond]);
| ^^^^ Could not preserve existing manual 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
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: 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
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.
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,10 +47,12 @@ error.hoist-optional-member-expression-with-conditional.ts:4:23
> 10 | return x;
| ^^^^^^^^^^^^^^^^^
> 11 | }, [props?.items, props.cond]);
| ^^^^ Could not preserve existing manual 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
12 | return (
13 | <ValidateMemoization inputs={[props?.items, props.cond]} output={data} />
14 | );
```

View File

@@ -18,8 +18,6 @@ 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 () => {
@@ -27,10 +25,12 @@ error.invalid-ReactUseMemo-async-callback.ts:2:24
> 3 | await a;
| ^^^^^^^^^^^^
> 4 | }, []);
| ^^^^ Async and generator functions are not supported
| ^^^^ useMemo callbacks may not be async or generator functions
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
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: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
error.invalid-conditional-setState-in-useMemo.ts:7:6
5 | useMemo(() => {
6 | if (cond) {
> 7 | setPrevItem(item);
| ^^^^^^^^^^^ Found setState() within useMemo()
| ^^^^^^^^^^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
8 | setState(0);
9 | }
10 | }, [cond, key, init]);
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: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
error.invalid-conditional-setState-in-useMemo.ts:8:6
6 | if (cond) {
7 | setPrevItem(item);
> 8 | setState(0);
| ^^^^^^^^ Found setState() within useMemo()
| ^^^^^^^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
9 | }
10 | }, [cond, key, init]);
11 |
```

View File

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

View File

@@ -47,18 +47,20 @@ function Component() {
```
Found 1 error:
Error: Cannot reassign a variable after render completes
Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
Reassigning variable `local` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
Variable `local` cannot be reassigned after render.
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;
| ^^^^^ Cannot reassign variable after render completes
| ^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
8 | };
9 | return reassignLocal;
10 | };
```

View File

@@ -19,9 +19,9 @@ function Component(props) {
```
Found 1 error:
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
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.
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,10 +35,12 @@ error.invalid-optional-member-expression-as-memo-dep-non-optional-in-body.ts:3:2
> 6 | // deps are optional
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 7 | }, [props.items?.edges?.nodes]);
| ^^^^ Could not preserve existing manual 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
8 | return <Foo data={data} />;
9 | }
10 |
```

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -19,10 +19,8 @@ function useFoo() {
## Error
```
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
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
error.invalid-return-mutable-function-from-hook.ts:7:9
5 | useHook(); // for inference to kick in
@@ -32,18 +30,23 @@ error.invalid-return-mutable-function-from-hook.ts:7:9
> 8 | cache.set('key', 'value');
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 9 | };
| ^^^^ This function may (indirectly) reassign or modify local variables after render
| ^^^^ 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
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');
| ^^^^^ This modifies a local variable
| ^^^^^ The function modifies a local variable here
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
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: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
error.invalid-setState-in-useMemo-indirect-useCallback.ts:13:4
11 |
12 | useMemo(() => {
> 13 | fn();
| ^^ Found setState() within useMemo()
| ^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
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
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: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
error.invalid-setState-in-useMemo.ts:6:4
4 |
5 | useMemo(() => {
> 6 | setPrevKey(key);
| ^^^^^^^^^^ Found setState() within useMemo()
| ^^^^^^^^^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
7 | setState(init);
8 | }, [key, init]);
9 |
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: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
error.invalid-setState-in-useMemo.ts:7:4
5 | useMemo(() => {
6 | setPrevKey(key);
> 7 | setState(init);
| ^^^^^^^^ Found setState() within useMemo()
| ^^^^^^^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
8 | }, [key, init]);
9 |
10 | return state;
```

View File

@@ -47,10 +47,8 @@ hook useMemoMap<TInput: interface {}, TOutput>(
## Error
```
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
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
undefined:21:9
19 | map: TInput => TOutput
@@ -88,18 +86,23 @@ undefined:21:9
> 36 | };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 37 | }, [map]);
| ^^^^^^^^^^^^ This function may (indirectly) reassign or modify local variables after render
| ^^^^^^^^^^^^ 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
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);
| ^^^^^ This modifies a local variable
| ^^^^^ The function modifies a local variable here
34 | }
35 | return output;
36 | };
```

View File

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

View File

@@ -18,8 +18,6 @@ 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 () => {
@@ -27,10 +25,12 @@ error.invalid-useMemo-async-callback.ts:2:18
> 3 | await a;
| ^^^^^^^^^^^^
> 4 | }, []);
| ^^^^ Async and generator functions are not supported
| ^^^^ useMemo callbacks may not be async or generator functions
5 | return x;
6 | }
7 |
```

View File

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

View File

@@ -32,9 +32,9 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
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
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.
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,10 +44,12 @@ error.ref-like-name-not-Ref.ts:11:30
> 12 | Ref.current?.click();
| ^^^^^^^^^^^^^^^^^^^^^^^^^
> 13 | }, []);
| ^^^^ Could not preserve existing manual 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
14 |
15 | return <button onClick={onClick} />;
16 | }
```

View File

@@ -32,9 +32,9 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
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
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.
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,10 +44,12 @@ error.ref-like-name-not-a-ref.ts:11:30
> 12 | notaref.current?.click();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 13 | }, []);
| ^^^^ Could not preserve existing manual 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
14 |
15 | return <button onClick={onClick} />;
16 | }
```

View File

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

View File

@@ -43,18 +43,18 @@ component Component() {
```
Found 1 error:
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.
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.
undefined:18:20
16 | // We infer that getIsEnabled returns a mutable value, such that
17 | // isEnabled is mutable
> 18 | const isEnabled = useMemo(() => getIsEnabled(), [getIsEnabled]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Could not preserve existing 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.
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,9 +53,7 @@ component Component(id) {
```
Found 3 errors:
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.
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.
undefined:11:18
9 | const [index, setIndex] = useState(0);
@@ -71,25 +69,25 @@ undefined:11:18
> 15 | };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 16 | }, [index, items]);
| ^^^^^^^^^^^^^^^^^^^^^ Could not preserve existing 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.
17 |
18 | const setCurrentIndex = useCallback(
19 | (index: number) => {
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.
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
undefined:28:12
26 | setIndex(index);
27 | },
> 28 | [index, logData, items]
| ^^^^^^^ This dependency may be modified later
| ^^^^^^^ 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
29 | );
30 |
31 | if (prevId !== id) {
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.
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.
undefined:19:4
17 |
@@ -111,10 +109,12 @@ undefined:19:4
> 26 | setIndex(index);
| ^^^^^^^^^^^^^^^^^^^^^^
> 27 | },
| ^^^^^^ Could not preserve existing 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.
28 | [index, logData, items]
29 | );
30 |
```

View File

@@ -51,18 +51,18 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
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.
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.
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(() => ({}), []);
| ^^^^^^^^^^^^^^^^^^^^^^^ Could not preserve existing 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.
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: 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: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
error.unconditional-set-state-in-render-after-loop-break.ts:11:2
9 | }
10 | }
> 11 | setState(true);
| ^^^^^^^^ Found setState() within useMemo()
| ^^^^^^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
12 | return state;
13 | }
14 |
```

View File

@@ -18,18 +18,18 @@ function Component(props) {
```
Found 1 error:
Error: Calling setState during render may trigger an infinite loop
Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)
Error: This is an unconditional set state during render, which will trigger an infinite loop. (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);
| ^^^^^^^^ Found setState() within useMemo()
| ^^^^^^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
7 | return state;
8 | }
9 |
```

View File

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

View File

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

View File

@@ -29,18 +29,18 @@ function Component(props) {
```
Found 1 error:
Error: Calling setState during render may trigger an infinite loop
Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)
Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
error.unconditional-set-state-nested-function-expressions.ts:16:2
14 | bar();
15 | };
> 16 | baz();
| ^^^ Found setState() within useMemo()
| ^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
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":{"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"}]}}}
{"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"}}}}
```
### Eval output

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -27,9 +27,9 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
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
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.
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,10 +47,12 @@ error.hoist-useCallback-conditional-access-own-scope.ts:5:21
> 10 | }
| ^^^^^^^^^^^^^^^^
> 11 | }, [propA, propB.x.y]);
| ^^^^ Could not preserve existing manual 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
12 | }
13 |
14 | export const FIXTURE_ENTRYPOINT = {
```

View File

@@ -30,9 +30,9 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 2 errors:
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
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.
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,13 +54,15 @@ error.hoist-useCallback-infer-conditional-value-block.ts:6:21
> 13 | }
| ^^^^^^^^^^^^^^^^^
> 14 | }, [propA.a, propB.x.y]);
| ^^^^ Could not preserve existing manual 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
15 | }
16 |
17 | export const FIXTURE_ENTRYPOINT = {
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. 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.
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.
error.hoist-useCallback-infer-conditional-value-block.ts:6:21
4 |
@@ -82,10 +84,12 @@ error.hoist-useCallback-infer-conditional-value-block.ts:6:21
> 13 | }
| ^^^^^^^^^^^^^^^^^
> 14 | }, [propA.a, propB.x.y]);
| ^^^^ Could not preserve existing manual 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
15 | }
16 |
17 | export const FIXTURE_ENTRYPOINT = {
```

View File

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

View File

@@ -18,9 +18,9 @@ function useHook(maybeRef) {
```
Found 1 error:
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
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.
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,9 +30,11 @@ error.maybe-invalid-useCallback-read-maybeRef.ts:5:21
> 6 | return [maybeRef.current];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 7 | }, [maybeRef]);
| ^^^^ Could not preserve existing manual 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
8 | }
9 |
```

View File

@@ -18,9 +18,9 @@ function useHook(maybeRef, shouldRead) {
```
Found 1 error:
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
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.
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,9 +30,11 @@ error.maybe-invalid-useMemo-read-maybeRef.ts:5:17
> 6 | return () => [maybeRef.current];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 7 | }, [shouldRead, maybeRef]);
| ^^^^ Could not preserve existing manual 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
8 | }
9 |
```

View File

@@ -29,9 +29,9 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
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
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.
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,10 +45,12 @@ error.preserve-use-memo-ref-missing-reactive.ts:9:21
> 12 | }
| ^^^^^^^^^^^^^^^^^^^^^^
> 13 | }, []);
| ^^^^ Could not preserve existing manual 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
14 | }
15 |
16 | export const FIXTURE_ENTRYPOINT = {
```

View File

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

View File

@@ -20,17 +20,19 @@ function useHook(x) {
```
Found 1 error:
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
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.
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]);
| ^^^^^^^^^^^^^^^^^^^^^^^ Could not preserve existing manual 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
10 | }
11 |
```

View File

@@ -26,9 +26,9 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
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
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.
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,10 +44,12 @@ error.useCallback-conditional-access-noAlloc.ts:5:21
> 9 | };
| ^^^^^^^^^^^^
> 10 | }, [propA, propB.x.y]);
| ^^^^ Could not preserve existing manual 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
11 | }
12 |
13 | export const FIXTURE_ENTRYPOINT = {
```

View File

@@ -25,9 +25,9 @@ function Component({propA, propB}) {
```
Found 1 error:
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
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.
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,9 +49,11 @@ error.useCallback-infer-less-specific-conditional-access.ts:6:21
> 13 | }
| ^^^^^^^^^^^^^^^^^
> 14 | }, [propA?.a, propB.x.y]);
| ^^^^ Could not preserve existing manual 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
15 | }
16 |
```

View File

@@ -18,9 +18,9 @@ function Component({propA}) {
```
Found 1 error:
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
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.
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,9 +30,11 @@ error.useCallback-property-call-dep.ts:5:21
> 6 | return propA.x();
| ^^^^^^^^^^^^^^^^^^^^^
> 7 | }, [propA.x]);
| ^^^^ Could not preserve existing manual 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
8 | }
9 |
```

View File

@@ -20,17 +20,19 @@ function useHook(x) {
```
Found 1 error:
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
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.
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]);
| ^^^^^^^^^^^^^^^^ Could not preserve existing manual 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
10 | }
11 |
```

View File

@@ -25,9 +25,9 @@ function Component({propA, propB}) {
```
Found 1 error:
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
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.
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,9 +49,11 @@ error.useMemo-infer-less-specific-conditional-access.ts:6:17
> 13 | }
| ^^^^^^^^^^^^^^^^^
> 14 | }, [propA?.a, propB.x.y]);
| ^^^^ Could not preserve existing manual 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
15 | }
16 |
```

View File

@@ -25,9 +25,9 @@ function Component({propA, propB}) {
```
Found 2 errors:
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
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.
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,12 +49,14 @@ error.useMemo-infer-less-specific-conditional-value-block.ts:6:17
> 13 | }
| ^^^^^^^^^^^^^^^^^
> 14 | }, [propA.a, propB.x.y]);
| ^^^^ Could not preserve existing manual 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
15 | }
16 |
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. 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.
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.
error.useMemo-infer-less-specific-conditional-value-block.ts:6:17
4 |
@@ -76,9 +78,11 @@ error.useMemo-infer-less-specific-conditional-value-block.ts:6:17
> 13 | }
| ^^^^^^^^^^^^^^^^^
> 14 | }, [propA.a, propB.x.y]);
| ^^^^ Could not preserve existing manual 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
15 | }
16 |
```

View File

@@ -20,9 +20,9 @@ function Component({propA}) {
```
Found 1 error:
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
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.
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,9 +36,11 @@ error.useMemo-property-call-chained-object.ts:5:17
> 8 | };
| ^^^^^^^^^^^^
> 9 | }, [propA.x]);
| ^^^^ Could not preserve existing manual 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
10 | }
11 |
```

View File

@@ -18,9 +18,9 @@ function Component({propA}) {
```
Found 1 error:
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
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.
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,9 +30,11 @@ error.useMemo-property-call-dep.ts:5:17
> 6 | return propA.x();
| ^^^^^^^^^^^^^^^^^^^^^
> 7 | }, [propA.x]);
| ^^^^ Could not preserve existing manual 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
8 | }
9 |
```

View File

@@ -31,9 +31,9 @@ function useFoo(input1) {
```
Found 1 error:
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
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.
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,10 +43,12 @@ error.useMemo-unrelated-mutation-in-depslist.ts:16:27
> 17 | return [y];
| ^^^^^^^^^^^^^^^
> 18 | }, [(mutate(x), y)]);
| ^^^^ Could not preserve existing manual 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
19 |
20 | return [x, memoized];
21 | }
```

View File

@@ -25,9 +25,9 @@ function Component(props) {
```
Found 1 error:
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
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.
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,10 +47,12 @@ error.todo-optional-member-expression-with-conditional-optional.ts:4:23
> 10 | return x;
| ^^^^^^^^^^^^^^^^^
> 11 | }, [props?.items, props.cond]);
| ^^^^ Could not preserve existing manual 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
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: 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
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.
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,10 +47,12 @@ error.todo-optional-member-expression-with-conditional.ts:4:23
> 10 | return x;
| ^^^^^^^^^^^^^^^^^
> 11 | }, [props?.items, props.cond]);
| ^^^^ Could not preserve existing manual 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
12 | return (
13 | <ValidateMemoization inputs={[props?.items, props.cond]} output={data} />
14 | );
```

View File

@@ -1,62 +0,0 @@
## Input
```javascript
import {Stringify} from 'shared-runtime';
function Component(props) {
const {a} = props;
const {b, ...rest} = a;
// Local mutation of `rest` is allowed since it is a newly allocated object
rest.value = props.value;
return <Stringify rest={rest} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{a: {b: 0, other: 'other'}, value: 42}],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
import { Stringify } from "shared-runtime";
function Component(props) {
const $ = _c(5);
const { a } = props;
let rest;
if ($[0] !== a || $[1] !== props.value) {
const { b, ...t0 } = a;
rest = t0;
rest.value = props.value;
$[0] = a;
$[1] = props.value;
$[2] = rest;
} else {
rest = $[2];
}
let t0;
if ($[3] !== rest) {
t0 = <Stringify rest={rest} />;
$[3] = rest;
$[4] = t0;
} else {
t0 = $[4];
}
return t0;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{ a: { b: 0, other: "other" }, value: 42 }],
};
```
### Eval output
(kind: ok) <div>{"rest":{"other":"other","value":42}}</div>

View File

@@ -1,14 +0,0 @@
import {Stringify} from 'shared-runtime';
function Component(props) {
const {a} = props;
const {b, ...rest} = a;
// Local mutation of `rest` is allowed since it is a newly allocated object
rest.value = props.value;
return <Stringify rest={rest} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{a: {b: 0, other: 'other'}, value: 42}],
};

View File

@@ -48,26 +48,32 @@ import { c as _c } from "react/compiler-runtime";
import { StaticText1, Stringify, Text } from "shared-runtime";
function Component(props) {
const $ = _c(4);
const $ = _c(6);
const { buttons } = props;
let t0;
let nonPrimaryButtons;
if ($[0] !== buttons) {
const [, ...nonPrimaryButtons] = buttons;
t0 = nonPrimaryButtons.map(_temp);
[, ...nonPrimaryButtons] = buttons;
$[0] = buttons;
$[1] = t0;
$[1] = nonPrimaryButtons;
} else {
t0 = $[1];
nonPrimaryButtons = $[1];
}
let t0;
if ($[2] !== nonPrimaryButtons) {
t0 = nonPrimaryButtons.map(_temp);
$[2] = nonPrimaryButtons;
$[3] = t0;
} else {
t0 = $[3];
}
const renderedNonPrimaryButtons = t0;
let t1;
if ($[2] !== renderedNonPrimaryButtons) {
if ($[4] !== renderedNonPrimaryButtons) {
t1 = <StaticText1>{renderedNonPrimaryButtons}</StaticText1>;
$[2] = renderedNonPrimaryButtons;
$[3] = t1;
$[4] = renderedNonPrimaryButtons;
$[5] = t1;
} else {
t1 = $[3];
t1 = $[5];
}
return t1;
}

View File

@@ -111,7 +111,7 @@ function createBridge() {
chrome.devtools.panels.elements.onSelectionChanged.removeListener(
onBrowserElementSelectionChanged,
);
if (sourcesPanel && sourcesPanel.onSelectionChanged) {
if (sourcesPanel) {
currentSelectedSource = null;
sourcesPanel.onSelectionChanged.removeListener(
onBrowserSourceSelectionChanged,
@@ -124,7 +124,7 @@ function createBridge() {
chrome.devtools.panels.elements.onSelectionChanged.addListener(
onBrowserElementSelectionChanged,
);
if (sourcesPanel && sourcesPanel.onSelectionChanged) {
if (sourcesPanel) {
sourcesPanel.onSelectionChanged.addListener(
onBrowserSourceSelectionChanged,
);
@@ -317,7 +317,7 @@ function createSourcesEditorPanel() {
}
const sourcesPanel = chrome.devtools.panels.sources;
if (!sourcesPanel || !sourcesPanel.createSidebarPane) {
if (!sourcesPanel) {
// Firefox doesn't currently support extending the source panel.
return;
}