Compare commits

..

2 Commits

Author SHA1 Message Date
Joe Savona
6cd727ccbd [compiler] clarify text for setState-in-effect error 2025-07-24 16:11:39 -07:00
Joe Savona
294fa2c422 [compiler] Fix for edge cases of mutation of potentially frozen values
Fixes two related cases of mutation of potentially frozen values.

The first is method calls on frozen values. Previously, we modeled unknown function calls as potentially aliasing their receiver+args into the return value. If the receiver or argument were known to be frozen, then we would downgrade the `Alias` effect into an `ImmutableCapture`. However, within a function expression it's possible to call a function using a frozen value as an argument (that gets `Alias`-ed into the return) but where we don't have the context locally to know that the value is frozen.

This results in cases like this:

```js
const frozen = useContext(...);
useEffect(() => {
  frozen.method().property = true;
  ^^^^^^^^^^^^^^^^^^^^^^^^ cannot mutate frozen value
}, [...]);
```

Within the function we would infer:

```
t0 = MethodCall ...
  Create t0 = mutable
  Alias t0 <- frozen
t1 = PropertyStore ...
  Mutate t0
```

And then transitively infer the function expression as having a `Mutate 'frozen'` effect, which when evaluated against the outer context (`frozen` is frozen) is an error.

The fix is to model unknown function calls as _maybe_ aliasing their receiver/args in the return, and then considering mutations of a maybe-aliased value to only be a conditional mutation of the source:


```
t0 = MethodCall ...
  Create t0 = mutable
  MaybeAlias t0 <- frozen // maybe alias now
t1 = PropertyStore ...
  Mutate t0
```

Then, the `Mutate t0` turns into a `MutateConditional 'frozen'`, which just gets ignored when we process the outer context.

The second, related fix is for known mutation of phis that may be a frozen value. The previous inference model correctly recorded these as errors, the new model does not. We now correctly report a validation error for this case in the new model.
2025-07-24 16:01:41 -07:00
195 changed files with 1743 additions and 4567 deletions

View File

