@samitouri / QOS-React-2 / commits / a023a2da72

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 +};