Compare commits

..

1 Commits

Author SHA1 Message Date
Joe Savona
e1f907d68d [compiler] Allow assigning ref-accessing functions to objects if not mutated
Allows assigning a ref-accessing function to an object so long as that object is not subsequently transitively mutated. We should likely rewrite the ref validation to use the new mutation/aliasing effects, which would provide a more consistent behavior across instruction types and require fewer special cases like this.
2025-07-29 10:57:08 -07:00
67 changed files with 746 additions and 1232 deletions

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

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

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

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

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

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

View File

@@ -25,17 +25,25 @@ export const FIXTURE_ENTRYPOINT = {
```javascript
import { c as _c } from "react/compiler-runtime"; // @enableUseTypeAnnotations
function Component(props) {
const $ = _c(2);
const $ = _c(4);
let t0;
if ($[0] !== props.id) {
const x = makeArray(props.id);
t0 = x.at(0);
t0 = makeArray(props.id);
$[0] = props.id;
$[1] = t0;
} else {
t0 = $[1];
}
const y = t0;
const x = t0;
let t1;
if ($[2] !== x) {
t1 = x.at(0);
$[2] = x;
$[3] = t1;
} else {
t1 = $[3];
}
const y = t1;
return y;
}

View File

@@ -29,17 +29,25 @@ import { c as _c } from "react/compiler-runtime";
import { identity } from "shared-runtime";
function Component(props) {
const $ = _c(2);
const $ = _c(4);
let t0;
if ($[0] !== props.id) {
const x = makeArray(props.id);
t0 = x.at(0);
t0 = makeArray(props.id);
$[0] = props.id;
$[1] = t0;
} else {
t0 = $[1];
}
const y = t0;
const x = t0;
let t1;
if ($[2] !== x) {
t1 = x.at(0);
$[2] = x;
$[3] = t1;
} else {
t1 = $[3];
}
const y = t1;
return y;
}

View File

@@ -22,17 +22,25 @@ export const FIXTURE_ENTRYPOINT = {
import { c as _c } from "react/compiler-runtime";
function Component(props) {
"use memo";
const $ = _c(2);
const $ = _c(4);
let t0;
if ($[0] !== props.foo) {
const x = [props.foo];
t0 = <div x={x}>"foo"</div>;
t0 = [props.foo];
$[0] = props.foo;
$[1] = t0;
} else {
t0 = $[1];
}
return t0;
const x = t0;
let t1;
if ($[2] !== x) {
t1 = <div x={x}>"foo"</div>;
$[2] = x;
$[3] = t1;
} else {
t1 = $[3];
}
return t1;
}
export const FIXTURE_ENTRYPOINT = {

View File

@@ -39,34 +39,41 @@ import { Stringify } from "shared-runtime";
const FooContext = createContext({ current: true });
function Component(props) {
const $ = _c(4);
const $ = _c(6);
const foo = useContext(FooContext);
let t0;
if ($[0] !== foo.current) {
const getValue = () => {
t0 = () => {
if (foo.current) {
return {};
} else {
return null;
}
};
t0 = getValue();
$[0] = foo.current;
$[1] = t0;
} else {
t0 = $[1];
}
const value = t0;
const getValue = t0;
let t1;
if ($[2] !== value) {
t1 = <Stringify value={value} />;
$[2] = value;
if ($[2] !== getValue) {
t1 = getValue();
$[2] = getValue;
$[3] = t1;
} else {
t1 = $[3];
}
return t1;
const value = t1;
let t2;
if ($[4] !== value) {
t2 = <Stringify value={value} />;
$[4] = value;
$[5] = t2;
} else {
t2 = $[5];
}
return t2;
}
export const FIXTURE_ENTRYPOINT = {

View File

@@ -101,7 +101,7 @@ const COMPILER_OPTIONS: Partial<PluginOptions> = {
// Don't emit errors on Flow suppressions--Flow already gave a signal
flowSuppressions: false,
environment: validateEnvironmentConfig({
validateRefAccessDuringRender: true,
validateRefAccessDuringRender: false,
validateNoSetStateInRender: true,
validateNoSetStateInEffects: true,
validateNoJSXInTryStatements: true,

View File

@@ -103,7 +103,7 @@ const COMPILER_OPTIONS: Partial<PluginOptions> = {
// Don't emit errors on Flow suppressions--Flow already gave a signal
flowSuppressions: false,
environment: validateEnvironmentConfig({
validateRefAccessDuringRender: true,
validateRefAccessDuringRender: false,
validateNoSetStateInRender: true,
validateNoSetStateInEffects: true,
validateNoJSXInTryStatements: true,