Skip to content

Commit 039c5c0

Browse files
committed
[compiler] Repros for missing memoization due to lack of phi type inference
This is a complex case: we not only need phi type inference but also need to be able infer the union of `MixedReadonly | Array`. ghstack-source-id: 9350889 Pull Request resolved: #30793
1 parent ee7f675 commit 039c5c0

File tree

4 files changed

+191
-0
lines changed

4 files changed

+191
-0
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
2+
## Input
3+
4+
```javascript
5+
// @flow @validatePreserveExistingMemoizationGuarantees
6+
import {useMemo} from 'react';
7+
import {useFragment} from 'shared-runtime';
8+
9+
function Component() {
10+
const data = useFragment();
11+
const nodes = data.nodes ?? [];
12+
const flatMap = nodes.flatMap(node => node.items);
13+
const filtered = flatMap.filter(item => item != null);
14+
const map = useMemo(() => filtered.map(), [filtered]);
15+
const index = filtered.findIndex(x => x === null);
16+
17+
return (
18+
<div>
19+
{map}
20+
{index}
21+
</div>
22+
);
23+
}
24+
25+
```
26+
27+
28+
## Error
29+
30+
```
31+
8 | const flatMap = nodes.flatMap(node => node.items);
32+
9 | const filtered = flatMap.filter(item => item != null);
33+
> 10 | const map = useMemo(() => filtered.map(), [filtered]);
34+
| ^^^^^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This dependency may be mutated later, which could cause the value to change unexpectedly (10:10)
35+
36+
CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output. (10:10)
37+
11 | const index = filtered.findIndex(x => x === null);
38+
12 |
39+
13 | return (
40+
```
41+
42+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// @flow @validatePreserveExistingMemoizationGuarantees
2+
import {useMemo} from 'react';
3+
import {useFragment} from 'shared-runtime';
4+
5+
function Component() {
6+
const data = useFragment();
7+
const nodes = data.nodes ?? [];
8+
const flatMap = nodes.flatMap(node => node.items);
9+
const filtered = flatMap.filter(item => item != null);
10+
const map = useMemo(() => filtered.map(), [filtered]);
11+
const index = filtered.findIndex(x => x === null);
12+
13+
return (
14+
<div>
15+
{map}
16+
{index}
17+
</div>
18+
);
19+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
2+
## Input
3+
4+
```javascript
5+
// @flow @validatePreserveExistingMemoizationGuarantees @enableUseTypeAnnotations
6+
import {useMemo} from 'react';
7+
import {useFragment} from 'shared-runtime';
8+
9+
// This is a version of error.todo-repro-missing-memoization-lack-of-phi-types
10+
// with explicit type annotations and using enableUseTypeAnnotations to demonstrate
11+
// that type information is sufficient to preserve memoization in this example
12+
function Component() {
13+
const data = useFragment();
14+
const nodes: Array<any> = data.nodes ?? [];
15+
const flatMap: Array<any> = nodes.flatMap(node => node.items);
16+
const filtered: Array<any> = flatMap.filter(item => item != null);
17+
const map: Array<any> = useMemo(() => filtered.map(), [filtered]);
18+
const index: Array<any> = filtered.findIndex(x => x === null);
19+
20+
return (
21+
<div>
22+
{map}
23+
{index}
24+
</div>
25+
);
26+
}
27+
28+
```
29+
30+
## Code
31+
32+
```javascript
33+
import { c as _c } from "react/compiler-runtime";
34+
import { useMemo } from "react";
35+
import { useFragment } from "shared-runtime";
36+
37+
function Component() {
38+
const $ = _c(11);
39+
const data = useFragment();
40+
let t0;
41+
if ($[0] !== data.nodes) {
42+
t0 = data.nodes ?? [];
43+
$[0] = data.nodes;
44+
$[1] = t0;
45+
} else {
46+
t0 = $[1];
47+
}
48+
const nodes = t0;
49+
let t1;
50+
if ($[2] !== nodes) {
51+
t1 = nodes.flatMap(_temp);
52+
$[2] = nodes;
53+
$[3] = t1;
54+
} else {
55+
t1 = $[3];
56+
}
57+
const flatMap = t1;
58+
let t2;
59+
if ($[4] !== flatMap) {
60+
t2 = flatMap.filter(_temp2);
61+
$[4] = flatMap;
62+
$[5] = t2;
63+
} else {
64+
t2 = $[5];
65+
}
66+
const filtered = t2;
67+
let t3;
68+
let t4;
69+
if ($[6] !== filtered) {
70+
t4 = filtered.map();
71+
$[6] = filtered;
72+
$[7] = t4;
73+
} else {
74+
t4 = $[7];
75+
}
76+
t3 = t4;
77+
const map = t3;
78+
const index = filtered.findIndex(_temp3);
79+
let t5;
80+
if ($[8] !== map || $[9] !== index) {
81+
t5 = (
82+
<div>
83+
{map}
84+
{index}
85+
</div>
86+
);
87+
$[8] = map;
88+
$[9] = index;
89+
$[10] = t5;
90+
} else {
91+
t5 = $[10];
92+
}
93+
return t5;
94+
}
95+
function _temp3(x) {
96+
return x === null;
97+
}
98+
function _temp2(item) {
99+
return item != null;
100+
}
101+
function _temp(node) {
102+
return node.items;
103+
}
104+
105+
```
106+
107+
### Eval output
108+
(kind: exception) Fixture not implemented
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// @flow @validatePreserveExistingMemoizationGuarantees @enableUseTypeAnnotations
2+
import {useMemo} from 'react';
3+
import {useFragment} from 'shared-runtime';
4+
5+
// This is a version of error.todo-repro-missing-memoization-lack-of-phi-types
6+
// with explicit type annotations and using enableUseTypeAnnotations to demonstrate
7+
// that type information is sufficient to preserve memoization in this example
8+
function Component() {
9+
const data = useFragment();
10+
const nodes: Array<any> = data.nodes ?? [];
11+
const flatMap: Array<any> = nodes.flatMap(node => node.items);
12+
const filtered: Array<any> = flatMap.filter(item => item != null);
13+
const map: Array<any> = useMemo(() => filtered.map(), [filtered]);
14+
const index: Array<any> = filtered.findIndex(x => x === null);
15+
16+
return (
17+
<div>
18+
{map}
19+
{index}
20+
</div>
21+
);
22+
}

0 commit comments

Comments
 (0)