mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[compiler] Tests for different orders of createfrom/capture w/wo function expressions
Adds some typed helpers to represent aliasing, assign, capture, createfrom, and mutate effects along with representative runtime behavior, and then adds tests to demonstrate that we model capture->createfrom and createfrom->capture correctly. There is one case (createfrom->capture in a lambda) where we infer a less precise effect, but in the more conservative direction (we include more code/deps than necesssary rather than fewer).
This commit is contained in:
+22
-2
@@ -271,9 +271,9 @@ a.property = value // a _is_ b, this mutates b
|
||||
|
||||
```
|
||||
CreateFrom a <- b
|
||||
Mutate A
|
||||
Mutate a
|
||||
=>
|
||||
MutateTransitive b
|
||||
Mutate b
|
||||
```
|
||||
|
||||
Example:
|
||||
@@ -301,6 +301,26 @@ a.b = 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
|
||||
|
||||
```
|
||||
|
||||
+166
@@ -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>;
|
||||
+46
@@ -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},
|
||||
],
|
||||
};
|
||||
+116
@@ -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>
|
||||
+33
@@ -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},
|
||||
],
|
||||
};
|
||||
+153
@@ -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>;
|
||||
+34
@@ -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},
|
||||
],
|
||||
};
|
||||
+115
@@ -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>
|
||||
+32
@@ -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},
|
||||
],
|
||||
};
|
||||
+106
@@ -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>
|
||||
+28
@@ -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},
|
||||
],
|
||||
};
|
||||
+103
@@ -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>
|
||||
+28
@@ -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},
|
||||
],
|
||||
};
|
||||
+122
@@ -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>
|
||||
+32
@@ -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 {
|
||||
Effect,
|
||||
ValueKind,
|
||||
ValueReason,
|
||||
printHIR,
|
||||
printFunctionWithOutlined,
|
||||
validateEnvironmentConfig,
|
||||
|
||||
@@ -18,7 +18,11 @@ import type {
|
||||
CompilerReactTarget,
|
||||
CompilerPipelineValue,
|
||||
} 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 * as HermesParser from 'hermes-parser';
|
||||
import invariant from 'invariant';
|
||||
@@ -42,6 +46,7 @@ function makePluginOptions(
|
||||
debugIRLogger: (value: CompilerPipelineValue) => void,
|
||||
EffectEnum: typeof Effect,
|
||||
ValueKindEnum: typeof ValueKind,
|
||||
ValueReasonEnum: typeof ValueReason,
|
||||
): [PluginOptions, Array<{filename: string | null; event: LoggerEvent}>] {
|
||||
// TODO(@mofeiZ) rewrite snap fixtures to @validatePreserveExistingMemo:false
|
||||
let validatePreserveExistingMemoizationGuarantees = false;
|
||||
@@ -77,6 +82,7 @@ function makePluginOptions(
|
||||
moduleTypeProvider: makeSharedRuntimeTypeProvider({
|
||||
EffectEnum,
|
||||
ValueKindEnum,
|
||||
ValueReasonEnum,
|
||||
}),
|
||||
assertValidMutableRanges: true,
|
||||
validatePreserveExistingMemoizationGuarantees,
|
||||
@@ -209,6 +215,7 @@ export async function transformFixtureInput(
|
||||
debugIRLogger: (value: CompilerPipelineValue) => void,
|
||||
EffectEnum: typeof Effect,
|
||||
ValueKindEnum: typeof ValueKind,
|
||||
ValueReasonEnum: typeof ValueReason,
|
||||
): Promise<{kind: 'ok'; value: TransformResult} | {kind: 'err'; msg: string}> {
|
||||
// Extract the first line to quickly check for custom test directives
|
||||
const firstLine = input.substring(0, input.indexOf('\n'));
|
||||
@@ -237,6 +244,7 @@ export async function transformFixtureInput(
|
||||
debugIRLogger,
|
||||
EffectEnum,
|
||||
ValueKindEnum,
|
||||
ValueReasonEnum,
|
||||
);
|
||||
const forgetResult = transformFromAstSync(inputAst, input, {
|
||||
filename: virtualFilepath,
|
||||
|
||||
@@ -24,6 +24,7 @@ import type {
|
||||
CompilerPipelineValue,
|
||||
Effect,
|
||||
ValueKind,
|
||||
ValueReason,
|
||||
} from 'babel-plugin-react-compiler/src';
|
||||
import chalk from 'chalk';
|
||||
|
||||
@@ -78,6 +79,9 @@ async function compile(
|
||||
const ValueKindEnum = importedCompilerPlugin[
|
||||
'ValueKind'
|
||||
] as typeof ValueKind;
|
||||
const ValueReasonEnum = importedCompilerPlugin[
|
||||
'ValueReason'
|
||||
] as typeof ValueReason;
|
||||
const printFunctionWithOutlined = importedCompilerPlugin[
|
||||
PRINT_HIR_IMPORT
|
||||
] as typeof PrintFunctionWithOutlined;
|
||||
@@ -128,6 +132,7 @@ async function compile(
|
||||
debugIRLogger,
|
||||
EffectEnum,
|
||||
ValueKindEnum,
|
||||
ValueReasonEnum,
|
||||
);
|
||||
|
||||
if (result.kind === 'err') {
|
||||
|
||||
@@ -5,15 +5,21 @@
|
||||
* 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';
|
||||
|
||||
export function makeSharedRuntimeTypeProvider({
|
||||
EffectEnum,
|
||||
ValueKindEnum,
|
||||
ValueReasonEnum,
|
||||
}: {
|
||||
EffectEnum: typeof Effect;
|
||||
ValueKindEnum: typeof ValueKind;
|
||||
ValueReasonEnum: typeof ValueReason;
|
||||
}) {
|
||||
return function sharedRuntimeTypeProvider(
|
||||
moduleName: string,
|
||||
@@ -85,6 +91,111 @@ export function makeSharedRuntimeTypeProvider({
|
||||
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') {
|
||||
|
||||
@@ -269,10 +269,12 @@ export function ValidateMemoization({
|
||||
inputs,
|
||||
output: rawOutput,
|
||||
onlyCheckCompiled = false,
|
||||
alwaysCheck = false,
|
||||
}: {
|
||||
inputs: Array<any>;
|
||||
output: any;
|
||||
onlyCheckCompiled: boolean;
|
||||
onlyCheckCompiled?: boolean;
|
||||
alwaysCheck?: boolean;
|
||||
}): React.ReactElement {
|
||||
'use no forget';
|
||||
// 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 [previousOutput, setPreviousOutput] = React.useState(output);
|
||||
if (
|
||||
onlyCheckCompiled &&
|
||||
(globalThis as any).__SNAP_EVALUATOR_MODE === 'forget'
|
||||
alwaysCheck ||
|
||||
(onlyCheckCompiled &&
|
||||
(globalThis as any).__SNAP_EVALUATOR_MODE === 'forget')
|
||||
) {
|
||||
if (
|
||||
inputs.length !== previousInputs.length ||
|
||||
@@ -400,4 +403,24 @@ export function typedIdentity<T>(value: T): T {
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user