@samitouri / QOS-React / commits / a023a2da72
Fork 0

The library for web and native user interfaces.

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