Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35e58360cb |
@@ -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
|
||||
|
||||
@@ -114,99 +114,6 @@ const TYPED_GLOBALS: Array<[string, BuiltInType]> = [
|
||||
returnValueKind: ValueKind.Mutable,
|
||||
}),
|
||||
],
|
||||
[
|
||||
'entries',
|
||||
addFunction(DEFAULT_SHAPES, [], {
|
||||
positionalParams: [Effect.Capture],
|
||||
restParam: null,
|
||||
returnType: {kind: 'Object', shapeId: BuiltInArrayId},
|
||||
calleeEffect: Effect.Read,
|
||||
returnValueKind: ValueKind.Mutable,
|
||||
aliasing: {
|
||||
receiver: '@receiver',
|
||||
params: ['@object'],
|
||||
rest: null,
|
||||
returns: '@returns',
|
||||
temporaries: [],
|
||||
effects: [
|
||||
{
|
||||
kind: 'Create',
|
||||
into: '@returns',
|
||||
reason: ValueReason.KnownReturnSignature,
|
||||
value: ValueKind.Mutable,
|
||||
},
|
||||
// Object values are captured into the return
|
||||
{
|
||||
kind: 'Capture',
|
||||
from: '@object',
|
||||
into: '@returns',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
],
|
||||
[
|
||||
'keys',
|
||||
addFunction(DEFAULT_SHAPES, [], {
|
||||
positionalParams: [Effect.Read],
|
||||
restParam: null,
|
||||
returnType: {kind: 'Object', shapeId: BuiltInArrayId},
|
||||
calleeEffect: Effect.Read,
|
||||
returnValueKind: ValueKind.Mutable,
|
||||
aliasing: {
|
||||
receiver: '@receiver',
|
||||
params: ['@object'],
|
||||
rest: null,
|
||||
returns: '@returns',
|
||||
temporaries: [],
|
||||
effects: [
|
||||
{
|
||||
kind: 'Create',
|
||||
into: '@returns',
|
||||
reason: ValueReason.KnownReturnSignature,
|
||||
value: ValueKind.Mutable,
|
||||
},
|
||||
// Only keys are captured, and keys are immutable
|
||||
{
|
||||
kind: 'ImmutableCapture',
|
||||
from: '@object',
|
||||
into: '@returns',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
],
|
||||
[
|
||||
'values',
|
||||
addFunction(DEFAULT_SHAPES, [], {
|
||||
positionalParams: [Effect.Capture],
|
||||
restParam: null,
|
||||
returnType: {kind: 'Object', shapeId: BuiltInArrayId},
|
||||
calleeEffect: Effect.Read,
|
||||
returnValueKind: ValueKind.Mutable,
|
||||
aliasing: {
|
||||
receiver: '@receiver',
|
||||
params: ['@object'],
|
||||
rest: null,
|
||||
returns: '@returns',
|
||||
temporaries: [],
|
||||
effects: [
|
||||
{
|
||||
kind: 'Create',
|
||||
into: '@returns',
|
||||
reason: ValueReason.KnownReturnSignature,
|
||||
value: ValueKind.Mutable,
|
||||
},
|
||||
// Object values are captured into the return
|
||||
{
|
||||
kind: 'Capture',
|
||||
from: '@object',
|
||||
into: '@returns',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
],
|
||||
]),
|
||||
],
|
||||
[
|
||||
|
||||
@@ -142,7 +142,6 @@ function parseAliasingSignatureConfig(
|
||||
const effects = typeConfig.effects.map(
|
||||
(effect: AliasingEffectConfig): AliasingEffect => {
|
||||
switch (effect.kind) {
|
||||
case 'ImmutableCapture':
|
||||
case 'CreateFrom':
|
||||
case 'Capture':
|
||||
case 'Alias':
|
||||
|
||||
@@ -111,19 +111,6 @@ export const AliasEffectSchema: z.ZodType<AliasEffectConfig> = z.object({
|
||||
into: LifetimeIdSchema,
|
||||
});
|
||||
|
||||
export type ImmutableCaptureEffectConfig = {
|
||||
kind: 'ImmutableCapture';
|
||||
from: string;
|
||||
into: string;
|
||||
};
|
||||
|
||||
export const ImmutableCaptureEffectSchema: z.ZodType<ImmutableCaptureEffectConfig> =
|
||||
z.object({
|
||||
kind: z.literal('ImmutableCapture'),
|
||||
from: LifetimeIdSchema,
|
||||
into: LifetimeIdSchema,
|
||||
});
|
||||
|
||||
export type CaptureEffectConfig = {
|
||||
kind: 'Capture';
|
||||
from: string;
|
||||
@@ -200,7 +187,6 @@ export type AliasingEffectConfig =
|
||||
| AssignEffectConfig
|
||||
| AliasEffectConfig
|
||||
| CaptureEffectConfig
|
||||
| ImmutableCaptureEffectConfig
|
||||
| ImpureEffectConfig
|
||||
| MutateEffectConfig
|
||||
| MutateTransitiveConditionallyConfig
|
||||
@@ -213,7 +199,6 @@ export const AliasingEffectSchema: z.ZodType<AliasingEffectConfig> = z.union([
|
||||
AssignEffectSchema,
|
||||
AliasEffectSchema,
|
||||
CaptureEffectSchema,
|
||||
ImmutableCaptureEffectSchema,
|
||||
ImpureEffectSchema,
|
||||
MutateEffectSchema,
|
||||
MutateTransitiveConditionallySchema,
|
||||
|
||||
@@ -119,7 +119,6 @@ class FindLastUsageVisitor extends ReactiveFunctionVisitor<void> {
|
||||
|
||||
class Transform extends ReactiveFunctionTransform<ReactiveScopeDependencies | null> {
|
||||
lastUsage: Map<DeclarationId, InstructionId>;
|
||||
temporaries: Map<DeclarationId, DeclarationId> = new Map();
|
||||
|
||||
constructor(lastUsage: Map<DeclarationId, InstructionId>) {
|
||||
super();
|
||||
@@ -216,12 +215,6 @@ class Transform extends ReactiveFunctionTransform<ReactiveScopeDependencies | nu
|
||||
current.lvalues.add(
|
||||
instr.instruction.lvalue.identifier.declarationId,
|
||||
);
|
||||
if (instr.instruction.value.kind === 'LoadLocal') {
|
||||
this.temporaries.set(
|
||||
instr.instruction.lvalue.identifier.declarationId,
|
||||
instr.instruction.value.place.identifier.declarationId,
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -243,13 +236,6 @@ class Transform extends ReactiveFunctionTransform<ReactiveScopeDependencies | nu
|
||||
)) {
|
||||
current.lvalues.add(lvalue.identifier.declarationId);
|
||||
}
|
||||
this.temporaries.set(
|
||||
instr.instruction.value.lvalue.place.identifier
|
||||
.declarationId,
|
||||
this.temporaries.get(
|
||||
instr.instruction.value.value.identifier.declarationId,
|
||||
) ?? instr.instruction.value.value.identifier.declarationId,
|
||||
);
|
||||
} else {
|
||||
log(
|
||||
`Reset scope @${current.block.scope.id} from StoreLocal in [${instr.instruction.id}]`,
|
||||
@@ -274,7 +260,7 @@ class Transform extends ReactiveFunctionTransform<ReactiveScopeDependencies | nu
|
||||
case 'scope': {
|
||||
if (
|
||||
current !== null &&
|
||||
canMergeScopes(current.block, instr, this.temporaries) &&
|
||||
canMergeScopes(current.block, instr) &&
|
||||
areLValuesLastUsedByScope(
|
||||
instr.scope,
|
||||
current.lvalues,
|
||||
@@ -440,7 +426,6 @@ function areLValuesLastUsedByScope(
|
||||
function canMergeScopes(
|
||||
current: ReactiveScopeBlock,
|
||||
next: ReactiveScopeBlock,
|
||||
temporaries: Map<DeclarationId, DeclarationId>,
|
||||
): boolean {
|
||||
// Don't merge scopes with reassignments
|
||||
if (
|
||||
@@ -480,14 +465,11 @@ function canMergeScopes(
|
||||
(next.scope.dependencies.size !== 0 &&
|
||||
[...next.scope.dependencies].every(
|
||||
dep =>
|
||||
dep.path.length === 0 &&
|
||||
isAlwaysInvalidatingType(dep.identifier.type) &&
|
||||
Iterable_some(
|
||||
current.scope.declarations.values(),
|
||||
decl =>
|
||||
decl.identifier.declarationId === dep.identifier.declarationId ||
|
||||
decl.identifier.declarationId ===
|
||||
temporaries.get(dep.identifier.declarationId),
|
||||
decl.identifier.declarationId === dep.identifier.declarationId,
|
||||
),
|
||||
))
|
||||
) {
|
||||
@@ -495,12 +477,8 @@ function canMergeScopes(
|
||||
return true;
|
||||
}
|
||||
log(` cannot merge scopes:`);
|
||||
log(
|
||||
` ${printReactiveScopeSummary(current.scope)} ${[...current.scope.declarations.values()].map(decl => decl.identifier.declarationId)}`,
|
||||
);
|
||||
log(
|
||||
` ${printReactiveScopeSummary(next.scope)} ${[...next.scope.dependencies].map(dep => `${dep.identifier.declarationId} ${temporaries.get(dep.identifier.declarationId) ?? dep.identifier.declarationId}`)}`,
|
||||
);
|
||||
log(` ${printReactiveScopeSummary(current.scope)}`);
|
||||
log(` ${printReactiveScopeSummary(next.scope)}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,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 +79,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 +90,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 +99,7 @@ class Env {
|
||||
) {
|
||||
this.#changed = true;
|
||||
}
|
||||
this.#data.set(operandId, widenedValue);
|
||||
return this;
|
||||
return super.set(key, widenedValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,48 +107,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 +262,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,
|
||||
@@ -486,20 +414,10 @@ function validateNoRefAccessInRenderImpl(
|
||||
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')
|
||||
) {
|
||||
if (hookKind != null) {
|
||||
validateNoDirectRefValueAccess(errors, operand, env);
|
||||
} else if (!isRefLValue) {
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@@ -510,23 +428,7 @@ function validateNoRefAccessInRenderImpl(
|
||||
* 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,
|
||||
@@ -566,39 +468,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);
|
||||
}
|
||||
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 +564,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -800,7 +683,11 @@ function validateNoRefUpdate(
|
||||
loc: SourceLocation,
|
||||
): void {
|
||||
const type = destructure(env.get(operand.identifier.id));
|
||||
if (type?.kind === 'Ref' || type?.kind === 'RefValue') {
|
||||
if (
|
||||
type?.kind === 'Ref' ||
|
||||
type?.kind === 'RefValue' ||
|
||||
(type?.kind === 'Structure' && type.fn?.readRefEffect)
|
||||
) {
|
||||
errors.pushDiagnostic(
|
||||
CompilerDiagnostic.create({
|
||||
severity: ErrorSeverity.InvalidReact,
|
||||
|
||||
@@ -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>
|
||||
@@ -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}],
|
||||
};
|
||||
@@ -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
|
||||
@@ -1,9 +0,0 @@
|
||||
// @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
|
||||
|
||||
import {useRef} from 'react';
|
||||
|
||||
function Component(props) {
|
||||
const ref = useRef(null);
|
||||
|
||||
return <Foo>{props.render({ref})}</Foo>;
|
||||
}
|
||||
@@ -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
|
||||
@@ -1,9 +0,0 @@
|
||||
// @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
|
||||
|
||||
import {useRef} from 'react';
|
||||
|
||||
function Component(props) {
|
||||
const ref = useRef(null);
|
||||
|
||||
return <Foo>{props.render(ref)}</Foo>;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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}],
|
||||
};
|
||||
@@ -19,7 +19,7 @@ function Component(props) {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(5);
|
||||
const $ = _c(7);
|
||||
let t0;
|
||||
if ($[0] !== props.x) {
|
||||
t0 = foo(props.x);
|
||||
@@ -31,19 +31,26 @@ function Component(props) {
|
||||
const x = t0;
|
||||
let t1;
|
||||
if ($[2] !== props || $[3] !== x) {
|
||||
const fn = function () {
|
||||
t1 = function () {
|
||||
const arr = [...bar(props)];
|
||||
return arr.at(x);
|
||||
};
|
||||
|
||||
t1 = fn();
|
||||
$[2] = props;
|
||||
$[3] = x;
|
||||
$[4] = t1;
|
||||
} else {
|
||||
t1 = $[4];
|
||||
}
|
||||
const fnResult = t1;
|
||||
const fn = t1;
|
||||
let t2;
|
||||
if ($[5] !== fn) {
|
||||
t2 = fn();
|
||||
$[5] = fn;
|
||||
$[6] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
}
|
||||
const fnResult = t2;
|
||||
return fnResult;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,18 +23,34 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(6);
|
||||
let t0;
|
||||
if ($[0] !== props.a) {
|
||||
const item = { a: props.a };
|
||||
const items = [item];
|
||||
t0 = items.map(_temp);
|
||||
t0 = { a: props.a };
|
||||
$[0] = props.a;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const mapped = t0;
|
||||
const item = t0;
|
||||
let t1;
|
||||
if ($[2] !== item) {
|
||||
t1 = [item];
|
||||
$[2] = item;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
const items = t1;
|
||||
let t2;
|
||||
if ($[4] !== items) {
|
||||
t2 = items.map(_temp);
|
||||
$[4] = items;
|
||||
$[5] = t2;
|
||||
} else {
|
||||
t2 = $[5];
|
||||
}
|
||||
const mapped = t2;
|
||||
return mapped;
|
||||
}
|
||||
function _temp(item_0) {
|
||||
|
||||
@@ -21,18 +21,26 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
const f = _temp;
|
||||
let t0;
|
||||
if ($[0] !== props.items) {
|
||||
const x = [...props.items].map(f);
|
||||
t0 = [x, f];
|
||||
t0 = [...props.items].map(f);
|
||||
$[0] = props.items;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
const x = t0;
|
||||
let t1;
|
||||
if ($[2] !== x) {
|
||||
t1 = [x, f];
|
||||
$[2] = x;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
function _temp(item) {
|
||||
return item;
|
||||
|
||||
@@ -23,19 +23,27 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function component(a) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== a) {
|
||||
const z = { a };
|
||||
t0 = () => {
|
||||
console.log(z);
|
||||
};
|
||||
t0 = { a };
|
||||
$[0] = a;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const x = t0;
|
||||
const z = t0;
|
||||
let t1;
|
||||
if ($[2] !== z) {
|
||||
t1 = () => {
|
||||
console.log(z);
|
||||
};
|
||||
$[2] = z;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
const x = t1;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,19 +23,27 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function component(a) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== a) {
|
||||
const z = { a };
|
||||
t0 = function () {
|
||||
console.log(z);
|
||||
};
|
||||
t0 = { a };
|
||||
$[0] = a;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const x = t0;
|
||||
const z = t0;
|
||||
let t1;
|
||||
if ($[2] !== z) {
|
||||
t1 = function () {
|
||||
console.log(z);
|
||||
};
|
||||
$[2] = z;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
const x = t1;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,19 +22,35 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { Stringify } from "shared-runtime";
|
||||
function Component(t0) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(6);
|
||||
const { a } = t0;
|
||||
let t1;
|
||||
if ($[0] !== a) {
|
||||
const z = { a };
|
||||
const p = () => <Stringify>{z}</Stringify>;
|
||||
t1 = p();
|
||||
t1 = { a };
|
||||
$[0] = a;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
const z = t1;
|
||||
let t2;
|
||||
if ($[2] !== z) {
|
||||
t2 = () => <Stringify>{z}</Stringify>;
|
||||
$[2] = z;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
const p = t2;
|
||||
let t3;
|
||||
if ($[4] !== p) {
|
||||
t3 = p();
|
||||
$[4] = p;
|
||||
$[5] = t3;
|
||||
} else {
|
||||
t3 = $[5];
|
||||
}
|
||||
return t3;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -25,19 +25,27 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function component(a) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== a) {
|
||||
const z = { a };
|
||||
t0 = function () {
|
||||
console.log(z);
|
||||
};
|
||||
t0 = { a };
|
||||
$[0] = a;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const x = t0;
|
||||
const z = t0;
|
||||
let t1;
|
||||
if ($[2] !== z) {
|
||||
t1 = function () {
|
||||
console.log(z);
|
||||
};
|
||||
$[2] = z;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
const x = t1;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,21 +25,29 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function component(a) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== a) {
|
||||
const z = { a };
|
||||
t0 = function () {
|
||||
(function () {
|
||||
console.log(z);
|
||||
})();
|
||||
};
|
||||
t0 = { a };
|
||||
$[0] = a;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const x = t0;
|
||||
const z = t0;
|
||||
let t1;
|
||||
if ($[2] !== z) {
|
||||
t1 = function () {
|
||||
(function () {
|
||||
console.log(z);
|
||||
})();
|
||||
};
|
||||
$[2] = z;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
const x = t1;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
@@ -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} />;
|
||||
```
|
||||
|
||||
|
||||
@@ -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}],
|
||||
};
|
||||
@@ -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 | }
|
||||
```
|
||||
|
||||
|
||||
@@ -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}],
|
||||
};
|
||||
@@ -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 |
|
||||
```
|
||||
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -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 | }
|
||||
```
|
||||
|
||||
|
||||
@@ -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}],
|
||||
};
|
||||
@@ -29,7 +29,7 @@ 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
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ Passing a ref to a function may read its value during render
|
||||
10 | }
|
||||
11 |
|
||||
```
|
||||
|
||||
@@ -28,7 +28,7 @@ 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
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ Passing a ref to a function may read its value during render
|
||||
9 | }
|
||||
10 |
|
||||
```
|
||||
|
||||
@@ -41,13 +41,14 @@ 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-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};
|
||||
| ^^^^^^^^^^^^^^^ Cannot access ref value during render
|
||||
11 |
|
||||
> 12 | return <VideoList videos={x} />;
|
||||
| ^ Cannot access ref value during render
|
||||
12 | return <VideoList videos={x} />;
|
||||
13 | }
|
||||
14 |
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
|
||||
## 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: 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.repro-ref-mutable-range.ts:11:36
|
||||
9 | mutate(value);
|
||||
10 | if (CONST_TRUE) {
|
||||
> 11 | return <Stringify ref={identity(ref)} />;
|
||||
| ^^^ Passing a ref to a function may read its value during render
|
||||
12 | }
|
||||
13 | return value;
|
||||
14 | }
|
||||
```
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {makeObject_Primitives, Stringify} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
const object = {object: props.object};
|
||||
const entries = useMemo(() => Object.entries(object), [object]);
|
||||
entries.map(([, value]) => {
|
||||
value.updated = true;
|
||||
});
|
||||
return <Stringify entries={entries} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{object: {key: makeObject_Primitives()}}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
Found 2 errors:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
|
||||
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This dependency may be mutated later, which could cause the value to change unexpectedly.
|
||||
|
||||
error.validate-object-entries-mutation.ts:6:57
|
||||
4 | function Component(props) {
|
||||
5 | const object = {object: props.object};
|
||||
> 6 | const entries = useMemo(() => Object.entries(object), [object]);
|
||||
| ^^^^^^ This dependency may be modified later
|
||||
7 | entries.map(([, value]) => {
|
||||
8 | value.updated = true;
|
||||
9 | });
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
|
||||
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output.
|
||||
|
||||
error.validate-object-entries-mutation.ts:6:18
|
||||
4 | function Component(props) {
|
||||
5 | const object = {object: props.object};
|
||||
> 6 | const entries = useMemo(() => Object.entries(object), [object]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Could not preserve existing memoization
|
||||
7 | entries.map(([, value]) => {
|
||||
8 | value.updated = true;
|
||||
9 | });
|
||||
```
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {makeObject_Primitives, Stringify} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
const object = {object: props.object};
|
||||
const entries = useMemo(() => Object.entries(object), [object]);
|
||||
entries.map(([, value]) => {
|
||||
value.updated = true;
|
||||
});
|
||||
return <Stringify entries={entries} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{object: {key: makeObject_Primitives()}}],
|
||||
};
|
||||
@@ -1,57 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {makeObject_Primitives, Stringify} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
const object = {object: props.object};
|
||||
const values = useMemo(() => Object.values(object), [object]);
|
||||
values.map(value => {
|
||||
value.updated = true;
|
||||
});
|
||||
return <Stringify values={values} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{object: {key: makeObject_Primitives()}}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
Found 2 errors:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
|
||||
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This dependency may be mutated later, which could cause the value to change unexpectedly.
|
||||
|
||||
error.validate-object-values-mutation.ts:6:55
|
||||
4 | function Component(props) {
|
||||
5 | const object = {object: props.object};
|
||||
> 6 | const values = useMemo(() => Object.values(object), [object]);
|
||||
| ^^^^^^ This dependency may be modified later
|
||||
7 | values.map(value => {
|
||||
8 | value.updated = true;
|
||||
9 | });
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
|
||||
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output.
|
||||
|
||||
error.validate-object-values-mutation.ts:6:17
|
||||
4 | function Component(props) {
|
||||
5 | const object = {object: props.object};
|
||||
> 6 | const values = useMemo(() => Object.values(object), [object]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Could not preserve existing memoization
|
||||
7 | values.map(value => {
|
||||
8 | value.updated = true;
|
||||
9 | });
|
||||
```
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {makeObject_Primitives, Stringify} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
const object = {object: props.object};
|
||||
const values = useMemo(() => Object.values(object), [object]);
|
||||
values.map(value => {
|
||||
value.updated = true;
|
||||
});
|
||||
return <Stringify values={values} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{object: {key: makeObject_Primitives()}}],
|
||||
};
|
||||
@@ -40,29 +40,36 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(5);
|
||||
const $ = _c(7);
|
||||
let t0;
|
||||
if ($[0] !== props.a) {
|
||||
const a = [props.a];
|
||||
|
||||
t0 = [a];
|
||||
t0 = [props.a];
|
||||
$[0] = props.a;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const b = t0;
|
||||
const a = t0;
|
||||
let t1;
|
||||
if ($[2] !== a) {
|
||||
t1 = [a];
|
||||
$[2] = a;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
const b = t1;
|
||||
let c;
|
||||
if ($[2] !== b || $[3] !== props.b) {
|
||||
if ($[4] !== b || $[5] !== props.b) {
|
||||
c = [];
|
||||
const d = {};
|
||||
d.b = b;
|
||||
c.push(props.b);
|
||||
$[2] = b;
|
||||
$[3] = props.b;
|
||||
$[4] = c;
|
||||
$[4] = b;
|
||||
$[5] = props.b;
|
||||
$[6] = c;
|
||||
} else {
|
||||
c = $[4];
|
||||
c = $[6];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -32,10 +32,10 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import fbt from "fbt";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== props.name) {
|
||||
const element = fbt._(
|
||||
t0 = fbt._(
|
||||
"Hello {a really long description that got split into multiple lines}",
|
||||
[
|
||||
fbt._param(
|
||||
@@ -46,14 +46,21 @@ function Component(props) {
|
||||
],
|
||||
{ hk: "1euPUp" },
|
||||
);
|
||||
|
||||
t0 = element.toString();
|
||||
$[0] = props.name;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
const element = t0;
|
||||
let t1;
|
||||
if ($[2] !== element) {
|
||||
t1 = element.toString();
|
||||
$[2] = element;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -27,28 +27,27 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import fbt from "fbt";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== props.name) {
|
||||
const element = fbt._(
|
||||
'Hello {"user" name}',
|
||||
[
|
||||
fbt._param(
|
||||
'"user" name',
|
||||
|
||||
props.name,
|
||||
),
|
||||
],
|
||||
{ hk: "S0vMe" },
|
||||
);
|
||||
|
||||
t0 = element.toString();
|
||||
t0 = fbt._('Hello {"user" name}', [fbt._param('"user" name', props.name)], {
|
||||
hk: "S0vMe",
|
||||
});
|
||||
$[0] = props.name;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
const element = t0;
|
||||
let t1;
|
||||
if ($[2] !== element) {
|
||||
t1 = element.toString();
|
||||
$[2] = element;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -27,28 +27,29 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import fbt from "fbt";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== props.name) {
|
||||
const element = fbt._(
|
||||
t0 = fbt._(
|
||||
"Hello {user name ☺}",
|
||||
[
|
||||
fbt._param(
|
||||
"user name \u263A",
|
||||
|
||||
props.name,
|
||||
),
|
||||
],
|
||||
[fbt._param("user name \u263A", props.name)],
|
||||
{ hk: "1En1lp" },
|
||||
);
|
||||
|
||||
t0 = element.toString();
|
||||
$[0] = props.name;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
const element = t0;
|
||||
let t1;
|
||||
if ($[2] !== element) {
|
||||
t1 = element.toString();
|
||||
$[2] = element;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -27,28 +27,27 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import fbt from "fbt";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== props.name) {
|
||||
const element = fbt._(
|
||||
"Hello {user name}",
|
||||
[
|
||||
fbt._param(
|
||||
"user name",
|
||||
|
||||
props.name,
|
||||
),
|
||||
],
|
||||
{ hk: "2zEDKF" },
|
||||
);
|
||||
|
||||
t0 = element.toString();
|
||||
t0 = fbt._("Hello {user name}", [fbt._param("user name", props.name)], {
|
||||
hk: "2zEDKF",
|
||||
});
|
||||
$[0] = props.name;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
const element = t0;
|
||||
let t1;
|
||||
if ($[2] !== element) {
|
||||
t1 = element.toString();
|
||||
$[2] = element;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -22,21 +22,28 @@ function Component(props) {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
const id = useSelectedEntitytId();
|
||||
let t0;
|
||||
if ($[0] !== id) {
|
||||
const onLoad = () => {
|
||||
t0 = () => {
|
||||
log(id);
|
||||
};
|
||||
|
||||
t0 = <Foo onLoad={onLoad} />;
|
||||
$[0] = id;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
const onLoad = t0;
|
||||
let t1;
|
||||
if ($[2] !== onLoad) {
|
||||
t1 = <Foo onLoad={onLoad} />;
|
||||
$[2] = onLoad;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -21,20 +21,27 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== props) {
|
||||
const f = function () {
|
||||
t0 = function () {
|
||||
return <div>{props.name}</div>;
|
||||
};
|
||||
|
||||
t0 = f.call();
|
||||
$[0] = props;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
const f = t0;
|
||||
let t1;
|
||||
if ($[2] !== f) {
|
||||
t1 = f.call();
|
||||
$[2] = f;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -55,26 +55,33 @@ import { Stringify } from "shared-runtime";
|
||||
* (kind: exception) Cannot read properties of null (reading 'prop')
|
||||
*/
|
||||
function Component(t0) {
|
||||
const $ = _c(3);
|
||||
const $ = _c(5);
|
||||
const { obj, isObjNull } = t0;
|
||||
let t1;
|
||||
if ($[0] !== isObjNull || $[1] !== obj) {
|
||||
const callback = () => {
|
||||
t1 = () => {
|
||||
if (!isObjNull) {
|
||||
return obj.prop;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
t1 = <Stringify shouldInvokeFns={true} callback={callback} />;
|
||||
$[0] = isObjNull;
|
||||
$[1] = obj;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
return t1;
|
||||
const callback = t1;
|
||||
let t2;
|
||||
if ($[3] !== callback) {
|
||||
t2 = <Stringify shouldInvokeFns={true} callback={callback} />;
|
||||
$[3] = callback;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -27,7 +27,7 @@ function useFoo() {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees
|
||||
function useFoo() {
|
||||
const $ = _c(7);
|
||||
const $ = _c(9);
|
||||
const onClick = (response) => {
|
||||
setState(DISABLED_FORM);
|
||||
};
|
||||
@@ -48,24 +48,31 @@ function useFoo() {
|
||||
const handleLogout = t1;
|
||||
let t2;
|
||||
if ($[2] !== handleLogout) {
|
||||
const getComponent = () => <ColumnItem onPress={() => handleLogout()} />;
|
||||
|
||||
t2 = getComponent();
|
||||
t2 = () => <ColumnItem onPress={() => handleLogout()} />;
|
||||
$[2] = handleLogout;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
const getComponent = t2;
|
||||
let t3;
|
||||
if ($[4] !== onClick || $[5] !== t2) {
|
||||
t3 = [t2, onClick];
|
||||
$[4] = onClick;
|
||||
$[5] = t2;
|
||||
$[6] = t3;
|
||||
if ($[4] !== getComponent) {
|
||||
t3 = getComponent();
|
||||
$[4] = getComponent;
|
||||
$[5] = t3;
|
||||
} else {
|
||||
t3 = $[6];
|
||||
t3 = $[5];
|
||||
}
|
||||
return t3;
|
||||
let t4;
|
||||
if ($[6] !== onClick || $[7] !== t3) {
|
||||
t4 = [t3, onClick];
|
||||
$[6] = onClick;
|
||||
$[7] = t3;
|
||||
$[8] = t4;
|
||||
} else {
|
||||
t4 = $[8];
|
||||
}
|
||||
return t4;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -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}
|
||||
```
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -42,58 +42,74 @@ import { c as _c } from "react/compiler-runtime"; /**
|
||||
* conservative and assume that all named lambdas are conditionally called.
|
||||
*/
|
||||
function useFoo(t0) {
|
||||
const $ = _c(13);
|
||||
const $ = _c(17);
|
||||
const { arr1, arr2 } = t0;
|
||||
let t1;
|
||||
if ($[0] !== arr1[0]) {
|
||||
const getVal1 = () => arr1[0].value;
|
||||
t1 = (e) => getVal1() + e.value;
|
||||
t1 = () => arr1[0].value;
|
||||
$[0] = arr1[0];
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
const cb1 = t1;
|
||||
const getVal1 = t1;
|
||||
let t2;
|
||||
if ($[2] !== arr1 || $[3] !== cb1) {
|
||||
t2 = arr1.map(cb1);
|
||||
$[2] = arr1;
|
||||
$[3] = cb1;
|
||||
$[4] = t2;
|
||||
if ($[2] !== getVal1) {
|
||||
t2 = (e) => getVal1() + e.value;
|
||||
$[2] = getVal1;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
t2 = $[3];
|
||||
}
|
||||
const x = t2;
|
||||
const cb1 = t2;
|
||||
let t3;
|
||||
if ($[5] !== arr2) {
|
||||
const getVal2 = () => arr2[0].value;
|
||||
t3 = (e_0) => getVal2() + e_0.value;
|
||||
$[5] = arr2;
|
||||
if ($[4] !== arr1 || $[5] !== cb1) {
|
||||
t3 = arr1.map(cb1);
|
||||
$[4] = arr1;
|
||||
$[5] = cb1;
|
||||
$[6] = t3;
|
||||
} else {
|
||||
t3 = $[6];
|
||||
}
|
||||
const cb2 = t3;
|
||||
const x = t3;
|
||||
let t4;
|
||||
if ($[7] !== arr1 || $[8] !== cb2) {
|
||||
t4 = arr1.map(cb2);
|
||||
$[7] = arr1;
|
||||
$[8] = cb2;
|
||||
$[9] = t4;
|
||||
if ($[7] !== arr2) {
|
||||
t4 = () => arr2[0].value;
|
||||
$[7] = arr2;
|
||||
$[8] = t4;
|
||||
} else {
|
||||
t4 = $[9];
|
||||
t4 = $[8];
|
||||
}
|
||||
const y = t4;
|
||||
const getVal2 = t4;
|
||||
let t5;
|
||||
if ($[10] !== x || $[11] !== y) {
|
||||
t5 = [x, y];
|
||||
$[10] = x;
|
||||
$[11] = y;
|
||||
$[12] = t5;
|
||||
if ($[9] !== getVal2) {
|
||||
t5 = (e_0) => getVal2() + e_0.value;
|
||||
$[9] = getVal2;
|
||||
$[10] = t5;
|
||||
} else {
|
||||
t5 = $[12];
|
||||
t5 = $[10];
|
||||
}
|
||||
return t5;
|
||||
const cb2 = t5;
|
||||
let t6;
|
||||
if ($[11] !== arr1 || $[12] !== cb2) {
|
||||
t6 = arr1.map(cb2);
|
||||
$[11] = arr1;
|
||||
$[12] = cb2;
|
||||
$[13] = t6;
|
||||
} else {
|
||||
t6 = $[13];
|
||||
}
|
||||
const y = t6;
|
||||
let t7;
|
||||
if ($[14] !== x || $[15] !== y) {
|
||||
t7 = [x, y];
|
||||
$[14] = x;
|
||||
$[15] = y;
|
||||
$[16] = t7;
|
||||
} else {
|
||||
t7 = $[16];
|
||||
}
|
||||
return t7;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -42,7 +42,7 @@ import { useRef } from "react";
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(7);
|
||||
const $ = _c(9);
|
||||
const { a, b } = t0;
|
||||
let t1;
|
||||
if ($[0] !== a.value) {
|
||||
@@ -70,22 +70,29 @@ function Component(t0) {
|
||||
const hasLogged = useRef(false);
|
||||
let t3;
|
||||
if ($[4] !== logA || $[5] !== logB) {
|
||||
const log = () => {
|
||||
t3 = () => {
|
||||
if (!hasLogged.current) {
|
||||
logA();
|
||||
logB();
|
||||
hasLogged.current = true;
|
||||
}
|
||||
};
|
||||
|
||||
t3 = <Stringify log={log} shouldInvokeFns={true} />;
|
||||
$[4] = logA;
|
||||
$[5] = logB;
|
||||
$[6] = t3;
|
||||
} else {
|
||||
t3 = $[6];
|
||||
}
|
||||
return t3;
|
||||
const log = t3;
|
||||
let t4;
|
||||
if ($[7] !== log) {
|
||||
t4 = <Stringify log={log} shouldInvokeFns={true} />;
|
||||
$[7] = log;
|
||||
$[8] = t4;
|
||||
} else {
|
||||
t4 = $[8];
|
||||
}
|
||||
return t4;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -24,20 +24,28 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import * as SharedRuntime from "shared-runtime";
|
||||
import { invoke } from "shared-runtime";
|
||||
function useComponentFactory(t0) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
const { name } = t0;
|
||||
let t1;
|
||||
if ($[0] !== name) {
|
||||
const cb = () => (
|
||||
t1 = () => (
|
||||
<SharedRuntime.Stringify>hello world {name}</SharedRuntime.Stringify>
|
||||
);
|
||||
t1 = invoke(cb);
|
||||
$[0] = name;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
const cb = t1;
|
||||
let t2;
|
||||
if ($[2] !== cb) {
|
||||
t2 = invoke(cb);
|
||||
$[2] = cb;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -25,18 +25,34 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableNewMutationAliasingModel
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(6);
|
||||
let t0;
|
||||
if ($[0] !== props.a) {
|
||||
const item = { a: props.a };
|
||||
const items = [item];
|
||||
t0 = items.map(_temp);
|
||||
t0 = { a: props.a };
|
||||
$[0] = props.a;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const mapped = t0;
|
||||
const item = t0;
|
||||
let t1;
|
||||
if ($[2] !== item) {
|
||||
t1 = [item];
|
||||
$[2] = item;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
const items = t1;
|
||||
let t2;
|
||||
if ($[4] !== items) {
|
||||
t2 = items.map(_temp);
|
||||
$[4] = items;
|
||||
$[5] = t2;
|
||||
} else {
|
||||
t2 = $[5];
|
||||
}
|
||||
const mapped = t2;
|
||||
return mapped;
|
||||
}
|
||||
function _temp(item_0) {
|
||||
|
||||
@@ -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}
|
||||
```
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {makeObject_Primitives, Stringify} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
const object = {object: props.object};
|
||||
const entries = Object.entries(object);
|
||||
entries.map(([, value]) => {
|
||||
value.updated = true;
|
||||
});
|
||||
return <Stringify entries={entries} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{object: {key: makeObject_Primitives()}}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { makeObject_Primitives, Stringify } from "shared-runtime";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] !== props.object) {
|
||||
const object = { object: props.object };
|
||||
const entries = Object.entries(object);
|
||||
entries.map(_temp);
|
||||
t0 = <Stringify entries={entries} />;
|
||||
$[0] = props.object;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
function _temp(t0) {
|
||||
const [, value] = t0;
|
||||
value.updated = true;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ object: { key: makeObject_Primitives() } }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"entries":[["object",{"key":{"a":0,"b":"value1","c":true},"updated":true}]]}</div>
|
||||
@@ -1,15 +0,0 @@
|
||||
import {makeObject_Primitives, Stringify} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
const object = {object: props.object};
|
||||
const entries = Object.entries(object);
|
||||
entries.map(([, value]) => {
|
||||
value.updated = true;
|
||||
});
|
||||
return <Stringify entries={entries} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{object: {key: makeObject_Primitives()}}],
|
||||
};
|
||||
@@ -1,108 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {useMemo} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
// derived from https://github.com/facebook/react/issues/32261
|
||||
function Component({items}) {
|
||||
const record = useMemo(
|
||||
() =>
|
||||
Object.fromEntries(
|
||||
items.map(item => [item.id, ref => <Stringify ref={ref} {...item} />])
|
||||
),
|
||||
[items]
|
||||
);
|
||||
|
||||
// Without a declaration for Object.entries(), this would be assumed to mutate
|
||||
// `record`, meaning existing memoization couldn't be preserved
|
||||
return (
|
||||
<div>
|
||||
{Object.keys(record).map(id => (
|
||||
<Stringify key={id} render={record[id]} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [
|
||||
{
|
||||
items: [
|
||||
{id: '0', name: 'Hello'},
|
||||
{id: '1', name: 'World!'},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees
|
||||
import { useMemo } from "react";
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
// derived from https://github.com/facebook/react/issues/32261
|
||||
function Component(t0) {
|
||||
const $ = _c(7);
|
||||
const { items } = t0;
|
||||
let t1;
|
||||
if ($[0] !== items) {
|
||||
t1 = Object.fromEntries(items.map(_temp));
|
||||
$[0] = items;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
const record = t1;
|
||||
let t2;
|
||||
if ($[2] !== record) {
|
||||
t2 = Object.keys(record);
|
||||
$[2] = record;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
let t3;
|
||||
if ($[4] !== record || $[5] !== t2) {
|
||||
t3 = (
|
||||
<div>
|
||||
{t2.map((id) => (
|
||||
<Stringify key={id} render={record[id]} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
$[4] = record;
|
||||
$[5] = t2;
|
||||
$[6] = t3;
|
||||
} else {
|
||||
t3 = $[6];
|
||||
}
|
||||
return t3;
|
||||
}
|
||||
function _temp(item) {
|
||||
return [item.id, (ref) => <Stringify ref={ref} {...item} />];
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [
|
||||
{
|
||||
items: [
|
||||
{ id: "0", name: "Hello" },
|
||||
{ id: "1", name: "World!" },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div><div>{"render":"[[ function params=1 ]]"}</div><div>{"render":"[[ function params=1 ]]"}</div></div>
|
||||
@@ -1,36 +0,0 @@
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {useMemo} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
// derived from https://github.com/facebook/react/issues/32261
|
||||
function Component({items}) {
|
||||
const record = useMemo(
|
||||
() =>
|
||||
Object.fromEntries(
|
||||
items.map(item => [item.id, ref => <Stringify ref={ref} {...item} />])
|
||||
),
|
||||
[items]
|
||||
);
|
||||
|
||||
// Without a declaration for Object.entries(), this would be assumed to mutate
|
||||
// `record`, meaning existing memoization couldn't be preserved
|
||||
return (
|
||||
<div>
|
||||
{Object.keys(record).map(id => (
|
||||
<Stringify key={id} render={record[id]} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [
|
||||
{
|
||||
items: [
|
||||
{id: '0', name: 'Hello'},
|
||||
{id: '1', name: 'World!'},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1,57 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {makeObject_Primitives, Stringify} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
const object = {object: props.object};
|
||||
const entries = Object.entries(object);
|
||||
entries.map(([, value]) => {
|
||||
value.updated = true;
|
||||
});
|
||||
return <Stringify entries={entries} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{object: {key: makeObject_Primitives()}}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { makeObject_Primitives, Stringify } from "shared-runtime";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] !== props.object) {
|
||||
const object = { object: props.object };
|
||||
const entries = Object.entries(object);
|
||||
entries.map(_temp);
|
||||
t0 = <Stringify entries={entries} />;
|
||||
$[0] = props.object;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
function _temp(t0) {
|
||||
const [, value] = t0;
|
||||
value.updated = true;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ object: { key: makeObject_Primitives() } }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"entries":[["object",{"key":{"a":0,"b":"value1","c":true},"updated":true}]]}</div>
|
||||
@@ -1,15 +0,0 @@
|
||||
import {makeObject_Primitives, Stringify} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
const object = {object: props.object};
|
||||
const entries = Object.entries(object);
|
||||
entries.map(([, value]) => {
|
||||
value.updated = true;
|
||||
});
|
||||
return <Stringify entries={entries} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{object: {key: makeObject_Primitives()}}],
|
||||
};
|
||||
@@ -1,103 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {useMemo} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
// derived from https://github.com/facebook/react/issues/32261
|
||||
function Component({items}) {
|
||||
const record = useMemo(
|
||||
() =>
|
||||
Object.fromEntries(
|
||||
items.map(item => [
|
||||
item.id,
|
||||
{id: item.id, render: ref => <Stringify ref={ref} {...item} />},
|
||||
])
|
||||
),
|
||||
[items]
|
||||
);
|
||||
|
||||
// Without a declaration for Object.entries(), this would be assumed to mutate
|
||||
// `record`, meaning existing memoization couldn't be preserved
|
||||
return (
|
||||
<div>
|
||||
{Object.values(record).map(({id, render}) => (
|
||||
<Stringify key={id} render={render} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [
|
||||
{
|
||||
items: [
|
||||
{id: '0', name: 'Hello'},
|
||||
{id: '1', name: 'World!'},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees
|
||||
import { useMemo } from "react";
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
// derived from https://github.com/facebook/react/issues/32261
|
||||
function Component(t0) {
|
||||
const $ = _c(4);
|
||||
const { items } = t0;
|
||||
let t1;
|
||||
if ($[0] !== items) {
|
||||
t1 = Object.fromEntries(items.map(_temp));
|
||||
$[0] = items;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
const record = t1;
|
||||
let t2;
|
||||
if ($[2] !== record) {
|
||||
t2 = <div>{Object.values(record).map(_temp2)}</div>;
|
||||
$[2] = record;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
function _temp2(t0) {
|
||||
const { id, render } = t0;
|
||||
return <Stringify key={id} render={render} />;
|
||||
}
|
||||
function _temp(item) {
|
||||
return [
|
||||
item.id,
|
||||
{ id: item.id, render: (ref) => <Stringify ref={ref} {...item} /> },
|
||||
];
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [
|
||||
{
|
||||
items: [
|
||||
{ id: "0", name: "Hello" },
|
||||
{ id: "1", name: "World!" },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div><div>{"render":"[[ function params=1 ]]"}</div><div>{"render":"[[ function params=1 ]]"}</div></div>
|
||||
@@ -1,39 +0,0 @@
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {useMemo} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
// derived from https://github.com/facebook/react/issues/32261
|
||||
function Component({items}) {
|
||||
const record = useMemo(
|
||||
() =>
|
||||
Object.fromEntries(
|
||||
items.map(item => [
|
||||
item.id,
|
||||
{id: item.id, render: ref => <Stringify ref={ref} {...item} />},
|
||||
])
|
||||
),
|
||||
[items]
|
||||
);
|
||||
|
||||
// Without a declaration for Object.entries(), this would be assumed to mutate
|
||||
// `record`, meaning existing memoization couldn't be preserved
|
||||
return (
|
||||
<div>
|
||||
{Object.values(record).map(({id, render}) => (
|
||||
<Stringify key={id} render={render} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [
|
||||
{
|
||||
items: [
|
||||
{id: '0', name: 'Hello'},
|
||||
{id: '1', name: 'World!'},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -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 |
|
||||
```
|
||||
|
||||
|
||||
@@ -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 |
|
||||
```
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -23,20 +23,28 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function component(a, b) {
|
||||
const $ = _c(3);
|
||||
const $ = _c(5);
|
||||
let t0;
|
||||
if ($[0] !== a || $[1] !== b) {
|
||||
const z = { a, b };
|
||||
t0 = function () {
|
||||
console.log(z);
|
||||
};
|
||||
t0 = { a, b };
|
||||
$[0] = a;
|
||||
$[1] = b;
|
||||
$[2] = t0;
|
||||
} else {
|
||||
t0 = $[2];
|
||||
}
|
||||
const x = t0;
|
||||
const z = t0;
|
||||
let t1;
|
||||
if ($[3] !== z) {
|
||||
t1 = function () {
|
||||
console.log(z);
|
||||
};
|
||||
$[3] = z;
|
||||
$[4] = t1;
|
||||
} else {
|
||||
t1 = $[4];
|
||||
}
|
||||
const x = t1;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR
|
||||
import { mutate, shallowCopy, Stringify } from "shared-runtime";
|
||||
|
||||
function useFoo(t0) {
|
||||
const $ = _c(4);
|
||||
const $ = _c(6);
|
||||
const { a } = t0;
|
||||
let local;
|
||||
if ($[0] !== a) {
|
||||
@@ -42,14 +42,22 @@ function useFoo(t0) {
|
||||
}
|
||||
let t1;
|
||||
if ($[2] !== local.b.c) {
|
||||
const fn = () => local.b.c;
|
||||
t1 = <Stringify fn={fn} shouldInvokeFns={true} />;
|
||||
t1 = () => local.b.c;
|
||||
$[2] = local.b.c;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
return t1;
|
||||
const fn = t1;
|
||||
let t2;
|
||||
if ($[4] !== fn) {
|
||||
t2 = <Stringify fn={fn} shouldInvokeFns={true} />;
|
||||
$[4] = fn;
|
||||
$[5] = t2;
|
||||
} else {
|
||||
t2 = $[5];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -29,7 +29,7 @@ import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR
|
||||
import { shallowCopy, Stringify, mutate } from "shared-runtime";
|
||||
|
||||
function useFoo(t0) {
|
||||
const $ = _c(4);
|
||||
const $ = _c(6);
|
||||
const { a } = t0;
|
||||
let local;
|
||||
if ($[0] !== a) {
|
||||
@@ -42,14 +42,22 @@ function useFoo(t0) {
|
||||
}
|
||||
let t1;
|
||||
if ($[2] !== local) {
|
||||
const fn = () => [() => local.b.c];
|
||||
t1 = <Stringify fn={fn} shouldInvokeFns={true} />;
|
||||
t1 = () => [() => local.b.c];
|
||||
$[2] = local;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
return t1;
|
||||
const fn = t1;
|
||||
let t2;
|
||||
if ($[4] !== fn) {
|
||||
t2 = <Stringify fn={fn} shouldInvokeFns={true} />;
|
||||
$[4] = fn;
|
||||
$[5] = t2;
|
||||
} else {
|
||||
t2 = $[5];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -31,19 +31,26 @@ import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
function useFoo(t0) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
const { a } = t0;
|
||||
let t1;
|
||||
if ($[0] !== a.b.c) {
|
||||
const fn = () => () => ({ value: a.b.c });
|
||||
|
||||
t1 = <Stringify fn={fn} shouldInvokeFns={true} />;
|
||||
t1 = () => () => ({ value: a.b.c });
|
||||
$[0] = a.b.c;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
const fn = t1;
|
||||
let t2;
|
||||
if ($[2] !== fn) {
|
||||
t2 = <Stringify fn={fn} shouldInvokeFns={true} />;
|
||||
$[2] = fn;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -31,23 +31,30 @@ import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR
|
||||
import { identity, Stringify } from "shared-runtime";
|
||||
|
||||
function useFoo(t0) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
const { a } = t0;
|
||||
let t1;
|
||||
if ($[0] !== a) {
|
||||
const x = {
|
||||
t1 = {
|
||||
fn() {
|
||||
return identity(a.b.c);
|
||||
},
|
||||
};
|
||||
|
||||
t1 = <Stringify x={x} shouldInvokeFns={true} />;
|
||||
$[0] = a;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
const x = t1;
|
||||
let t2;
|
||||
if ($[2] !== x) {
|
||||
t2 = <Stringify x={x} shouldInvokeFns={true} />;
|
||||
$[2] = x;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -29,7 +29,7 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import { useHook } from "shared-runtime";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(4);
|
||||
const $ = _c(6);
|
||||
const o = {};
|
||||
let t0;
|
||||
if ($[0] !== props.value) {
|
||||
@@ -44,15 +44,22 @@ function Component(props) {
|
||||
o.value = props.value;
|
||||
let t1;
|
||||
if ($[2] !== x) {
|
||||
const y = <div>{x}</div>;
|
||||
|
||||
t1 = <div>{y}</div>;
|
||||
t1 = <div>{x}</div>;
|
||||
$[2] = x;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
return t1;
|
||||
const y = t1;
|
||||
let t2;
|
||||
if ($[4] !== y) {
|
||||
t2 = <div>{y}</div>;
|
||||
$[4] = y;
|
||||
$[5] = t2;
|
||||
} else {
|
||||
t2 = $[5];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -31,7 +31,7 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import { useHook, identity } from "shared-runtime";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
let x = 42;
|
||||
if (props.cond) {
|
||||
x = [];
|
||||
@@ -41,15 +41,22 @@ function Component(props) {
|
||||
identity(x);
|
||||
let t0;
|
||||
if ($[0] !== x) {
|
||||
const y = [x];
|
||||
|
||||
t0 = [y];
|
||||
t0 = [x];
|
||||
$[0] = x;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
const y = t0;
|
||||
let t1;
|
||||
if ($[2] !== y) {
|
||||
t1 = [y];
|
||||
$[2] = y;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -66,17 +66,25 @@ function Parent(t0) {
|
||||
}
|
||||
|
||||
function ChildImpl(_props, ref) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== ref) {
|
||||
const cb = () => ref.current;
|
||||
t0 = <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
t0 = () => ref.current;
|
||||
$[0] = ref;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
const cb = t0;
|
||||
let t1;
|
||||
if ($[2] !== cb) {
|
||||
t1 = <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
$[2] = cb;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
const Child = forwardRef(ChildImpl);
|
||||
|
||||
@@ -41,21 +41,29 @@ import { Stringify } from "shared-runtime";
|
||||
* `pruneNonReactiveDependencies`
|
||||
*/
|
||||
function Component(t0) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
const { cond } = t0;
|
||||
const ref1 = useRef(1);
|
||||
const ref2 = useRef(2);
|
||||
const ref = cond ? ref1 : ref2;
|
||||
let t1;
|
||||
if ($[0] !== ref) {
|
||||
const cb = () => ref.current;
|
||||
t1 = <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
t1 = () => ref.current;
|
||||
$[0] = ref;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
const cb = t1;
|
||||
let t2;
|
||||
if ($[2] !== cb) {
|
||||
t2 = <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
$[2] = cb;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -35,23 +35,34 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(6);
|
||||
let a;
|
||||
let t0;
|
||||
if ($[0] !== props.b) {
|
||||
const a = {};
|
||||
a = {};
|
||||
const b = [];
|
||||
b.push(props.b);
|
||||
a.a = null;
|
||||
|
||||
const c = [a];
|
||||
|
||||
t0 = [c, a];
|
||||
t0 = [a];
|
||||
$[0] = props.b;
|
||||
$[1] = t0;
|
||||
$[1] = a;
|
||||
$[2] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
a = $[1];
|
||||
t0 = $[2];
|
||||
}
|
||||
return t0;
|
||||
const c = t0;
|
||||
let t1;
|
||||
if ($[3] !== a || $[4] !== c) {
|
||||
t1 = [c, a];
|
||||
$[3] = a;
|
||||
$[4] = c;
|
||||
$[5] = t1;
|
||||
} else {
|
||||
t1 = $[5];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -32,24 +32,18 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(4);
|
||||
let x;
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] !== props.input) {
|
||||
x = [];
|
||||
const x = [];
|
||||
const y = x;
|
||||
y.push(props.input);
|
||||
$[0] = props.input;
|
||||
$[1] = x;
|
||||
} else {
|
||||
x = $[1];
|
||||
}
|
||||
let t0;
|
||||
if ($[2] !== x[0]) {
|
||||
|
||||
t0 = [x[0]];
|
||||
$[2] = x[0];
|
||||
$[3] = t0;
|
||||
$[0] = props.input;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[3];
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
@@ -35,28 +35,22 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(4);
|
||||
let x;
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] !== props.input) {
|
||||
x = [];
|
||||
const x = [];
|
||||
const f = (arg) => {
|
||||
const y = x;
|
||||
y.push(arg);
|
||||
};
|
||||
|
||||
f(props.input);
|
||||
$[0] = props.input;
|
||||
$[1] = x;
|
||||
} else {
|
||||
x = $[1];
|
||||
}
|
||||
let t0;
|
||||
if ($[2] !== x[0]) {
|
||||
|
||||
t0 = [x[0]];
|
||||
$[2] = x[0];
|
||||
$[3] = t0;
|
||||
$[0] = props.input;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[3];
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
@@ -18,21 +18,28 @@ function Foo({a}) {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRender:false
|
||||
function Foo(t0) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
const { a } = t0;
|
||||
const ref = useRef();
|
||||
const val = ref.current;
|
||||
let t1;
|
||||
if ($[0] !== a) {
|
||||
const x = { a, val };
|
||||
|
||||
t1 = <VideoList videos={x} />;
|
||||
t1 = { a, val };
|
||||
$[0] = a;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
const x = t1;
|
||||
let t2;
|
||||
if ($[2] !== x) {
|
||||
t2 = <VideoList videos={x} />;
|
||||
$[2] = x;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -17,20 +17,27 @@ function Foo({a}) {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRender:false
|
||||
function Foo(t0) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
const { a } = t0;
|
||||
const ref = useRef();
|
||||
let t1;
|
||||
if ($[0] !== a) {
|
||||
const x = { a, val: ref.current };
|
||||
|
||||
t1 = <VideoList videos={x} />;
|
||||
t1 = { a, val: ref.current };
|
||||
$[0] = a;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
const x = t1;
|
||||
let t2;
|
||||
if ($[2] !== x) {
|
||||
t2 = <VideoList videos={x} />;
|
||||
$[2] = x;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -41,11 +41,11 @@ const $ = "module_$";
|
||||
const t0 = "module_t0";
|
||||
const c_0 = "module_c_0";
|
||||
function useFoo(props) {
|
||||
const $0 = _c(2);
|
||||
const $0 = _c(4);
|
||||
const c_00 = $0[0] !== props.value;
|
||||
let t1;
|
||||
if (c_00) {
|
||||
const a = () => {
|
||||
t1 = () => {
|
||||
const b = () => {
|
||||
const c = () => {
|
||||
console.log($);
|
||||
@@ -57,14 +57,22 @@ function useFoo(props) {
|
||||
};
|
||||
return b;
|
||||
};
|
||||
|
||||
t1 = a()()();
|
||||
$0[0] = props.value;
|
||||
$0[1] = t1;
|
||||
} else {
|
||||
t1 = $0[1];
|
||||
}
|
||||
return t1;
|
||||
const a = t1;
|
||||
const c_2 = $0[2] !== a;
|
||||
let t2;
|
||||
if (c_2) {
|
||||
t2 = a()()();
|
||||
$0[2] = a;
|
||||
$0[3] = t2;
|
||||
} else {
|
||||
t2 = $0[3];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -35,44 +35,60 @@ import { useMemo } from "react";
|
||||
import { useFragment } from "shared-runtime";
|
||||
|
||||
function Component() {
|
||||
const $ = _c(7);
|
||||
const $ = _c(11);
|
||||
const data = useFragment();
|
||||
let t0;
|
||||
if ($[0] !== data.nodes) {
|
||||
const nodes = data.nodes ?? [];
|
||||
const flatMap = nodes.flatMap(_temp);
|
||||
t0 = flatMap.filter(_temp2);
|
||||
t0 = data.nodes ?? [];
|
||||
$[0] = data.nodes;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const filtered = t0;
|
||||
const nodes = t0;
|
||||
let t1;
|
||||
if ($[2] !== filtered) {
|
||||
t1 = filtered.map();
|
||||
$[2] = filtered;
|
||||
if ($[2] !== nodes) {
|
||||
t1 = nodes.flatMap(_temp);
|
||||
$[2] = nodes;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
const map = t1;
|
||||
const index = filtered.findIndex(_temp3);
|
||||
const flatMap = t1;
|
||||
let t2;
|
||||
if ($[4] !== index || $[5] !== map) {
|
||||
t2 = (
|
||||
if ($[4] !== flatMap) {
|
||||
t2 = flatMap.filter(_temp2);
|
||||
$[4] = flatMap;
|
||||
$[5] = t2;
|
||||
} else {
|
||||
t2 = $[5];
|
||||
}
|
||||
const filtered = t2;
|
||||
let t3;
|
||||
if ($[6] !== filtered) {
|
||||
t3 = filtered.map();
|
||||
$[6] = filtered;
|
||||
$[7] = t3;
|
||||
} else {
|
||||
t3 = $[7];
|
||||
}
|
||||
const map = t3;
|
||||
const index = filtered.findIndex(_temp3);
|
||||
let t4;
|
||||
if ($[8] !== index || $[9] !== map) {
|
||||
t4 = (
|
||||
<div>
|
||||
{map}
|
||||
{index}
|
||||
</div>
|
||||
);
|
||||
$[4] = index;
|
||||
$[5] = map;
|
||||
$[6] = t2;
|
||||
$[8] = index;
|
||||
$[9] = map;
|
||||
$[10] = t4;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
t4 = $[10];
|
||||
}
|
||||
return t2;
|
||||
return t4;
|
||||
}
|
||||
function _temp3(x) {
|
||||
return x === null;
|
||||
|
||||
@@ -32,44 +32,60 @@ import { useMemo } from "react";
|
||||
import { useFragment } from "shared-runtime";
|
||||
|
||||
function Component() {
|
||||
const $ = _c(7);
|
||||
const $ = _c(11);
|
||||
const data = useFragment();
|
||||
let t0;
|
||||
if ($[0] !== data.nodes) {
|
||||
const nodes = data.nodes ?? [];
|
||||
const flatMap = nodes.flatMap(_temp);
|
||||
t0 = flatMap.filter(_temp2);
|
||||
t0 = data.nodes ?? [];
|
||||
$[0] = data.nodes;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const filtered = t0;
|
||||
const nodes = t0;
|
||||
let t1;
|
||||
if ($[2] !== filtered) {
|
||||
t1 = filtered.map();
|
||||
$[2] = filtered;
|
||||
if ($[2] !== nodes) {
|
||||
t1 = nodes.flatMap(_temp);
|
||||
$[2] = nodes;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
const map = t1;
|
||||
const index = filtered.findIndex(_temp3);
|
||||
const flatMap = t1;
|
||||
let t2;
|
||||
if ($[4] !== index || $[5] !== map) {
|
||||
t2 = (
|
||||
if ($[4] !== flatMap) {
|
||||
t2 = flatMap.filter(_temp2);
|
||||
$[4] = flatMap;
|
||||
$[5] = t2;
|
||||
} else {
|
||||
t2 = $[5];
|
||||
}
|
||||
const filtered = t2;
|
||||
let t3;
|
||||
if ($[6] !== filtered) {
|
||||
t3 = filtered.map();
|
||||
$[6] = filtered;
|
||||
$[7] = t3;
|
||||
} else {
|
||||
t3 = $[7];
|
||||
}
|
||||
const map = t3;
|
||||
const index = filtered.findIndex(_temp3);
|
||||
let t4;
|
||||
if ($[8] !== index || $[9] !== map) {
|
||||
t4 = (
|
||||
<div>
|
||||
{map}
|
||||
{index}
|
||||
</div>
|
||||
);
|
||||
$[4] = index;
|
||||
$[5] = map;
|
||||
$[6] = t2;
|
||||
$[8] = index;
|
||||
$[9] = map;
|
||||
$[10] = t4;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
t4 = $[10];
|
||||
}
|
||||
return t2;
|
||||
return t4;
|
||||
}
|
||||
function _temp3(x) {
|
||||
return x === null;
|
||||
|
||||
@@ -30,33 +30,40 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import { identity, makeObject_Primitives, Stringify } from "shared-runtime";
|
||||
|
||||
function Example(props) {
|
||||
const $ = _c(5);
|
||||
const $ = _c(7);
|
||||
const object = props.object;
|
||||
let t0;
|
||||
if ($[0] !== object || $[1] !== props.value) {
|
||||
const f = () => {
|
||||
t0 = () => {
|
||||
const obj = identity(object);
|
||||
obj.property = props.value;
|
||||
return obj;
|
||||
};
|
||||
|
||||
t0 = f();
|
||||
$[0] = object;
|
||||
$[1] = props.value;
|
||||
$[2] = t0;
|
||||
} else {
|
||||
t0 = $[2];
|
||||
}
|
||||
const obj_0 = t0;
|
||||
const f = t0;
|
||||
let t1;
|
||||
if ($[3] !== obj_0) {
|
||||
t1 = <Stringify obj={obj_0} />;
|
||||
$[3] = obj_0;
|
||||
if ($[3] !== f) {
|
||||
t1 = f();
|
||||
$[3] = f;
|
||||
$[4] = t1;
|
||||
} else {
|
||||
t1 = $[4];
|
||||
}
|
||||
return t1;
|
||||
const obj_0 = t1;
|
||||
let t2;
|
||||
if ($[5] !== obj_0) {
|
||||
t2 = <Stringify obj={obj_0} />;
|
||||
$[5] = obj_0;
|
||||
$[6] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -30,33 +30,40 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import { makeObject_Primitives, Stringify } from "shared-runtime";
|
||||
|
||||
function Example(props) {
|
||||
const $ = _c(5);
|
||||
const $ = _c(7);
|
||||
const object = props.object;
|
||||
let t0;
|
||||
if ($[0] !== object || $[1] !== props.value) {
|
||||
const f = () => {
|
||||
t0 = () => {
|
||||
const obj = object.makeObject();
|
||||
obj.property = props.value;
|
||||
return obj;
|
||||
};
|
||||
|
||||
t0 = f();
|
||||
$[0] = object;
|
||||
$[1] = props.value;
|
||||
$[2] = t0;
|
||||
} else {
|
||||
t0 = $[2];
|
||||
}
|
||||
const obj_0 = t0;
|
||||
const f = t0;
|
||||
let t1;
|
||||
if ($[3] !== obj_0) {
|
||||
t1 = <Stringify obj={obj_0} />;
|
||||
$[3] = obj_0;
|
||||
if ($[3] !== f) {
|
||||
t1 = f();
|
||||
$[3] = f;
|
||||
$[4] = t1;
|
||||
} else {
|
||||
t1 = $[4];
|
||||
}
|
||||
return t1;
|
||||
const obj_0 = t1;
|
||||
let t2;
|
||||
if ($[5] !== obj_0) {
|
||||
t2 = <Stringify obj={obj_0} />;
|
||||
$[5] = obj_0;
|
||||
$[6] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {useMemo} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
// derived from https://github.com/facebook/react/issues/32261
|
||||
function Component({items}) {
|
||||
const record = useMemo(
|
||||
() =>
|
||||
Object.fromEntries(
|
||||
items.map(item => [item.id, ref => <Stringify ref={ref} {...item} />])
|
||||
),
|
||||
[items]
|
||||
);
|
||||
|
||||
// Without a declaration for Object.entries(), this would be assumed to mutate
|
||||
// `record`, meaning existing memoization couldn't be preserved
|
||||
return (
|
||||
<div>
|
||||
{Object.entries(record).map(([id, render]) => (
|
||||
<Stringify key={id} render={render} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [
|
||||
{
|
||||
items: [
|
||||
{id: '0', name: 'Hello'},
|
||||
{id: '1', name: 'World!'},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees
|
||||
import { useMemo } from "react";
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
// derived from https://github.com/facebook/react/issues/32261
|
||||
function Component(t0) {
|
||||
const $ = _c(4);
|
||||
const { items } = t0;
|
||||
let t1;
|
||||
if ($[0] !== items) {
|
||||
t1 = Object.fromEntries(items.map(_temp));
|
||||
$[0] = items;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
const record = t1;
|
||||
let t2;
|
||||
if ($[2] !== record) {
|
||||
t2 = <div>{Object.entries(record).map(_temp2)}</div>;
|
||||
$[2] = record;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
function _temp2(t0) {
|
||||
const [id, render] = t0;
|
||||
return <Stringify key={id} render={render} />;
|
||||
}
|
||||
function _temp(item) {
|
||||
return [item.id, (ref) => <Stringify ref={ref} {...item} />];
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [
|
||||
{
|
||||
items: [
|
||||
{ id: "0", name: "Hello" },
|
||||
{ id: "1", name: "World!" },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div><div>{"render":"[[ function params=1 ]]"}</div><div>{"render":"[[ function params=1 ]]"}</div></div>
|
||||
@@ -1,36 +0,0 @@
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {useMemo} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
// derived from https://github.com/facebook/react/issues/32261
|
||||
function Component({items}) {
|
||||
const record = useMemo(
|
||||
() =>
|
||||
Object.fromEntries(
|
||||
items.map(item => [item.id, ref => <Stringify ref={ref} {...item} />])
|
||||
),
|
||||
[items]
|
||||
);
|
||||
|
||||
// Without a declaration for Object.entries(), this would be assumed to mutate
|
||||
// `record`, meaning existing memoization couldn't be preserved
|
||||
return (
|
||||
<div>
|
||||
{Object.entries(record).map(([id, render]) => (
|
||||
<Stringify key={id} render={render} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [
|
||||
{
|
||||
items: [
|
||||
{id: '0', name: 'Hello'},
|
||||
{id: '1', name: 'World!'},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -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>
|
||||
@@ -45,7 +45,7 @@ import { Stringify, identity, makeArray, toJSON } from "shared-runtime";
|
||||
import { useMemo } from "react";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(10);
|
||||
const $ = _c(12);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== props) {
|
||||
@@ -71,50 +71,57 @@ function Component(props) {
|
||||
}
|
||||
let t2;
|
||||
if ($[3] !== t0) {
|
||||
const linkProps = { url: t0 };
|
||||
|
||||
const x = {};
|
||||
let t3;
|
||||
let t4;
|
||||
let t5;
|
||||
let t6;
|
||||
let t7;
|
||||
if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t3 = [1];
|
||||
t4 = [2];
|
||||
t5 = [3];
|
||||
t6 = [4];
|
||||
t7 = [5];
|
||||
$[5] = t3;
|
||||
$[6] = t4;
|
||||
$[7] = t5;
|
||||
$[8] = t6;
|
||||
$[9] = t7;
|
||||
} else {
|
||||
t3 = $[5];
|
||||
t4 = $[6];
|
||||
t5 = $[7];
|
||||
t6 = $[8];
|
||||
t7 = $[9];
|
||||
}
|
||||
t2 = (
|
||||
<Stringify
|
||||
link={linkProps}
|
||||
val1={t3}
|
||||
val2={t4}
|
||||
val3={t5}
|
||||
val4={t6}
|
||||
val5={t7}
|
||||
>
|
||||
{makeArray(x, 2)}
|
||||
</Stringify>
|
||||
);
|
||||
t2 = { url: t0 };
|
||||
$[3] = t0;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
return t2;
|
||||
const linkProps = t2;
|
||||
let t3;
|
||||
if ($[5] !== linkProps) {
|
||||
const x = {};
|
||||
let t4;
|
||||
let t5;
|
||||
let t6;
|
||||
let t7;
|
||||
let t8;
|
||||
if ($[7] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t4 = [1];
|
||||
t5 = [2];
|
||||
t6 = [3];
|
||||
t7 = [4];
|
||||
t8 = [5];
|
||||
$[7] = t4;
|
||||
$[8] = t5;
|
||||
$[9] = t6;
|
||||
$[10] = t7;
|
||||
$[11] = t8;
|
||||
} else {
|
||||
t4 = $[7];
|
||||
t5 = $[8];
|
||||
t6 = $[9];
|
||||
t7 = $[10];
|
||||
t8 = $[11];
|
||||
}
|
||||
t3 = (
|
||||
<Stringify
|
||||
link={linkProps}
|
||||
val1={t4}
|
||||
val2={t5}
|
||||
val3={t6}
|
||||
val4={t7}
|
||||
val5={t8}
|
||||
>
|
||||
{makeArray(x, 2)}
|
||||
</Stringify>
|
||||
);
|
||||
$[5] = linkProps;
|
||||
$[6] = t3;
|
||||
} else {
|
||||
t3 = $[6];
|
||||
}
|
||||
return t3;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -48,21 +48,28 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import { StaticText1, Stringify, Text } from "shared-runtime";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
const { buttons } = props;
|
||||
let t0;
|
||||
if ($[0] !== buttons) {
|
||||
const [, ...nonPrimaryButtons] = buttons;
|
||||
|
||||
const renderedNonPrimaryButtons = nonPrimaryButtons.map(_temp);
|
||||
|
||||
t0 = <StaticText1>{renderedNonPrimaryButtons}</StaticText1>;
|
||||
t0 = nonPrimaryButtons.map(_temp);
|
||||
$[0] = buttons;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
const renderedNonPrimaryButtons = t0;
|
||||
let t1;
|
||||
if ($[2] !== renderedNonPrimaryButtons) {
|
||||
t1 = <StaticText1>{renderedNonPrimaryButtons}</StaticText1>;
|
||||
$[2] = renderedNonPrimaryButtons;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
function _temp(buttonProps, i) {
|
||||
return (
|
||||
|
||||
@@ -29,10 +29,10 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import { throwInput } from "shared-runtime";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== props) {
|
||||
const callback = () => {
|
||||
t0 = () => {
|
||||
try {
|
||||
throwInput([props.value]);
|
||||
} catch (t1) {
|
||||
@@ -40,14 +40,21 @@ function Component(props) {
|
||||
return e;
|
||||
}
|
||||
};
|
||||
|
||||
t0 = callback();
|
||||
$[0] = props;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
const callback = t0;
|
||||
let t1;
|
||||
if ($[2] !== callback) {
|
||||
t1 = callback();
|
||||
$[2] = callback;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user