@@ -608,7 +608,6 @@ module.exports = {
symbol: 'readonly',
SyntheticEvent: 'readonly',
SyntheticMouseEvent: 'readonly',
SyntheticPointerEvent: 'readonly',
Thenable: 'readonly',
TimeoutID: 'readonly',
WheelEventHandler: 'readonly',

View File

@@ -1,8 +1,3 @@
## 19.1.1 (July 28, 2025)
### React
* Fixed Owner Stacks to work with ES2015 function.name semantics ([#33680](https://github.com/facebook/react/pull/33680) by @hoxyq)
## 19.1.0 (March 28, 2025)
### Owner Stack

View File

@@ -219,7 +219,6 @@ function compile(
validateNoImpureFunctionsInRender: true,
validateStaticComponents: true,
validateNoFreezingKnownMutableFunctions: true,
validateNoVoidUseMemo: true,
}
: {
/* use defaults for compiler mode */

View File

@@ -174,7 +174,7 @@ function runWithEnvironment(
!env.config.disableMemoizationForDebugging &&
!env.config.enableChangeDetectionForDebugging
) {
dropManualMemoization(hir).unwrap();
dropManualMemoization(hir);
log({kind: 'hir', name: 'DropManualMemoization', value: hir});
}

View File

@@ -189,7 +189,6 @@ export function lower(
const fallthrough = builder.reserve('block');
const terminal: ReturnTerminal = {
kind: 'return',
returnVariant: 'Implicit',
loc: GeneratedSource,
value: lowerExpressionToTemporary(builder, body),
id: makeInstructionId(0),
@@ -220,7 +219,6 @@ export function lower(
builder.terminate(
{
kind: 'return',
returnVariant: 'Void',
loc: GeneratedSource,
value: lowerValueToTemporary(builder, {
kind: 'Primitive',
@@ -304,7 +302,6 @@ function lowerStatement(
}
const terminal: ReturnTerminal = {
kind: 'return',
returnVariant: 'Explicit',
loc: stmt.node.loc ?? GeneratedSource,
value,
id: makeInstructionId(0),

View File

@@ -608,7 +608,7 @@ export const EnvironmentConfigSchema = z.object({
*
* Here the variables `ref` and `myRef` will be typed as Refs.
*/
enableTreatRefLikeIdentifiersAsRefs: z.boolean().default(true),
enableTreatRefLikeIdentifiersAsRefs: z.boolean().default(false),
/*
* If specified a value, the compiler lowers any calls to `useContext` to use
@@ -631,17 +631,6 @@ export const EnvironmentConfigSchema = z.object({
* ```
*/
lowerContextAccess: ExternalFunctionSchema.nullable().default(null),
/**
* If enabled, will validate useMemos that don't return any values:
*
* Valid:
* useMemo(() => foo, [foo]);
* useMemo(() => { return foo }, [foo]);
* Invalid:
* useMemo(() => { ... }, [...]);
*/
validateNoVoidUseMemo: z.boolean().default(false),
});
export type EnvironmentConfig = z.infer<typeof EnvironmentConfigSchema>;

View File

@@ -446,20 +446,8 @@ export type ThrowTerminal = {
};
export type Case = {test: Place | null; block: BlockId};
export type ReturnVariant = 'Void' | 'Implicit' | 'Explicit';
export type ReturnTerminal = {
kind: 'return';
/**
* Void:
* () => { ... }
* function() { ... }
* Implicit (ArrowFunctionExpression only):
* () => foo
* Explicit:
* () => { return ... }
* function () { return ... }
*/
returnVariant: ReturnVariant;
loc: SourceLocation;
value: Place;
id: InstructionId;

View File

@@ -1211,8 +1211,6 @@ addObject(BUILTIN_SHAPES, BuiltInRefValueId, [
['*', {kind: 'Object', shapeId: BuiltInRefValueId}],
]);
addObject(BUILTIN_SHAPES, ReanimatedSharedValueId, []);
addFunction(
BUILTIN_SHAPES,
[],

View File

@@ -215,7 +215,7 @@ export function printTerminal(terminal: Terminal): Array<string> | string {
break;
}
case 'return': {
value = `[${terminal.id}] Return ${terminal.returnVariant}${
value = `[${terminal.id}] Return${
terminal.value != null ? ' ' + printPlace(terminal.value) : ''
}`;
if (terminal.effects != null) {

View File

@@ -777,7 +777,6 @@ export function mapTerminalSuccessors(
case 'return': {
return {
kind: 'return',
returnVariant: terminal.returnVariant,
loc: terminal.loc,
value: terminal.value,
id: makeInstructionId(0),

View File

@@ -5,12 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {
CompilerDiagnostic,
CompilerError,
ErrorSeverity,
SourceLocation,
} from '..';
import {CompilerError, SourceLocation} from '..';
import {
CallExpression,
Effect,
@@ -35,7 +30,6 @@ import {
makeInstructionId,
} from '../HIR';
import {createTemporaryPlace, markInstructionIds} from '../HIR/HIRBuilder';
import {Result} from '../Utils/Result';
type ManualMemoCallee = {
kind: 'useMemo' | 'useCallback';
@@ -289,43 +283,26 @@ function extractManualMemoizationArgs(
instr: TInstruction<CallExpression> | TInstruction<MethodCall>,
kind: 'useCallback' | 'useMemo',
sidemap: IdentifierSidemap,
errors: CompilerError,
): {
fnPlace: Place | null;
fnPlace: Place;
depsList: Array<ManualMemoDependency> | null;
} {
const [fnPlace, depsListPlace] = instr.value.args as Array<
Place | SpreadPattern | undefined
>;
if (fnPlace == null) {
errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.InvalidReact,
category: `Expected a callback function to be passed to ${kind}`,
description: `Expected a callback function to be passed to ${kind}`,
suggestions: null,
}).withDetail({
kind: 'error',
loc: instr.value.loc,
message: `Expected a callback function to be passed to ${kind}`,
}),
);
return {fnPlace: null, depsList: null};
CompilerError.throwInvalidReact({
reason: `Expected a callback function to be passed to ${kind}`,
loc: instr.value.loc,
suggestions: null,
});
}
if (fnPlace.kind === 'Spread' || depsListPlace?.kind === 'Spread') {
errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.InvalidReact,
category: `Unexpected spread argument to ${kind}`,
description: `Unexpected spread argument to ${kind}`,
suggestions: null,
}).withDetail({
kind: 'error',
loc: instr.value.loc,
message: `Unexpected spread argument to ${kind}`,
}),
);
return {fnPlace: null, depsList: null};
CompilerError.throwInvalidReact({
reason: `Unexpected spread argument to ${kind}`,
loc: instr.value.loc,
suggestions: null,
});
}
let depsList: Array<ManualMemoDependency> | null = null;
if (depsListPlace != null) {
@@ -333,40 +310,23 @@ function extractManualMemoizationArgs(
depsListPlace.identifier.id,
);
if (maybeDepsList == null) {
errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.InvalidReact,
category: `Expected the dependency list for ${kind} to be an array literal`,
description: `Expected the dependency list for ${kind} to be an array literal`,
suggestions: null,
}).withDetail({
kind: 'error',
loc: depsListPlace.loc,
message: `Expected the dependency list for ${kind} to be an array literal`,
}),
);
return {fnPlace, depsList: null};
CompilerError.throwInvalidReact({
reason: `Expected the dependency list for ${kind} to be an array literal`,
suggestions: null,
loc: depsListPlace.loc,
});
}
depsList = [];
for (const dep of maybeDepsList) {
depsList = maybeDepsList.map(dep => {
const maybeDep = sidemap.maybeDeps.get(dep.identifier.id);
if (maybeDep == null) {
errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.InvalidReact,
category: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
description: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
suggestions: null,
}).withDetail({
kind: 'error',
loc: dep.loc,
message: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
}),
);
} else {
depsList.push(maybeDep);
CompilerError.throwInvalidReact({
reason: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
suggestions: null,
loc: dep.loc,
});
}
}
return maybeDep;
});
}
return {
fnPlace,
@@ -381,14 +341,8 @@ function extractManualMemoizationArgs(
* rely on type inference to find useMemo/useCallback invocations, and instead does basic tracking
* of globals and property loads to find both direct calls as well as usage via the React namespace,
* eg `React.useMemo()`.
*
* This pass also validates that useMemo callbacks return a value (not void), ensuring that useMemo
* is only used for memoizing values and not for running arbitrary side effects.
*/
export function dropManualMemoization(
func: HIRFunction,
): Result<void, CompilerError> {
const errors = new CompilerError();
export function dropManualMemoization(func: HIRFunction): void {
const isValidationEnabled =
func.env.config.validatePreserveExistingMemoizationGuarantees ||
func.env.config.validateNoSetStateInRender ||
@@ -435,47 +389,7 @@ export function dropManualMemoization(
instr as TInstruction<CallExpression> | TInstruction<MethodCall>,
manualMemo.kind,
sidemap,
errors,
);
if (fnPlace == null) {
continue;
}
/**
* Bailout on void return useMemos. This is an anti-pattern where code might be using
* useMemo like useEffect: running arbirtary side-effects synced to changes in specific
* values.
*/
if (
func.env.config.validateNoVoidUseMemo &&
manualMemo.kind === 'useMemo'
) {
const funcToCheck = sidemap.functions.get(
fnPlace.identifier.id,
)?.value;
if (funcToCheck !== undefined && funcToCheck.loweredFunc.func) {
if (!hasNonVoidReturn(funcToCheck.loweredFunc.func)) {
errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.InvalidReact,
category: 'useMemo() callbacks must return a value',
description: `This ${
manualMemo.loadInstr.value.kind === 'PropertyLoad'
? 'React.useMemo'
: 'useMemo'
} callback doesn't return a value. useMemo is for computing and caching values, not for arbitrary side effects.`,
suggestions: null,
}).withDetail({
kind: 'error',
loc: instr.value.loc,
message: 'useMemo() callbacks must return a value',
}),
);
}
}
}
instr.value = getManualMemoizationReplacement(
fnPlace,
instr.value.loc,
@@ -496,19 +410,11 @@ export function dropManualMemoization(
* is rare and likely sketchy.
*/
if (!sidemap.functions.has(fnPlace.identifier.id)) {
errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.InvalidReact,
category: `Expected the first argument to be an inline function expression`,
description: `Expected the first argument to be an inline function expression`,
suggestions: [],
}).withDetail({
kind: 'error',
loc: fnPlace.loc,
message: `Expected the first argument to be an inline function expression`,
}),
);
continue;
CompilerError.throwInvalidReact({
reason: `Expected the first argument to be an inline function expression`,
suggestions: [],
loc: fnPlace.loc,
});
}
const memoDecl: Place =
manualMemo.kind === 'useMemo'
@@ -580,8 +486,6 @@ export function dropManualMemoization(
markInstructionIds(func.body);
}
}
return errors.asResult();
}
function findOptionalPlaces(fn: HIRFunction): Set<IdentifierId> {
@@ -626,17 +530,3 @@ function findOptionalPlaces(fn: HIRFunction): Set<IdentifierId> {
}
return optionals;
}
function hasNonVoidReturn(func: HIRFunction): boolean {
for (const [, block] of func.body.blocks) {
if (block.terminal.kind === 'return') {
if (
block.terminal.returnVariant === 'Explicit' ||
block.terminal.returnVariant === 'Implicit'
) {
return true;
}
}
}
return false;
}

View File

@@ -249,7 +249,6 @@ export function inferMutationAliasingRanges(
}
for (const param of [...fn.context, ...fn.params]) {
const place = param.kind === 'Identifier' ? param : param.place;
const node = state.nodes.get(place.identifier);
if (node == null) {
continue;

View File

@@ -21,6 +21,7 @@ import {
isStableType,
isStableTypeContainer,
isUseOperator,
isUseRefType,
} from '../HIR';
import {PostDominator} from '../HIR/Dominator';
import {
@@ -69,6 +70,13 @@ class StableSidemap {
isStable: false,
});
}
} else if (
this.env.config.enableTreatRefLikeIdentifiersAsRefs &&
isUseRefType(lvalue.identifier)
) {
this.map.set(lvalue.identifier.id, {
isStable: true,
});
}
break;
}

View File

@@ -237,7 +237,6 @@ function emitSelectorFn(env: Environment, keys: Array<string>): Instruction {
terminal: {
id: makeInstructionId(0),
kind: 'return',
returnVariant: 'Explicit',
loc: GeneratedSource,
value: arrayInstr.lvalue,
effects: null,

View File

@@ -352,7 +352,6 @@ function emitOutlinedFn(
terminal: {
id: makeInstructionId(0),
kind: 'return',
returnVariant: 'Explicit',
loc: GeneratedSource,
value: instructions.at(-1)!.lvalue,
effects: null,

View File

@@ -14,7 +14,6 @@ import {
Identifier,
IdentifierId,
Instruction,
InstructionKind,
makePropertyLiteral,
makeType,
PropType,
@@ -195,29 +194,12 @@ function* generateInstructionTypes(
break;
}
// We intentionally do not infer types for most context variables
// We intentionally do not infer types for context variables
case 'DeclareContext':
case 'StoreContext':
case 'LoadContext': {
break;
}
case 'StoreContext': {
/**
* The caveat is StoreContext const, where we know the value is
* assigned once such that everywhere the value is accessed, it
* must have the same type from the rvalue.
*
* A concrete example where this is useful is `const ref = useRef()`
* where the ref is referenced before its declaration in a function
* expression, causing it to be converted to a const context variable.
*/
if (value.lvalue.kind === InstructionKind.Const) {
yield equation(
value.lvalue.place.identifier.type,
value.value.identifier.type,
);
}
break;
}
case 'StoreLocal': {
if (env.config.enableUseTypeAnnotations) {
@@ -451,18 +433,6 @@ function* generateInstructionTypes(
case 'JsxExpression':
case 'JsxFragment': {
if (env.config.enableTreatRefLikeIdentifiersAsRefs) {
if (value.kind === 'JsxExpression') {
for (const prop of value.props) {
if (prop.kind === 'JsxAttribute' && prop.name === 'ref') {
yield equation(prop.place.identifier.type, {
kind: 'Object',
shapeId: BuiltInUseRefId,
});
}
}
}
}
yield equation(left, {kind: 'Object', shapeId: BuiltInJsxId});
break;
}
@@ -478,36 +448,7 @@ function* generateInstructionTypes(
yield equation(left, returnType);
break;
}
case 'PropertyStore': {
/**
* Infer types based on assignments to known object properties
* This is important for refs, where assignment to `<maybeRef>.current`
* can help us infer that an object itself is a ref
*/
yield equation(
/**
* Our property type declarations are best-effort and we haven't tested
* using them to drive inference of rvalues from lvalues. We want to emit
* a Property type in order to infer refs from `.current` accesses, but
* stay conservative by not otherwise inferring anything about rvalues.
* So we use a dummy type here.
*
* TODO: consider using the rvalue type here
*/
makeType(),
// unify() only handles properties in the second position
{
kind: 'Property',
objectType: value.object.identifier.type,
objectName: getName(names, value.object.identifier.id),
propertyName: {
kind: 'literal',
value: value.property,
},
},
);
break;
}
case 'PropertyStore':
case 'DeclareLocal':
case 'RegExpLiteral':
case 'MetaProperty':

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 {
BlockId,
HIRFunction,
@@ -27,7 +23,6 @@ import {
eachTerminalOperand,
} from '../HIR/visitors';
import {Err, Ok, Result} from '../Utils/Result';
import {retainWhere} from '../Utils/utils';
/**
* Validates that a function does not access a ref value during render. This includes a partial check
@@ -80,18 +75,8 @@ type RefAccessRefType =
type RefFnType = {readRefEffect: boolean; returnType: RefAccessType};
class Env {
class Env extends Map<IdentifierId, RefAccessType> {
#changed = false;
#data: Map<IdentifierId, RefAccessType> = new Map();
#temporaries: Map<IdentifierId, Place> = new Map();
lookup(place: Place): Place {
return this.#temporaries.get(place.identifier.id) ?? place;
}
define(place: Place, value: Place): void {
this.#temporaries.set(place.identifier.id, value);
}
resetChanged(): void {
this.#changed = false;
@@ -101,14 +86,8 @@ class Env {
return this.#changed;
}
get(key: IdentifierId): RefAccessType | undefined {
const operandId = this.#temporaries.get(key)?.identifier.id ?? key;
return this.#data.get(operandId);
}
set(key: IdentifierId, value: RefAccessType): this {
const operandId = this.#temporaries.get(key)?.identifier.id ?? key;
const cur = this.#data.get(operandId);
override set(key: IdentifierId, value: RefAccessType): this {
const cur = this.get(key);
const widenedValue = joinRefAccessTypes(value, cur ?? {kind: 'None'});
if (
!(cur == null && widenedValue.kind === 'None') &&
@@ -116,8 +95,7 @@ class Env {
) {
this.#changed = true;
}
this.#data.set(operandId, widenedValue);
return this;
return super.set(key, widenedValue);
}
}
@@ -125,48 +103,9 @@ export function validateNoRefAccessInRender(
fn: HIRFunction,
): Result<void, CompilerError> {
const env = new Env();
collectTemporariesSidemap(fn, env);
return validateNoRefAccessInRenderImpl(fn, env).map(_ => undefined);
}
function collectTemporariesSidemap(fn: HIRFunction, env: Env): void {
for (const block of fn.body.blocks.values()) {
for (const instr of block.instructions) {
const {lvalue, value} = instr;
switch (value.kind) {
case 'LoadLocal': {
const temp = env.lookup(value.place);
if (temp != null) {
env.define(lvalue, temp);
}
break;
}
case 'StoreLocal': {
const temp = env.lookup(value.value);
if (temp != null) {
env.define(lvalue, temp);
env.define(value.lvalue.place, temp);
}
break;
}
case 'PropertyLoad': {
if (
isUseRefType(value.object.identifier) &&
value.property === 'current'
) {
continue;
}
const temp = env.lookup(value.object);
if (temp != null) {
env.define(lvalue, temp);
}
break;
}
}
}
}
}
function refTypeOfType(place: Place): RefAccessType {
if (isRefValueType(place.identifier)) {
return {kind: 'RefValue'};
@@ -319,27 +258,12 @@ function validateNoRefAccessInRenderImpl(
env.set(place.identifier.id, type);
}
const interpolatedAsJsx = new Set<IdentifierId>();
for (const block of fn.body.blocks.values()) {
for (const instr of block.instructions) {
const {value} = instr;
if (value.kind === 'JsxExpression' || value.kind === 'JsxFragment') {
if (value.children != null) {
for (const child of value.children) {
interpolatedAsJsx.add(child.identifier.id);
}
}
}
}
}
for (let i = 0; (i == 0 || env.hasChanged()) && i < 10; i++) {
env.resetChanged();
returnValues = [];
const safeBlocks: Array<{block: BlockId; ref: RefId}> = [];
const safeBlocks = new Map<BlockId, RefId>();
const errors = new CompilerError();
for (const [, block] of fn.body.blocks) {
retainWhere(safeBlocks, entry => entry.block !== block.id);
for (const phi of block.phis) {
env.set(
phi.place.identifier.id,
@@ -461,79 +385,28 @@ function validateNoRefAccessInRenderImpl(
const hookKind = getHookKindForType(fn.env, callee.identifier.type);
let returnType: RefAccessType = {kind: 'None'};
const fnType = env.get(callee.identifier.id);
let didError = false;
if (fnType?.kind === 'Structure' && fnType.fn !== null) {
returnType = fnType.fn.returnType;
if (fnType.fn.readRefEffect) {
didError = true;
errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.InvalidReact,
category: 'Cannot access refs during render',
description: ERROR_DESCRIPTION,
}).withDetail({
kind: 'error',
loc: callee.loc,
message: `This function accesses a ref value`,
}),
);
errors.push({
severity: ErrorSeverity.InvalidReact,
reason:
'This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)',
loc: callee.loc,
description:
callee.identifier.name !== null &&
callee.identifier.name.kind === 'named'
? `Function \`${callee.identifier.name.value}\` accesses a ref`
: null,
suggestions: null,
});
}
}
/*
* If we already reported an error on this instruction, don't report
* duplicate errors
*/
if (!didError) {
const isRefLValue = isUseRefType(instr.lvalue.identifier);
for (const operand of eachInstructionValueOperand(instr.value)) {
/**
* By default we check that function call operands are not refs,
* ref values, or functions that can access refs.
*/
if (
isRefLValue ||
(hookKind != null &&
hookKind !== 'useState' &&
hookKind !== 'useReducer')
) {
/**
* Special cases:
*
* 1. the lvalue is a ref
* In general passing a ref to a function may access that ref
* value during render, so we disallow it.
*
* The main exception is the "mergeRefs" pattern, ie a function
* that accepts multiple refs as arguments (or an array of refs)
* and returns a new, aggregated ref. If the lvalue is a ref,
* we assume that the user is doing this pattern and allow passing
* refs.
*
* Eg `const mergedRef = mergeRefs(ref1, ref2)`
*
* 2. calling hooks
*
* Hooks are independently checked to ensure they don't access refs
* during render.
*/
validateNoDirectRefValueAccess(errors, operand, env);
} else if (interpolatedAsJsx.has(instr.lvalue.identifier.id)) {
/**
* Special case: the lvalue is passed as a jsx child
*
* For example `<Foo>{renderHelper(ref)}</Foo>`. Here we have more
* context and infer that the ref is being passed to a component-like
* render function which attempts to obey the rules.
*/
validateNoRefValueAccess(errors, env, operand);
} else {
validateNoRefPassedToFunction(
errors,
env,
operand,
operand.loc,
);
}
for (const operand of eachInstructionValueOperand(instr.value)) {
if (hookKind != null) {
validateNoDirectRefValueAccess(errors, operand, env);
} else {
validateNoRefAccess(errors, env, operand, operand.loc);
}
}
env.set(instr.lvalue.identifier.id, returnType);
@@ -566,39 +439,23 @@ function validateNoRefAccessInRenderImpl(
case 'PropertyStore':
case 'ComputedDelete':
case 'ComputedStore': {
const safe = safeBlocks.get(block.id);
const target = env.get(instr.value.object.identifier.id);
let safe: (typeof safeBlocks)['0'] | null | undefined = null;
if (
instr.value.kind === 'PropertyStore' &&
target != null &&
target.kind === 'Ref'
safe != null &&
target?.kind === 'Ref' &&
target.refId === safe
) {
safe = safeBlocks.find(entry => entry.ref === target.refId);
}
if (safe != null) {
retainWhere(safeBlocks, entry => entry !== safe);
safeBlocks.delete(block.id);
} else {
validateNoRefUpdate(errors, env, instr.value.object, instr.loc);
validateNoRefAccess(errors, env, instr.value.object, instr.loc);
}
if (
instr.value.kind === 'ComputedDelete' ||
instr.value.kind === 'ComputedStore'
) {
validateNoRefValueAccess(errors, env, instr.value.property);
}
if (
instr.value.kind === 'ComputedStore' ||
instr.value.kind === 'PropertyStore'
) {
validateNoDirectRefValueAccess(errors, instr.value.value, env);
const type = env.get(instr.value.value.identifier.id);
if (type != null && type.kind === 'Structure') {
let objectType: RefAccessType = type;
if (target != null) {
objectType = joinRefAccessTypes(objectType, target);
}
env.set(instr.value.object.identifier.id, objectType);
for (const operand of eachInstructionValueOperand(instr.value)) {
if (operand === instr.value.object) {
continue;
}
validateNoRefValueAccess(errors, env, operand);
}
break;
}
@@ -678,11 +535,8 @@ function validateNoRefAccessInRenderImpl(
if (block.terminal.kind === 'if') {
const test = env.get(block.terminal.test.identifier.id);
if (
test?.kind === 'Guard' &&
safeBlocks.find(entry => entry.ref === test.refId) == null
) {
safeBlocks.push({block: block.terminal.fallthrough, ref: test.refId});
if (test?.kind === 'Guard') {
safeBlocks.set(block.terminal.consequent, test.refId);
}
}
@@ -729,17 +583,18 @@ function destructure(
function guardCheck(errors: CompilerError, operand: Place, env: Env): void {
if (env.get(operand.identifier.id)?.kind === 'Guard') {
errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.InvalidReact,
category: 'Cannot access refs during render',
description: ERROR_DESCRIPTION,
}).withDetail({
kind: 'error',
loc: operand.loc,
message: `Cannot access ref value during render`,
}),
);
errors.push({
severity: ErrorSeverity.InvalidReact,
reason:
'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)',
loc: operand.loc,
description:
operand.identifier.name !== null &&
operand.identifier.name.kind === 'named'
? `Cannot access ref value \`${operand.identifier.name.value}\``
: null,
suggestions: null,
});
}
}
@@ -753,21 +608,22 @@ function validateNoRefValueAccess(
type?.kind === 'RefValue' ||
(type?.kind === 'Structure' && type.fn?.readRefEffect)
) {
errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.InvalidReact,
category: 'Cannot access refs during render',
description: ERROR_DESCRIPTION,
}).withDetail({
kind: 'error',
loc: (type.kind === 'RefValue' && type.loc) || operand.loc,
message: `Cannot access ref value during render`,
}),
);
errors.push({
severity: ErrorSeverity.InvalidReact,
reason:
'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)',
loc: (type.kind === 'RefValue' && type.loc) || operand.loc,
description:
operand.identifier.name !== null &&
operand.identifier.name.kind === 'named'
? `Cannot access ref value \`${operand.identifier.name.value}\``
: null,
suggestions: null,
});
}
}
function validateNoRefPassedToFunction(
function validateNoRefAccess(
errors: CompilerError,
env: Env,
operand: Place,
@@ -779,39 +635,18 @@ function validateNoRefPassedToFunction(
type?.kind === 'RefValue' ||
(type?.kind === 'Structure' && type.fn?.readRefEffect)
) {
errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.InvalidReact,
category: 'Cannot access refs during render',
description: ERROR_DESCRIPTION,
}).withDetail({
kind: 'error',
loc: (type.kind === 'RefValue' && type.loc) || loc,
message: `Passing a ref to a function may read its value during render`,
}),
);
}
}
function validateNoRefUpdate(
errors: CompilerError,
env: Env,
operand: Place,
loc: SourceLocation,
): void {
const type = destructure(env.get(operand.identifier.id));
if (type?.kind === 'Ref' || type?.kind === 'RefValue') {
errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.InvalidReact,
category: 'Cannot access refs during render',
description: ERROR_DESCRIPTION,
}).withDetail({
kind: 'error',
loc: (type.kind === 'RefValue' && type.loc) || loc,
message: `Cannot update ref during render`,
}),
);
errors.push({
severity: ErrorSeverity.InvalidReact,
reason:
'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)',
loc: (type.kind === 'RefValue' && type.loc) || loc,
description:
operand.identifier.name !== null &&
operand.identifier.name.kind === 'named'
? `Cannot access ref value \`${operand.identifier.name.value}\``
: null,
suggestions: null,
});
}
}
@@ -822,22 +657,17 @@ function validateNoDirectRefValueAccess(
): void {
const type = destructure(env.get(operand.identifier.id));
if (type?.kind === 'RefValue') {
errors.pushDiagnostic(
CompilerDiagnostic.create({
severity: ErrorSeverity.InvalidReact,
category: 'Cannot access refs during render',
description: ERROR_DESCRIPTION,
}).withDetail({
kind: 'error',
loc: type.loc ?? operand.loc,
message: `Cannot access ref value during render`,
}),
);
errors.push({
severity: ErrorSeverity.InvalidReact,
reason:
'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)',
loc: type.loc ?? operand.loc,
description:
operand.identifier.name !== null &&
operand.identifier.name.kind === 'named'
? `Cannot access ref value \`${operand.identifier.name.value}\``
: null,
suggestions: null,
});
}
}
const ERROR_DESCRIPTION =
'React refs are values that are not needed for rendering. Refs should only be accessed ' +
'outside of render, such as in event handlers or effects. ' +
'Accessing a ref value (the `current` property) during render can cause your component ' +
'not to update as expected (https://react.dev/reference/react/useRef)';

View File

@@ -1,52 +0,0 @@
## Input
```javascript
import {useRef} from 'react';
import {Stringify} from 'shared-runtime';
function Component(props) {
const ref = useRef(props.value);
const object = {};
object.foo = () => ref.current;
return <Stringify object={object} shouldInvokeFns={true} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
import { useRef } from "react";
import { Stringify } from "shared-runtime";
function Component(props) {
const $ = _c(1);
const ref = useRef(props.value);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
const object = {};
object.foo = () => ref.current;
t0 = <Stringify object={object} shouldInvokeFns={true} />;
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{ value: 42 }],
};
```
### Eval output
(kind: ok) <div>{"object":{"foo":{"kind":"Function","result":42}},"shouldInvokeFns":true}</div>

View File

@@ -1,14 +0,0 @@
import {useRef} from 'react';
import {Stringify} from 'shared-runtime';
function Component(props) {
const ref = useRef(props.value);
const object = {};
object.foo = () => ref.current;
return <Stringify object={object} shouldInvokeFns={true} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
};

View File

@@ -1,44 +0,0 @@
## Input
```javascript
// @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
import {useRef} from 'react';
function Component() {
const ref = useRef(null);
const ref2 = useRef(null);
const mergedRef = mergeRefs([ref], ref2);
return <Stringify ref={mergedRef} />;
}
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime"; // @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
import { useRef } from "react";
function Component() {
const $ = _c(1);
const ref = useRef(null);
const ref2 = useRef(null);
const mergedRef = mergeRefs([ref], ref2);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = <Stringify ref={mergedRef} />;
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}
```
### Eval output
(kind: exception) Fixture not implemented

View File

@@ -1,11 +0,0 @@
// @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
import {useRef} from 'react';
function Component() {
const ref = useRef(null);
const ref2 = useRef(null);
const mergedRef = mergeRefs([ref], ref2);
return <Stringify ref={mergedRef} />;
}

View File

@@ -1,45 +0,0 @@
## Input
```javascript
// @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
import {useRef} from 'react';
function Component(props) {
const ref = useRef(null);
return <Foo>{props.render({ref})}</Foo>;
}
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime"; // @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
import { useRef } from "react";
function Component(props) {
const $ = _c(3);
const ref = useRef(null);
const T0 = Foo;
const t0 = props.render({ ref });
let t1;
if ($[0] !== T0 || $[1] !== t0) {
t1 = <T0>{t0}</T0>;
$[0] = T0;
$[1] = t0;
$[2] = t1;
} else {
t1 = $[2];
}
return t1;
}
```
### Eval output
(kind: exception) Fixture not implemented

View File

@@ -1,9 +0,0 @@
// @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
import {useRef} from 'react';
function Component(props) {
const ref = useRef(null);
return <Foo>{props.render({ref})}</Foo>;
}

View File

@@ -1,49 +0,0 @@
## Input
```javascript
// @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
import {useRef} from 'react';
function Component(props) {
const ref = useRef(null);
return <Foo>{props.render(ref)}</Foo>;
}
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime"; // @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
import { useRef } from "react";
function Component(props) {
const $ = _c(4);
const ref = useRef(null);
let t0;
if ($[0] !== props.render) {
t0 = props.render(ref);
$[0] = props.render;
$[1] = t0;
} else {
t0 = $[1];
}
let t1;
if ($[2] !== t0) {
t1 = <Foo>{t0}</Foo>;
$[2] = t0;
$[3] = t1;
} else {
t1 = $[3];
}
return t1;
}
```
### Eval output
(kind: exception) Fixture not implemented

View File

@@ -1,9 +0,0 @@
// @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
import {useRef} from 'react';
function Component(props) {
const ref = useRef(null);
return <Foo>{props.render(ref)}</Foo>;
}

View File

@@ -27,7 +27,6 @@ function Component() {
}
function Child({ref}) {
'use no memo';
// This violates the rules of React, so we access the ref in a child
// component
return ref.current;
@@ -101,10 +100,8 @@ function Component() {
return t6;
}
function Child({ ref }) {
"use no memo";
// This violates the rules of React, so we access the ref in a child
// component
function Child(t0) {
const { ref } = t0;
return ref.current;
}

View File

@@ -23,7 +23,6 @@ function Component() {
}
function Child({ref}) {
'use no memo';
// This violates the rules of React, so we access the ref in a child
// component
return ref.current;

View File

@@ -23,7 +23,6 @@ function Component() {
}
function Child({ref}) {
'use no memo';
// This violates the rules of React, so we access the ref in a child
// component
return ref.current;
@@ -87,10 +86,8 @@ function Component() {
return t5;
}
function Child({ ref }) {
"use no memo";
// This violates the rules of React, so we access the ref in a child
// component
function Child(t0) {
const { ref } = t0;
return ref.current;
}

View File

@@ -19,7 +19,6 @@ function Component() {
}
function Child({ref}) {
'use no memo';
// This violates the rules of React, so we access the ref in a child
// component
return ref.current;

View File

@@ -25,7 +25,6 @@ function Component() {
}
function Child({ref}) {
'use no memo';
// This violates the rules of React, so we access the ref in a child
// component
return ref.current;
@@ -84,10 +83,8 @@ function Component() {
}
function _temp() {}
function Child({ ref }) {
"use no memo";
// This violates the rules of React, so we access the ref in a child
// component
function Child(t0) {
const { ref } = t0;
return ref.current;
}

View File

@@ -21,7 +21,6 @@ function Component() {
}
function Child({ref}) {
'use no memo';
// This violates the rules of React, so we access the ref in a child
// component
return ref.current;

View File

@@ -1,68 +0,0 @@
## Input
```javascript
// @validateRefAccessDuringRender
import {useRef} from 'react';
function Component(props) {
const ref = useRef(null);
if (ref.current == null) {
// the logical means the ref write is in a different block
// from the if consequent. this tests that the "safe" blocks
// extend up to the if's fallthrough
ref.current = props.unknownKey ?? props.value;
}
return <Child ref={ref} />;
}
function Child({ref}) {
'use no memo';
return ref.current;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRender
import { useRef } from "react";
function Component(props) {
const $ = _c(1);
const ref = useRef(null);
if (ref.current == null) {
ref.current = props.unknownKey ?? props.value;
}
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = <Child ref={ref} />;
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}
function Child({ ref }) {
"use no memo";
return ref.current;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{ value: 42 }],
};
```
### Eval output
(kind: ok) 42

View File

@@ -1,24 +0,0 @@
// @validateRefAccessDuringRender
import {useRef} from 'react';
function Component(props) {
const ref = useRef(null);
if (ref.current == null) {
// the logical means the ref write is in a different block
// from the if consequent. this tests that the "safe" blocks
// extend up to the if's fallthrough
ref.current = props.unknownKey ?? props.value;
}
return <Child ref={ref} />;
}
function Child({ref}) {
'use no memo';
return ref.current;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
};

View File

@@ -32,30 +32,48 @@ export const FIXTURE_ENTRYPOINT = {
## Error
```
Found 2 errors:
Found 4 errors:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)
error.capture-ref-for-mutation.ts:12:13
10 | };
11 | const moveLeft = {
> 12 | handler: handleKey('left')(),
| ^^^^^^^^^^^^^^^^^ This function accesses a ref value
| ^^^^^^^^^^^^^^^^^ This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)
13 | };
14 | const moveRight = {
15 | handler: handleKey('right')(),
Error: Cannot access refs during render
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
error.capture-ref-for-mutation.ts:12:13
10 | };
11 | const moveLeft = {
> 12 | handler: handleKey('left')(),
| ^^^^^^^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
13 | };
14 | const moveRight = {
15 | handler: handleKey('right')(),
Error: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)
error.capture-ref-for-mutation.ts:15:13
13 | };
14 | const moveRight = {
> 15 | handler: handleKey('right')(),
| ^^^^^^^^^^^^^^^^^^ This function accesses a ref value
| ^^^^^^^^^^^^^^^^^^ This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)
16 | };
17 | return [moveLeft, moveRight];
18 | }
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.capture-ref-for-mutation.ts:15:13
13 | };
14 | const moveRight = {
> 15 | handler: handleKey('right')(),
| ^^^^^^^^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
16 | };
17 | return [moveLeft, moveRight];
18 | }

View File

@@ -22,28 +22,24 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 2 errors:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.hook-ref-value.ts:5:23
3 | function Component(props) {
4 | const ref = useRef();
> 5 | useEffect(() => {}, [ref.current]);
| ^^^^^^^^^^^ Cannot access ref value during render
| ^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
6 | }
7 |
8 | export const FIXTURE_ENTRYPOINT = {
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.hook-ref-value.ts:5:23
3 | function Component(props) {
4 | const ref = useRef();
> 5 | useEffect(() => {}, [ref.current]);
| ^^^^^^^^^^^ Cannot access ref value during render
| ^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
6 | }
7 |
8 | export const FIXTURE_ENTRYPOINT = {

View File

@@ -17,15 +17,13 @@ function Component(props) {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.invalid-access-ref-during-render.ts:4:16
2 | function Component(props) {
3 | const ref = useRef(null);
> 4 | const value = ref.current;
| ^^^^^^^^^^^ Cannot access ref value during render
| ^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
5 | return value;
6 | }
7 |

View File

@@ -1,45 +0,0 @@
## Input
```javascript
import {useReducer, useRef} from 'react';
function Component(props) {
const ref = useRef(props.value);
const [state] = useReducer(
(state, action) => state + action,
0,
init => ref.current
);
return <Stringify state={state} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
};
```
## Error
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
error.invalid-access-ref-in-reducer-init.ts:8:4
6 | (state, action) => state + action,
7 | 0,
> 8 | init => ref.current
| ^^^^^^^^^^^^^^^^^^^ Passing a ref to a function may read its value during render
9 | );
10 |
11 | return <Stringify state={state} />;
```

View File

@@ -1,17 +0,0 @@
import {useReducer, useRef} from 'react';
function Component(props) {
const ref = useRef(props.value);
const [state] = useReducer(
(state, action) => state + action,
0,
init => ref.current
);
return <Stringify state={state} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
};

View File

@@ -1,41 +0,0 @@
## Input
```javascript
import {useReducer, useRef} from 'react';
function Component(props) {
const ref = useRef(props.value);
const [state] = useReducer(() => ref.current, null);
return <Stringify state={state} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
};
```
## Error
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
error.invalid-access-ref-in-reducer.ts:5:29
3 | function Component(props) {
4 | const ref = useRef(props.value);
> 5 | const [state] = useReducer(() => ref.current, null);
| ^^^^^^^^^^^^^^^^^ Passing a ref to a function may read its value during render
6 |
7 | return <Stringify state={state} />;
8 | }
```

View File

@@ -1,13 +0,0 @@
import {useReducer, useRef} from 'react';
function Component(props) {
const ref = useRef(props.value);
const [state] = useReducer(() => ref.current, null);
return <Stringify state={state} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
};

View File

@@ -1,37 +0,0 @@
## Input
```javascript
import {useRef} from 'react';
function Component() {
const ref = useRef(null);
const object = {};
object.foo = () => ref.current;
const refValue = object.foo();
return <div>{refValue}</div>;
}
```
## Error
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
error.invalid-access-ref-in-render-mutate-object-with-ref-function.ts:7:19
5 | const object = {};
6 | object.foo = () => ref.current;
> 7 | const refValue = object.foo();
| ^^^^^^^^^^ This function accesses a ref value
8 | return <div>{refValue}</div>;
9 | }
10 |
```

View File

@@ -1,9 +0,0 @@
import {useRef} from 'react';
function Component() {
const ref = useRef(null);
const object = {};
object.foo = () => ref.current;
const refValue = object.foo();
return <div>{refValue}</div>;
}

View File

@@ -1,41 +0,0 @@
## Input
```javascript
import {useRef, useState} from 'react';
function Component(props) {
const ref = useRef(props.value);
const [state] = useState(() => ref.current);
return <Stringify state={state} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
};
```
## Error
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
error.invalid-access-ref-in-state-initializer.ts:5:27
3 | function Component(props) {
4 | const ref = useRef(props.value);
> 5 | const [state] = useState(() => ref.current);
| ^^^^^^^^^^^^^^^^^ Passing a ref to a function may read its value during render
6 |
7 | return <Stringify state={state} />;
8 | }
```

View File

@@ -1,13 +0,0 @@
import {useRef, useState} from 'react';
function Component(props) {
const ref = useRef(props.value);
const [state] = useState(() => ref.current);
return <Stringify state={state} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
};

View File

@@ -21,15 +21,13 @@ function Component(props) {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.invalid-aliased-ref-in-callback-invoked-during-render-.ts:9:33
7 | return <Foo item={item} current={current} />;
8 | };
> 9 | return <Items>{props.items.map(item => renderItem(item))}</Items>;
| ^^^^^^^^^^^^^^^^^^^^^^^^ Cannot access ref value during render
| ^^^^^^^^^^^^^^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
10 | }
11 |
```

View File

@@ -1,36 +0,0 @@
## Input
```javascript
// @flow @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
import {makeObject_Primitives} from 'shared-runtime';
component Example() {
const fooRef = makeObject_Primitives();
fooRef.current = true;
return <Stringify foo={fooRef} />;
}
```
## Error
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
4 | component Example() {
5 | const fooRef = makeObject_Primitives();
> 6 | fooRef.current = true;
| ^^^^^^^^^^^^^^ Cannot update ref during render
7 |
8 | return <Stringify foo={fooRef} />;
9 | }
```

View File

@@ -1,9 +0,0 @@
// @flow @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
import {makeObject_Primitives} from 'shared-runtime';
component Example() {
const fooRef = makeObject_Primitives();
fooRef.current = true;
return <Stringify foo={fooRef} />;
}

View File

@@ -18,15 +18,13 @@ function Component() {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.invalid-disallow-mutating-ref-in-render.ts:4:2
2 | function Component() {
3 | const ref = useRef(null);
> 4 | ref.current = false;
| ^^^^^^^^^^^ Cannot update ref during render
| ^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
5 |
6 | return <button ref={ref} />;
7 | }

View File

@@ -21,17 +21,26 @@ function Component() {
## Error
```
Found 1 error:
Found 2 errors:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)
error.invalid-disallow-mutating-refs-in-render-transitive.ts:9:2
7 | };
8 | const changeRef = setRef;
> 9 | changeRef();
| ^^^^^^^^^ This function accesses a ref value
| ^^^^^^^^^ This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)
10 |
11 | return <button ref={ref} />;
12 | }
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.invalid-disallow-mutating-refs-in-render-transitive.ts:9:2
7 | };
8 | const changeRef = setRef;
> 9 | changeRef();
| ^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
10 |
11 | return <button ref={ref} />;
12 | }

View File

@@ -17,15 +17,13 @@ function Component(props) {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.invalid-pass-ref-to-function.ts:4:16
2 | function Component(props) {
3 | const ref = useRef(null);
> 4 | const x = foo(ref);
| ^^^ Passing a ref to a function may read its value during render
| ^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
5 | return x.current;
6 | }
7 |

View File

@@ -16,15 +16,13 @@ function Component({ref}) {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.invalid-read-ref-prop-in-render-destructure.ts:3:16
1 | // @validateRefAccessDuringRender @compilationMode:"infer"
2 | function Component({ref}) {
> 3 | const value = ref.current;
| ^^^^^^^^^^^ Cannot access ref value during render
| ^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
4 | return <div>{value}</div>;
5 | }
6 |

View File

@@ -16,15 +16,13 @@ function Component(props) {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.invalid-read-ref-prop-in-render-property-load.ts:3:16
1 | // @validateRefAccessDuringRender @compilationMode:"infer"
2 | function Component(props) {
> 3 | const value = props.ref.current;
| ^^^^^^^^^^^^^^^^^ Cannot access ref value during render
| ^^^^^^^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
4 | return <div>{value}</div>;
5 | }
6 |

View File

@@ -20,15 +20,13 @@ function Component(props) {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.invalid-ref-in-callback-invoked-during-render.ts:8:33
6 | return <Foo item={item} current={current} />;
7 | };
> 8 | return <Items>{props.items.map(item => renderItem(item))}</Items>;
| ^^^^^^^^^^^^^^^^^^^^^^^^ Cannot access ref value during render
| ^^^^^^^^^^^^^^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
9 | }
10 |
```

View File

@@ -16,15 +16,13 @@ function Component(props) {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.invalid-ref-value-as-props.ts:4:19
2 | function Component(props) {
3 | const ref = useRef(null);
> 4 | return <Foo ref={ref.current} />;
| ^^^^^^^^^^^ Cannot access ref value during render
| ^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
5 | }
6 |
```

View File

@@ -17,28 +17,24 @@ function Component(props) {
```
Found 2 errors:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.invalid-set-and-read-ref-during-render.ts:4:2
2 | function Component(props) {
3 | const ref = useRef(null);
> 4 | ref.current = props.value;
| ^^^^^^^^^^^ Cannot update ref during render
| ^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
5 | return ref.current;
6 | }
7 |
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.invalid-set-and-read-ref-during-render.ts:5:9
3 | const ref = useRef(null);
4 | ref.current = props.value;
> 5 | return ref.current;
| ^^^^^^^^^^^ Cannot access ref value during render
| ^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
6 | }
7 |
```

View File

@@ -17,28 +17,24 @@ function Component(props) {
```
Found 2 errors:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.invalid-set-and-read-ref-nested-property-during-render.ts:4:2
2 | function Component(props) {
3 | const ref = useRef({inner: null});
> 4 | ref.current.inner = props.value;
| ^^^^^^^^^^^ Cannot update ref during render
| ^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
5 | return ref.current.inner;
6 | }
7 |
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.invalid-set-and-read-ref-nested-property-during-render.ts:5:9
3 | const ref = useRef({inner: null});
4 | ref.current.inner = props.value;
> 5 | return ref.current.inner;
| ^^^^^^^^^^^^^^^^^ Cannot access ref value during render
| ^^^^^^^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
6 | }
7 |
```

View File

@@ -24,30 +24,27 @@ function Foo({a}) {
```
Found 2 errors:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.invalid-use-ref-added-to-dep-without-type-info.ts:10:21
8 | // however, this is an instance of accessing a ref during render and is disallowed
9 | // under React's rules, so we reject this input
> 10 | const x = {a, val: val.ref.current};
| ^^^^^^^^^^^^^^^ Cannot access ref value during render
| ^^^^^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
11 |
12 | return <VideoList videos={x} />;
13 | }
Error: Cannot access refs during render
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
error.invalid-use-ref-added-to-dep-without-type-info.ts:12:28
10 | const x = {a, val: val.ref.current};
error.invalid-use-ref-added-to-dep-without-type-info.ts:10:21
8 | // however, this is an instance of accessing a ref during render and is disallowed
9 | // under React's rules, so we reject this input
> 10 | const x = {a, val: val.ref.current};
| ^^^^^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
11 |
> 12 | return <VideoList videos={x} />;
| ^ Cannot access ref value during render
12 | return <VideoList videos={x} />;
13 | }
14 |
```

View File

@@ -19,15 +19,13 @@ function useHook({value}) {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.invalid-write-but-dont-read-ref-in-render.ts:5:2
3 | const ref = useRef(null);
4 | // Writing to a ref in render is against the rules:
> 5 | ref.current = value;
| ^^^^^^^^^^^ Cannot update ref during render
| ^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
6 | // returning a ref is allowed, so this alone doesn't trigger an error:
7 | return ref;
8 | }

View File

@@ -17,15 +17,13 @@ function Component(props) {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.invalid-write-ref-prop-in-render.ts:4:2
2 | function Component(props) {
3 | const ref = props.ref;
> 4 | ref.current = true;
| ^^^^^^^^^^^ Cannot update ref during render
| ^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
5 | return <div>{value}</div>;
6 | }
7 |

View File

@@ -27,26 +27,22 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 2 errors:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
6 | component C() {
7 | const r = useRef(DEFAULT_VALUE);
> 8 | if (r.current == DEFAULT_VALUE) {
| ^^^^^^^^^ Cannot access ref value during render
| ^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
9 | r.current = 1;
10 | }
11 | }
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
7 | const r = useRef(DEFAULT_VALUE);
8 | if (r.current == DEFAULT_VALUE) {
> 9 | r.current = 1;
| ^^^^^^^^^ Cannot update ref during render
| ^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
10 | }
11 | }
12 |

View File

@@ -25,14 +25,12 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
5 | const r = useRef(null);
6 | if (r.current == null) {
> 7 | f(r);
| ^ Passing a ref to a function may read its value during render
| ^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
8 | }
9 | }
10 |

View File

@@ -25,14 +25,12 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
5 | const r = useRef(null);
6 | if (r.current == null) {
> 7 | f(r.current);
| ^^^^^^^^^ Passing a ref to a function may read its value during render
| ^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
8 | }
9 | }
10 |

View File

@@ -26,14 +26,12 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
6 | if (r.current == null) {
7 | r.current = 42;
> 8 | r.current = 42;
| ^^^^^^^^^ Cannot update ref during render
| ^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
9 | }
10 | }
11 |

View File

@@ -26,26 +26,24 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 2 errors:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
4 | component C() {
5 | const r = useRef(null);
> 6 | const guard = r.current == null;
| ^^^^^^^^^^^^^^^^^ Cannot access ref value during render
| ^^^^^^^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
7 | if (guard) {
8 | r.current = 1;
9 | }
Error: Cannot access refs during render
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Cannot access ref value `guard`.
5 | const r = useRef(null);
6 | const guard = r.current == null;
> 7 | if (guard) {
| ^^^^^ Cannot access ref value during render
| ^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
8 | r.current = 1;
9 | }
10 | }

View File

@@ -26,14 +26,12 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
6 | const r2 = useRef(null);
7 | if (r.current == null) {
> 8 | r2.current = 1;
| ^^^^^^^^^^ Cannot update ref during render
| ^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
9 | }
10 | }
11 |

View File

@@ -26,14 +26,12 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
7 | r.current = 1;
8 | }
> 9 | f(r.current);
| ^^^^^^^^^ Passing a ref to a function may read its value during render
| ^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
10 | }
11 |
12 | export const FIXTURE_ENTRYPOINT = {

View File

@@ -26,14 +26,12 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
7 | r.current = 1;
8 | }
> 9 | r.current = 1;
| ^^^^^^^^^ Cannot update ref during render
| ^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
10 | }
11 |
12 | export const FIXTURE_ENTRYPOINT = {

View File

@@ -22,15 +22,13 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.ref-optional.ts:5:9
3 | function Component(props) {
4 | const ref = useRef();
> 5 | return ref?.current;
| ^^^^^^^^^^^^ Cannot access ref value during render
| ^^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
6 | }
7 |
8 | export const FIXTURE_ENTRYPOINT = {

View File

@@ -0,0 +1,45 @@
## Input
```javascript
import {Stringify, identity, mutate, CONST_TRUE} from 'shared-runtime';
function Foo(props, ref) {
const value = {};
if (CONST_TRUE) {
mutate(value);
return <Stringify ref={ref} />;
}
mutate(value);
if (CONST_TRUE) {
return <Stringify ref={identity(ref)} />;
}
return value;
}
export const FIXTURE_ENTRYPOINT = {
fn: Foo,
params: [{}, {current: 'fake-ref-object'}],
};
```
## Error
```
Found 1 error:
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.repro-ref-mutable-range.ts:11:36
9 | mutate(value);
10 | if (CONST_TRUE) {
> 11 | return <Stringify ref={identity(ref)} />;
| ^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
12 | }
13 | return value;
14 | }
```

View File

@@ -33,15 +33,13 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.ts:14:2
12 |
13 | // The ref is modified later, extending its range and preventing memoization of onChange
> 14 | ref.current.inner = null;
| ^^^^^^^^^^^ Cannot update ref during render
| ^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
15 |
16 | return <input onChange={onChange} />;
17 | }

View File

@@ -34,17 +34,26 @@ export const FIXTURE_ENTRYPOINT = {
## Error
```
Found 1 error:
Found 2 errors:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)
error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.ts:17:2
15 | ref.current.inner = null;
16 | };
> 17 | reset();
| ^^^^^ This function accesses a ref value
| ^^^^^ This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)
18 |
19 | return <input onChange={onChange} />;
20 | }
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.ts:17:2
15 | ref.current.inner = null;
16 | };
> 17 | reset();
| ^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
18 |
19 | return <input onChange={onChange} />;
20 | }

View File

@@ -32,15 +32,13 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.useCallback-set-ref-nested-property-dont-preserve-memoization.ts:13:2
11 | });
12 |
> 13 | ref.current.inner = null;
| ^^^^^^^^^^^ Cannot update ref during render
| ^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
14 |
15 | return <input onChange={onChange} />;
16 | }

View File

@@ -1,64 +0,0 @@
## Input
```javascript
// @validateNoVoidUseMemo
function Component() {
const value = useMemo(() => {
console.log('computing');
}, []);
const value2 = React.useMemo(() => {
console.log('computing');
}, []);
return (
<div>
{value}
{value2}
</div>
);
}
```
## Error
```
Found 2 errors:
Error: useMemo() callbacks must return a value
This useMemo callback doesn't return a value. useMemo is for computing and caching values, not for arbitrary side effects.
error.useMemo-no-return-value.ts:3:16
1 | // @validateNoVoidUseMemo
2 | function Component() {
> 3 | const value = useMemo(() => {
| ^^^^^^^^^^^^^^^
> 4 | console.log('computing');
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 5 | }, []);
| ^^^^^^^^^ useMemo() callbacks must return a value
6 | const value2 = React.useMemo(() => {
7 | console.log('computing');
8 | }, []);
Error: useMemo() callbacks must return a value
This React.useMemo callback doesn't return a value. useMemo is for computing and caching values, not for arbitrary side effects.
error.useMemo-no-return-value.ts:6:17
4 | console.log('computing');
5 | }, []);
> 6 | const value2 = React.useMemo(() => {
| ^^^^^^^^^^^^^^^^^^^^^
> 7 | console.log('computing');
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 8 | }, []);
| ^^^^^^^^^ useMemo() callbacks must return a value
9 | return (
10 | <div>
11 | {value}
```

View File

@@ -1,15 +0,0 @@
// @validateNoVoidUseMemo
function Component() {
const value = useMemo(() => {
console.log('computing');
}, []);
const value2 = React.useMemo(() => {
console.log('computing');
}, []);
return (
<div>
{value}
{value2}
</div>
);
}

View File

@@ -32,8 +32,6 @@ Found 1 error:
Error: Expected the dependency list for useMemo to be an array literal
Expected the dependency list for useMemo to be an array literal
error.useMemo-non-literal-depslist.ts:10:4
8 | return text.toUpperCase();
9 | },

View File

@@ -22,15 +22,13 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.validate-mutate-ref-arg-in-render.ts:3:14
1 | // @validateRefAccessDuringRender:true
2 | function Foo(props, ref) {
> 3 | console.log(ref.current);
| ^^^^^^^^^^^ Passing a ref to a function may read its value during render
| ^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
4 | return <div>{props.bar}</div>;
5 | }
6 |

View File

@@ -47,7 +47,7 @@ export const FIXTURE_ENTRYPOINT = {
## Logs
```
{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":158},"end":{"line":11,"column":1,"index":331},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"options":{"severity":"InvalidReact","category":"Cannot access refs during render","description":"React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":289},"end":{"line":9,"column":16,"index":303},"filename":"mutate-after-useeffect-ref-access.ts"},"message":"Cannot update ref during render"}]}}}
{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":158},"end":{"line":11,"column":1,"index":331},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"options":{"severity":"InvalidReact","category":"This value cannot be modified","description":"Modifying component props or hook arguments is not allowed. Consider using a local variable instead.","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":289},"end":{"line":9,"column":16,"index":303},"filename":"mutate-after-useeffect-ref-access.ts"},"message":"value cannot be modified"}]}}}
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":237},"end":{"line":8,"column":50,"index":285},"filename":"mutate-after-useeffect-ref-access.ts"},"decorations":[{"start":{"line":8,"column":24,"index":259},"end":{"line":8,"column":30,"index":265},"filename":"mutate-after-useeffect-ref-access.ts","identifierName":"arrRef"}]}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":158},"end":{"line":11,"column":1,"index":331},"filename":"mutate-after-useeffect-ref-access.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
```

View File

@@ -51,12 +51,12 @@ function RefsInEffects() {
const ref = useRefHelper();
const wrapped = useDeeperRefHelper();
let t0;
if ($[0] !== ref || $[1] !== wrapped.foo.current) {
if ($[0] !== ref.current || $[1] !== wrapped.foo.current) {
t0 = () => {
print(ref.current);
print(wrapped.foo.current);
};
$[0] = ref;
$[0] = ref.current;
$[1] = wrapped.foo.current;
$[2] = t0;
} else {

View File

@@ -47,7 +47,7 @@ export const FIXTURE_ENTRYPOINT = {
## Logs
```
{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":190},"end":{"line":11,"column":1,"index":363},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"options":{"severity":"InvalidReact","category":"Cannot access refs during render","description":"React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":321},"end":{"line":9,"column":16,"index":335},"filename":"mutate-after-useeffect-ref-access.ts"},"message":"Cannot update ref during render"}]}}}
{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":190},"end":{"line":11,"column":1,"index":363},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"options":{"severity":"InvalidReact","category":"This value cannot be modified","description":"Modifying component props or hook arguments is not allowed. Consider using a local variable instead.","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":321},"end":{"line":9,"column":16,"index":335},"filename":"mutate-after-useeffect-ref-access.ts"},"message":"value cannot be modified"}]}}}
{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":269},"end":{"line":8,"column":50,"index":317},"filename":"mutate-after-useeffect-ref-access.ts"},"decorations":[{"start":{"line":8,"column":24,"index":291},"end":{"line":8,"column":30,"index":297},"filename":"mutate-after-useeffect-ref-access.ts","identifierName":"arrRef"}]}
{"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":190},"end":{"line":11,"column":1,"index":363},"filename":"mutate-after-useeffect-ref-access.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
```

View File

@@ -0,0 +1,39 @@
## Input
```javascript
// @validatePreserveExistingMemoizationGuarantees
import {useCallback} from 'react';
function useHook(maybeRef) {
return useCallback(() => {
return [maybeRef.current];
}, [maybeRef]);
}
```
## Error
```
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. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `maybeRef.current`, but the source dependencies were [maybeRef]. Differences in ref.current access.
error.maybe-invalid-useCallback-read-maybeRef.ts:5:21
3 |
4 | function useHook(maybeRef) {
> 5 | return useCallback(() => {
| ^^^^^^^
> 6 | return [maybeRef.current];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 7 | }, [maybeRef]);
| ^^^^ Could not preserve existing manual memoization
8 | }
9 |
```

View File

@@ -0,0 +1,39 @@
## Input
```javascript
// @validatePreserveExistingMemoizationGuarantees
import {useMemo} from 'react';
function useHook(maybeRef, shouldRead) {
return useMemo(() => {
return () => [maybeRef.current];
}, [shouldRead, maybeRef]);
}
```
## Error
```
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. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `maybeRef.current`, but the source dependencies were [shouldRead, maybeRef]. Differences in ref.current access.
error.maybe-invalid-useMemo-read-maybeRef.ts:5:17
3 |
4 | function useHook(maybeRef, shouldRead) {
> 5 | return useMemo(() => {
| ^^^^^^^
> 6 | return () => [maybeRef.current];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 7 | }, [shouldRead, maybeRef]);
| ^^^^ Could not preserve existing manual memoization
8 | }
9 |
```

View File

@@ -25,15 +25,13 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
error.maybe-mutable-ref-not-preserved.ts:8:33
6 | function useFoo() {
7 | const r = useRef();
> 8 | return useMemo(() => makeArray(r), []);
| ^ Passing a ref to a function may read its value during render
| ^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
9 | }
10 |
11 | export const FIXTURE_ENTRYPOINT = {

View File

@@ -21,14 +21,12 @@ component Component(disableLocalRef, ref) {
```
Found 1 error:
Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)
Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
5 | const localRef = useFooRef();
6 | const mergedRef = useMemo(() => {
> 7 | return disableLocalRef ? ref : identity(ref, localRef);
| ^^^ Passing a ref to a function may read its value during render
| ^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
8 | }, [disableLocalRef, ref, localRef]);
9 | return <div ref={mergedRef} />;
10 | }

View File

@@ -24,8 +24,6 @@ Found 1 error:
Error: Expected the first argument to be an inline function expression
Expected the first argument to be an inline function expression
error.validate-useMemo-named-function.ts:9:20
7 | // for now.
8 | function Component(props) {

View File

@@ -1,38 +0,0 @@
## Input
```javascript
// @validatePreserveExistingMemoizationGuarantees
import {useCallback} from 'react';
function useHook(maybeRef) {
return useCallback(() => {
return [maybeRef.current];
}, [maybeRef]);
}
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees
import { useCallback } from "react";
function useHook(maybeRef) {
const $ = _c(2);
let t0;
if ($[0] !== maybeRef) {
t0 = () => [maybeRef.current];
$[0] = maybeRef;
$[1] = t0;
} else {
t0 = $[1];
}
return t0;
}
```
### Eval output
(kind: exception) Fixture not implemented

View File

@@ -1,38 +0,0 @@
## Input
```javascript
// @validatePreserveExistingMemoizationGuarantees
import {useMemo} from 'react';
function useHook(maybeRef, shouldRead) {
return useMemo(() => {
return () => [maybeRef.current];
}, [shouldRead, maybeRef]);
}
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees
import { useMemo } from "react";
function useHook(maybeRef, shouldRead) {
const $ = _c(2);
let t0;
if ($[0] !== maybeRef) {
t0 = () => [maybeRef.current];
$[0] = maybeRef;
$[1] = t0;
} else {
t0 = $[1];
}
return t0;
}
```
### Eval output
(kind: exception) Fixture not implemented

View File

@@ -3,7 +3,7 @@
```javascript
// @enableCustomTypeDefinitionForReanimated
import {useAnimatedProps, useSharedValue} from 'react-native-reanimated';
import {useAnimatedProps} from 'react-native-reanimated';
function Component() {
const radius = useSharedValue(50);
@@ -39,7 +39,7 @@ export const FIXTURE_ENTRYPOINT = {
```javascript
import { c as _c } from "react/compiler-runtime"; // @enableCustomTypeDefinitionForReanimated
import { useAnimatedProps, useSharedValue } from "react-native-reanimated";
import { useAnimatedProps } from "react-native-reanimated";
function Component() {
const $ = _c(2);
const radius = useSharedValue(50);

View File

@@ -1,5 +1,5 @@
// @enableCustomTypeDefinitionForReanimated
import {useAnimatedProps, useSharedValue} from 'react-native-reanimated';
import {useAnimatedProps} from 'react-native-reanimated';
function Component() {
const radius = useSharedValue(50);

View File

@@ -47,32 +47,28 @@ function useCustomRef() {
function _temp() {}
function Foo() {
const $ = _c(4);
const $ = _c(3);
const ref = useCustomRef();
let t0;
if ($[0] !== ref) {
let t1;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = () => {
ref.current?.click();
};
$[0] = ref;
$[1] = t0;
} else {
t0 = $[1];
}
let t1;
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t1 = [];
$[2] = t1;
$[0] = t0;
$[1] = t1;
} else {
t1 = $[2];
t0 = $[0];
t1 = $[1];
}
useEffect(t0, t1);
let t2;
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t2 = <div>foo</div>;
$[3] = t2;
$[2] = t2;
} else {
t2 = $[3];
t2 = $[2];
}
return t2;
}

View File

@@ -14,7 +14,7 @@ function Foo() {
const onClick = useCallback(() => {
ref.current?.click();
}, [ref]);
}, []);
return <button onClick={onClick} />;
}
@@ -47,26 +47,24 @@ function useCustomRef() {
function _temp() {}
function Foo() {
const $ = _c(4);
const $ = _c(2);
const ref = useCustomRef();
let t0;
if ($[0] !== ref) {
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = () => {
ref.current?.click();
};
$[0] = ref;
$[1] = t0;
$[0] = t0;
} else {
t0 = $[1];
t0 = $[0];
}
const onClick = t0;
let t1;
if ($[2] !== onClick) {
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t1 = <button onClick={onClick} />;
$[2] = onClick;
$[3] = t1;
$[1] = t1;
} else {
t1 = $[3];
t1 = $[1];
}
return t1;
}

View File

@@ -10,7 +10,7 @@ function Foo() {
const onClick = useCallback(() => {
ref.current?.click();
}, [ref]);
}, []);
return <button onClick={onClick} />;
}

View File

@@ -14,7 +14,7 @@ function Foo() {
const onClick = useCallback(() => {
customRef.current?.click();
}, [customRef]);
}, []);
return <button onClick={onClick} />;
}
@@ -47,26 +47,24 @@ function useCustomRef() {
function _temp() {}
function Foo() {
const $ = _c(4);
const $ = _c(2);
const customRef = useCustomRef();
let t0;
if ($[0] !== customRef) {
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = () => {
customRef.current?.click();
};
$[0] = customRef;
$[1] = t0;
$[0] = t0;
} else {
t0 = $[1];
t0 = $[0];
}
const onClick = t0;
let t1;
if ($[2] !== onClick) {
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t1 = <button onClick={onClick} />;
$[2] = onClick;
$[3] = t1;
$[1] = t1;
} else {
t1 = $[3];
t1 = $[1];
}
return t1;
}

View File

@@ -10,7 +10,7 @@ function Foo() {
const onClick = useCallback(() => {
customRef.current?.click();
}, [customRef]);
}, []);
return <button onClick={onClick} />;
}

View File

@@ -1,114 +0,0 @@
## Input
```javascript
// @flow
component Example() {
const fooRef = useRef();
function updateStyles() {
const foo = fooRef.current;
// The access of `barRef` here before its declaration causes it be hoisted...
if (barRef.current == null || foo == null) {
return;
}
foo.style.height = '100px';
}
// ...which previously meant that we didn't infer a type...
const barRef = useRef(null);
const resizeRef = useResizeObserver(
rect => {
const {width} = rect;
// ...which meant that we failed to ignore the mutation here...
barRef.current = width;
} // ...which caused this to fail with "can't freeze a mutable function"
);
useLayoutEffect(() => {
const observer = new ResizeObserver(_ => {
updateStyles();
});
return () => {
observer.disconnect();
};
}, []);
return <div ref={resizeRef} />;
}
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
function Example() {
const $ = _c(6);
const fooRef = useRef();
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = function updateStyles() {
const foo = fooRef.current;
if (barRef.current == null || foo == null) {
return;
}
foo.style.height = "100px";
};
$[0] = t0;
} else {
t0 = $[0];
}
const updateStyles = t0;
const barRef = useRef(null);
let t1;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t1 = (rect) => {
const { width } = rect;
barRef.current = width;
};
$[1] = t1;
} else {
t1 = $[1];
}
const resizeRef = useResizeObserver(t1);
let t2;
let t3;
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t2 = () => {
const observer = new ResizeObserver((_) => {
updateStyles();
});
return () => {
observer.disconnect();
};
};
t3 = [];
$[2] = t2;
$[3] = t3;
} else {
t2 = $[2];
t3 = $[3];
}
useLayoutEffect(t2, t3);
let t4;
if ($[4] !== resizeRef) {
t4 = <div ref={resizeRef} />;
$[4] = resizeRef;
$[5] = t4;
} else {
t4 = $[5];
}
return t4;
}
```
### Eval output
(kind: exception) Fixture not implemented

View File

@@ -1,36 +0,0 @@
// @flow
component Example() {
const fooRef = useRef();
function updateStyles() {
const foo = fooRef.current;
// The access of `barRef` here before its declaration causes it be hoisted...
if (barRef.current == null || foo == null) {
return;
}
foo.style.height = '100px';
}
// ...which previously meant that we didn't infer a type...
const barRef = useRef(null);
const resizeRef = useResizeObserver(
rect => {
const {width} = rect;
// ...which meant that we failed to ignore the mutation here...
barRef.current = width;
} // ...which caused this to fail with "can't freeze a mutable function"
);
useLayoutEffect(() => {
const observer = new ResizeObserver(_ => {
updateStyles();
});
return () => {
observer.disconnect();
};
}, []);
return <div ref={resizeRef} />;
}

View File

@@ -1,89 +0,0 @@
## Input
```javascript
import {Stringify, identity, mutate, CONST_TRUE} from 'shared-runtime';
function Foo(props, ref) {
const value = {};
if (CONST_TRUE) {
mutate(value);
return <Stringify ref={ref} />;
}
mutate(value);
if (CONST_TRUE) {
return <Stringify ref={identity(ref)} />;
}
return value;
}
export const FIXTURE_ENTRYPOINT = {
fn: Foo,
params: [{}, {current: 'fake-ref-object'}],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
import { Stringify, identity, mutate, CONST_TRUE } from "shared-runtime";
function Foo(props, ref) {
const $ = _c(7);
let t0;
let value;
if ($[0] !== ref) {
t0 = Symbol.for("react.early_return_sentinel");
bb0: {
value = {};
if (CONST_TRUE) {
mutate(value);
t0 = <Stringify ref={ref} />;
break bb0;
}
mutate(value);
}
$[0] = ref;
$[1] = t0;
$[2] = value;
} else {
t0 = $[1];
value = $[2];
}
if (t0 !== Symbol.for("react.early_return_sentinel")) {
return t0;
}
if (CONST_TRUE) {
let t1;
if ($[3] !== ref) {
t1 = identity(ref);
$[3] = ref;
$[4] = t1;
} else {
t1 = $[4];
}
let t2;
if ($[5] !== t1) {
t2 = <Stringify ref={t1} />;
$[5] = t1;
$[6] = t2;
} else {
t2 = $[6];
}
return t2;
}
return value;
}
export const FIXTURE_ENTRYPOINT = {
fn: Foo,
params: [{}, { current: "fake-ref-object" }],
};
```
### Eval output
(kind: ok) <div>{"ref":{"current":"fake-ref-object"}}</div>

View File

@@ -1,40 +0,0 @@
## Input
```javascript
// @validateNoVoidUseMemo
function Component() {
const value = useMemo(() => computeValue(), []);
return <div>{value}</div>;
}
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime"; // @validateNoVoidUseMemo
function Component() {
const $ = _c(2);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = computeValue();
$[0] = t0;
} else {
t0 = $[0];
}
const value = t0;
let t1;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t1 = <div>{value}</div>;
$[1] = t1;
} else {
t1 = $[1];
}
return t1;
}
```
### Eval output
(kind: exception) Fixture not implemented

Some files were not shown because too many files have changed in this diff Show More