Repro for missing dep with while/if using externally declared "index" variable
What happens here is that the phi node for `i` has its mutable range set to start at 0, because it has a back edge and we haven't initialized the mutable ranges of all its operands yet when we iterate the operands and set range.start = min(start of operand starts). Then the corresponding scope has its range set to start at 0 too. When PropagateScopeDeps runs it sees that `b` is from instruction 1, which is after the start of the scope (0), so it thinks `b` isn't a valid dependency. The fix is in InferMutableRanges, where we need to make sure that phis ignore their operand's ranges until those ranges are initialized.
Joe Savona committed
Mar 22, 2024 at 21:49 UTC
2ce112dbf2442c87f89b649e31dd132c170d64fd
3 files changed
+108
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug-repro-missing-dependency-if-within-while.expect.md
new
+79
@@ -0,0 +1,79 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+const someGlobal = true;
6
+export default function Component(props) {
7
+ const { b } = props;
8
+ const items = [];
9
+ let i = 0;
10
+ while (i < 10) {
11
+ if (someGlobal) {
12
+ items.push(<div key={i}>{b}</div>);
13
+ i++;
14
+ }
15
+ }
16
+ return <>{items}</>;
17
+}
18
+
19
+export const FIXTURE_ENTRYPOINT = {
20
+ fn: Component,
21
+ params: [{ b: 42 }],
22
+ sequentialRenders: [
23
+ { b: 0 },
24
+ { b: 0 },
25
+ { b: 42 },
26
+ { b: 42 },
27
+ { b: 0 },
28
+ { b: 42 },
29
+ { b: 0 },
30
+ { b: 42 },
31
+ ],
32
+};
33
+
34
+```
35
+
36
+## Code
37
+
38
+```javascript
39
+import { unstable_useMemoCache as useMemoCache } from "react";
40
+const someGlobal = true;
41
+export default function Component(props) {
42
+ const $ = useMemoCache(1);
43
+ const { b } = props;
44
+ let t0;
45
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
46
+ const items = [];
47
+ let i = 0;
48
+ while (i < 10) {
49
+ if (someGlobal) {
50
+ items.push(<div key={i}>{b}</div>);
51
+ i++;
52
+ }
53
+ }
54
+
55
+ t0 = <>{items}</>;
56
+ $[0] = t0;
57
+ } else {
58
+ t0 = $[0];
59
+ }
60
+ return t0;
61
+}
62
+
63
+export const FIXTURE_ENTRYPOINT = {
64
+ fn: Component,
65
+ params: [{ b: 42 }],
66
+ sequentialRenders: [
67
+ { b: 0 },
68
+ { b: 0 },
69
+ { b: 42 },
70
+ { b: 42 },
71
+ { b: 0 },
72
+ { b: 42 },
73
+ { b: 0 },
74
+ { b: 42 },
75
+ ],
76
+};
77
+
78
+```
79
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug-repro-missing-dependency-if-within-while.js
new
+28
@@ -0,0 +1,28 @@
1
+const someGlobal = true;
2
+export default function Component(props) {
3
+ const { b } = props;
4
+ const items = [];
5
+ let i = 0;
6
+ while (i < 10) {
7
+ if (someGlobal) {
8
+ items.push(<div key={i}>{b}</div>);
9
+ i++;
10
+ }
11
+ }
12
+ return <>{items}</>;
13
+}
14
+
15
+export const FIXTURE_ENTRYPOINT = {
16
+ fn: Component,
17
+ params: [{ b: 42 }],
18
+ sequentialRenders: [
19
+ { b: 0 },
20
+ { b: 0 },
21
+ { b: 42 },
22
+ { b: 42 },
23
+ { b: 0 },
24
+ { b: 42 },
25
+ { b: 0 },
26
+ { b: 42 },
27
+ ],
28
+};
compiler/packages/snap/src/SproutTodoFilter.ts
+1
@@ -534,6 +534,7 @@ const skipFilter = new Set([
534
// bugs
535
"bug-reduce-reactive-deps-return-in-scope",
536
"bug-reduce-reactive-deps-break-in-scope",
537
+ "bug-repro-missing-dependency-if-within-while",
538
539
// 'react-forget-runtime' not yet supported
540
"flag-enable-emit-hook-guards",