Fixtures for control values that become reactive due to interleaving
See the previous PR, interleaved mutation can cause values that were not reactive to become reactive. I swear I had a case where this was observable, but I came up with it before reordering the PRs in this stack. I think my repro relied on an immutable reference to a mutable value, which is now handled in InferReactivePlaces. So here i'm just adding fixtures, and allowing this case since it's unobservable.
Joe Savona committed
Jan 23, 2024 at 08:59 UTC
a023a2da723b730149667d783b1e08aadccbfeae
18 files changed
+838
-4
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-do-while.expect.md
new
+73
@@ -0,0 +1,73 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ // a and b are independent but their mutations are interleaved, so
7
+ // they get grouped in a reactive scope. this means that a becomes
8
+ // reactive since it will effectively re-evaluate based on a reactive
9
+ // input
10
+ const a = [];
11
+ const b = [];
12
+ b.push(props.cond);
13
+ a.push(false);
14
+
15
+ // Downstream consumer of a, which initially seems non-reactive except
16
+ // that a becomes reactive, per above
17
+ const c = [a];
18
+
19
+ let x = 0;
20
+ do {
21
+ x += 1;
22
+ } while (c[0][0]);
23
+ // The values assigned to `x` are non-reactive, but the value of `x`
24
+ // depends on the "control" value `c[0]` which becomes reactive via
25
+ // being interleaved with `b`.
26
+ // Therefore x should be treated as reactive too.
27
+ return [x];
28
+}
29
+
30
+export const FIXTURE_ENTRYPOINT = {
31
+ fn: Component,
32
+ params: [{ cond: true }],
33
+};
34
+
35
+```
36
+
37
+## Code
38
+
39
+```javascript
40
+import { unstable_useMemoCache as useMemoCache } from "react";
41
+function Component(props) {
42
+ const $ = useMemoCache(1);
43
+
44
+ const a = [];
45
+ const b = [];
46
+ b.push(props.cond);
47
+ a.push(false);
48
+
49
+ const c = [a];
50
+
51
+ let x = 0;
52
+ do {
53
+ x = x + 1;
54
+ } while (c[0][0]);
55
+ let t0;
56
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
57
+ t0 = [x];
58
+ $[0] = t0;
59
+ } else {
60
+ t0 = $[0];
61
+ }
62
+ return t0;
63
+}
64
+
65
+export const FIXTURE_ENTRYPOINT = {
66
+ fn: Component,
67
+ params: [{ cond: true }],
68
+};
69
+
70
+```
71
+
72
+### Eval output
73
+(kind: ok) [1]
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-do-while.js
new
+29
@@ -0,0 +1,29 @@
1
+function Component(props) {
2
+ // a and b are independent but their mutations are interleaved, so
3
+ // they get grouped in a reactive scope. this means that a becomes
4
+ // reactive since it will effectively re-evaluate based on a reactive
5
+ // input
6
+ const a = [];
7
+ const b = [];
8
+ b.push(props.cond);
9
+ a.push(false);
10
+
11
+ // Downstream consumer of a, which initially seems non-reactive except
12
+ // that a becomes reactive, per above
13
+ const c = [a];
14
+
15
+ let x = 0;
16
+ do {
17
+ x += 1;
18
+ } while (c[0][0]);
19
+ // The values assigned to `x` are non-reactive, but the value of `x`
20
+ // depends on the "control" value `c[0]` which becomes reactive via
21
+ // being interleaved with `b`.
22
+ // Therefore x should be treated as reactive too.
23
+ return [x];
24
+}
25
+
26
+export const FIXTURE_ENTRYPOINT = {
27
+ fn: Component,
28
+ params: [{ cond: true }],
29
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-for-in.expect.md
new
+73
@@ -0,0 +1,73 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ // a and b are independent but their mutations are interleaved, so
7
+ // they get grouped in a reactive scope. this means that a becomes
8
+ // reactive since it will effectively re-evaluate based on a reactive
9
+ // input
10
+ const a = [];
11
+ const b = [];
12
+ b.push(props.cond);
13
+ a.push({ a: false });
14
+
15
+ // Downstream consumer of a, which initially seems non-reactive except
16
+ // that a becomes reactive, per above
17
+ const c = [a];
18
+
19
+ let x;
20
+ for (const i in c[0][0]) {
21
+ x = 1;
22
+ }
23
+ // The values assigned to `x` are non-reactive, but the value of `x`
24
+ // depends on the "control" value `c[0]` which becomes reactive via
25
+ // being interleaved with `b`.
26
+ // Therefore x should be treated as reactive too.
27
+ return [x];
28
+}
29
+
30
+export const FIXTURE_ENTRYPOINT = {
31
+ fn: Component,
32
+ params: [{ cond: true }],
33
+};
34
+
35
+```
36
+
37
+## Code
38
+
39
+```javascript
40
+import { unstable_useMemoCache as useMemoCache } from "react";
41
+function Component(props) {
42
+ const $ = useMemoCache(1);
43
+
44
+ const a = [];
45
+ const b = [];
46
+ b.push(props.cond);
47
+ a.push({ a: false });
48
+
49
+ const c = [a];
50
+
51
+ let x;
52
+ for (const i in c[0][0]) {
53
+ x = 1;
54
+ }
55
+ let t0;
56
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
57
+ t0 = [x];
58
+ $[0] = t0;
59
+ } else {
60
+ t0 = $[0];
61
+ }
62
+ return t0;
63
+}
64
+
65
+export const FIXTURE_ENTRYPOINT = {
66
+ fn: Component,
67
+ params: [{ cond: true }],
68
+};
69
+
70
+```
71
+
72
+### Eval output
73
+(kind: ok) [1]
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-for-in.js
new
+29
@@ -0,0 +1,29 @@
1
+function Component(props) {
2
+ // a and b are independent but their mutations are interleaved, so
3
+ // they get grouped in a reactive scope. this means that a becomes
4
+ // reactive since it will effectively re-evaluate based on a reactive
5
+ // input
6
+ const a = [];
7
+ const b = [];
8
+ b.push(props.cond);
9
+ a.push({ a: false });
10
+
11
+ // Downstream consumer of a, which initially seems non-reactive except
12
+ // that a becomes reactive, per above
13
+ const c = [a];
14
+
15
+ let x;
16
+ for (const i in c[0][0]) {
17
+ x = 1;
18
+ }
19
+ // The values assigned to `x` are non-reactive, but the value of `x`
20
+ // depends on the "control" value `c[0]` which becomes reactive via
21
+ // being interleaved with `b`.
22
+ // Therefore x should be treated as reactive too.
23
+ return [x];
24
+}
25
+
26
+export const FIXTURE_ENTRYPOINT = {
27
+ fn: Component,
28
+ params: [{ cond: true }],
29
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-for-init.expect.md
new
+73
@@ -0,0 +1,73 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ // a and b are independent but their mutations are interleaved, so
7
+ // they get grouped in a reactive scope. this means that a becomes
8
+ // reactive since it will effectively re-evaluate based on a reactive
9
+ // input
10
+ const a = [];
11
+ const b = [];
12
+ b.push(props.cond);
13
+ a.push(0);
14
+
15
+ // Downstream consumer of a, which initially seems non-reactive except
16
+ // that a becomes reactive, per above
17
+ const c = [a];
18
+
19
+ let x;
20
+ for (let i = c[0][0]; i < 10; i++) {
21
+ x = 1;
22
+ }
23
+ // The values assigned to `x` are non-reactive, but the value of `x`
24
+ // depends on the "control" value `c[0]` which becomes reactive via
25
+ // being interleaved with `b`.
26
+ // Therefore x should be treated as reactive too.
27
+ return [x];
28
+}
29
+
30
+export const FIXTURE_ENTRYPOINT = {
31
+ fn: Component,
32
+ params: [{ cond: true }],
33
+};
34
+
35
+```
36
+
37
+## Code
38
+
39
+```javascript
40
+import { unstable_useMemoCache as useMemoCache } from "react";
41
+function Component(props) {
42
+ const $ = useMemoCache(1);
43
+
44
+ const a = [];
45
+ const b = [];
46
+ b.push(props.cond);
47
+ a.push(0);
48
+
49
+ const c = [a];
50
+
51
+ let x;
52
+ for (let i = c[0][0]; i < 10; i++) {
53
+ x = 1;
54
+ }
55
+ let t0;
56
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
57
+ t0 = [x];
58
+ $[0] = t0;
59
+ } else {
60
+ t0 = $[0];
61
+ }
62
+ return t0;
63
+}
64
+
65
+export const FIXTURE_ENTRYPOINT = {
66
+ fn: Component,
67
+ params: [{ cond: true }],
68
+};
69
+
70
+```
71
+
72
+### Eval output
73
+(kind: ok) [1]
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-for-init.js
new
+29
@@ -0,0 +1,29 @@
1
+function Component(props) {
2
+ // a and b are independent but their mutations are interleaved, so
3
+ // they get grouped in a reactive scope. this means that a becomes
4
+ // reactive since it will effectively re-evaluate based on a reactive
5
+ // input
6
+ const a = [];
7
+ const b = [];
8
+ b.push(props.cond);
9
+ a.push(0);
10
+
11
+ // Downstream consumer of a, which initially seems non-reactive except
12
+ // that a becomes reactive, per above
13
+ const c = [a];
14
+
15
+ let x;
16
+ for (let i = c[0][0]; i < 10; i++) {
17
+ x = 1;
18
+ }
19
+ // The values assigned to `x` are non-reactive, but the value of `x`
20
+ // depends on the "control" value `c[0]` which becomes reactive via
21
+ // being interleaved with `b`.
22
+ // Therefore x should be treated as reactive too.
23
+ return [x];
24
+}
25
+
26
+export const FIXTURE_ENTRYPOINT = {
27
+ fn: Component,
28
+ params: [{ cond: true }],
29
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-for-of.expect.md
new
+73
@@ -0,0 +1,73 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ // a and b are independent but their mutations are interleaved, so
7
+ // they get grouped in a reactive scope. this means that a becomes
8
+ // reactive since it will effectively re-evaluate based on a reactive
9
+ // input
10
+ const a = [];
11
+ const b = [];
12
+ b.push(props.cond);
13
+ a.push(null);
14
+
15
+ // Downstream consumer of a, which initially seems non-reactive except
16
+ // that a becomes reactive, per above
17
+ const c = [a];
18
+
19
+ let x;
20
+ for (const i of c[0]) {
21
+ x = 1;
22
+ }
23
+ // The values assigned to `x` are non-reactive, but the value of `x`
24
+ // depends on the "control" value `c[0]` which becomes reactive via
25
+ // being interleaved with `b`.
26
+ // Therefore x should be treated as reactive too.
27
+ return [x];
28
+}
29
+
30
+export const FIXTURE_ENTRYPOINT = {
31
+ fn: Component,
32
+ params: [{ cond: true }],
33
+};
34
+
35
+```
36
+
37
+## Code
38
+
39
+```javascript
40
+import { unstable_useMemoCache as useMemoCache } from "react";
41
+function Component(props) {
42
+ const $ = useMemoCache(1);
43
+
44
+ const a = [];
45
+ const b = [];
46
+ b.push(props.cond);
47
+ a.push(null);
48
+
49
+ const c = [a];
50
+
51
+ let x;
52
+ for (const i of c[0]) {
53
+ x = 1;
54
+ }
55
+ let t0;
56
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
57
+ t0 = [x];
58
+ $[0] = t0;
59
+ } else {
60
+ t0 = $[0];
61
+ }
62
+ return t0;
63
+}
64
+
65
+export const FIXTURE_ENTRYPOINT = {
66
+ fn: Component,
67
+ params: [{ cond: true }],
68
+};
69
+
70
+```
71
+
72
+### Eval output
73
+(kind: ok) [1]
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-for-of.js
new
+29
@@ -0,0 +1,29 @@
1
+function Component(props) {
2
+ // a and b are independent but their mutations are interleaved, so
3
+ // they get grouped in a reactive scope. this means that a becomes
4
+ // reactive since it will effectively re-evaluate based on a reactive
5
+ // input
6
+ const a = [];
7
+ const b = [];
8
+ b.push(props.cond);
9
+ a.push(null);
10
+
11
+ // Downstream consumer of a, which initially seems non-reactive except
12
+ // that a becomes reactive, per above
13
+ const c = [a];
14
+
15
+ let x;
16
+ for (const i of c[0]) {
17
+ x = 1;
18
+ }
19
+ // The values assigned to `x` are non-reactive, but the value of `x`
20
+ // depends on the "control" value `c[0]` which becomes reactive via
21
+ // being interleaved with `b`.
22
+ // Therefore x should be treated as reactive too.
23
+ return [x];
24
+}
25
+
26
+export const FIXTURE_ENTRYPOINT = {
27
+ fn: Component,
28
+ params: [{ cond: true }],
29
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-for-test.expect.md
new
+73
@@ -0,0 +1,73 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ // a and b are independent but their mutations are interleaved, so
7
+ // they get grouped in a reactive scope. this means that a becomes
8
+ // reactive since it will effectively re-evaluate based on a reactive
9
+ // input
10
+ const a = [];
11
+ const b = [];
12
+ b.push(props.cond);
13
+ a.push(10);
14
+
15
+ // Downstream consumer of a, which initially seems non-reactive except
16
+ // that a becomes reactive, per above
17
+ const c = [a];
18
+
19
+ let x;
20
+ for (let i = 0; i < c[0][0]; i++) {
21
+ x = 1;
22
+ }
23
+ // The values assigned to `x` are non-reactive, but the value of `x`
24
+ // depends on the "control" value `c[0]` which becomes reactive via
25
+ // being interleaved with `b`.
26
+ // Therefore x should be treated as reactive too.
27
+ return [x];
28
+}
29
+
30
+export const FIXTURE_ENTRYPOINT = {
31
+ fn: Component,
32
+ params: [{ cond: true }],
33
+};
34
+
35
+```
36
+
37
+## Code
38
+
39
+```javascript
40
+import { unstable_useMemoCache as useMemoCache } from "react";
41
+function Component(props) {
42
+ const $ = useMemoCache(1);
43
+
44
+ const a = [];
45
+ const b = [];
46
+ b.push(props.cond);
47
+ a.push(10);
48
+
49
+ const c = [a];
50
+
51
+ let x;
52
+ for (let i = 0; i < c[0][0]; i++) {
53
+ x = 1;
54
+ }
55
+ let t0;
56
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
57
+ t0 = [x];
58
+ $[0] = t0;
59
+ } else {
60
+ t0 = $[0];
61
+ }
62
+ return t0;
63
+}
64
+
65
+export const FIXTURE_ENTRYPOINT = {
66
+ fn: Component,
67
+ params: [{ cond: true }],
68
+};
69
+
70
+```
71
+
72
+### Eval output
73
+(kind: ok) [1]
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-for-test.js
new
+29
@@ -0,0 +1,29 @@
1
+function Component(props) {
2
+ // a and b are independent but their mutations are interleaved, so
3
+ // they get grouped in a reactive scope. this means that a becomes
4
+ // reactive since it will effectively re-evaluate based on a reactive
5
+ // input
6
+ const a = [];
7
+ const b = [];
8
+ b.push(props.cond);
9
+ a.push(10);
10
+
11
+ // Downstream consumer of a, which initially seems non-reactive except
12
+ // that a becomes reactive, per above
13
+ const c = [a];
14
+
15
+ let x;
16
+ for (let i = 0; i < c[0][0]; i++) {
17
+ x = 1;
18
+ }
19
+ // The values assigned to `x` are non-reactive, but the value of `x`
20
+ // depends on the "control" value `c[0]` which becomes reactive via
21
+ // being interleaved with `b`.
22
+ // Therefore x should be treated as reactive too.
23
+ return [x];
24
+}
25
+
26
+export const FIXTURE_ENTRYPOINT = {
27
+ fn: Component,
28
+ params: [{ cond: true }],
29
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-for-update.expect.md
new
+73
@@ -0,0 +1,73 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ // a and b are independent but their mutations are interleaved, so
7
+ // they get grouped in a reactive scope. this means that a becomes
8
+ // reactive since it will effectively re-evaluate based on a reactive
9
+ // input
10
+ const a = [];
11
+ const b = [];
12
+ b.push(props.cond);
13
+ a.push(10);
14
+
15
+ // Downstream consumer of a, which initially seems non-reactive except
16
+ // that a becomes reactive, per above
17
+ const c = [a];
18
+
19
+ let x;
20
+ for (let i = 0; i < 10; i += c[0][0]) {
21
+ x = 1;
22
+ }
23
+ // The values assigned to `x` are non-reactive, but the value of `x`
24
+ // depends on the "control" value `c[0]` which becomes reactive via
25
+ // being interleaved with `b`.
26
+ // Therefore x should be treated as reactive too.
27
+ return [x];
28
+}
29
+
30
+export const FIXTURE_ENTRYPOINT = {
31
+ fn: Component,
32
+ params: [{ cond: true }],
33
+};
34
+
35
+```
36
+
37
+## Code
38
+
39
+```javascript
40
+import { unstable_useMemoCache as useMemoCache } from "react";
41
+function Component(props) {
42
+ const $ = useMemoCache(1);
43
+
44
+ const a = [];
45
+ const b = [];
46
+ b.push(props.cond);
47
+ a.push(10);
48
+
49
+ const c = [a];
50
+
51
+ let x;
52
+ for (let i = 0; i < 10; i = i + c[0][0], i) {
53
+ x = 1;
54
+ }
55
+ let t0;
56
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
57
+ t0 = [x];
58
+ $[0] = t0;
59
+ } else {
60
+ t0 = $[0];
61
+ }
62
+ return t0;
63
+}
64
+
65
+export const FIXTURE_ENTRYPOINT = {
66
+ fn: Component,
67
+ params: [{ cond: true }],
68
+};
69
+
70
+```
71
+
72
+### Eval output
73
+(kind: ok) [1]
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-for-update.js
new
+29
@@ -0,0 +1,29 @@
1
+function Component(props) {
2
+ // a and b are independent but their mutations are interleaved, so
3
+ // they get grouped in a reactive scope. this means that a becomes
4
+ // reactive since it will effectively re-evaluate based on a reactive
5
+ // input
6
+ const a = [];
7
+ const b = [];
8
+ b.push(props.cond);
9
+ a.push(10);
10
+
11
+ // Downstream consumer of a, which initially seems non-reactive except
12
+ // that a becomes reactive, per above
13
+ const c = [a];
14
+
15
+ let x;
16
+ for (let i = 0; i < 10; i += c[0][0]) {
17
+ x = 1;
18
+ }
19
+ // The values assigned to `x` are non-reactive, but the value of `x`
20
+ // depends on the "control" value `c[0]` which becomes reactive via
21
+ // being interleaved with `b`.
22
+ // Therefore x should be treated as reactive too.
23
+ return [x];
24
+}
25
+
26
+export const FIXTURE_ENTRYPOINT = {
27
+ fn: Component,
28
+ params: [{ cond: true }],
29
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-if.expect.md
+3
-3
@@ -17,7 +17,7 @@ function Component(props) {
17
const c = [a];
18
19
let x;
20
- if (c[0]) {
20
+ if (c[0][0]) {
21
x = 1;
22
} else {
23
x = 2;
@@ -51,7 +51,7 @@ function Component(props) {
51
const c = [a];
52
53
let x;
54
- if (c[0]) {
54
+ if (c[0][0]) {
55
x = 1;
56
} else {
57
x = 2;
@@ -74,4 +74,4 @@ export const FIXTURE_ENTRYPOINT = {
74
```
75
76
### Eval output
77
-(kind: ok) [1]
\ No newline at end of file
77
+(kind: ok) [2]
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-if.js
+1
-1
@@ -13,7 +13,7 @@ function Component(props) {
13
const c = [a];
14
15
let x;
16
- if (c[0]) {
16
+ if (c[0][0]) {
17
x = 1;
18
} else {
19
x = 2;
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-switch.expect.md
new
+85
@@ -0,0 +1,85 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ // a and b are independent but their mutations are interleaved, so
7
+ // they get grouped in a reactive scope. this means that a becomes
8
+ // reactive since it will effectively re-evaluate based on a reactive
9
+ // input
10
+ const a = [];
11
+ const b = [];
12
+ b.push(props.cond);
13
+ a.push(null);
14
+
15
+ // Downstream consumer of a, which initially seems non-reactive except
16
+ // that a becomes reactive, per above
17
+ const c = [a];
18
+
19
+ let x;
20
+ switch (c[0][0]) {
21
+ case true: {
22
+ x = 1;
23
+ break;
24
+ }
25
+ default: {
26
+ x = 2;
27
+ }
28
+ }
29
+ // The values assigned to `x` are non-reactive, but the value of `x`
30
+ // depends on the "control" value `c[0]` which becomes reactive via
31
+ // being interleaved with `b`.
32
+ // Therefore x should be treated as reactive too.
33
+ return [x];
34
+}
35
+
36
+export const FIXTURE_ENTRYPOINT = {
37
+ fn: Component,
38
+ params: [{ cond: true }],
39
+};
40
+
41
+```
42
+
43
+## Code
44
+
45
+```javascript
46
+import { unstable_useMemoCache as useMemoCache } from "react";
47
+function Component(props) {
48
+ const $ = useMemoCache(1);
49
+
50
+ const a = [];
51
+ const b = [];
52
+ b.push(props.cond);
53
+ a.push(null);
54
+
55
+ const c = [a];
56
+
57
+ let x;
58
+ bb1: switch (c[0][0]) {
59
+ case true: {
60
+ x = 1;
61
+ break bb1;
62
+ }
63
+ default: {
64
+ x = 2;
65
+ }
66
+ }
67
+ let t0;
68
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
69
+ t0 = [x];
70
+ $[0] = t0;
71
+ } else {
72
+ t0 = $[0];
73
+ }
74
+ return t0;
75
+}
76
+
77
+export const FIXTURE_ENTRYPOINT = {
78
+ fn: Component,
79
+ params: [{ cond: true }],
80
+};
81
+
82
+```
83
+
84
+### Eval output
85
+(kind: ok) [2]
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-switch.js
new
+35
@@ -0,0 +1,35 @@
1
+function Component(props) {
2
+ // a and b are independent but their mutations are interleaved, so
3
+ // they get grouped in a reactive scope. this means that a becomes
4
+ // reactive since it will effectively re-evaluate based on a reactive
5
+ // input
6
+ const a = [];
7
+ const b = [];
8
+ b.push(props.cond);
9
+ a.push(null);
10
+
11
+ // Downstream consumer of a, which initially seems non-reactive except
12
+ // that a becomes reactive, per above
13
+ const c = [a];
14
+
15
+ let x;
16
+ switch (c[0][0]) {
17
+ case true: {
18
+ x = 1;
19
+ break;
20
+ }
21
+ default: {
22
+ x = 2;
23
+ }
24
+ }
25
+ // The values assigned to `x` are non-reactive, but the value of `x`
26
+ // depends on the "control" value `c[0]` which becomes reactive via
27
+ // being interleaved with `b`.
28
+ // Therefore x should be treated as reactive too.
29
+ return [x];
30
+}
31
+
32
+export const FIXTURE_ENTRYPOINT = {
33
+ fn: Component,
34
+ params: [{ cond: true }],
35
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-while.expect.md
new
+73
@@ -0,0 +1,73 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ // a and b are independent but their mutations are interleaved, so
7
+ // they get grouped in a reactive scope. this means that a becomes
8
+ // reactive since it will effectively re-evaluate based on a reactive
9
+ // input
10
+ const a = [];
11
+ const b = [];
12
+ b.push(props.cond);
13
+ a.push(null);
14
+
15
+ // Downstream consumer of a, which initially seems non-reactive except
16
+ // that a becomes reactive, per above
17
+ const c = [a];
18
+
19
+ let x;
20
+ while (c[0][0]) {
21
+ x = 1;
22
+ }
23
+ // The values assigned to `x` are non-reactive, but the value of `x`
24
+ // depends on the "control" value `c[0]` which becomes reactive via
25
+ // being interleaved with `b`.
26
+ // Therefore x should be treated as reactive too.
27
+ return [x];
28
+}
29
+
30
+export const FIXTURE_ENTRYPOINT = {
31
+ fn: Component,
32
+ params: [{ cond: true }],
33
+};
34
+
35
+```
36
+
37
+## Code
38
+
39
+```javascript
40
+import { unstable_useMemoCache as useMemoCache } from "react";
41
+function Component(props) {
42
+ const $ = useMemoCache(1);
43
+
44
+ const a = [];
45
+ const b = [];
46
+ b.push(props.cond);
47
+ a.push(null);
48
+
49
+ const c = [a];
50
+
51
+ let x;
52
+ while (c[0][0]) {
53
+ x = 1;
54
+ }
55
+ let t0;
56
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
57
+ t0 = [x];
58
+ $[0] = t0;
59
+ } else {
60
+ t0 = $[0];
61
+ }
62
+ return t0;
63
+}
64
+
65
+export const FIXTURE_ENTRYPOINT = {
66
+ fn: Component,
67
+ params: [{ cond: true }],
68
+};
69
+
70
+```
71
+
72
+### Eval output
73
+(kind: ok) [null]
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactive-control-dependency-from-interleaved-reactivity-while.js
new
+29
@@ -0,0 +1,29 @@
1
+function Component(props) {
2
+ // a and b are independent but their mutations are interleaved, so
3
+ // they get grouped in a reactive scope. this means that a becomes
4
+ // reactive since it will effectively re-evaluate based on a reactive
5
+ // input
6
+ const a = [];
7
+ const b = [];
8
+ b.push(props.cond);
9
+ a.push(null);
10
+
11
+ // Downstream consumer of a, which initially seems non-reactive except
12
+ // that a becomes reactive, per above
13
+ const c = [a];
14
+
15
+ let x;
16
+ while (c[0][0]) {
17
+ x = 1;
18
+ }
19
+ // The values assigned to `x` are non-reactive, but the value of `x`
20
+ // depends on the "control" value `c[0]` which becomes reactive via
21
+ // being interleaved with `b`.
22
+ // Therefore x should be treated as reactive too.
23
+ return [x];
24
+}
25
+
26
+export const FIXTURE_ENTRYPOINT = {
27
+ fn: Component,
28
+ params: [{ cond: true }],
29
+};