mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
[compiler] Repro for object spread and Array.from with mutable iterators (#32520)
See newly added test fixtures. Repros fixed in later prs of this stack --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32520). * #32522 * #32521 * __->__ #32520
This commit is contained in:
parent
75c979847f
commit
3456b6634a
|
|
@ -0,0 +1,87 @@
|
|||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* TODO: object spreads should have conditionally mutate semantics
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok) [3,1,5,4]
|
||||
* [3,1,5,4]
|
||||
* [4,1,5,4]
|
||||
* Forget:
|
||||
* (kind: ok) [3,1,5,4]
|
||||
* [3,1,5,4]
|
||||
* [4]
|
||||
*/
|
||||
|
||||
function useBar({arg}) {
|
||||
'use memo';
|
||||
|
||||
/**
|
||||
* Note that mutableIterator is mutated by the later object spread. Therefore,
|
||||
* `s.values()` should be memoized within the same block as the object spread.
|
||||
* In terms of compiler internals, they should have the same reactive scope.
|
||||
*/
|
||||
const s = new Set([1, 5, 4]);
|
||||
const mutableIterator = s.values();
|
||||
|
||||
return [arg, ...mutableIterator];
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useBar,
|
||||
params: [{arg: 3}],
|
||||
sequentialRenders: [{arg: 3}, {arg: 3}, {arg: 4}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; /**
|
||||
* TODO: object spreads should have conditionally mutate semantics
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok) [3,1,5,4]
|
||||
* [3,1,5,4]
|
||||
* [4,1,5,4]
|
||||
* Forget:
|
||||
* (kind: ok) [3,1,5,4]
|
||||
* [3,1,5,4]
|
||||
* [4]
|
||||
*/
|
||||
|
||||
function useBar(t0) {
|
||||
"use memo";
|
||||
const $ = _c(3);
|
||||
const { arg } = t0;
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
const s = new Set([1, 5, 4]);
|
||||
t1 = s.values();
|
||||
$[0] = t1;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
}
|
||||
const mutableIterator = t1;
|
||||
let t2;
|
||||
if ($[1] !== arg) {
|
||||
t2 = [arg, ...mutableIterator];
|
||||
$[1] = arg;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t2 = $[2];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useBar,
|
||||
params: [{ arg: 3 }],
|
||||
sequentialRenders: [{ arg: 3 }, { arg: 3 }, { arg: 4 }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* TODO: object spreads should have conditionally mutate semantics
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok) [3,1,5,4]
|
||||
* [3,1,5,4]
|
||||
* [4,1,5,4]
|
||||
* Forget:
|
||||
* (kind: ok) [3,1,5,4]
|
||||
* [3,1,5,4]
|
||||
* [4]
|
||||
*/
|
||||
|
||||
function useBar({arg}) {
|
||||
'use memo';
|
||||
|
||||
/**
|
||||
* Note that mutableIterator is mutated by the later object spread. Therefore,
|
||||
* `s.values()` should be memoized within the same block as the object spread.
|
||||
* In terms of compiler internals, they should have the same reactive scope.
|
||||
*/
|
||||
const s = new Set([1, 5, 4]);
|
||||
const mutableIterator = s.values();
|
||||
|
||||
return [arg, ...mutableIterator];
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useBar,
|
||||
params: [{arg: 3}],
|
||||
sequentialRenders: [{arg: 3}, {arg: 3}, {arg: 4}],
|
||||
};
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {useIdentity, ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* TODO fixture for granular iterator semantics:
|
||||
* 1. ConditionallyMutate the iterator itself, depending on whether the iterator
|
||||
* is a mutable iterator.
|
||||
* 2. Capture effect on elements within the iterator.
|
||||
*/
|
||||
function Validate({x, input}) {
|
||||
'use no memo';
|
||||
return (
|
||||
<>
|
||||
<ValidateMemoization inputs={[]} output={x[0]} onlyCheckCompiled={true} />
|
||||
<ValidateMemoization
|
||||
inputs={[input]}
|
||||
output={x[1]}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
function useFoo(input) {
|
||||
'use memo';
|
||||
/**
|
||||
* TODO: We should be able to memoize {} separately from `x`.
|
||||
*/
|
||||
const x = Array.from([{}]);
|
||||
useIdentity();
|
||||
x.push([input]);
|
||||
return <Validate x={x} input={input} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [1],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { useIdentity, ValidateMemoization } from "shared-runtime";
|
||||
|
||||
/**
|
||||
* TODO fixture for granular iterator semantics:
|
||||
* 1. ConditionallyMutate the iterator itself, depending on whether the iterator
|
||||
* is a mutable iterator.
|
||||
* 2. Capture effect on elements within the iterator.
|
||||
*/
|
||||
function Validate({ x, input }) {
|
||||
"use no memo";
|
||||
return (
|
||||
<>
|
||||
<ValidateMemoization inputs={[]} output={x[0]} onlyCheckCompiled={true} />
|
||||
<ValidateMemoization
|
||||
inputs={[input]}
|
||||
output={x[1]}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
function useFoo(input) {
|
||||
"use memo";
|
||||
const $ = _c(3);
|
||||
|
||||
const x = Array.from([{}]);
|
||||
useIdentity();
|
||||
x.push([input]);
|
||||
let t0;
|
||||
if ($[0] !== input || $[1] !== x) {
|
||||
t0 = <Validate x={x} input={input} />;
|
||||
$[0] = input;
|
||||
$[1] = x;
|
||||
$[2] = t0;
|
||||
} else {
|
||||
t0 = $[2];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [1],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"inputs":[],"output":{}}</div><div>{"inputs":[1],"output":[1]}</div>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
import {useIdentity, ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* TODO fixture for granular iterator semantics:
|
||||
* 1. ConditionallyMutate the iterator itself, depending on whether the iterator
|
||||
* is a mutable iterator.
|
||||
* 2. Capture effect on elements within the iterator.
|
||||
*/
|
||||
function Validate({x, input}) {
|
||||
'use no memo';
|
||||
return (
|
||||
<>
|
||||
<ValidateMemoization inputs={[]} output={x[0]} onlyCheckCompiled={true} />
|
||||
<ValidateMemoization
|
||||
inputs={[input]}
|
||||
output={x[1]}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
function useFoo(input) {
|
||||
'use memo';
|
||||
/**
|
||||
* TODO: We should be able to memoize {} separately from `x`.
|
||||
*/
|
||||
const x = Array.from([{}]);
|
||||
useIdentity();
|
||||
x.push([input]);
|
||||
return <Validate x={x} input={input} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [1],
|
||||
};
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {useIdentity, ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Fixture to assert that we can infer the type and effects of an array created
|
||||
* with `Array.from`.
|
||||
*/
|
||||
function Validate({x, val1, val2}) {
|
||||
'use no memo';
|
||||
return (
|
||||
<>
|
||||
<ValidateMemoization
|
||||
inputs={[val1]}
|
||||
output={x[0]}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
<ValidateMemoization
|
||||
inputs={[val2]}
|
||||
output={x[1]}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
function useFoo({val1, val2}) {
|
||||
'use memo';
|
||||
const x = Array.from([]);
|
||||
useIdentity();
|
||||
x.push([val1]);
|
||||
x.push([val2]);
|
||||
return <Validate x={x} val1={val1} val2={val2} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [{val1: 1, val2: 2}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { useIdentity, ValidateMemoization } from "shared-runtime";
|
||||
|
||||
/**
|
||||
* Fixture to assert that we can infer the type and effects of an array created
|
||||
* with `Array.from`.
|
||||
*/
|
||||
function Validate({ x, val1, val2 }) {
|
||||
"use no memo";
|
||||
return (
|
||||
<>
|
||||
<ValidateMemoization
|
||||
inputs={[val1]}
|
||||
output={x[0]}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
|
||||
<ValidateMemoization
|
||||
inputs={[val2]}
|
||||
output={x[1]}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
function useFoo(t0) {
|
||||
"use memo";
|
||||
const $ = _c(4);
|
||||
const { val1, val2 } = t0;
|
||||
|
||||
const x = Array.from([]);
|
||||
useIdentity();
|
||||
x.push([val1]);
|
||||
x.push([val2]);
|
||||
let t1;
|
||||
if ($[0] !== val1 || $[1] !== val2 || $[2] !== x) {
|
||||
t1 = <Validate x={x} val1={val1} val2={val2} />;
|
||||
$[0] = val1;
|
||||
$[1] = val2;
|
||||
$[2] = x;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [{ val1: 1, val2: 2 }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"inputs":[1],"output":[1]}</div><div>{"inputs":[2],"output":[2]}</div>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
import {useIdentity, ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Fixture to assert that we can infer the type and effects of an array created
|
||||
* with `Array.from`.
|
||||
*/
|
||||
function Validate({x, val1, val2}) {
|
||||
'use no memo';
|
||||
return (
|
||||
<>
|
||||
<ValidateMemoization
|
||||
inputs={[val1]}
|
||||
output={x[0]}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
<ValidateMemoization
|
||||
inputs={[val2]}
|
||||
output={x[1]}
|
||||
onlyCheckCompiled={true}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
function useFoo({val1, val2}) {
|
||||
'use memo';
|
||||
const x = Array.from([]);
|
||||
useIdentity();
|
||||
x.push([val1]);
|
||||
x.push([val2]);
|
||||
return <Validate x={x} val1={val1} val2={val2} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [{val1: 1, val2: 2}],
|
||||
};
|
||||
|
|
@ -462,6 +462,7 @@ const skipFilter = new Set([
|
|||
|
||||
// bugs
|
||||
'bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr',
|
||||
'bug-array-spread-mutable-iterator',
|
||||
`bug-capturing-func-maybealias-captured-mutate`,
|
||||
'bug-aliased-capture-aliased-mutate',
|
||||
'bug-aliased-capture-mutate',
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user