@samitouri / QOS-React-2 / commits / 275c755715

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