Compare commits
1 Commits
asserts-st
...
pr33543
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbb5efe024 |
@@ -271,9 +271,9 @@ a.property = value // a _is_ b, this mutates b
|
|||||||
|
|
||||||
```
|
```
|
||||||
CreateFrom a <- b
|
CreateFrom a <- b
|
||||||
Mutate A
|
Mutate a
|
||||||
=>
|
=>
|
||||||
MutateTransitive b
|
Mutate b
|
||||||
```
|
```
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@@ -301,6 +301,26 @@ a.b = b;
|
|||||||
a.property = value; // mutates a, not b
|
a.property = value; // mutates a, not b
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Mutation of Source Affects Alias, Assignment, CreateFrom, and Capture
|
||||||
|
|
||||||
|
```
|
||||||
|
Alias a <- b OR Assign a <- b OR CreateFrom a <- b OR Capture a <- b
|
||||||
|
Mutate b
|
||||||
|
=>
|
||||||
|
Mutate a
|
||||||
|
```
|
||||||
|
|
||||||
|
A derived value changes when it's source value is mutated.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const x = {};
|
||||||
|
const y = [x];
|
||||||
|
x.y = true; // this changes the value within `y` ie mutates y
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### TransitiveMutation of Alias, Assignment, CreateFrom, or Capture Mutates the Source
|
### TransitiveMutation of Alias, Assignment, CreateFrom, or Capture Mutates the Source
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import {useMemo} from 'react';
|
||||||
|
import {
|
||||||
|
mutate,
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({a, b, c}: {a: number; b: number; c: number}) {
|
||||||
|
const x = useMemo(() => [{value: a}], [a, b, c]);
|
||||||
|
if (b === 0) {
|
||||||
|
// This object should only depend on c, it cannot be affected by the later mutation
|
||||||
|
x.push({value: c});
|
||||||
|
} else {
|
||||||
|
// This mutation shouldn't affect the object in the consequent
|
||||||
|
mutate(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ValidateMemoization inputs={[a, b, c]} output={x} alwaysCheck={true} />;
|
||||||
|
{/* TODO: should only depend on c */}
|
||||||
|
<ValidateMemoization
|
||||||
|
inputs={[a, b, c]}
|
||||||
|
output={x[0]}
|
||||||
|
alwaysCheck={true}
|
||||||
|
/>
|
||||||
|
;
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{a: 0, b: 0, c: 0}],
|
||||||
|
sequentialRenders: [
|
||||||
|
{a: 0, b: 0, c: 0},
|
||||||
|
{a: 0, b: 1, c: 0},
|
||||||
|
{a: 1, b: 1, c: 0},
|
||||||
|
{a: 1, b: 1, c: 1},
|
||||||
|
{a: 1, b: 1, c: 0},
|
||||||
|
{a: 1, b: 0, c: 0},
|
||||||
|
{a: 0, b: 0, c: 0},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { c as _c } from "react/compiler-runtime";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import {
|
||||||
|
mutate,
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from "shared-runtime";
|
||||||
|
|
||||||
|
function Component(t0) {
|
||||||
|
const $ = _c(22);
|
||||||
|
const { a, b, c } = t0;
|
||||||
|
let t1;
|
||||||
|
let x;
|
||||||
|
if ($[0] !== a || $[1] !== b || $[2] !== c) {
|
||||||
|
t1 = [{ value: a }];
|
||||||
|
x = t1;
|
||||||
|
if (b === 0) {
|
||||||
|
x.push({ value: c });
|
||||||
|
} else {
|
||||||
|
mutate(x);
|
||||||
|
}
|
||||||
|
$[0] = a;
|
||||||
|
$[1] = b;
|
||||||
|
$[2] = c;
|
||||||
|
$[3] = x;
|
||||||
|
$[4] = t1;
|
||||||
|
} else {
|
||||||
|
x = $[3];
|
||||||
|
t1 = $[4];
|
||||||
|
}
|
||||||
|
let t2;
|
||||||
|
if ($[5] !== a || $[6] !== b || $[7] !== c) {
|
||||||
|
t2 = [a, b, c];
|
||||||
|
$[5] = a;
|
||||||
|
$[6] = b;
|
||||||
|
$[7] = c;
|
||||||
|
$[8] = t2;
|
||||||
|
} else {
|
||||||
|
t2 = $[8];
|
||||||
|
}
|
||||||
|
let t3;
|
||||||
|
if ($[9] !== t2 || $[10] !== x) {
|
||||||
|
t3 = <ValidateMemoization inputs={t2} output={x} alwaysCheck={true} />;
|
||||||
|
$[9] = t2;
|
||||||
|
$[10] = x;
|
||||||
|
$[11] = t3;
|
||||||
|
} else {
|
||||||
|
t3 = $[11];
|
||||||
|
}
|
||||||
|
let t4;
|
||||||
|
if ($[12] !== a || $[13] !== b || $[14] !== c) {
|
||||||
|
t4 = [a, b, c];
|
||||||
|
$[12] = a;
|
||||||
|
$[13] = b;
|
||||||
|
$[14] = c;
|
||||||
|
$[15] = t4;
|
||||||
|
} else {
|
||||||
|
t4 = $[15];
|
||||||
|
}
|
||||||
|
let t5;
|
||||||
|
if ($[16] !== t4 || $[17] !== x[0]) {
|
||||||
|
t5 = <ValidateMemoization inputs={t4} output={x[0]} alwaysCheck={true} />;
|
||||||
|
$[16] = t4;
|
||||||
|
$[17] = x[0];
|
||||||
|
$[18] = t5;
|
||||||
|
} else {
|
||||||
|
t5 = $[18];
|
||||||
|
}
|
||||||
|
let t6;
|
||||||
|
if ($[19] !== t3 || $[20] !== t5) {
|
||||||
|
t6 = (
|
||||||
|
<>
|
||||||
|
{t3};{t5};
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
$[19] = t3;
|
||||||
|
$[20] = t5;
|
||||||
|
$[21] = t6;
|
||||||
|
} else {
|
||||||
|
t6 = $[21];
|
||||||
|
}
|
||||||
|
return t6;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{ a: 0, b: 0, c: 0 }],
|
||||||
|
sequentialRenders: [
|
||||||
|
{ a: 0, b: 0, c: 0 },
|
||||||
|
{ a: 0, b: 1, c: 0 },
|
||||||
|
{ a: 1, b: 1, c: 0 },
|
||||||
|
{ a: 1, b: 1, c: 1 },
|
||||||
|
{ a: 1, b: 1, c: 0 },
|
||||||
|
{ a: 1, b: 0, c: 0 },
|
||||||
|
{ a: 0, b: 0, c: 0 },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Eval output
|
||||||
|
(kind: ok) <div>{"inputs":[0,0,0],"output":[{"value":0},{"value":0}]}</div>;<div>{"inputs":[0,0,0],"output":{"value":0}}</div>;
|
||||||
|
<div>{"inputs":[0,1,0],"output":[{"value":0},"joe"]}</div>;<div>{"inputs":[0,1,0],"output":{"value":0}}</div>;
|
||||||
|
<div>{"inputs":[1,1,0],"output":[{"value":1},"joe"]}</div>;<div>{"inputs":[1,1,0],"output":{"value":1}}</div>;
|
||||||
|
<div>{"inputs":[1,1,1],"output":[{"value":1},"joe"]}</div>;<div>{"inputs":[1,1,1],"output":{"value":1}}</div>;
|
||||||
|
<div>{"inputs":[1,1,0],"output":[{"value":1},"joe"]}</div>;<div>{"inputs":[1,1,0],"output":{"value":1}}</div>;
|
||||||
|
<div>{"inputs":[1,0,0],"output":[{"value":1},{"value":0}]}</div>;<div>{"inputs":[1,0,0],"output":{"value":1}}</div>;
|
||||||
|
<div>{"inputs":[0,0,0],"output":[{"value":0},{"value":0}]}</div>;<div>{"inputs":[0,0,0],"output":{"value":0}}</div>;
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import {useMemo} from 'react';
|
||||||
|
import {
|
||||||
|
mutate,
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({a, b, c}: {a: number; b: number; c: number}) {
|
||||||
|
const x = useMemo(() => [{value: a}], [a, b, c]);
|
||||||
|
if (b === 0) {
|
||||||
|
// This object should only depend on c, it cannot be affected by the later mutation
|
||||||
|
x.push({value: c});
|
||||||
|
} else {
|
||||||
|
// This mutation shouldn't affect the object in the consequent
|
||||||
|
mutate(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ValidateMemoization inputs={[a, b, c]} output={x} alwaysCheck={true} />;
|
||||||
|
{/* TODO: should only depend on c */}
|
||||||
|
<ValidateMemoization
|
||||||
|
inputs={[a, b, c]}
|
||||||
|
output={x[0]}
|
||||||
|
alwaysCheck={true}
|
||||||
|
/>
|
||||||
|
;
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{a: 0, b: 0, c: 0}],
|
||||||
|
sequentialRenders: [
|
||||||
|
{a: 0, b: 0, c: 0},
|
||||||
|
{a: 0, b: 1, c: 0},
|
||||||
|
{a: 1, b: 1, c: 0},
|
||||||
|
{a: 1, b: 1, c: 1},
|
||||||
|
{a: 1, b: 1, c: 0},
|
||||||
|
{a: 1, b: 0, c: 0},
|
||||||
|
{a: 0, b: 0, c: 0},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import {useMemo} from 'react';
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({a, b}) {
|
||||||
|
const x = useMemo(() => [{a}], [a]);
|
||||||
|
const f = () => {
|
||||||
|
const y = typedCreateFrom(x);
|
||||||
|
const z = typedCapture(y);
|
||||||
|
return z;
|
||||||
|
};
|
||||||
|
const z = f();
|
||||||
|
// does not mutate x, so x should not depend on b
|
||||||
|
typedMutate(z, b);
|
||||||
|
|
||||||
|
// TODO: this *should* only depend on `a`
|
||||||
|
return <ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{a: 0, b: 0}],
|
||||||
|
sequentialRenders: [
|
||||||
|
{a: 0, b: 0},
|
||||||
|
{a: 0, b: 1},
|
||||||
|
{a: 1, b: 1},
|
||||||
|
{a: 0, b: 0},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { c as _c } from "react/compiler-runtime";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from "shared-runtime";
|
||||||
|
|
||||||
|
function Component(t0) {
|
||||||
|
const $ = _c(10);
|
||||||
|
const { a, b } = t0;
|
||||||
|
let t1;
|
||||||
|
let x;
|
||||||
|
if ($[0] !== a || $[1] !== b) {
|
||||||
|
t1 = [{ a }];
|
||||||
|
x = t1;
|
||||||
|
const f = () => {
|
||||||
|
const y = typedCreateFrom(x);
|
||||||
|
const z = typedCapture(y);
|
||||||
|
return z;
|
||||||
|
};
|
||||||
|
|
||||||
|
const z_0 = f();
|
||||||
|
|
||||||
|
typedMutate(z_0, b);
|
||||||
|
$[0] = a;
|
||||||
|
$[1] = b;
|
||||||
|
$[2] = x;
|
||||||
|
$[3] = t1;
|
||||||
|
} else {
|
||||||
|
x = $[2];
|
||||||
|
t1 = $[3];
|
||||||
|
}
|
||||||
|
let t2;
|
||||||
|
if ($[4] !== a || $[5] !== b) {
|
||||||
|
t2 = [a, b];
|
||||||
|
$[4] = a;
|
||||||
|
$[5] = b;
|
||||||
|
$[6] = t2;
|
||||||
|
} else {
|
||||||
|
t2 = $[6];
|
||||||
|
}
|
||||||
|
let t3;
|
||||||
|
if ($[7] !== t2 || $[8] !== x) {
|
||||||
|
t3 = <ValidateMemoization inputs={t2} output={x} alwaysCheck={true} />;
|
||||||
|
$[7] = t2;
|
||||||
|
$[8] = x;
|
||||||
|
$[9] = t3;
|
||||||
|
} else {
|
||||||
|
t3 = $[9];
|
||||||
|
}
|
||||||
|
return t3;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{ a: 0, b: 0 }],
|
||||||
|
sequentialRenders: [
|
||||||
|
{ a: 0, b: 0 },
|
||||||
|
{ a: 0, b: 1 },
|
||||||
|
{ a: 1, b: 1 },
|
||||||
|
{ a: 0, b: 0 },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Eval output
|
||||||
|
(kind: ok) <div>{"inputs":[0,0],"output":[{"a":0}]}</div>
|
||||||
|
<div>{"inputs":[0,1],"output":[{"a":0}]}</div>
|
||||||
|
<div>{"inputs":[1,1],"output":[{"a":1}]}</div>
|
||||||
|
<div>{"inputs":[0,0],"output":[{"a":0}]}</div>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import {useMemo} from 'react';
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({a, b}) {
|
||||||
|
const x = useMemo(() => [{a}], [a]);
|
||||||
|
const f = () => {
|
||||||
|
const y = typedCreateFrom(x);
|
||||||
|
const z = typedCapture(y);
|
||||||
|
return z;
|
||||||
|
};
|
||||||
|
const z = f();
|
||||||
|
// does not mutate x, so x should not depend on b
|
||||||
|
typedMutate(z, b);
|
||||||
|
|
||||||
|
// TODO: this *should* only depend on `a`
|
||||||
|
return <ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{a: 0, b: 0}],
|
||||||
|
sequentialRenders: [
|
||||||
|
{a: 0, b: 0},
|
||||||
|
{a: 0, b: 1},
|
||||||
|
{a: 1, b: 1},
|
||||||
|
{a: 0, b: 0},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import {useMemo} from 'react';
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({a, b}) {
|
||||||
|
const o: any = useMemo(() => ({a}), [a]);
|
||||||
|
const x: Array<any> = useMemo(() => [o], [o, b]);
|
||||||
|
const y = typedCapture(x);
|
||||||
|
const z = typedCapture(y);
|
||||||
|
x.push(z);
|
||||||
|
x.push(b);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ValidateMemoization inputs={[a]} output={o} alwaysCheck={true} />;
|
||||||
|
<ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{a: 0, b: 0}],
|
||||||
|
sequentialRenders: [
|
||||||
|
{a: 0, b: 0},
|
||||||
|
{a: 0, b: 1},
|
||||||
|
{a: 1, b: 1},
|
||||||
|
{a: 0, b: 0},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { c as _c } from "react/compiler-runtime";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from "shared-runtime";
|
||||||
|
|
||||||
|
function Component(t0) {
|
||||||
|
const $ = _c(20);
|
||||||
|
const { a, b } = t0;
|
||||||
|
let t1;
|
||||||
|
let t2;
|
||||||
|
if ($[0] !== a) {
|
||||||
|
t2 = { a };
|
||||||
|
$[0] = a;
|
||||||
|
$[1] = t2;
|
||||||
|
} else {
|
||||||
|
t2 = $[1];
|
||||||
|
}
|
||||||
|
t1 = t2;
|
||||||
|
const o = t1;
|
||||||
|
let t3;
|
||||||
|
let x;
|
||||||
|
if ($[2] !== b || $[3] !== o) {
|
||||||
|
t3 = [o];
|
||||||
|
x = t3;
|
||||||
|
const y = typedCapture(x);
|
||||||
|
const z = typedCapture(y);
|
||||||
|
x.push(z);
|
||||||
|
x.push(b);
|
||||||
|
$[2] = b;
|
||||||
|
$[3] = o;
|
||||||
|
$[4] = x;
|
||||||
|
$[5] = t3;
|
||||||
|
} else {
|
||||||
|
x = $[4];
|
||||||
|
t3 = $[5];
|
||||||
|
}
|
||||||
|
let t4;
|
||||||
|
if ($[6] !== a) {
|
||||||
|
t4 = [a];
|
||||||
|
$[6] = a;
|
||||||
|
$[7] = t4;
|
||||||
|
} else {
|
||||||
|
t4 = $[7];
|
||||||
|
}
|
||||||
|
let t5;
|
||||||
|
if ($[8] !== o || $[9] !== t4) {
|
||||||
|
t5 = <ValidateMemoization inputs={t4} output={o} alwaysCheck={true} />;
|
||||||
|
$[8] = o;
|
||||||
|
$[9] = t4;
|
||||||
|
$[10] = t5;
|
||||||
|
} else {
|
||||||
|
t5 = $[10];
|
||||||
|
}
|
||||||
|
let t6;
|
||||||
|
if ($[11] !== a || $[12] !== b) {
|
||||||
|
t6 = [a, b];
|
||||||
|
$[11] = a;
|
||||||
|
$[12] = b;
|
||||||
|
$[13] = t6;
|
||||||
|
} else {
|
||||||
|
t6 = $[13];
|
||||||
|
}
|
||||||
|
let t7;
|
||||||
|
if ($[14] !== t6 || $[15] !== x) {
|
||||||
|
t7 = <ValidateMemoization inputs={t6} output={x} alwaysCheck={true} />;
|
||||||
|
$[14] = t6;
|
||||||
|
$[15] = x;
|
||||||
|
$[16] = t7;
|
||||||
|
} else {
|
||||||
|
t7 = $[16];
|
||||||
|
}
|
||||||
|
let t8;
|
||||||
|
if ($[17] !== t5 || $[18] !== t7) {
|
||||||
|
t8 = (
|
||||||
|
<>
|
||||||
|
{t5};{t7};
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
$[17] = t5;
|
||||||
|
$[18] = t7;
|
||||||
|
$[19] = t8;
|
||||||
|
} else {
|
||||||
|
t8 = $[19];
|
||||||
|
}
|
||||||
|
return t8;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{ a: 0, b: 0 }],
|
||||||
|
sequentialRenders: [
|
||||||
|
{ a: 0, b: 0 },
|
||||||
|
{ a: 0, b: 1 },
|
||||||
|
{ a: 1, b: 1 },
|
||||||
|
{ a: 0, b: 0 },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Eval output
|
||||||
|
(kind: ok) <div>{"inputs":[0],"output":{"a":0}}</div>;<div>{"inputs":[0,0],"output":[{"a":0},[["[[ cyclic ref *2 ]]"]],0]}</div>;
|
||||||
|
<div>{"inputs":[0],"output":{"a":0}}</div>;<div>{"inputs":[0,1],"output":[{"a":0},[["[[ cyclic ref *2 ]]"]],1]}</div>;
|
||||||
|
<div>{"inputs":[1],"output":{"a":1}}</div>;<div>{"inputs":[1,1],"output":[{"a":1},[["[[ cyclic ref *2 ]]"]],1]}</div>;
|
||||||
|
<div>{"inputs":[0],"output":{"a":0}}</div>;<div>{"inputs":[0,0],"output":[{"a":0},[["[[ cyclic ref *2 ]]"]],0]}</div>;
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import {useMemo} from 'react';
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({a, b}) {
|
||||||
|
const o: any = useMemo(() => ({a}), [a]);
|
||||||
|
const x: Array<any> = useMemo(() => [o], [o, b]);
|
||||||
|
const y = typedCapture(x);
|
||||||
|
const z = typedCapture(y);
|
||||||
|
x.push(z);
|
||||||
|
x.push(b);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ValidateMemoization inputs={[a]} output={o} alwaysCheck={true} />;
|
||||||
|
<ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{a: 0, b: 0}],
|
||||||
|
sequentialRenders: [
|
||||||
|
{a: 0, b: 0},
|
||||||
|
{a: 0, b: 1},
|
||||||
|
{a: 1, b: 1},
|
||||||
|
{a: 0, b: 0},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import {useMemo} from 'react';
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({a, b}: {a: number; b: number}) {
|
||||||
|
const x = useMemo(() => ({a}), [a, b]);
|
||||||
|
const f = () => {
|
||||||
|
const y = typedCapture(x);
|
||||||
|
const z = typedCreateFrom(y);
|
||||||
|
return z;
|
||||||
|
};
|
||||||
|
const z = f();
|
||||||
|
// mutates x
|
||||||
|
typedMutate(z, b);
|
||||||
|
|
||||||
|
return <ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{a: 0, b: 0}],
|
||||||
|
sequentialRenders: [
|
||||||
|
{a: 0, b: 0},
|
||||||
|
{a: 0, b: 1},
|
||||||
|
{a: 1, b: 1},
|
||||||
|
{a: 0, b: 0},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { c as _c } from "react/compiler-runtime";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from "shared-runtime";
|
||||||
|
|
||||||
|
function Component(t0) {
|
||||||
|
const $ = _c(10);
|
||||||
|
const { a, b } = t0;
|
||||||
|
let t1;
|
||||||
|
let x;
|
||||||
|
if ($[0] !== a || $[1] !== b) {
|
||||||
|
t1 = { a };
|
||||||
|
x = t1;
|
||||||
|
const f = () => {
|
||||||
|
const y = typedCapture(x);
|
||||||
|
const z = typedCreateFrom(y);
|
||||||
|
return z;
|
||||||
|
};
|
||||||
|
|
||||||
|
const z_0 = f();
|
||||||
|
|
||||||
|
typedMutate(z_0, b);
|
||||||
|
$[0] = a;
|
||||||
|
$[1] = b;
|
||||||
|
$[2] = x;
|
||||||
|
$[3] = t1;
|
||||||
|
} else {
|
||||||
|
x = $[2];
|
||||||
|
t1 = $[3];
|
||||||
|
}
|
||||||
|
let t2;
|
||||||
|
if ($[4] !== a || $[5] !== b) {
|
||||||
|
t2 = [a, b];
|
||||||
|
$[4] = a;
|
||||||
|
$[5] = b;
|
||||||
|
$[6] = t2;
|
||||||
|
} else {
|
||||||
|
t2 = $[6];
|
||||||
|
}
|
||||||
|
let t3;
|
||||||
|
if ($[7] !== t2 || $[8] !== x) {
|
||||||
|
t3 = <ValidateMemoization inputs={t2} output={x} alwaysCheck={true} />;
|
||||||
|
$[7] = t2;
|
||||||
|
$[8] = x;
|
||||||
|
$[9] = t3;
|
||||||
|
} else {
|
||||||
|
t3 = $[9];
|
||||||
|
}
|
||||||
|
return t3;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{ a: 0, b: 0 }],
|
||||||
|
sequentialRenders: [
|
||||||
|
{ a: 0, b: 0 },
|
||||||
|
{ a: 0, b: 1 },
|
||||||
|
{ a: 1, b: 1 },
|
||||||
|
{ a: 0, b: 0 },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Eval output
|
||||||
|
(kind: ok) <div>{"inputs":[0,0],"output":{"a":0,"property":0}}</div>
|
||||||
|
<div>{"inputs":[0,1],"output":{"a":0,"property":1}}</div>
|
||||||
|
<div>{"inputs":[1,1],"output":{"a":1,"property":1}}</div>
|
||||||
|
<div>{"inputs":[0,0],"output":{"a":0,"property":0}}</div>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import {useMemo} from 'react';
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({a, b}: {a: number; b: number}) {
|
||||||
|
const x = useMemo(() => ({a}), [a, b]);
|
||||||
|
const f = () => {
|
||||||
|
const y = typedCapture(x);
|
||||||
|
const z = typedCreateFrom(y);
|
||||||
|
return z;
|
||||||
|
};
|
||||||
|
const z = f();
|
||||||
|
// mutates x
|
||||||
|
typedMutate(z, b);
|
||||||
|
|
||||||
|
return <ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{a: 0, b: 0}],
|
||||||
|
sequentialRenders: [
|
||||||
|
{a: 0, b: 0},
|
||||||
|
{a: 0, b: 1},
|
||||||
|
{a: 1, b: 1},
|
||||||
|
{a: 0, b: 0},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import {useMemo} from 'react';
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({a, b}: {a: number; b: number}) {
|
||||||
|
const x = useMemo(() => ({a}), [a, b]);
|
||||||
|
const y = typedCapture(x);
|
||||||
|
const z = typedCreateFrom(y);
|
||||||
|
// mutates x
|
||||||
|
typedMutate(z, b);
|
||||||
|
|
||||||
|
return <ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{a: 0, b: 0}],
|
||||||
|
sequentialRenders: [
|
||||||
|
{a: 0, b: 0},
|
||||||
|
{a: 0, b: 1},
|
||||||
|
{a: 1, b: 1},
|
||||||
|
{a: 0, b: 0},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { c as _c } from "react/compiler-runtime";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from "shared-runtime";
|
||||||
|
|
||||||
|
function Component(t0) {
|
||||||
|
const $ = _c(10);
|
||||||
|
const { a, b } = t0;
|
||||||
|
let t1;
|
||||||
|
let x;
|
||||||
|
if ($[0] !== a || $[1] !== b) {
|
||||||
|
t1 = { a };
|
||||||
|
x = t1;
|
||||||
|
const y = typedCapture(x);
|
||||||
|
const z = typedCreateFrom(y);
|
||||||
|
|
||||||
|
typedMutate(z, b);
|
||||||
|
$[0] = a;
|
||||||
|
$[1] = b;
|
||||||
|
$[2] = x;
|
||||||
|
$[3] = t1;
|
||||||
|
} else {
|
||||||
|
x = $[2];
|
||||||
|
t1 = $[3];
|
||||||
|
}
|
||||||
|
let t2;
|
||||||
|
if ($[4] !== a || $[5] !== b) {
|
||||||
|
t2 = [a, b];
|
||||||
|
$[4] = a;
|
||||||
|
$[5] = b;
|
||||||
|
$[6] = t2;
|
||||||
|
} else {
|
||||||
|
t2 = $[6];
|
||||||
|
}
|
||||||
|
let t3;
|
||||||
|
if ($[7] !== t2 || $[8] !== x) {
|
||||||
|
t3 = <ValidateMemoization inputs={t2} output={x} alwaysCheck={true} />;
|
||||||
|
$[7] = t2;
|
||||||
|
$[8] = x;
|
||||||
|
$[9] = t3;
|
||||||
|
} else {
|
||||||
|
t3 = $[9];
|
||||||
|
}
|
||||||
|
return t3;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{ a: 0, b: 0 }],
|
||||||
|
sequentialRenders: [
|
||||||
|
{ a: 0, b: 0 },
|
||||||
|
{ a: 0, b: 1 },
|
||||||
|
{ a: 1, b: 1 },
|
||||||
|
{ a: 0, b: 0 },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Eval output
|
||||||
|
(kind: ok) <div>{"inputs":[0,0],"output":{"a":0,"property":0}}</div>
|
||||||
|
<div>{"inputs":[0,1],"output":{"a":0,"property":1}}</div>
|
||||||
|
<div>{"inputs":[1,1],"output":{"a":1,"property":1}}</div>
|
||||||
|
<div>{"inputs":[0,0],"output":{"a":0,"property":0}}</div>
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import {useMemo} from 'react';
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({a, b}: {a: number; b: number}) {
|
||||||
|
const x = useMemo(() => ({a}), [a, b]);
|
||||||
|
const y = typedCapture(x);
|
||||||
|
const z = typedCreateFrom(y);
|
||||||
|
// mutates x
|
||||||
|
typedMutate(z, b);
|
||||||
|
|
||||||
|
return <ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{a: 0, b: 0}],
|
||||||
|
sequentialRenders: [
|
||||||
|
{a: 0, b: 0},
|
||||||
|
{a: 0, b: 1},
|
||||||
|
{a: 1, b: 1},
|
||||||
|
{a: 0, b: 0},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import {useMemo} from 'react';
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({a, b}) {
|
||||||
|
const x = useMemo(() => [{a}], [a]);
|
||||||
|
const y = typedCreateFrom(x);
|
||||||
|
const z = typedCapture(y);
|
||||||
|
// does not mutate x, so x should not depend on b
|
||||||
|
typedMutate(z, b);
|
||||||
|
|
||||||
|
return <ValidateMemoization inputs={[a]} output={x} alwaysCheck={true} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{a: 0, b: 0}],
|
||||||
|
sequentialRenders: [
|
||||||
|
{a: 0, b: 0},
|
||||||
|
{a: 0, b: 1},
|
||||||
|
{a: 1, b: 1},
|
||||||
|
{a: 0, b: 0},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { c as _c } from "react/compiler-runtime";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from "shared-runtime";
|
||||||
|
|
||||||
|
function Component(t0) {
|
||||||
|
const $ = _c(7);
|
||||||
|
const { a, b } = t0;
|
||||||
|
let t1;
|
||||||
|
let t2;
|
||||||
|
if ($[0] !== a) {
|
||||||
|
t2 = [{ a }];
|
||||||
|
$[0] = a;
|
||||||
|
$[1] = t2;
|
||||||
|
} else {
|
||||||
|
t2 = $[1];
|
||||||
|
}
|
||||||
|
t1 = t2;
|
||||||
|
const x = t1;
|
||||||
|
const y = typedCreateFrom(x);
|
||||||
|
const z = typedCapture(y);
|
||||||
|
|
||||||
|
typedMutate(z, b);
|
||||||
|
let t3;
|
||||||
|
if ($[2] !== a) {
|
||||||
|
t3 = [a];
|
||||||
|
$[2] = a;
|
||||||
|
$[3] = t3;
|
||||||
|
} else {
|
||||||
|
t3 = $[3];
|
||||||
|
}
|
||||||
|
let t4;
|
||||||
|
if ($[4] !== t3 || $[5] !== x) {
|
||||||
|
t4 = <ValidateMemoization inputs={t3} output={x} alwaysCheck={true} />;
|
||||||
|
$[4] = t3;
|
||||||
|
$[5] = x;
|
||||||
|
$[6] = t4;
|
||||||
|
} else {
|
||||||
|
t4 = $[6];
|
||||||
|
}
|
||||||
|
return t4;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{ a: 0, b: 0 }],
|
||||||
|
sequentialRenders: [
|
||||||
|
{ a: 0, b: 0 },
|
||||||
|
{ a: 0, b: 1 },
|
||||||
|
{ a: 1, b: 1 },
|
||||||
|
{ a: 0, b: 0 },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Eval output
|
||||||
|
(kind: ok) <div>{"inputs":[0],"output":[{"a":0}]}</div>
|
||||||
|
<div>{"inputs":[0],"output":[{"a":0}]}</div>
|
||||||
|
<div>{"inputs":[1],"output":[{"a":1}]}</div>
|
||||||
|
<div>{"inputs":[0],"output":[{"a":0}]}</div>
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import {useMemo} from 'react';
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({a, b}) {
|
||||||
|
const x = useMemo(() => [{a}], [a]);
|
||||||
|
const y = typedCreateFrom(x);
|
||||||
|
const z = typedCapture(y);
|
||||||
|
// does not mutate x, so x should not depend on b
|
||||||
|
typedMutate(z, b);
|
||||||
|
|
||||||
|
return <ValidateMemoization inputs={[a]} output={x} alwaysCheck={true} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{a: 0, b: 0}],
|
||||||
|
sequentialRenders: [
|
||||||
|
{a: 0, b: 0},
|
||||||
|
{a: 0, b: 1},
|
||||||
|
{a: 1, b: 1},
|
||||||
|
{a: 0, b: 0},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import {useMemo} from 'react';
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({a, b}) {
|
||||||
|
const x = useMemo(() => [{a}], [a, b]);
|
||||||
|
let z: any;
|
||||||
|
if (b) {
|
||||||
|
z = x;
|
||||||
|
} else {
|
||||||
|
z = typedCapture(x);
|
||||||
|
}
|
||||||
|
// could mutate x
|
||||||
|
typedMutate(z, b);
|
||||||
|
|
||||||
|
return <ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{a: 0, b: 0}],
|
||||||
|
sequentialRenders: [
|
||||||
|
{a: 0, b: 0},
|
||||||
|
{a: 0, b: 1},
|
||||||
|
{a: 1, b: 1},
|
||||||
|
{a: 0, b: 0},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { c as _c } from "react/compiler-runtime";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from "shared-runtime";
|
||||||
|
|
||||||
|
function Component(t0) {
|
||||||
|
const $ = _c(12);
|
||||||
|
const { a, b } = t0;
|
||||||
|
let t1;
|
||||||
|
let t2;
|
||||||
|
if ($[0] !== a) {
|
||||||
|
t2 = { a };
|
||||||
|
$[0] = a;
|
||||||
|
$[1] = t2;
|
||||||
|
} else {
|
||||||
|
t2 = $[1];
|
||||||
|
}
|
||||||
|
let x;
|
||||||
|
if ($[2] !== b || $[3] !== t2) {
|
||||||
|
t1 = [t2];
|
||||||
|
x = t1;
|
||||||
|
let z;
|
||||||
|
if (b) {
|
||||||
|
z = x;
|
||||||
|
} else {
|
||||||
|
z = typedCapture(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedMutate(z, b);
|
||||||
|
$[2] = b;
|
||||||
|
$[3] = t2;
|
||||||
|
$[4] = x;
|
||||||
|
$[5] = t1;
|
||||||
|
} else {
|
||||||
|
x = $[4];
|
||||||
|
t1 = $[5];
|
||||||
|
}
|
||||||
|
let t3;
|
||||||
|
if ($[6] !== a || $[7] !== b) {
|
||||||
|
t3 = [a, b];
|
||||||
|
$[6] = a;
|
||||||
|
$[7] = b;
|
||||||
|
$[8] = t3;
|
||||||
|
} else {
|
||||||
|
t3 = $[8];
|
||||||
|
}
|
||||||
|
let t4;
|
||||||
|
if ($[9] !== t3 || $[10] !== x) {
|
||||||
|
t4 = <ValidateMemoization inputs={t3} output={x} alwaysCheck={true} />;
|
||||||
|
$[9] = t3;
|
||||||
|
$[10] = x;
|
||||||
|
$[11] = t4;
|
||||||
|
} else {
|
||||||
|
t4 = $[11];
|
||||||
|
}
|
||||||
|
return t4;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{ a: 0, b: 0 }],
|
||||||
|
sequentialRenders: [
|
||||||
|
{ a: 0, b: 0 },
|
||||||
|
{ a: 0, b: 1 },
|
||||||
|
{ a: 1, b: 1 },
|
||||||
|
{ a: 0, b: 0 },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Eval output
|
||||||
|
(kind: ok) <div>{"inputs":[0,0],"output":[{"a":0}]}</div>
|
||||||
|
<div>{"inputs":[0,1],"output":[{"a":0}]}</div>
|
||||||
|
<div>{"inputs":[1,1],"output":[{"a":1}]}</div>
|
||||||
|
<div>{"inputs":[0,0],"output":[{"a":0}]}</div>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import {useMemo} from 'react';
|
||||||
|
import {
|
||||||
|
typedCapture,
|
||||||
|
typedCreateFrom,
|
||||||
|
typedMutate,
|
||||||
|
ValidateMemoization,
|
||||||
|
} from 'shared-runtime';
|
||||||
|
|
||||||
|
function Component({a, b}) {
|
||||||
|
const x = useMemo(() => [{a}], [a, b]);
|
||||||
|
let z: any;
|
||||||
|
if (b) {
|
||||||
|
z = x;
|
||||||
|
} else {
|
||||||
|
z = typedCapture(x);
|
||||||
|
}
|
||||||
|
// could mutate x
|
||||||
|
typedMutate(z, b);
|
||||||
|
|
||||||
|
return <ValidateMemoization inputs={[a, b]} output={x} alwaysCheck={true} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIXTURE_ENTRYPOINT = {
|
||||||
|
fn: Component,
|
||||||
|
params: [{a: 0, b: 0}],
|
||||||
|
sequentialRenders: [
|
||||||
|
{a: 0, b: 0},
|
||||||
|
{a: 0, b: 1},
|
||||||
|
{a: 1, b: 1},
|
||||||
|
{a: 0, b: 0},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -30,6 +30,7 @@ export {
|
|||||||
export {
|
export {
|
||||||
Effect,
|
Effect,
|
||||||
ValueKind,
|
ValueKind,
|
||||||
|
ValueReason,
|
||||||
printHIR,
|
printHIR,
|
||||||
printFunctionWithOutlined,
|
printFunctionWithOutlined,
|
||||||
validateEnvironmentConfig,
|
validateEnvironmentConfig,
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ import type {
|
|||||||
CompilerReactTarget,
|
CompilerReactTarget,
|
||||||
CompilerPipelineValue,
|
CompilerPipelineValue,
|
||||||
} from 'babel-plugin-react-compiler/src/Entrypoint';
|
} from 'babel-plugin-react-compiler/src/Entrypoint';
|
||||||
import type {Effect, ValueKind} from 'babel-plugin-react-compiler/src/HIR';
|
import type {
|
||||||
|
Effect,
|
||||||
|
ValueKind,
|
||||||
|
ValueReason,
|
||||||
|
} from 'babel-plugin-react-compiler/src/HIR';
|
||||||
import type {parseConfigPragmaForTests as ParseConfigPragma} from 'babel-plugin-react-compiler/src/Utils/TestUtils';
|
import type {parseConfigPragmaForTests as ParseConfigPragma} from 'babel-plugin-react-compiler/src/Utils/TestUtils';
|
||||||
import * as HermesParser from 'hermes-parser';
|
import * as HermesParser from 'hermes-parser';
|
||||||
import invariant from 'invariant';
|
import invariant from 'invariant';
|
||||||
@@ -42,6 +46,7 @@ function makePluginOptions(
|
|||||||
debugIRLogger: (value: CompilerPipelineValue) => void,
|
debugIRLogger: (value: CompilerPipelineValue) => void,
|
||||||
EffectEnum: typeof Effect,
|
EffectEnum: typeof Effect,
|
||||||
ValueKindEnum: typeof ValueKind,
|
ValueKindEnum: typeof ValueKind,
|
||||||
|
ValueReasonEnum: typeof ValueReason,
|
||||||
): [PluginOptions, Array<{filename: string | null; event: LoggerEvent}>] {
|
): [PluginOptions, Array<{filename: string | null; event: LoggerEvent}>] {
|
||||||
// TODO(@mofeiZ) rewrite snap fixtures to @validatePreserveExistingMemo:false
|
// TODO(@mofeiZ) rewrite snap fixtures to @validatePreserveExistingMemo:false
|
||||||
let validatePreserveExistingMemoizationGuarantees = false;
|
let validatePreserveExistingMemoizationGuarantees = false;
|
||||||
@@ -77,6 +82,7 @@ function makePluginOptions(
|
|||||||
moduleTypeProvider: makeSharedRuntimeTypeProvider({
|
moduleTypeProvider: makeSharedRuntimeTypeProvider({
|
||||||
EffectEnum,
|
EffectEnum,
|
||||||
ValueKindEnum,
|
ValueKindEnum,
|
||||||
|
ValueReasonEnum,
|
||||||
}),
|
}),
|
||||||
assertValidMutableRanges: true,
|
assertValidMutableRanges: true,
|
||||||
validatePreserveExistingMemoizationGuarantees,
|
validatePreserveExistingMemoizationGuarantees,
|
||||||
@@ -209,6 +215,7 @@ export async function transformFixtureInput(
|
|||||||
debugIRLogger: (value: CompilerPipelineValue) => void,
|
debugIRLogger: (value: CompilerPipelineValue) => void,
|
||||||
EffectEnum: typeof Effect,
|
EffectEnum: typeof Effect,
|
||||||
ValueKindEnum: typeof ValueKind,
|
ValueKindEnum: typeof ValueKind,
|
||||||
|
ValueReasonEnum: typeof ValueReason,
|
||||||
): Promise<{kind: 'ok'; value: TransformResult} | {kind: 'err'; msg: string}> {
|
): Promise<{kind: 'ok'; value: TransformResult} | {kind: 'err'; msg: string}> {
|
||||||
// Extract the first line to quickly check for custom test directives
|
// Extract the first line to quickly check for custom test directives
|
||||||
const firstLine = input.substring(0, input.indexOf('\n'));
|
const firstLine = input.substring(0, input.indexOf('\n'));
|
||||||
@@ -237,6 +244,7 @@ export async function transformFixtureInput(
|
|||||||
debugIRLogger,
|
debugIRLogger,
|
||||||
EffectEnum,
|
EffectEnum,
|
||||||
ValueKindEnum,
|
ValueKindEnum,
|
||||||
|
ValueReasonEnum,
|
||||||
);
|
);
|
||||||
const forgetResult = transformFromAstSync(inputAst, input, {
|
const forgetResult = transformFromAstSync(inputAst, input, {
|
||||||
filename: virtualFilepath,
|
filename: virtualFilepath,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import type {
|
|||||||
CompilerPipelineValue,
|
CompilerPipelineValue,
|
||||||
Effect,
|
Effect,
|
||||||
ValueKind,
|
ValueKind,
|
||||||
|
ValueReason,
|
||||||
} from 'babel-plugin-react-compiler/src';
|
} from 'babel-plugin-react-compiler/src';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
|
|
||||||
@@ -78,6 +79,9 @@ async function compile(
|
|||||||
const ValueKindEnum = importedCompilerPlugin[
|
const ValueKindEnum = importedCompilerPlugin[
|
||||||
'ValueKind'
|
'ValueKind'
|
||||||
] as typeof ValueKind;
|
] as typeof ValueKind;
|
||||||
|
const ValueReasonEnum = importedCompilerPlugin[
|
||||||
|
'ValueReason'
|
||||||
|
] as typeof ValueReason;
|
||||||
const printFunctionWithOutlined = importedCompilerPlugin[
|
const printFunctionWithOutlined = importedCompilerPlugin[
|
||||||
PRINT_HIR_IMPORT
|
PRINT_HIR_IMPORT
|
||||||
] as typeof PrintFunctionWithOutlined;
|
] as typeof PrintFunctionWithOutlined;
|
||||||
@@ -128,6 +132,7 @@ async function compile(
|
|||||||
debugIRLogger,
|
debugIRLogger,
|
||||||
EffectEnum,
|
EffectEnum,
|
||||||
ValueKindEnum,
|
ValueKindEnum,
|
||||||
|
ValueReasonEnum,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (result.kind === 'err') {
|
if (result.kind === 'err') {
|
||||||
|
|||||||
@@ -5,15 +5,21 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {Effect, ValueKind} from 'babel-plugin-react-compiler/src';
|
import type {
|
||||||
|
Effect,
|
||||||
|
ValueKind,
|
||||||
|
ValueReason,
|
||||||
|
} from 'babel-plugin-react-compiler/src';
|
||||||
import type {TypeConfig} from 'babel-plugin-react-compiler/src/HIR/TypeSchema';
|
import type {TypeConfig} from 'babel-plugin-react-compiler/src/HIR/TypeSchema';
|
||||||
|
|
||||||
export function makeSharedRuntimeTypeProvider({
|
export function makeSharedRuntimeTypeProvider({
|
||||||
EffectEnum,
|
EffectEnum,
|
||||||
ValueKindEnum,
|
ValueKindEnum,
|
||||||
|
ValueReasonEnum,
|
||||||
}: {
|
}: {
|
||||||
EffectEnum: typeof Effect;
|
EffectEnum: typeof Effect;
|
||||||
ValueKindEnum: typeof ValueKind;
|
ValueKindEnum: typeof ValueKind;
|
||||||
|
ValueReasonEnum: typeof ValueReason;
|
||||||
}) {
|
}) {
|
||||||
return function sharedRuntimeTypeProvider(
|
return function sharedRuntimeTypeProvider(
|
||||||
moduleName: string,
|
moduleName: string,
|
||||||
@@ -85,6 +91,111 @@ export function makeSharedRuntimeTypeProvider({
|
|||||||
effects: [{kind: 'Assign', from: '@value', into: '@return'}],
|
effects: [{kind: 'Assign', from: '@value', into: '@return'}],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
typedAssign: {
|
||||||
|
kind: 'function',
|
||||||
|
positionalParams: [EffectEnum.Read],
|
||||||
|
restParam: null,
|
||||||
|
calleeEffect: EffectEnum.Read,
|
||||||
|
returnType: {kind: 'type', name: 'Any'},
|
||||||
|
returnValueKind: ValueKindEnum.Mutable,
|
||||||
|
aliasing: {
|
||||||
|
receiver: '@receiver',
|
||||||
|
params: ['@value'],
|
||||||
|
rest: null,
|
||||||
|
returns: '@return',
|
||||||
|
temporaries: [],
|
||||||
|
effects: [{kind: 'Assign', from: '@value', into: '@return'}],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
typedAlias: {
|
||||||
|
kind: 'function',
|
||||||
|
positionalParams: [EffectEnum.Read],
|
||||||
|
restParam: null,
|
||||||
|
calleeEffect: EffectEnum.Read,
|
||||||
|
returnType: {kind: 'type', name: 'Any'},
|
||||||
|
returnValueKind: ValueKindEnum.Mutable,
|
||||||
|
aliasing: {
|
||||||
|
receiver: '@receiver',
|
||||||
|
params: ['@value'],
|
||||||
|
rest: null,
|
||||||
|
returns: '@return',
|
||||||
|
temporaries: [],
|
||||||
|
effects: [
|
||||||
|
{
|
||||||
|
kind: 'Create',
|
||||||
|
into: '@return',
|
||||||
|
value: ValueKindEnum.Mutable,
|
||||||
|
reason: ValueReasonEnum.KnownReturnSignature,
|
||||||
|
},
|
||||||
|
{kind: 'Alias', from: '@value', into: '@return'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
typedCapture: {
|
||||||
|
kind: 'function',
|
||||||
|
positionalParams: [EffectEnum.Read],
|
||||||
|
restParam: null,
|
||||||
|
calleeEffect: EffectEnum.Read,
|
||||||
|
returnType: {kind: 'type', name: 'Array'},
|
||||||
|
returnValueKind: ValueKindEnum.Mutable,
|
||||||
|
aliasing: {
|
||||||
|
receiver: '@receiver',
|
||||||
|
params: ['@value'],
|
||||||
|
rest: null,
|
||||||
|
returns: '@return',
|
||||||
|
temporaries: [],
|
||||||
|
effects: [
|
||||||
|
{
|
||||||
|
kind: 'Create',
|
||||||
|
into: '@return',
|
||||||
|
value: ValueKindEnum.Mutable,
|
||||||
|
reason: ValueReasonEnum.KnownReturnSignature,
|
||||||
|
},
|
||||||
|
{kind: 'Capture', from: '@value', into: '@return'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
typedCreateFrom: {
|
||||||
|
kind: 'function',
|
||||||
|
positionalParams: [EffectEnum.Read],
|
||||||
|
restParam: null,
|
||||||
|
calleeEffect: EffectEnum.Read,
|
||||||
|
returnType: {kind: 'type', name: 'Any'},
|
||||||
|
returnValueKind: ValueKindEnum.Mutable,
|
||||||
|
aliasing: {
|
||||||
|
receiver: '@receiver',
|
||||||
|
params: ['@value'],
|
||||||
|
rest: null,
|
||||||
|
returns: '@return',
|
||||||
|
temporaries: [],
|
||||||
|
effects: [{kind: 'CreateFrom', from: '@value', into: '@return'}],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
typedMutate: {
|
||||||
|
kind: 'function',
|
||||||
|
positionalParams: [EffectEnum.Read, EffectEnum.Capture],
|
||||||
|
restParam: null,
|
||||||
|
calleeEffect: EffectEnum.Store,
|
||||||
|
returnType: {kind: 'type', name: 'Primitive'},
|
||||||
|
returnValueKind: ValueKindEnum.Primitive,
|
||||||
|
aliasing: {
|
||||||
|
receiver: '@receiver',
|
||||||
|
params: ['@object', '@value'],
|
||||||
|
rest: null,
|
||||||
|
returns: '@return',
|
||||||
|
temporaries: [],
|
||||||
|
effects: [
|
||||||
|
{
|
||||||
|
kind: 'Create',
|
||||||
|
into: '@return',
|
||||||
|
value: ValueKindEnum.Primitive,
|
||||||
|
reason: ValueReasonEnum.KnownReturnSignature,
|
||||||
|
},
|
||||||
|
{kind: 'Mutate', value: '@object'},
|
||||||
|
{kind: 'Capture', from: '@value', into: '@object'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
} else if (moduleName === 'ReactCompilerTest') {
|
} else if (moduleName === 'ReactCompilerTest') {
|
||||||
|
|||||||
@@ -269,10 +269,12 @@ export function ValidateMemoization({
|
|||||||
inputs,
|
inputs,
|
||||||
output: rawOutput,
|
output: rawOutput,
|
||||||
onlyCheckCompiled = false,
|
onlyCheckCompiled = false,
|
||||||
|
alwaysCheck = false,
|
||||||
}: {
|
}: {
|
||||||
inputs: Array<any>;
|
inputs: Array<any>;
|
||||||
output: any;
|
output: any;
|
||||||
onlyCheckCompiled: boolean;
|
onlyCheckCompiled?: boolean;
|
||||||
|
alwaysCheck?: boolean;
|
||||||
}): React.ReactElement {
|
}): React.ReactElement {
|
||||||
'use no forget';
|
'use no forget';
|
||||||
// Wrap rawOutput as it might be a function, which useState would invoke.
|
// Wrap rawOutput as it might be a function, which useState would invoke.
|
||||||
@@ -280,8 +282,9 @@ export function ValidateMemoization({
|
|||||||
const [previousInputs, setPreviousInputs] = React.useState(inputs);
|
const [previousInputs, setPreviousInputs] = React.useState(inputs);
|
||||||
const [previousOutput, setPreviousOutput] = React.useState(output);
|
const [previousOutput, setPreviousOutput] = React.useState(output);
|
||||||
if (
|
if (
|
||||||
onlyCheckCompiled &&
|
alwaysCheck ||
|
||||||
(globalThis as any).__SNAP_EVALUATOR_MODE === 'forget'
|
(onlyCheckCompiled &&
|
||||||
|
(globalThis as any).__SNAP_EVALUATOR_MODE === 'forget')
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
inputs.length !== previousInputs.length ||
|
inputs.length !== previousInputs.length ||
|
||||||
@@ -400,4 +403,24 @@ export function typedIdentity<T>(value: T): T {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function typedAssign<T>(x: T): T {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function typedAlias<T>(x: T): T {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function typedCapture<T>(x: T): Array<T> {
|
||||||
|
return [x];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function typedCreateFrom<T>(array: Array<T>): T {
|
||||||
|
return array[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function typedMutate(x: any, v: any = null): void {
|
||||||
|
x.property = v;
|
||||||
|
}
|
||||||
|
|
||||||
export default typedLog;
|
export default typedLog;
|
||||||
|
|||||||
Reference in New Issue
Block a user