Skip to content

Commit fbfe37e

Browse files
authored
[compiler] Test fixture: non-reactive phi creates 'dangling ref' scope (#31103)
1 parent 77f4389 commit fbfe37e

File tree

3 files changed

+122
-0
lines changed

3 files changed

+122
-0
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,7 @@ const skipFilter = new Set([
481481
'bug-invalid-hoisting-functionexpr',
482482
'bug-try-catch-maybe-null-dependency',
483483
'reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted',
484+
'bug-invalid-phi-as-dependency',
484485
'reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond',
485486
'original-reactive-scopes-fork/bug-nonmutating-capture-in-unsplittable-memo-block',
486487
'original-reactive-scopes-fork/bug-hoisted-declaration-with-scope',

0 commit comments

Comments
 (0)