Test cases for reactive (control) dependencies
Adds test cases for all the cases of control dependencies that I can think of. We don't currently handle control dependencies correctly in any of these cases. There's also another test case which demonstrates why reactive dependency inference needs to be fixpoint, even for non-control dependencies.
Joe Savona committed
Oct 17, 2023 at 09:48 UTC
84da8994bd55f4a908fe0ca8446d1bb4d09adee2
25 files changed
+1011
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-do-while-test.expect.md
new
+64
@@ -0,0 +1,64 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ let x;
7
+ let i = 0;
8
+ do {
9
+ if (i > 10) {
10
+ x = 10;
11
+ } else {
12
+ x = 1;
13
+ }
14
+ i++;
15
+ } while (i < props.test);
16
+ // The values assigned to `x` are non-reactive, but the value of `x`
17
+ // depends on the "control" variable `i`, whose value is affected by
18
+ // `props.test` which is reactive.
19
+ // Therefore x should be treated as reactive too.
20
+ return [x];
21
+}
22
+
23
+export const FIXTURE_ENTRYPOINT = {
24
+ fn: Component,
25
+ params: [{ test: 12 }],
26
+};
27
+
28
+```
29
+
30
+## Code
31
+
32
+```javascript
33
+import { unstable_useMemoCache as useMemoCache } from "react";
34
+function Component(props) {
35
+ const $ = useMemoCache(1);
36
+
37
+ let i = 0;
38
+ do {
39
+ let x = undefined;
40
+ if (i > 10) {
41
+ x = 10;
42
+ } else {
43
+ x = 1;
44
+ }
45
+
46
+ i++;
47
+ } while (i < props.test);
48
+ let t0;
49
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
50
+ t0 = [x];
51
+ $[0] = t0;
52
+ } else {
53
+ t0 = $[0];
54
+ }
55
+ return t0;
56
+}
57
+
58
+export const FIXTURE_ENTRYPOINT = {
59
+ fn: Component,
60
+ params: [{ test: 12 }],
61
+};
62
+
63
+```
64
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-do-while-test.js
new
+22
@@ -0,0 +1,22 @@
1
+function Component(props) {
2
+ let x;
3
+ let i = 0;
4
+ do {
5
+ if (i > 10) {
6
+ x = 10;
7
+ } else {
8
+ x = 1;
9
+ }
10
+ i++;
11
+ } while (i < props.test);
12
+ // The values assigned to `x` are non-reactive, but the value of `x`
13
+ // depends on the "control" variable `i`, whose value is affected by
14
+ // `props.test` which is reactive.
15
+ // Therefore x should be treated as reactive too.
16
+ return [x];
17
+}
18
+
19
+export const FIXTURE_ENTRYPOINT = {
20
+ fn: Component,
21
+ params: [{ test: 12 }],
22
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-for-init.expect.md
new
+61
@@ -0,0 +1,61 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ let x;
7
+ for (let i = props.init; i < 10; i++) {
8
+ if (i === 0) {
9
+ x = 0;
10
+ break;
11
+ } else {
12
+ x = 1;
13
+ break;
14
+ }
15
+ }
16
+ // The values assigned to `x` are non-reactive, but the value of `x`
17
+ // depends on the "control" variable `i`, whose initial value `props.init` is reactive.
18
+ // Therefore x should be treated as reactive too.
19
+ return [x];
20
+}
21
+
22
+export const FIXTURE_ENTRYPOINT = {
23
+ fn: Component,
24
+ params: [{ init: 0 }],
25
+};
26
+
27
+```
28
+
29
+## Code
30
+
31
+```javascript
32
+import { unstable_useMemoCache as useMemoCache } from "react";
33
+function Component(props) {
34
+ const $ = useMemoCache(1);
35
+ let x;
36
+ for (const i = props.init; i < 10; ) {
37
+ if (i === 0) {
38
+ x = 0;
39
+ break;
40
+ } else {
41
+ x = 1;
42
+ break;
43
+ }
44
+ }
45
+ let t0;
46
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
47
+ t0 = [x];
48
+ $[0] = t0;
49
+ } else {
50
+ t0 = $[0];
51
+ }
52
+ return t0;
53
+}
54
+
55
+export const FIXTURE_ENTRYPOINT = {
56
+ fn: Component,
57
+ params: [{ init: 0 }],
58
+};
59
+
60
+```
61
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-for-init.js
new
+21
@@ -0,0 +1,21 @@
1
+function Component(props) {
2
+ let x;
3
+ for (let i = props.init; i < 10; i++) {
4
+ if (i === 0) {
5
+ x = 0;
6
+ break;
7
+ } else {
8
+ x = 1;
9
+ break;
10
+ }
11
+ }
12
+ // The values assigned to `x` are non-reactive, but the value of `x`
13
+ // depends on the "control" variable `i`, whose initial value `props.init` is reactive.
14
+ // Therefore x should be treated as reactive too.
15
+ return [x];
16
+}
17
+
18
+export const FIXTURE_ENTRYPOINT = {
19
+ fn: Component,
20
+ params: [{ init: 0 }],
21
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-for-test.expect.md
new
+58
@@ -0,0 +1,58 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ let x;
7
+ for (let i = 0; i < props.test; i++) {
8
+ if (i > 10) {
9
+ x = 10;
10
+ } else {
11
+ x = 1;
12
+ }
13
+ }
14
+ // The values assigned to `x` are non-reactive, but the value of `x`
15
+ // depends on the "control" variable `i`, whose value is capped by
16
+ // `props.test` which is reactive.
17
+ // Therefore x should be treated as reactive too.
18
+ return [x];
19
+}
20
+
21
+export const FIXTURE_ENTRYPOINT = {
22
+ fn: Component,
23
+ params: [{ test: 12 }],
24
+};
25
+
26
+```
27
+
28
+## Code
29
+
30
+```javascript
31
+import { unstable_useMemoCache as useMemoCache } from "react";
32
+function Component(props) {
33
+ const $ = useMemoCache(1);
34
+ let x;
35
+ for (let i = 0; i < props.test; i++) {
36
+ if (i > 10) {
37
+ x = 10;
38
+ } else {
39
+ x = 1;
40
+ }
41
+ }
42
+ let t0;
43
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
44
+ t0 = [x];
45
+ $[0] = t0;
46
+ } else {
47
+ t0 = $[0];
48
+ }
49
+ return t0;
50
+}
51
+
52
+export const FIXTURE_ENTRYPOINT = {
53
+ fn: Component,
54
+ params: [{ test: 12 }],
55
+};
56
+
57
+```
58
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-for-test.js
new
+20
@@ -0,0 +1,20 @@
1
+function Component(props) {
2
+ let x;
3
+ for (let i = 0; i < props.test; i++) {
4
+ if (i > 10) {
5
+ x = 10;
6
+ } else {
7
+ x = 1;
8
+ }
9
+ }
10
+ // The values assigned to `x` are non-reactive, but the value of `x`
11
+ // depends on the "control" variable `i`, whose value is capped by
12
+ // `props.test` which is reactive.
13
+ // Therefore x should be treated as reactive too.
14
+ return [x];
15
+}
16
+
17
+export const FIXTURE_ENTRYPOINT = {
18
+ fn: Component,
19
+ params: [{ test: 12 }],
20
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-for-update.expect.md
new
+58
@@ -0,0 +1,58 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ let x;
7
+ for (let i = 0; i < 10; i += props.update) {
8
+ if (i > 0 && i % 2 === 0) {
9
+ x = 2;
10
+ } else {
11
+ x = 1;
12
+ }
13
+ }
14
+ // The values assigned to `x` are non-reactive, but the value of `x`
15
+ // depends on the "control" variable `i`, whose possible values are
16
+ // affected by `props.update` which is reactive.
17
+ // Therefore x should be treated as reactive too.
18
+ return [x];
19
+}
20
+
21
+export const FIXTURE_ENTRYPOINT = {
22
+ fn: Component,
23
+ params: [{ update: 2 }],
24
+};
25
+
26
+```
27
+
28
+## Code
29
+
30
+```javascript
31
+import { unstable_useMemoCache as useMemoCache } from "react";
32
+function Component(props) {
33
+ const $ = useMemoCache(1);
34
+ let x;
35
+ for (let i = 0; i < 10; i = i + props.update, i) {
36
+ if (i > 0 && i % 2 === 0) {
37
+ x = 2;
38
+ } else {
39
+ x = 1;
40
+ }
41
+ }
42
+ let t0;
43
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
44
+ t0 = [x];
45
+ $[0] = t0;
46
+ } else {
47
+ t0 = $[0];
48
+ }
49
+ return t0;
50
+}
51
+
52
+export const FIXTURE_ENTRYPOINT = {
53
+ fn: Component,
54
+ params: [{ update: 2 }],
55
+};
56
+
57
+```
58
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-for-update.js
new
+20
@@ -0,0 +1,20 @@
1
+function Component(props) {
2
+ let x;
3
+ for (let i = 0; i < 10; i += props.update) {
4
+ if (i > 0 && i % 2 === 0) {
5
+ x = 2;
6
+ } else {
7
+ x = 1;
8
+ }
9
+ }
10
+ // The values assigned to `x` are non-reactive, but the value of `x`
11
+ // depends on the "control" variable `i`, whose possible values are
12
+ // affected by `props.update` which is reactive.
13
+ // Therefore x should be treated as reactive too.
14
+ return [x];
15
+}
16
+
17
+export const FIXTURE_ENTRYPOINT = {
18
+ fn: Component,
19
+ params: [{ update: 2 }],
20
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-forin-collection.expect.md
new
+60
@@ -0,0 +1,60 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ let x;
7
+ for (const key in props.values) {
8
+ const i = parseInt(key, 10);
9
+ if (i > 10) {
10
+ x = 10;
11
+ } else {
12
+ x = 1;
13
+ }
14
+ }
15
+ // The values assigned to `x` are non-reactive, but the value of `x`
16
+ // depends on the "control" variable `i`, whose value is derived from
17
+ // `props.values` which is reactive.
18
+ // Therefore x should be treated as reactive too.
19
+ return [x];
20
+}
21
+
22
+export const FIXTURE_ENTRYPOINT = {
23
+ fn: Component,
24
+ params: [{ values: { "12": true } }],
25
+};
26
+
27
+```
28
+
29
+## Code
30
+
31
+```javascript
32
+import { unstable_useMemoCache as useMemoCache } from "react";
33
+function Component(props) {
34
+ const $ = useMemoCache(1);
35
+ let x;
36
+ for (const key in props.values) {
37
+ const i = parseInt(key, 10);
38
+ if (i > 10) {
39
+ x = 10;
40
+ } else {
41
+ x = 1;
42
+ }
43
+ }
44
+ let t0;
45
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
46
+ t0 = [x];
47
+ $[0] = t0;
48
+ } else {
49
+ t0 = $[0];
50
+ }
51
+ return t0;
52
+}
53
+
54
+export const FIXTURE_ENTRYPOINT = {
55
+ fn: Component,
56
+ params: [{ values: { "12": true } }],
57
+};
58
+
59
+```
60
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-forin-collection.js
new
+21
@@ -0,0 +1,21 @@
1
+function Component(props) {
2
+ let x;
3
+ for (const key in props.values) {
4
+ const i = parseInt(key, 10);
5
+ if (i > 10) {
6
+ x = 10;
7
+ } else {
8
+ x = 1;
9
+ }
10
+ }
11
+ // The values assigned to `x` are non-reactive, but the value of `x`
12
+ // depends on the "control" variable `i`, whose value is derived from
13
+ // `props.values` which is reactive.
14
+ // Therefore x should be treated as reactive too.
15
+ return [x];
16
+}
17
+
18
+export const FIXTURE_ENTRYPOINT = {
19
+ fn: Component,
20
+ params: [{ values: { "12": true } }],
21
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-forof-collection.expect.md
new
+58
@@ -0,0 +1,58 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ let x;
7
+ for (const i of props.values) {
8
+ if (i > 10) {
9
+ x = 10;
10
+ } else {
11
+ x = 1;
12
+ }
13
+ }
14
+ // The values assigned to `x` are non-reactive, but the value of `x`
15
+ // depends on the "control" variable `i`, whose value is derived from
16
+ // `props.values` which is reactive.
17
+ // Therefore x should be treated as reactive too.
18
+ return [x];
19
+}
20
+
21
+export const FIXTURE_ENTRYPOINT = {
22
+ fn: Component,
23
+ params: [{ values: [12] }],
24
+};
25
+
26
+```
27
+
28
+## Code
29
+
30
+```javascript
31
+import { unstable_useMemoCache as useMemoCache } from "react";
32
+function Component(props) {
33
+ const $ = useMemoCache(1);
34
+ let x;
35
+ for (const i of props.values) {
36
+ if (i > 10) {
37
+ x = 10;
38
+ } else {
39
+ x = 1;
40
+ }
41
+ }
42
+ let t0;
43
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
44
+ t0 = [x];
45
+ $[0] = t0;
46
+ } else {
47
+ t0 = $[0];
48
+ }
49
+ return t0;
50
+}
51
+
52
+export const FIXTURE_ENTRYPOINT = {
53
+ fn: Component,
54
+ params: [{ values: [12] }],
55
+};
56
+
57
+```
58
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-forof-collection.js
new
+20
@@ -0,0 +1,20 @@
1
+function Component(props) {
2
+ let x;
3
+ for (const i of props.values) {
4
+ if (i > 10) {
5
+ x = 10;
6
+ } else {
7
+ x = 1;
8
+ }
9
+ }
10
+ // The values assigned to `x` are non-reactive, but the value of `x`
11
+ // depends on the "control" variable `i`, whose value is derived from
12
+ // `props.values` which is reactive.
13
+ // Therefore x should be treated as reactive too.
14
+ return [x];
15
+}
16
+
17
+export const FIXTURE_ENTRYPOINT = {
18
+ fn: Component,
19
+ params: [{ values: [12] }],
20
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-if.expect.md
new
+53
@@ -0,0 +1,53 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ let x;
7
+ if (props.cond) {
8
+ x = 1;
9
+ } else {
10
+ x = 2;
11
+ }
12
+ // The values assigned to `x` are non-reactive, but the value of `x`
13
+ // depends on the "control" value `props.cond` which is reactive.
14
+ // Therefore x should be treated as reactive too.
15
+ return [x];
16
+}
17
+
18
+export const FIXTURE_ENTRYPOINT = {
19
+ fn: Component,
20
+ params: [{ cond: true }],
21
+};
22
+
23
+```
24
+
25
+## Code
26
+
27
+```javascript
28
+import { unstable_useMemoCache as useMemoCache } from "react";
29
+function Component(props) {
30
+ const $ = useMemoCache(1);
31
+ let x = undefined;
32
+ if (props.cond) {
33
+ x = 1;
34
+ } else {
35
+ x = 2;
36
+ }
37
+ let t0;
38
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
39
+ t0 = [x];
40
+ $[0] = t0;
41
+ } else {
42
+ t0 = $[0];
43
+ }
44
+ return t0;
45
+}
46
+
47
+export const FIXTURE_ENTRYPOINT = {
48
+ fn: Component,
49
+ params: [{ cond: true }],
50
+};
51
+
52
+```
53
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-if.js
new
+17
@@ -0,0 +1,17 @@
1
+function Component(props) {
2
+ let x;
3
+ if (props.cond) {
4
+ x = 1;
5
+ } else {
6
+ x = 2;
7
+ }
8
+ // The values assigned to `x` are non-reactive, but the value of `x`
9
+ // depends on the "control" value `props.cond` which is reactive.
10
+ // Therefore x should be treated as reactive too.
11
+ return [x];
12
+}
13
+
14
+export const FIXTURE_ENTRYPOINT = {
15
+ fn: Component,
16
+ params: [{ cond: true }],
17
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-reactive-after-fixpoint.expect.md
new
+78
@@ -0,0 +1,78 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ let x = 0;
7
+
8
+ let value = null;
9
+ loop: for (let i = 0; i < 10; i++) {
10
+ switch (value) {
11
+ case true: {
12
+ x = 1;
13
+ break loop;
14
+ }
15
+ case false: {
16
+ x = 2;
17
+ break loop;
18
+ }
19
+ }
20
+
21
+ value = props.value;
22
+ }
23
+
24
+ // The values assigned to `x` are non-reactive, but the value of `x`
25
+ // depends on the "control" variable `value` used as the switch test
26
+ // condition. That variable is initially null on the first iteration
27
+ // of the loop, but is later set to `props.value` which is reactive.
28
+ // Therefore x should be treated as reactive.
29
+ return [x];
30
+}
31
+
32
+export const FIXTURE_ENTRYPOINT = {
33
+ fn: Component,
34
+ params: [{ cond: true }],
35
+};
36
+
37
+```
38
+
39
+## Code
40
+
41
+```javascript
42
+import { unstable_useMemoCache as useMemoCache } from "react";
43
+function Component(props) {
44
+ const $ = useMemoCache(1);
45
+ let x = 0;
46
+
47
+ let value = null;
48
+ for (let i = 0; i < 10; i++) {
49
+ switch (value) {
50
+ case true: {
51
+ x = 1;
52
+ break;
53
+ }
54
+ case false: {
55
+ x = 2;
56
+ break;
57
+ }
58
+ }
59
+
60
+ value = props.value;
61
+ }
62
+ let t0;
63
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
64
+ t0 = [x];
65
+ $[0] = t0;
66
+ } else {
67
+ t0 = $[0];
68
+ }
69
+ return t0;
70
+}
71
+
72
+export const FIXTURE_ENTRYPOINT = {
73
+ fn: Component,
74
+ params: [{ cond: true }],
75
+};
76
+
77
+```
78
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-reactive-after-fixpoint.js
new
+31
@@ -0,0 +1,31 @@
1
+function Component(props) {
2
+ let x = 0;
3
+
4
+ let value = null;
5
+ loop: for (let i = 0; i < 10; i++) {
6
+ switch (value) {
7
+ case true: {
8
+ x = 1;
9
+ break loop;
10
+ }
11
+ case false: {
12
+ x = 2;
13
+ break loop;
14
+ }
15
+ }
16
+
17
+ value = props.value;
18
+ }
19
+
20
+ // The values assigned to `x` are non-reactive, but the value of `x`
21
+ // depends on the "control" variable `value` used as the switch test
22
+ // condition. That variable is initially null on the first iteration
23
+ // of the loop, but is later set to `props.value` which is reactive.
24
+ // Therefore x should be treated as reactive.
25
+ return [x];
26
+}
27
+
28
+export const FIXTURE_ENTRYPOINT = {
29
+ fn: Component,
30
+ params: [{ cond: true }],
31
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-switch-case-test.expect.md
new
+69
@@ -0,0 +1,69 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ let x;
7
+ switch (props.cond) {
8
+ case true: {
9
+ x = 1;
10
+ break;
11
+ }
12
+ case false: {
13
+ x = 2;
14
+ break;
15
+ }
16
+ default: {
17
+ x = 3;
18
+ }
19
+ }
20
+ // The values assigned to `x` are non-reactive, but the value of `x`
21
+ // depends on the "control" value `props.cond` which is reactive.
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
+};
30
+
31
+```
32
+
33
+## Code
34
+
35
+```javascript
36
+import { unstable_useMemoCache as useMemoCache } from "react";
37
+function Component(props) {
38
+ const $ = useMemoCache(1);
39
+ let x = undefined;
40
+ bb1: switch (props.cond) {
41
+ case true: {
42
+ x = 1;
43
+ break bb1;
44
+ }
45
+ case false: {
46
+ x = 2;
47
+ break bb1;
48
+ }
49
+ default: {
50
+ x = 3;
51
+ }
52
+ }
53
+ let t0;
54
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
55
+ t0 = [x];
56
+ $[0] = t0;
57
+ } else {
58
+ t0 = $[0];
59
+ }
60
+ return t0;
61
+}
62
+
63
+export const FIXTURE_ENTRYPOINT = {
64
+ fn: Component,
65
+ params: [{ cond: true }],
66
+};
67
+
68
+```
69
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-switch-case-test.js
new
+25
@@ -0,0 +1,25 @@
1
+function Component(props) {
2
+ let x;
3
+ switch (props.cond) {
4
+ case true: {
5
+ x = 1;
6
+ break;
7
+ }
8
+ case false: {
9
+ x = 2;
10
+ break;
11
+ }
12
+ default: {
13
+ x = 3;
14
+ }
15
+ }
16
+ // The values assigned to `x` are non-reactive, but the value of `x`
17
+ // depends on the "control" value `props.cond` which is reactive.
18
+ // Therefore x should be treated as reactive too.
19
+ return [x];
20
+}
21
+
22
+export const FIXTURE_ENTRYPOINT = {
23
+ fn: Component,
24
+ params: [{ cond: true }],
25
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-switch-condition.expect.md
new
+68
@@ -0,0 +1,68 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+const GLOBAL = 42;
6
+
7
+function Component({ value }) {
8
+ let x;
9
+ switch (GLOBAL) {
10
+ case value: {
11
+ x = 1;
12
+ break;
13
+ }
14
+ default: {
15
+ x = 2;
16
+ }
17
+ }
18
+ // The values assigned to `x` are non-reactive, but the value of `x`
19
+ // depends on the "control" value `props.value` which is reactive.
20
+ // Therefore x should be treated as reactive too.
21
+ return [x];
22
+}
23
+
24
+export const FIXTURE_ENTRYPOINT = {
25
+ fn: Component,
26
+ params: [{ value: GLOBAL }],
27
+ // TODO: test executing the sequence {value: GLOBAL}, {value: null}, {value: GLOBAL}
28
+};
29
+
30
+```
31
+
32
+## Code
33
+
34
+```javascript
35
+import { unstable_useMemoCache as useMemoCache } from "react";
36
+const GLOBAL = 42;
37
+
38
+function Component(t14) {
39
+ const $ = useMemoCache(1);
40
+ const { value } = t14;
41
+ let x = undefined;
42
+ bb1: switch (GLOBAL) {
43
+ case value: {
44
+ x = 1;
45
+ break bb1;
46
+ }
47
+ default: {
48
+ x = 2;
49
+ }
50
+ }
51
+ let t0;
52
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
53
+ t0 = [x];
54
+ $[0] = t0;
55
+ } else {
56
+ t0 = $[0];
57
+ }
58
+ return t0;
59
+}
60
+
61
+export const FIXTURE_ENTRYPOINT = {
62
+ fn: Component,
63
+ params: [{ value: GLOBAL }],
64
+ // TODO: test executing the sequence {value: GLOBAL}, {value: null}, {value: GLOBAL}
65
+};
66
+
67
+```
68
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-switch-condition.js
new
+24
@@ -0,0 +1,24 @@
1
+const GLOBAL = 42;
2
+
3
+function Component({ value }) {
4
+ let x;
5
+ switch (GLOBAL) {
6
+ case value: {
7
+ x = 1;
8
+ break;
9
+ }
10
+ default: {
11
+ x = 2;
12
+ }
13
+ }
14
+ // The values assigned to `x` are non-reactive, but the value of `x`
15
+ // depends on the "control" value `props.value` which is reactive.
16
+ // Therefore x should be treated as reactive too.
17
+ return [x];
18
+}
19
+
20
+export const FIXTURE_ENTRYPOINT = {
21
+ fn: Component,
22
+ params: [{ value: GLOBAL }],
23
+ // TODO: test executing the sequence {value: GLOBAL}, {value: null}, {value: GLOBAL}
24
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-while-test.expect.md
new
+63
@@ -0,0 +1,63 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ let x;
7
+ let i = 0;
8
+ while (i < props.test) {
9
+ if (i > 10) {
10
+ x = 10;
11
+ } else {
12
+ x = 1;
13
+ }
14
+ i++;
15
+ }
16
+ // The values assigned to `x` are non-reactive, but the value of `x`
17
+ // depends on the "control" variable `i`, whose value is affected by
18
+ // `props.test` which is reactive.
19
+ // Therefore x should be treated as reactive too.
20
+ return [x];
21
+}
22
+
23
+export const FIXTURE_ENTRYPOINT = {
24
+ fn: Component,
25
+ params: [{ test: 12 }],
26
+};
27
+
28
+```
29
+
30
+## Code
31
+
32
+```javascript
33
+import { unstable_useMemoCache as useMemoCache } from "react";
34
+function Component(props) {
35
+ const $ = useMemoCache(1);
36
+ let x;
37
+ let i = 0;
38
+ while (i < props.test) {
39
+ if (i > 10) {
40
+ x = 10;
41
+ } else {
42
+ x = 1;
43
+ }
44
+
45
+ i++;
46
+ }
47
+ let t0;
48
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
49
+ t0 = [x];
50
+ $[0] = t0;
51
+ } else {
52
+ t0 = $[0];
53
+ }
54
+ return t0;
55
+}
56
+
57
+export const FIXTURE_ENTRYPOINT = {
58
+ fn: Component,
59
+ params: [{ test: 12 }],
60
+};
61
+
62
+```
63
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-control-dependency-while-test.js
new
+22
@@ -0,0 +1,22 @@
1
+function Component(props) {
2
+ let x;
3
+ let i = 0;
4
+ while (i < props.test) {
5
+ if (i > 10) {
6
+ x = 10;
7
+ } else {
8
+ x = 1;
9
+ }
10
+ i++;
11
+ }
12
+ // The values assigned to `x` are non-reactive, but the value of `x`
13
+ // depends on the "control" variable `i`, whose value is affected by
14
+ // `props.test` which is reactive.
15
+ // Therefore x should be treated as reactive too.
16
+ return [x];
17
+}
18
+
19
+export const FIXTURE_ENTRYPOINT = {
20
+ fn: Component,
21
+ params: [{ test: 12 }],
22
+};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-dependency-fixpoint.expect.md
new
+56
@@ -0,0 +1,56 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ let x = 0;
7
+ let y = 0;
8
+
9
+ while (x === 0) {
10
+ x = y;
11
+ y = props.value;
12
+ }
13
+
14
+ // x and y initially start out with non-reactive values,
15
+ // but after an iteration of the loop y becomes reactive,
16
+ // and this reactive value then flows into x on the next
17
+ // loop iteration, making x reactive.
18
+ return [x];
19
+}
20
+
21
+export const FIXTURE_ENTRYPOINT = {
22
+ fn: Component,
23
+ params: [{ value: 42 }],
24
+};
25
+
26
+```
27
+
28
+## Code
29
+
30
+```javascript
31
+import { unstable_useMemoCache as useMemoCache } from "react";
32
+function Component(props) {
33
+ const $ = useMemoCache(1);
34
+ let x = 0;
35
+ let y = 0;
36
+ while (x === 0) {
37
+ x = y;
38
+ y = props.value;
39
+ }
40
+ let t0;
41
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
42
+ t0 = [x];
43
+ $[0] = t0;
44
+ } else {
45
+ t0 = $[0];
46
+ }
47
+ return t0;
48
+}
49
+
50
+export const FIXTURE_ENTRYPOINT = {
51
+ fn: Component,
52
+ params: [{ value: 42 }],
53
+};
54
+
55
+```
56
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/bug.reactive-dependency-fixpoint.js
new
+20
@@ -0,0 +1,20 @@
1
+function Component(props) {
2
+ let x = 0;
3
+ let y = 0;
4
+
5
+ while (x === 0) {
6
+ x = y;
7
+ y = props.value;
8
+ }
9
+
10
+ // x and y initially start out with non-reactive values,
11
+ // but after an iteration of the loop y becomes reactive,
12
+ // and this reactive value then flows into x on the next
13
+ // loop iteration, making x reactive.
14
+ return [x];
15
+}
16
+
17
+export const FIXTURE_ENTRYPOINT = {
18
+ fn: Component,
19
+ params: [{ value: 42 }],
20
+};
compiler/packages/sprout/src/SproutTodoFilter.ts
+2
@@ -416,6 +416,8 @@ const skipFilter = new Set([
416
"readonly-object-method-calls",
417
"readonly-object-method-calls-mutable-lambda",
418
419
+ "bug.reactive-control-dependency-do-while-test",
420
+
421
// TODO: 🌲
422
"forest-basic",
423