Repro for scope merging bug
This is a repro for a bug that occurs when `enableMergeConsecutiveScopes` is enabled. Reminder that this feature is off by default and not enabled yet internally. I found this via #2121, where eliminating extraneous whitespace JSXText instructions meant that MergeConsecutiveScopes started merging a fixture differently, revealing a bug. This PR reproduces that case by keeping the identical structure, but using plain objects to represent the JSX elements instead of JSX syntax.
Joe Savona committed
Oct 9, 2023 at 16:15 UTC
49d16ba7e561d8d401a75121637d5f7a1c002d2a
2 files changed
+163
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/merge-consecutive-scopes-objects.expect.md
new
+138
@@ -0,0 +1,138 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @enableMergeConsecutiveScopes
6
+// This is a translation of the original merge-consecutive-scopes which uses plain objects
7
+// to describe the UI instead of JSX. The JSXText elements in that fixture happen to
8
+// prevent scome scopes from merging, which concealed a bug with the merging logic.
9
+// By avoiding JSX we eliminate extraneous instructions and more accurately test the merging.
10
+function Component(props) {
11
+ let [state, setState] = useState(0);
12
+ return [
13
+ { component: Title, props: { text: "Counter" } },
14
+ { component: "span", props: { children: [state] } },
15
+ {
16
+ component: "button",
17
+ props: {
18
+ "data-testid": "button",
19
+ onClick: () => setState(state + 1),
20
+ children: ["increment"],
21
+ },
22
+ },
23
+ ];
24
+}
25
+
26
+export const FIXTURE_ENTRYPOINT = {
27
+ fn: Component,
28
+ params: [{}],
29
+};
30
+
31
+```
32
+
33
+## Code
34
+
35
+```javascript
36
+import { unstable_useMemoCache as useMemoCache } from "react"; // @enableMergeConsecutiveScopes
37
+// This is a translation of the original merge-consecutive-scopes which uses plain objects
38
+// to describe the UI instead of JSX. The JSXText elements in that fixture happen to
39
+// prevent scome scopes from merging, which concealed a bug with the merging logic.
40
+// By avoiding JSX we eliminate extraneous instructions and more accurately test the merging.
41
+function Component(props) {
42
+ const $ = useMemoCache(18);
43
+ const [state, setState] = useState(0);
44
+ let t0;
45
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
46
+ t0 = { component: Title, props: { text: "Counter" } };
47
+ $[0] = t0;
48
+ } else {
49
+ t0 = $[0];
50
+ }
51
+ const c_1 = $[1] !== state;
52
+ let t1;
53
+ if (c_1) {
54
+ const t2 = [state];
55
+ t1 = { children: t2 };
56
+ $[1] = state;
57
+ $[2] = t1;
58
+ } else {
59
+ t1 = $[2];
60
+ }
61
+ const c_3 = $[3] !== t2;
62
+ if (c_3) {
63
+ t1 = { children: t2 };
64
+ $[3] = t2;
65
+ $[4] = t1;
66
+ } else {
67
+ t1 = $[4];
68
+ }
69
+ const c_5 = $[5] !== t1;
70
+ let t3;
71
+ if (c_5) {
72
+ t3 = { component: "span", props: t1 };
73
+ $[5] = t1;
74
+ $[6] = t3;
75
+ } else {
76
+ t3 = $[6];
77
+ }
78
+ const c_7 = $[7] !== state;
79
+ let t4;
80
+ if (c_7) {
81
+ t4 = () => setState(state + 1);
82
+ $[7] = state;
83
+ $[8] = t4;
84
+ } else {
85
+ t4 = $[8];
86
+ }
87
+ let t5;
88
+ if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
89
+ t5 = ["increment"];
90
+ $[9] = t5;
91
+ } else {
92
+ t5 = $[9];
93
+ }
94
+ if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
95
+ t5 = ["increment"];
96
+ $[10] = t5;
97
+ } else {
98
+ t5 = $[10];
99
+ }
100
+ const c_11 = $[11] !== t4;
101
+ let t6;
102
+ if (c_11) {
103
+ const t7 = { "data-testid": "button", onClick: t4, children: t5 };
104
+ t6 = { component: "button", props: t7 };
105
+ $[11] = t4;
106
+ $[12] = t6;
107
+ } else {
108
+ t6 = $[12];
109
+ }
110
+ const c_13 = $[13] !== t7;
111
+ if (c_13) {
112
+ t6 = { component: "button", props: t7 };
113
+ $[13] = t7;
114
+ $[14] = t6;
115
+ } else {
116
+ t6 = $[14];
117
+ }
118
+ const c_15 = $[15] !== t3;
119
+ const c_16 = $[16] !== t6;
120
+ let t8;
121
+ if (c_15 || c_16) {
122
+ t8 = [t0, t3, t6];
123
+ $[15] = t3;
124
+ $[16] = t6;
125
+ $[17] = t8;
126
+ } else {
127
+ t8 = $[17];
128
+ }
129
+ return t8;
130
+}
131
+
132
+export const FIXTURE_ENTRYPOINT = {
133
+ fn: Component,
134
+ params: [{}],
135
+};
136
+
137
+```
138
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/merge-consecutive-scopes-objects.js
new
+25
@@ -0,0 +1,25 @@
1
+// @enableMergeConsecutiveScopes
2
+// This is a translation of the original merge-consecutive-scopes which uses plain objects
3
+// to describe the UI instead of JSX. The JSXText elements in that fixture happen to
4
+// prevent scome scopes from merging, which concealed a bug with the merging logic.
5
+// By avoiding JSX we eliminate extraneous instructions and more accurately test the merging.
6
+function Component(props) {
7
+ let [state, setState] = useState(0);
8
+ return [
9
+ { component: Title, props: { text: "Counter" } },
10
+ { component: "span", props: { children: [state] } },
11
+ {
12
+ component: "button",
13
+ props: {
14
+ "data-testid": "button",
15
+ onClick: () => setState(state + 1),
16
+ children: ["increment"],
17
+ },
18
+ },
19
+ ];
20
+}
21
+
22
+export const FIXTURE_ENTRYPOINT = {
23
+ fn: Component,
24
+ params: [{}],
25
+};