[compiler] Test fixture: non-reactive phi creates 'dangling ref' scope (#31103)
mofeiZ committed
Oct 10, 2024 at 12:23 UTC
fbfe37ee4010d36dad795d9144bb88fbeb8e1419
3 files changed
+122
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-phi-as-dependency.expect.md
new
+91
@@ -0,0 +1,91 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+import {CONST_TRUE, Stringify, mutate, useIdentity} from 'shared-runtime';
6
+
7
+/**
8
+ * Fixture showing an edge case for ReactiveScope variable propagation.
9
+ *
10
+ * Found differences in evaluator results
11
+ * Non-forget (expected):
12
+ * <div>{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}</div>
13
+ * <div>{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}</div>
14
+ * Forget:
15
+ * <div>{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}</div>
16
+ * [[ (exception in render) Error: invariant broken ]]
17
+ *
18
+ */
19
+function Component() {
20
+ const obj = CONST_TRUE ? {inner: {value: 'hello'}} : null;
21
+ const boxedInner = [obj?.inner];
22
+ useIdentity(null);
23
+ mutate(obj);
24
+ if (boxedInner[0] !== obj?.inner) {
25
+ throw new Error('invariant broken');
26
+ }
27
+ return <Stringify obj={obj} inner={boxedInner} />;
28
+}
29
+
30
+export const FIXTURE_ENTRYPOINT = {
31
+ fn: Component,
32
+ params: [{arg: 0}],
33
+ sequentialRenders: [{arg: 0}, {arg: 1}],
34
+};
35
+
36
+```
37
+
38
+## Code
39
+
40
+```javascript
41
+import { c as _c } from "react/compiler-runtime";
42
+import { CONST_TRUE, Stringify, mutate, useIdentity } from "shared-runtime";
43
+
44
+/**
45
+ * Fixture showing an edge case for ReactiveScope variable propagation.
46
+ *
47
+ * Found differences in evaluator results
48
+ * Non-forget (expected):
49
+ * <div>{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}</div>
50
+ * <div>{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}</div>
51
+ * Forget:
52
+ * <div>{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}</div>
53
+ * [[ (exception in render) Error: invariant broken ]]
54
+ *
55
+ */
56
+function Component() {
57
+ const $ = _c(4);
58
+ const obj = CONST_TRUE ? { inner: { value: "hello" } } : null;
59
+ let t0;
60
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
61
+ t0 = [obj?.inner];
62
+ $[0] = t0;
63
+ } else {
64
+ t0 = $[0];
65
+ }
66
+ const boxedInner = t0;
67
+ useIdentity(null);
68
+ mutate(obj);
69
+ if (boxedInner[0] !== obj?.inner) {
70
+ throw new Error("invariant broken");
71
+ }
72
+ let t1;
73
+ if ($[1] !== obj || $[2] !== boxedInner) {
74
+ t1 = <Stringify obj={obj} inner={boxedInner} />;
75
+ $[1] = obj;
76
+ $[2] = boxedInner;
77
+ $[3] = t1;
78
+ } else {
79
+ t1 = $[3];
80
+ }
81
+ return t1;
82
+}
83
+
84
+export const FIXTURE_ENTRYPOINT = {
85
+ fn: Component,
86
+ params: [{ arg: 0 }],
87
+ sequentialRenders: [{ arg: 0 }, { arg: 1 }],
88
+};
89
+
90
+```
91
+
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-phi-as-dependency.tsx
new
+30
@@ -0,0 +1,30 @@
1
+import {CONST_TRUE, Stringify, mutate, useIdentity} from 'shared-runtime';
2
+
3
+/**
4
+ * Fixture showing an edge case for ReactiveScope variable propagation.
5
+ *
6
+ * Found differences in evaluator results
7
+ * Non-forget (expected):
8
+ * <div>{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}</div>
9
+ * <div>{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}</div>
10
+ * Forget:
11
+ * <div>{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}</div>
12
+ * [[ (exception in render) Error: invariant broken ]]
13
+ *
14
+ */
15
+function Component() {
16
+ const obj = CONST_TRUE ? {inner: {value: 'hello'}} : null;
17
+ const boxedInner = [obj?.inner];
18
+ useIdentity(null);
19
+ mutate(obj);
20
+ if (boxedInner[0] !== obj?.inner) {
21
+ throw new Error('invariant broken');
22
+ }
23
+ return <Stringify obj={obj} inner={boxedInner} />;
24
+}
25
+
26
+export const FIXTURE_ENTRYPOINT = {
27
+ fn: Component,
28
+ params: [{arg: 0}],
29
+ sequentialRenders: [{arg: 0}, {arg: 1}],
30
+};
compiler/packages/snap/src/SproutTodoFilter.ts
+1
@@ -481,6 +481,7 @@ const skipFilter = new Set([
481
'bug-invalid-hoisting-functionexpr',
482
'bug-try-catch-maybe-null-dependency',
483
'reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted',
484
+ 'bug-invalid-phi-as-dependency',
485
'reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond',
486
'original-reactive-scopes-fork/bug-nonmutating-capture-in-unsplittable-memo-block',
487
'original-reactive-scopes-fork/bug-hoisted-declaration-with-scope',