Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5eda822159 | ||
|
|
2de9ddac73 | ||
|
|
6ef9e5bd49 | ||
|
|
440d8c2876 |
@@ -285,7 +285,7 @@ function runWithEnvironment(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (env.config.validateRefAccessDuringRender) {
|
if (env.config.validateRefAccessDuringRender) {
|
||||||
validateNoRefAccessInRender(hir).unwrap();
|
// validateNoRefAccessInRender(hir).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (env.config.validateNoSetStateInRender) {
|
if (env.config.validateNoSetStateInRender) {
|
||||||
|
|||||||
@@ -221,7 +221,6 @@ export function lower(
|
|||||||
params,
|
params,
|
||||||
fnType: bindings == null ? env.fnType : 'Other',
|
fnType: bindings == null ? env.fnType : 'Other',
|
||||||
returnTypeAnnotation: null, // TODO: extract the actual return type node if present
|
returnTypeAnnotation: null, // TODO: extract the actual return type node if present
|
||||||
returnType: makeType(),
|
|
||||||
returns: createTemporaryPlace(env, func.node.loc ?? GeneratedSource),
|
returns: createTemporaryPlace(env, func.node.loc ?? GeneratedSource),
|
||||||
body: builder.build(),
|
body: builder.build(),
|
||||||
context,
|
context,
|
||||||
|
|||||||
@@ -279,7 +279,6 @@ export type HIRFunction = {
|
|||||||
env: Environment;
|
env: Environment;
|
||||||
params: Array<Place | SpreadPattern>;
|
params: Array<Place | SpreadPattern>;
|
||||||
returnTypeAnnotation: t.FlowType | t.TSType | null;
|
returnTypeAnnotation: t.FlowType | t.TSType | null;
|
||||||
returnType: Type;
|
|
||||||
returns: Place;
|
returns: Place;
|
||||||
context: Array<Place>;
|
context: Array<Place>;
|
||||||
effects: Array<FunctionEffect> | null;
|
effects: Array<FunctionEffect> | null;
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ export function printFunction(fn: HIRFunction): string {
|
|||||||
let definition = '';
|
let definition = '';
|
||||||
if (fn.id !== null) {
|
if (fn.id !== null) {
|
||||||
definition += fn.id;
|
definition += fn.id;
|
||||||
|
} else {
|
||||||
|
definition += '<<anonymous>>';
|
||||||
}
|
}
|
||||||
if (fn.params.length !== 0) {
|
if (fn.params.length !== 0) {
|
||||||
definition +=
|
definition +=
|
||||||
@@ -71,10 +73,8 @@ export function printFunction(fn: HIRFunction): string {
|
|||||||
} else {
|
} else {
|
||||||
definition += '()';
|
definition += '()';
|
||||||
}
|
}
|
||||||
if (definition.length !== 0) {
|
definition += `: ${printPlace(fn.returns)}`;
|
||||||
output.push(definition);
|
output.push(definition);
|
||||||
}
|
|
||||||
output.push(`: ${printType(fn.returnType)} @ ${printPlace(fn.returns)}`);
|
|
||||||
output.push(...fn.directives);
|
output.push(...fn.directives);
|
||||||
output.push(printHIR(fn.body));
|
output.push(printHIR(fn.body));
|
||||||
return output.join('\n');
|
return output.join('\n');
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ import {
|
|||||||
isMapType,
|
isMapType,
|
||||||
isPrimitiveType,
|
isPrimitiveType,
|
||||||
isRefOrRefValue,
|
isRefOrRefValue,
|
||||||
|
isRefValueType,
|
||||||
isSetType,
|
isSetType,
|
||||||
|
isUseRefType,
|
||||||
makeIdentifierId,
|
makeIdentifierId,
|
||||||
Phi,
|
Phi,
|
||||||
Place,
|
Place,
|
||||||
@@ -219,6 +221,9 @@ export function inferMutationAliasingEffects(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (fn.env.config.validateRefAccessDuringRender) {
|
||||||
|
inferRefAccessEffects(fn, isFunctionExpression);
|
||||||
|
}
|
||||||
return Ok(undefined);
|
return Ok(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2513,3 +2518,127 @@ export type AbstractValue = {
|
|||||||
kind: ValueKind;
|
kind: ValueKind;
|
||||||
reason: ReadonlySet<ValueReason>;
|
reason: ReadonlySet<ValueReason>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function inferRefAccessEffects(
|
||||||
|
fn: HIRFunction,
|
||||||
|
_isFunctionExpression: boolean,
|
||||||
|
): void {
|
||||||
|
const nullish = new Set<IdentifierId>();
|
||||||
|
const nullishTest = new Map<IdentifierId, Place>();
|
||||||
|
let guard: {ref: IdentifierId; fallthrough: BlockId} | null = null;
|
||||||
|
const temporaries: Map<IdentifierId, Place> = new Map();
|
||||||
|
|
||||||
|
function visitOperand(operand: Place): AliasingEffect | null {
|
||||||
|
const nullTestRef = nullishTest.get(operand.identifier.id);
|
||||||
|
if (isRefValueType(operand.identifier) || nullTestRef != null) {
|
||||||
|
const refOperand = nullTestRef ?? operand;
|
||||||
|
return {
|
||||||
|
kind: 'Impure',
|
||||||
|
error: {
|
||||||
|
severity: ErrorSeverity.InvalidReact,
|
||||||
|
reason:
|
||||||
|
'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)',
|
||||||
|
loc: refOperand.loc,
|
||||||
|
description:
|
||||||
|
refOperand.identifier.name !== null &&
|
||||||
|
refOperand.identifier.name.kind === 'named'
|
||||||
|
? `Cannot access ref value \`${refOperand.identifier.name.value}\``
|
||||||
|
: null,
|
||||||
|
suggestions: null,
|
||||||
|
},
|
||||||
|
place: refOperand,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const block of fn.body.blocks.values()) {
|
||||||
|
if (guard !== null && guard.fallthrough === block.id) {
|
||||||
|
guard = null;
|
||||||
|
}
|
||||||
|
for (const instr of block.instructions) {
|
||||||
|
const {lvalue, value} = instr;
|
||||||
|
if (value.kind === 'LoadLocal' && isUseRefType(value.place.identifier)) {
|
||||||
|
temporaries.set(lvalue.identifier.id, value.place);
|
||||||
|
} else if (
|
||||||
|
value.kind === 'StoreLocal' &&
|
||||||
|
isUseRefType(value.value.identifier)
|
||||||
|
) {
|
||||||
|
temporaries.set(value.lvalue.place.identifier.id, value.value);
|
||||||
|
temporaries.set(lvalue.identifier.id, value.value);
|
||||||
|
} else if (
|
||||||
|
value.kind === 'BinaryExpression' &&
|
||||||
|
((isRefValueType(value.left.identifier) &&
|
||||||
|
nullish.has(value.right.identifier.id)) ||
|
||||||
|
(nullish.has(value.left.identifier.id) &&
|
||||||
|
isRefValueType(value.right.identifier)))
|
||||||
|
) {
|
||||||
|
const refOperand = isRefValueType(value.left.identifier)
|
||||||
|
? value.left
|
||||||
|
: value.right;
|
||||||
|
const operand = temporaries.get(refOperand.identifier.id) ?? refOperand;
|
||||||
|
nullishTest.set(lvalue.identifier.id, operand);
|
||||||
|
} else if (value.kind === 'Primitive' && value.value == null) {
|
||||||
|
nullish.add(lvalue.identifier.id);
|
||||||
|
} else if (
|
||||||
|
value.kind === 'PropertyLoad' &&
|
||||||
|
isUseRefType(value.object.identifier) &&
|
||||||
|
value.property === 'current'
|
||||||
|
) {
|
||||||
|
const refOperand =
|
||||||
|
temporaries.get(value.object.identifier.id) ?? value.object;
|
||||||
|
temporaries.set(lvalue.identifier.id, refOperand);
|
||||||
|
} else if (
|
||||||
|
value.kind === 'PropertyStore' &&
|
||||||
|
value.property === 'current' &&
|
||||||
|
isUseRefType(value.object.identifier)
|
||||||
|
) {
|
||||||
|
const refOperand =
|
||||||
|
temporaries.get(value.object.identifier.id) ?? value.object;
|
||||||
|
if (guard != null && refOperand.identifier.id === guard.ref) {
|
||||||
|
// Allow a single write within the guard
|
||||||
|
guard = null;
|
||||||
|
} else {
|
||||||
|
instr.effects ??= [];
|
||||||
|
instr.effects.push({
|
||||||
|
kind: 'Impure',
|
||||||
|
error: {
|
||||||
|
severity: ErrorSeverity.InvalidReact,
|
||||||
|
reason:
|
||||||
|
'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)',
|
||||||
|
loc: value.loc,
|
||||||
|
description:
|
||||||
|
value.object.identifier.name !== null &&
|
||||||
|
value.object.identifier.name.kind === 'named'
|
||||||
|
? `Cannot access ref value \`${value.object.identifier.name.value}\``
|
||||||
|
: null,
|
||||||
|
suggestions: null,
|
||||||
|
},
|
||||||
|
place: value.object,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const operand of eachInstructionValueOperand(value)) {
|
||||||
|
const error = visitOperand(operand);
|
||||||
|
if (error) {
|
||||||
|
instr.effects ??= [];
|
||||||
|
instr.effects.push(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
guard == null &&
|
||||||
|
block.terminal.kind === 'if' &&
|
||||||
|
nullishTest.has(block.terminal.test.identifier.id)
|
||||||
|
) {
|
||||||
|
const ref = nullishTest.get(block.terminal.test.identifier.id)!;
|
||||||
|
guard = {ref: ref.identifier.id, fallthrough: block.terminal.fallthrough};
|
||||||
|
} else {
|
||||||
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
||||||
|
const _effect = visitOperand(operand);
|
||||||
|
// TODO: need a place to store terminal effects generically
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
ValueKind,
|
ValueKind,
|
||||||
ValueReason,
|
ValueReason,
|
||||||
Place,
|
Place,
|
||||||
|
isPrimitiveType,
|
||||||
} from '../HIR/HIR';
|
} from '../HIR/HIR';
|
||||||
import {
|
import {
|
||||||
eachInstructionLValue,
|
eachInstructionLValue,
|
||||||
@@ -471,15 +472,15 @@ export function inferMutationAliasingRanges(
|
|||||||
* Here we populate an effect to create the return value as well as populating alias/capture
|
* Here we populate an effect to create the return value as well as populating alias/capture
|
||||||
* effects for how data flows between the params, context vars, and return.
|
* effects for how data flows between the params, context vars, and return.
|
||||||
*/
|
*/
|
||||||
|
const returns = fn.returns.identifier;
|
||||||
functionEffects.push({
|
functionEffects.push({
|
||||||
kind: 'Create',
|
kind: 'Create',
|
||||||
into: fn.returns,
|
into: fn.returns,
|
||||||
value:
|
value: isPrimitiveType(returns)
|
||||||
fn.returnType.kind === 'Primitive'
|
? ValueKind.Primitive
|
||||||
? ValueKind.Primitive
|
: isJsxType(returns.type)
|
||||||
: isJsxType(fn.returnType)
|
? ValueKind.Frozen
|
||||||
? ValueKind.Frozen
|
: ValueKind.Mutable,
|
||||||
: ValueKind.Mutable,
|
|
||||||
reason: ValueReason.KnownReturnSignature,
|
reason: ValueReason.KnownReturnSignature,
|
||||||
});
|
});
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import {
|
|||||||
makeBlockId,
|
makeBlockId,
|
||||||
makeInstructionId,
|
makeInstructionId,
|
||||||
makePropertyLiteral,
|
makePropertyLiteral,
|
||||||
makeType,
|
|
||||||
markInstructionIds,
|
markInstructionIds,
|
||||||
promoteTemporary,
|
promoteTemporary,
|
||||||
reversePostorderBlocks,
|
reversePostorderBlocks,
|
||||||
@@ -253,7 +252,6 @@ function emitSelectorFn(env: Environment, keys: Array<string>): Instruction {
|
|||||||
env,
|
env,
|
||||||
params: [obj],
|
params: [obj],
|
||||||
returnTypeAnnotation: null,
|
returnTypeAnnotation: null,
|
||||||
returnType: makeType(),
|
|
||||||
returns: createTemporaryPlace(env, GeneratedSource),
|
returns: createTemporaryPlace(env, GeneratedSource),
|
||||||
context: [],
|
context: [],
|
||||||
effects: null,
|
effects: null,
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import {
|
|||||||
makeBlockId,
|
makeBlockId,
|
||||||
makeIdentifierName,
|
makeIdentifierName,
|
||||||
makeInstructionId,
|
makeInstructionId,
|
||||||
makeType,
|
|
||||||
ObjectProperty,
|
ObjectProperty,
|
||||||
Place,
|
Place,
|
||||||
promoteTemporary,
|
promoteTemporary,
|
||||||
@@ -368,7 +367,6 @@ function emitOutlinedFn(
|
|||||||
env,
|
env,
|
||||||
params: [propsObj],
|
params: [propsObj],
|
||||||
returnTypeAnnotation: null,
|
returnTypeAnnotation: null,
|
||||||
returnType: makeType(),
|
|
||||||
returns: createTemporaryPlace(env, GeneratedSource),
|
returns: createTemporaryPlace(env, GeneratedSource),
|
||||||
context: [],
|
context: [],
|
||||||
effects: null,
|
effects: null,
|
||||||
|
|||||||
@@ -349,11 +349,9 @@ function codegenReactiveFunction(
|
|||||||
fn: ReactiveFunction,
|
fn: ReactiveFunction,
|
||||||
): Result<CodegenFunction, CompilerError> {
|
): Result<CodegenFunction, CompilerError> {
|
||||||
for (const param of fn.params) {
|
for (const param of fn.params) {
|
||||||
if (param.kind === 'Identifier') {
|
const place = param.kind === 'Identifier' ? param : param.place;
|
||||||
cx.temp.set(param.identifier.declarationId, null);
|
cx.temp.set(place.identifier.declarationId, null);
|
||||||
} else {
|
cx.declare(place.identifier);
|
||||||
cx.temp.set(param.place.identifier.declarationId, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const params = fn.params.map(param => convertParameter(param));
|
const params = fn.params.map(param => convertParameter(param));
|
||||||
@@ -1183,7 +1181,7 @@ function codegenTerminal(
|
|||||||
? codegenPlaceToExpression(cx, case_.test)
|
? codegenPlaceToExpression(cx, case_.test)
|
||||||
: null;
|
: null;
|
||||||
const block = codegenBlock(cx, case_.block!);
|
const block = codegenBlock(cx, case_.block!);
|
||||||
return t.switchCase(test, [block]);
|
return t.switchCase(test, block.body.length === 0 ? [] : [block]);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,6 +79,10 @@ export function extractScopeDeclarationsFromDestructuring(
|
|||||||
fn: ReactiveFunction,
|
fn: ReactiveFunction,
|
||||||
): void {
|
): void {
|
||||||
const state = new State(fn.env);
|
const state = new State(fn.env);
|
||||||
|
for (const param of fn.params) {
|
||||||
|
const place = param.kind === 'Identifier' ? param : param.place;
|
||||||
|
state.declared.add(place.identifier.declarationId);
|
||||||
|
}
|
||||||
visitReactiveFunction(fn, new Visitor(), state);
|
visitReactiveFunction(fn, new Visitor(), state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,8 @@ function apply(func: HIRFunction, unifier: Unifier): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func.returnType = unifier.get(func.returnType);
|
const returns = func.returns.identifier;
|
||||||
|
returns.type = unifier.get(returns.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
type TypeEquation = {
|
type TypeEquation = {
|
||||||
@@ -143,12 +144,12 @@ function* generate(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (returnTypes.length > 1) {
|
if (returnTypes.length > 1) {
|
||||||
yield equation(func.returnType, {
|
yield equation(func.returns.identifier.type, {
|
||||||
kind: 'Phi',
|
kind: 'Phi',
|
||||||
operands: returnTypes,
|
operands: returnTypes,
|
||||||
});
|
});
|
||||||
} else if (returnTypes.length === 1) {
|
} else if (returnTypes.length === 1) {
|
||||||
yield equation(func.returnType, returnTypes[0]!);
|
yield equation(func.returns.identifier.type, returnTypes[0]!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,7 +408,7 @@ function* generateInstructionTypes(
|
|||||||
yield equation(left, {
|
yield equation(left, {
|
||||||
kind: 'Function',
|
kind: 'Function',
|
||||||
shapeId: BuiltInFunctionId,
|
shapeId: BuiltInFunctionId,
|
||||||
return: value.loweredFunc.func.returnType,
|
return: value.loweredFunc.func.returns.identifier.type,
|
||||||
isConstructor: false,
|
isConstructor: false,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -50,8 +50,7 @@ function Component(props) {
|
|||||||
console.log(handlers.value);
|
console.log(handlers.value);
|
||||||
break bb0;
|
break bb0;
|
||||||
}
|
}
|
||||||
default: {
|
default:
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t0 = handlers;
|
t0 = handlers;
|
||||||
|
|||||||
@@ -67,8 +67,7 @@ function Component(props) {
|
|||||||
case "b": {
|
case "b": {
|
||||||
break bb1;
|
break bb1;
|
||||||
}
|
}
|
||||||
case "c": {
|
case "c":
|
||||||
}
|
|
||||||
default: {
|
default: {
|
||||||
x = 6;
|
x = 6;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ export const FIXTURE_ENTRYPOINT = {
|
|||||||
4 | const ref = useRef();
|
4 | const ref = useRef();
|
||||||
> 5 | useEffect(() => {}, [ref.current]);
|
> 5 | useEffect(() => {}, [ref.current]);
|
||||||
| ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (5:5)
|
| ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (5:5)
|
||||||
|
|
||||||
InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (5:5)
|
|
||||||
6 | }
|
6 | }
|
||||||
7 |
|
7 |
|
||||||
8 | export const FIXTURE_ENTRYPOINT = {
|
8 | export const FIXTURE_ENTRYPOINT = {
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ function Component(props) {
|
|||||||
3 | const ref = useRef(null);
|
3 | const ref = useRef(null);
|
||||||
> 4 | const value = ref.current;
|
> 4 | const value = ref.current;
|
||||||
| ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (4:4)
|
| ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (4:4)
|
||||||
|
|
||||||
|
InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value `value` (5:5)
|
||||||
5 | return value;
|
5 | return value;
|
||||||
6 | }
|
6 | }
|
||||||
7 |
|
7 |
|
||||||
|
|||||||
@@ -19,12 +19,17 @@ function Component(props) {
|
|||||||
## Error
|
## Error
|
||||||
|
|
||||||
```
|
```
|
||||||
7 | return <Foo item={item} current={current} />;
|
4 | const renderItem = item => {
|
||||||
8 | };
|
5 | const aliasedRef = ref;
|
||||||
> 9 | return <Items>{props.items.map(item => renderItem(item))}</Items>;
|
> 6 | const current = aliasedRef.current;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (9:9)
|
| ^^^^^^^^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (6:6)
|
||||||
10 | }
|
|
||||||
11 |
|
InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value `current` (7:7)
|
||||||
|
|
||||||
|
InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (7:7)
|
||||||
|
7 | return <Foo item={item} current={current} />;
|
||||||
|
8 | };
|
||||||
|
9 | return <Items>{props.items.map(item => renderItem(item))}</Items>;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -21,15 +21,13 @@ function Component() {
|
|||||||
## Error
|
## Error
|
||||||
|
|
||||||
```
|
```
|
||||||
7 | };
|
4 |
|
||||||
8 | const changeRef = setRef;
|
5 | const setRef = () => {
|
||||||
> 9 | changeRef();
|
> 6 | ref.current = false;
|
||||||
| ^^^^^^^^^ InvalidReact: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef) (9:9)
|
| ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (6:6)
|
||||||
|
7 | };
|
||||||
InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (9:9)
|
8 | const changeRef = setRef;
|
||||||
10 |
|
9 | changeRef();
|
||||||
11 | return <button ref={ref} />;
|
|
||||||
12 | }
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -18,6 +18,10 @@ function Component({ref}) {
|
|||||||
2 | function Component({ref}) {
|
2 | function Component({ref}) {
|
||||||
> 3 | const value = ref.current;
|
> 3 | const value = ref.current;
|
||||||
| ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (3:3)
|
| ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (3:3)
|
||||||
|
|
||||||
|
InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value `value` (4:4)
|
||||||
|
|
||||||
|
InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (4:4)
|
||||||
4 | return <div>{value}</div>;
|
4 | return <div>{value}</div>;
|
||||||
5 | }
|
5 | }
|
||||||
6 |
|
6 |
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ function Component(props) {
|
|||||||
2 | function Component(props) {
|
2 | function Component(props) {
|
||||||
> 3 | const value = props.ref.current;
|
> 3 | const value = props.ref.current;
|
||||||
| ^^^^^^^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (3:3)
|
| ^^^^^^^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (3:3)
|
||||||
|
|
||||||
|
InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value `value` (4:4)
|
||||||
|
|
||||||
|
InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (4:4)
|
||||||
4 | return <div>{value}</div>;
|
4 | return <div>{value}</div>;
|
||||||
5 | }
|
5 | }
|
||||||
6 |
|
6 |
|
||||||
|
|||||||
@@ -18,12 +18,17 @@ function Component(props) {
|
|||||||
## Error
|
## Error
|
||||||
|
|
||||||
```
|
```
|
||||||
6 | return <Foo item={item} current={current} />;
|
3 | const ref = useRef(null);
|
||||||
7 | };
|
4 | const renderItem = item => {
|
||||||
> 8 | return <Items>{props.items.map(item => renderItem(item))}</Items>;
|
> 5 | const current = ref.current;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (8:8)
|
| ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (5:5)
|
||||||
9 | }
|
|
||||||
10 |
|
InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value `current` (6:6)
|
||||||
|
|
||||||
|
InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (6:6)
|
||||||
|
6 | return <Foo item={item} current={current} />;
|
||||||
|
7 | };
|
||||||
|
8 | return <Items>{props.items.map(item => renderItem(item))}</Items>;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -19,8 +19,6 @@ function Component(props) {
|
|||||||
3 | const ref = useRef(null);
|
3 | const ref = useRef(null);
|
||||||
> 4 | ref.current = props.value;
|
> 4 | ref.current = props.value;
|
||||||
| ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (4:4)
|
| ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (4:4)
|
||||||
|
|
||||||
InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (5:5)
|
|
||||||
5 | return ref.current;
|
5 | return ref.current;
|
||||||
6 | }
|
6 | }
|
||||||
7 |
|
7 |
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ export const FIXTURE_ENTRYPOINT = {
|
|||||||
4 | component C() {
|
4 | component C() {
|
||||||
5 | const r = useRef(null);
|
5 | const r = useRef(null);
|
||||||
> 6 | const guard = r.current == null;
|
> 6 | const guard = r.current == null;
|
||||||
| ^^^^^^^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (6:6)
|
| ^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value `r` (6:6)
|
||||||
|
|
||||||
InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value `guard` (7:7)
|
InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (8:8)
|
||||||
7 | if (guard) {
|
7 | if (guard) {
|
||||||
8 | r.current = 1;
|
8 | r.current = 1;
|
||||||
9 | }
|
9 | }
|
||||||
|
|||||||
@@ -34,15 +34,13 @@ export const FIXTURE_ENTRYPOINT = {
|
|||||||
## Error
|
## Error
|
||||||
|
|
||||||
```
|
```
|
||||||
15 | ref.current.inner = null;
|
13 | // The ref is modified later, extending its range and preventing memoization of onChange
|
||||||
|
14 | const reset = () => {
|
||||||
|
> 15 | ref.current.inner = null;
|
||||||
|
| ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (15:15)
|
||||||
16 | };
|
16 | };
|
||||||
> 17 | reset();
|
17 | reset();
|
||||||
| ^^^^^ InvalidReact: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef) (17:17)
|
|
||||||
|
|
||||||
InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (17:17)
|
|
||||||
18 |
|
18 |
|
||||||
19 | return <input onChange={onChange} />;
|
|
||||||
20 | }
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
## Input
|
## Input
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// @validateRefAccessDuringRender false
|
// @validateRefAccessDuringRender:false
|
||||||
function VideoTab() {
|
function VideoTab() {
|
||||||
const ref = useRef();
|
const ref = useRef();
|
||||||
const t = ref.current;
|
const t = ref.current;
|
||||||
@@ -18,7 +18,7 @@ function VideoTab() {
|
|||||||
## Code
|
## Code
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRender false
|
import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRender:false
|
||||||
function VideoTab() {
|
function VideoTab() {
|
||||||
const $ = _c(1);
|
const $ = _c(1);
|
||||||
const ref = useRef();
|
const ref = useRef();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// @validateRefAccessDuringRender false
|
// @validateRefAccessDuringRender:false
|
||||||
function VideoTab() {
|
function VideoTab() {
|
||||||
const ref = useRef();
|
const ref = useRef();
|
||||||
const t = ref.current;
|
const t = ref.current;
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import {Stringify, useIdentity} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({other, ...props}, ref) {
|
||||||
|
[props, ref] = useIdentity([props, ref]);
|
||||||
|
return <Stringify props={props} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{a: 0, b: 'hello', children: <div>Hello</div>}],
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { c as _c } from "react/compiler-runtime";
|
||||||
|
import { Stringify, useIdentity } from "shared-runtime";
|
||||||
|
|
||||||
|
function Component(t0, ref) {
|
||||||
|
const $ = _c(7);
|
||||||
|
let props;
|
||||||
|
if ($[0] !== t0) {
|
||||||
|
let { other, ...t1 } = t0;
|
||||||
|
props = t1;
|
||||||
|
$[0] = t0;
|
||||||
|
$[1] = props;
|
||||||
|
} else {
|
||||||
|
props = $[1];
|
||||||
|
}
|
||||||
|
let t1;
|
||||||
|
if ($[2] !== props || $[3] !== ref) {
|
||||||
|
t1 = [props, ref];
|
||||||
|
$[2] = props;
|
||||||
|
$[3] = ref;
|
||||||
|
$[4] = t1;
|
||||||
|
} else {
|
||||||
|
t1 = $[4];
|
||||||
|
}
|
||||||
|
[props, ref] = useIdentity(t1);
|
||||||
|
let t2;
|
||||||
|
if ($[5] !== props) {
|
||||||
|
t2 = <Stringify props={props} />;
|
||||||
|
$[5] = props;
|
||||||
|
$[6] = t2;
|
||||||
|
} else {
|
||||||
|
t2 = $[6];
|
||||||
|
}
|
||||||
|
return t2;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{ a: 0, b: "hello", children: <div>Hello</div> }],
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Eval output
|
||||||
|
(kind: ok) <div>{"props":{"a":0,"b":"hello","children":{"type":"div","key":null,"props":{"children":"Hello"},"_owner":"[[ cyclic ref *3 ]]","_store":{}}}}</div>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import {Stringify, useIdentity} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({other, ...props}, ref) {
|
||||||
|
[props, ref] = useIdentity([props, ref]);
|
||||||
|
return <Stringify props={props} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{a: 0, b: 'hello', children: <div>Hello</div>}],
|
||||||
|
};
|
||||||
@@ -50,10 +50,8 @@ function Component(props) {
|
|||||||
case 1: {
|
case 1: {
|
||||||
break bb0;
|
break bb0;
|
||||||
}
|
}
|
||||||
case 2: {
|
case 2:
|
||||||
}
|
default:
|
||||||
default: {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (props.cond2) {
|
if (props.cond2) {
|
||||||
|
|||||||
@@ -41,8 +41,7 @@ function foo() {
|
|||||||
case 2: {
|
case 2: {
|
||||||
break bb0;
|
break bb0;
|
||||||
}
|
}
|
||||||
default: {
|
default:
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,22 +43,17 @@ export const FIXTURE_ENTRYPOINT = {
|
|||||||
```javascript
|
```javascript
|
||||||
function foo(x) {
|
function foo(x) {
|
||||||
bb0: switch (x) {
|
bb0: switch (x) {
|
||||||
case 0: {
|
case 0:
|
||||||
}
|
case 1:
|
||||||
case 1: {
|
|
||||||
}
|
|
||||||
case 2: {
|
case 2: {
|
||||||
break bb0;
|
break bb0;
|
||||||
}
|
}
|
||||||
case 3: {
|
case 3: {
|
||||||
break bb0;
|
break bb0;
|
||||||
}
|
}
|
||||||
case 4: {
|
case 4:
|
||||||
}
|
case 5:
|
||||||
case 5: {
|
default:
|
||||||
}
|
|
||||||
default: {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user