Skip to content

Commit 464a6c6

Browse files
committed
[compiler] Repro for object spread and Array.from with mutable iterators
See newly added test fixtures. Repros fixed in later prs of this stack
1 parent 443b7ff commit 464a6c6

File tree

7 files changed

+390
-0
lines changed

7 files changed

+390
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
2+
## Input
3+
4+
```javascript
5+
/**
6+
* TODO: object spreads should have conditionally mutate semantics
7+
* Found differences in evaluator results
8+
* Non-forget (expected):
9+
* (kind: ok) [3,1,5,4]
10+
* [3,1,5,4]
11+
* [4,1,5,4]
12+
* Forget:
13+
* (kind: ok) [3,1,5,4]
14+
* [3,1,5,4]
15+
* [4]
16+
*/
17+
18+
function useBar({arg}) {
19+
'use memo';
20+
21+
/**
22+
* Note that mutableIterator is mutated by the later object spread. Therefore,
23+
* `s.values()` should be memoized within the same block as the object spread.
24+
* In terms of compiler internals, they should have the same reactive scope.
25+
*/
26+
const s = new Set([1, 5, 4]);
27+
const mutableIterator = s.values();
28+
29+
return [arg, ...mutableIterator];
30+
}
31+
32+
export const FIXTURE_ENTRYPOINT = {
33+
fn: useBar,
34+
params: [{arg: 3}],
35+
sequentialRenders: [{arg: 3}, {arg: 3}, {arg: 4}],
36+
};
37+
38+
```
39+
40+
## Code
41+
42+
```javascript
43+
import { c as _c } from "react/compiler-runtime"; /**
44+
* TODO: object spreads should have conditionally mutate semantics
45+
* Found differences in evaluator results
46+
* Non-forget (expected):
47+
* (kind: ok) [3,1,5,4]
48+
* [3,1,5,4]
49+
* [4,1,5,4]
50+
* Forget:
51+
* (kind: ok) [3,1,5,4]
52+
* [3,1,5,4]
53+
* [4]
54+
*/
55+
56+
function useBar(t0) {
57+
"use memo";
58+
const $ = _c(3);
59+
const { arg } = t0;
60+
let t1;
61+
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
62+
const s = new Set([1, 5, 4]);
63+
t1 = s.values();
64+
$[0] = t1;
65+
} else {
66+
t1 = $[0];
67+
}
68+
const mutableIterator = t1;
69+
let t2;
70+
if ($[1] !== arg) {
71+
t2 = [arg, ...mutableIterator];
72+
$[1] = arg;
73+
$[2] = t2;
74+
} else {
75+
t2 = $[2];
76+
}
77+
return t2;
78+
}
79+
80+
export const FIXTURE_ENTRYPOINT = {
81+
fn: useBar,
82+
params: [{ arg: 3 }],
83+
sequentialRenders: [{ arg: 3 }, { arg: 3 }, { arg: 4 }],
84+
};
85+
86+
```
87+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* TODO: object spreads should have conditionally mutate semantics
3+
* Found differences in evaluator results
4+
* Non-forget (expected):
5+
* (kind: ok) [3,1,5,4]
6+
* [3,1,5,4]
7+
* [4,1,5,4]
8+
* Forget:
9+
* (kind: ok) [3,1,5,4]
10+
* [3,1,5,4]
11+
* [4]
12+
*/
13+
14+
function useBar({arg}) {
15+
'use memo';
16+
17+
/**
18+
* Note that mutableIterator is mutated by the later object spread. Therefore,
19+
* `s.values()` should be memoized within the same block as the object spread.
20+
* In terms of compiler internals, they should have the same reactive scope.
21+
*/
22+
const s = new Set([1, 5, 4]);
23+
const mutableIterator = s.values();
24+
25+
return [arg, ...mutableIterator];
26+
}
27+
28+
export const FIXTURE_ENTRYPOINT = {
29+
fn: useBar,
30+
params: [{arg: 3}],
31+
sequentialRenders: [{arg: 3}, {arg: 3}, {arg: 4}],
32+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
2+
## Input
3+
4+
```javascript
5+
import {useIdentity, ValidateMemoization} from 'shared-runtime';
6+
7+
/**
8+
* TODO fixture for granular iterator semantics:
9+
* 1. ConditionallyMutate the iterator itself, depending on whether the iterator
10+
* is a mutable iterator.
11+
* 2. Capture effect on elements within the iterator.
12+
*/
13+
function Validate({x, input}) {
14+
'use no memo';
15+
return (
16+
<>
17+
<ValidateMemoization inputs={[]} output={x[0]} onlyCheckCompiled={true} />
18+
<ValidateMemoization
19+
inputs={[input]}
20+
output={x[1]}
21+
onlyCheckCompiled={true}
22+
/>
23+
</>
24+
);
25+
}
26+
function useFoo(input) {
27+
'use memo';
28+
/**
29+
* TODO: We should be able to memoize {} separately from `x`.
30+
*/
31+
const x = Array.from([{}]);
32+
useIdentity();
33+
x.push([input]);
34+
return <Validate x={x} input={input} />;
35+
}
36+
37+
export const FIXTURE_ENTRYPOINT = {
38+
fn: useFoo,
39+
params: [1],
40+
};
41+
42+
```
43+
44+
## Code
45+
46+
```javascript
47+
import { c as _c } from "react/compiler-runtime";
48+
import { useIdentity, ValidateMemoization } from "shared-runtime";
49+
50+
/**
51+
* TODO fixture for granular iterator semantics:
52+
* 1. ConditionallyMutate the iterator itself, depending on whether the iterator
53+
* is a mutable iterator.
54+
* 2. Capture effect on elements within the iterator.
55+
*/
56+
function Validate({ x, input }) {
57+
"use no memo";
58+
return (
59+
<>
60+
<ValidateMemoization inputs={[]} output={x[0]} onlyCheckCompiled={true} />
61+
<ValidateMemoization
62+
inputs={[input]}
63+
output={x[1]}
64+
onlyCheckCompiled={true}
65+
/>
66+
</>
67+
);
68+
}
69+
function useFoo(input) {
70+
"use memo";
71+
const $ = _c(3);
72+
73+
const x = Array.from([{}]);
74+
useIdentity();
75+
x.push([input]);
76+
let t0;
77+
if ($[0] !== input || $[1] !== x) {
78+
t0 = <Validate x={x} input={input} />;
79+
$[0] = input;
80+
$[1] = x;
81+
$[2] = t0;
82+
} else {
83+
t0 = $[2];
84+
}
85+
return t0;
86+
}
87+
88+
export const FIXTURE_ENTRYPOINT = {
89+
fn: useFoo,
90+
params: [1],
91+
};
92+
93+
```
94+
95+
### Eval output
96+
(kind: ok) <div>{"inputs":[],"output":{}}</div><div>{"inputs":[1],"output":[1]}</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {useIdentity, ValidateMemoization} from 'shared-runtime';
2+
3+
/**
4+
* TODO fixture for granular iterator semantics:
5+
* 1. ConditionallyMutate the iterator itself, depending on whether the iterator
6+
* is a mutable iterator.
7+
* 2. Capture effect on elements within the iterator.
8+
*/
9+
function Validate({x, input}) {
10+
'use no memo';
11+
return (
12+
<>
13+
<ValidateMemoization inputs={[]} output={x[0]} onlyCheckCompiled={true} />
14+
<ValidateMemoization
15+
inputs={[input]}
16+
output={x[1]}
17+
onlyCheckCompiled={true}
18+
/>
19+
</>
20+
);
21+
}
22+
function useFoo(input) {
23+
'use memo';
24+
/**
25+
* TODO: We should be able to memoize {} separately from `x`.
26+
*/
27+
const x = Array.from([{}]);
28+
useIdentity();
29+
x.push([input]);
30+
return <Validate x={x} input={input} />;
31+
}
32+
33+
export const FIXTURE_ENTRYPOINT = {
34+
fn: useFoo,
35+
params: [1],
36+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
2+
## Input
3+
4+
```javascript
5+
import {useIdentity, ValidateMemoization} from 'shared-runtime';
6+
7+
/**
8+
* Fixture to assert that we can infer the type and effects of an array created
9+
* with `Array.from`.
10+
*/
11+
function Validate({x, val1, val2}) {
12+
'use no memo';
13+
return (
14+
<>
15+
<ValidateMemoization
16+
inputs={[val1]}
17+
output={x[0]}
18+
onlyCheckCompiled={true}
19+
/>
20+
<ValidateMemoization
21+
inputs={[val2]}
22+
output={x[1]}
23+
onlyCheckCompiled={true}
24+
/>
25+
</>
26+
);
27+
}
28+
function useFoo({val1, val2}) {
29+
'use memo';
30+
const x = Array.from([]);
31+
useIdentity();
32+
x.push([val1]);
33+
x.push([val2]);
34+
return <Validate x={x} val1={val1} val2={val2} />;
35+
}
36+
37+
export const FIXTURE_ENTRYPOINT = {
38+
fn: useFoo,
39+
params: [{val1: 1, val2: 2}],
40+
};
41+
42+
```
43+
44+
## Code
45+
46+
```javascript
47+
import { c as _c } from "react/compiler-runtime";
48+
import { useIdentity, ValidateMemoization } from "shared-runtime";
49+
50+
/**
51+
* Fixture to assert that we can infer the type and effects of an array created
52+
* with `Array.from`.
53+
*/
54+
function Validate({ x, val1, val2 }) {
55+
"use no memo";
56+
return (
57+
<>
58+
<ValidateMemoization
59+
inputs={[val1]}
60+
output={x[0]}
61+
onlyCheckCompiled={true}
62+
/>
63+
64+
<ValidateMemoization
65+
inputs={[val2]}
66+
output={x[1]}
67+
onlyCheckCompiled={true}
68+
/>
69+
</>
70+
);
71+
}
72+
function useFoo(t0) {
73+
"use memo";
74+
const $ = _c(4);
75+
const { val1, val2 } = t0;
76+
77+
const x = Array.from([]);
78+
useIdentity();
79+
x.push([val1]);
80+
x.push([val2]);
81+
let t1;
82+
if ($[0] !== val1 || $[1] !== val2 || $[2] !== x) {
83+
t1 = <Validate x={x} val1={val1} val2={val2} />;
84+
$[0] = val1;
85+
$[1] = val2;
86+
$[2] = x;
87+
$[3] = t1;
88+
} else {
89+
t1 = $[3];
90+
}
91+
return t1;
92+
}
93+
94+
export const FIXTURE_ENTRYPOINT = {
95+
fn: useFoo,
96+
params: [{ val1: 1, val2: 2 }],
97+
};
98+
99+
```
100+
101+
### Eval output
102+
(kind: ok) <div>{"inputs":[1],"output":[1]}</div><div>{"inputs":[2],"output":[2]}</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {useIdentity, ValidateMemoization} from 'shared-runtime';
2+
3+
/**
4+
* Fixture to assert that we can infer the type and effects of an array created
5+
* with `Array.from`.
6+
*/
7+
function Validate({x, val1, val2}) {
8+
'use no memo';
9+
return (
10+
<>
11+
<ValidateMemoization
12+
inputs={[val1]}
13+
output={x[0]}
14+
onlyCheckCompiled={true}
15+
/>
16+
<ValidateMemoization
17+
inputs={[val2]}
18+
output={x[1]}
19+
onlyCheckCompiled={true}
20+
/>
21+
</>
22+
);
23+
}
24+
function useFoo({val1, val2}) {
25+
'use memo';
26+
const x = Array.from([]);
27+
useIdentity();
28+
x.push([val1]);
29+
x.push([val2]);
30+
return <Validate x={x} val1={val1} val2={val2} />;
31+
}
32+
33+
export const FIXTURE_ENTRYPOINT = {
34+
fn: useFoo,
35+
params: [{val1: 1, val2: 2}],
36+
};

0 commit comments

Comments
 (0)