Repro for jsx lowering issues
* JSX tag value temporaries getting promoted due to being sandwiched inside the mutation of some other item * Incorrect order-of-evaluation for jsx tag relative to props/children
Joe Savona committed
Apr 20, 2023 at 09:29 UTC
275c7557156778168c455d6086846cbde9cb7adf
4 files changed
+122
compiler/forget/src/__tests__/fixtures/compiler/_bug.global-jsx-tag-lowered-between-mutations.expect.md
new
+53
@@ -0,0 +1,53 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ const maybeMutable = new MaybeMutable();
7
+ // NOTE: this will produce invalid output.
8
+ // The HIR is roughly:
9
+ // ⌵ mutable range of `maybeMutable`
10
+ // StoreLocal maybeMutable = ... ⌝
11
+ // t0 = LoadGlobal View ⎮ <-- View is lowered inside this mutable range
12
+ // and thus gets becomes an output of this scope,
13
+ // gets promoted to temporary
14
+ // t1 = LoadGlobal maybeMutate ⎮
15
+ // t2 = LoadLocal maybeMutable ⎮
16
+ // t3 = Call t1(t2) ⌟
17
+ // t4 = Jsx tag=t0 props=[] children=[t3] <-- `t0` is an invalid tag
18
+ return <View>{maybeMutate(maybeMutable)}</View>;
19
+}
20
+
21
+```
22
+
23
+## Code
24
+
25
+```javascript
26
+import * as React from "react";
27
+function Component(props) {
28
+ const $ = React.unstable_useMemoCache(3);
29
+ let t0;
30
+ let t1;
31
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
32
+ const maybeMutable = new MaybeMutable();
33
+
34
+ t0 = View;
35
+ t1 = maybeMutate(maybeMutable);
36
+ $[0] = t0;
37
+ $[1] = t1;
38
+ } else {
39
+ t0 = $[0];
40
+ t1 = $[1];
41
+ }
42
+ let t2;
43
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
44
+ t2 = <t0>{t1}</t0>;
45
+ $[2] = t2;
46
+ } else {
47
+ t2 = $[2];
48
+ }
49
+ return t2;
50
+}
51
+
52
+```
53
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/_bug.global-jsx-tag-lowered-between-mutations.js
new
+15
@@ -0,0 +1,15 @@
1
+function Component(props) {
2
+ const maybeMutable = new MaybeMutable();
3
+ // NOTE: this will produce invalid output.
4
+ // The HIR is roughly:
5
+ // ⌵ mutable range of `maybeMutable`
6
+ // StoreLocal maybeMutable = ... ⌝
7
+ // t0 = LoadGlobal View ⎮ <-- View is lowered inside this mutable range
8
+ // and thus gets becomes an output of this scope,
9
+ // gets promoted to temporary
10
+ // t1 = LoadGlobal maybeMutate ⎮
11
+ // t2 = LoadLocal maybeMutable ⎮
12
+ // t3 = Call t1(t2) ⌟
13
+ // t4 = Jsx tag=t0 props=[] children=[t3] <-- `t0` is an invalid tag
14
+ return <View>{maybeMutate(maybeMutable)}</View>;
15
+}
compiler/forget/src/__tests__/fixtures/compiler/_bug.jsx-tag-evaluation-order.expect.md
new
+46
@@ -0,0 +1,46 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ const maybeMutable = new MaybeMutable();
7
+ let Tag = View;
8
+ // NOTE: the order of evaluation in the lowering is incorrect:
9
+ // the jsx element's tag observes `Tag` after reassignment, but should observe
10
+ // it before the reassignment.
11
+ return <Tag>{((Tag = HScroll), maybeMutae(maybeMutable))}</Tag>;
12
+}
13
+
14
+```
15
+
16
+## Code
17
+
18
+```javascript
19
+import * as React from "react";
20
+function Component(props) {
21
+ const $ = React.unstable_useMemoCache(3);
22
+ let Tag;
23
+ let t0;
24
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
25
+ const maybeMutable = new MaybeMutable();
26
+
27
+ Tag = HScroll;
28
+ t0 = maybeMutae(maybeMutable);
29
+ $[0] = Tag;
30
+ $[1] = t0;
31
+ } else {
32
+ Tag = $[0];
33
+ t0 = $[1];
34
+ }
35
+ let t1;
36
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
37
+ t1 = <Tag>{t0}</Tag>;
38
+ $[2] = t1;
39
+ } else {
40
+ t1 = $[2];
41
+ }
42
+ return t1;
43
+}
44
+
45
+```
46
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/_bug.jsx-tag-evaluation-order.js
new
+8
@@ -0,0 +1,8 @@
1
+function Component(props) {
2
+ const maybeMutable = new MaybeMutable();
3
+ let Tag = View;
4
+ // NOTE: the order of evaluation in the lowering is incorrect:
5
+ // the jsx element's tag observes `Tag` after reassignment, but should observe
6
+ // it before the reassignment.
7
+ return <Tag>{((Tag = HScroll), maybeMutae(maybeMutable))}</Tag>;
8
+}