Compare commits

..

1 Commits

Author SHA1 Message Date
Joe Savona
35e58360cb [compiler] Allow mergeRefs pattern (and detect refs passed as ref prop)
Two related changes:
* ValidateNoRefAccessInRender now allows the mergeRefs pattern, ie a function that aggregates multiple refs into a new ref. This is the main case where we have seen false positive no-ref-in-render errors.
* Behind `@enableTreatRefLikeIdentifiersAsRefs`, we infer values passed as the `ref` prop to some JSX as refs.

The second change is potentially helpful for situations such as

```js
function Component({ref: parentRef}) {
  const childRef = useRef(null);
  const mergedRef = mergeRefs(parentRef, childRef);
  useEffect(() => {
    // generally accesses childRef, not mergedRef
  }, []);
  return <Foo ref={mergedRef} />;
}
```

Ie where you create a merged ref but don't access its `.current` property. Without inferring `ref` props as refs, we'd fail to allow this merge refs case.
2025-07-29 10:05:10 -07:00
106 changed files with 914 additions and 2050 deletions

View File

@@ -608,7 +608,7 @@ export const EnvironmentConfigSchema = z.object({
*
* Here the variables `ref` and `myRef` will be typed as Refs.
*/
enableTreatRefLikeIdentifiersAsRefs: z.boolean().default(true),
enableTreatRefLikeIdentifiersAsRefs: z.boolean().default(false),
/*
* If specified a value, the compiler lowers any calls to `useContext` to use

View File

@@ -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',
},
],
},
}),
],
]),
],
[

View File

@@ -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':

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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 = {

View File

@@ -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;
}

View File

@@ -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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 |
```

View File

@@ -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 |
```

View File

@@ -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 |
```

View File

@@ -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 | }
```

View File

@@ -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 | });
```

View File

@@ -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()}}],
};

View File

@@ -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 | });
```

View File

@@ -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()}}],
};

View File

@@ -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;
}

View File

@@ -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 = {

View File

@@ -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 = {

View File

@@ -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 = {

View File

@@ -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 = {

View File

@@ -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;
}
```

View File

@@ -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 = {

View File

@@ -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 = {

View File

@@ -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;
}
```

View File

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

View File

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

View File

@@ -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 = {

View File

@@ -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 = {

View File

@@ -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 = {

View File

@@ -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) {

View File

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

View File

@@ -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>

View File

@@ -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()}}],
};

View File

@@ -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>

View File

@@ -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!'},
],
},
],
};

View File

@@ -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>

View File

@@ -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()}}],
};

View File

@@ -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>

View File

@@ -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!'},
],
},
],
};

View File

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

View File

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

View File

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

View File

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

View File

@@ -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;
}

View File

@@ -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 = {

View File

@@ -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 = {

View File

@@ -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 = {

View File

@@ -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 = {

View File

@@ -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 = {

View File

@@ -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 = {

View File

@@ -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);

View File

@@ -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 = {

View File

@@ -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 = {

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}
```

View File

@@ -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;
}
```

View File

@@ -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 = {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 = {

View File

@@ -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 = {

View File

@@ -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>

View File

@@ -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!'},
],
},
],
};

View File

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

View File

@@ -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 = {

View File

@@ -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 (

View File

@@ -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