[compiler] add fixture for optimization across scopes
Adds a fixture based on internal case where our current output is quite a bit more verbose than the original memoization. See the comment in the fixture for more about the heuristic we can apply. ghstack-source-id: e637a3814077559a1a56724eafe2567efed0b8d7 Pull Request resolved: https://github.com/facebook/react/pull/29998
Joe Savona committed
Jun 21, 2024 at 16:48 UTC
454fb35065053d5572689af1a7c125a41849604a
2 files changed
+153
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reordering-across-blocks.expect.md
new
+109
@@ -0,0 +1,109 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+import { Stringify } from "shared-runtime";
6
+
7
+function Component({ config }) {
8
+ /**
9
+ * The original memoization is optimal in the sense that it has
10
+ * one output (the object) and one dependency (`config`). Both
11
+ * the `a` and `b` functions will have to be recreated whenever
12
+ * `config` changes, cascading to update the object.
13
+ *
14
+ * However, we currently only consider consecutive scopes for
15
+ * merging, so we first see the `a` scope, then the `b` scope,
16
+ * and see that the output of the `a` scope is used later -
17
+ * so we don't merge these scopes, and so on.
18
+ *
19
+ * The more optimal thing would be to build a dependency graph
20
+ * of scopes so that we can see the data flow is along the lines
21
+ * of:
22
+ *
23
+ * config
24
+ * / \
25
+ * [a] [b]
26
+ * \ /
27
+ * [object]
28
+ *
29
+ * All the scopes (shown in []) are transitively dependent on
30
+ * `config`, so they can be merged.
31
+ */
32
+ const object = useMemo(() => {
33
+ const a = (event) => {
34
+ config?.onA?.(event);
35
+ };
36
+
37
+ const b = (event) => {
38
+ config?.onB?.(event);
39
+ };
40
+
41
+ return {
42
+ b,
43
+ a,
44
+ };
45
+ }, [config]);
46
+
47
+ return <Stringify value={object} />;
48
+}
49
+
50
+```
51
+
52
+## Code
53
+
54
+```javascript
55
+import { c as _c } from "react/compiler-runtime";
56
+import { Stringify } from "shared-runtime";
57
+
58
+function Component(t0) {
59
+ const $ = _c(9);
60
+ const { config } = t0;
61
+ let t1;
62
+ let t2;
63
+ if ($[0] !== config) {
64
+ t2 = (event) => {
65
+ config?.onA?.(event);
66
+ };
67
+ $[0] = config;
68
+ $[1] = t2;
69
+ } else {
70
+ t2 = $[1];
71
+ }
72
+ const a = t2;
73
+ let t3;
74
+ if ($[2] !== config) {
75
+ t3 = (event_0) => {
76
+ config?.onB?.(event_0);
77
+ };
78
+ $[2] = config;
79
+ $[3] = t3;
80
+ } else {
81
+ t3 = $[3];
82
+ }
83
+ const b = t3;
84
+ let t4;
85
+ if ($[4] !== b || $[5] !== a) {
86
+ t4 = { b, a };
87
+ $[4] = b;
88
+ $[5] = a;
89
+ $[6] = t4;
90
+ } else {
91
+ t4 = $[6];
92
+ }
93
+ t1 = t4;
94
+ const object = t1;
95
+ let t5;
96
+ if ($[7] !== object) {
97
+ t5 = <Stringify value={object} />;
98
+ $[7] = object;
99
+ $[8] = t5;
100
+ } else {
101
+ t5 = $[8];
102
+ }
103
+ return t5;
104
+}
105
+
106
+```
107
+
108
+### Eval output
109
+(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reordering-across-blocks.js
new
+44
@@ -0,0 +1,44 @@
1
+import { Stringify } from "shared-runtime";
2
+
3
+function Component({ config }) {
4
+ /**
5
+ * The original memoization is optimal in the sense that it has
6
+ * one output (the object) and one dependency (`config`). Both
7
+ * the `a` and `b` functions will have to be recreated whenever
8
+ * `config` changes, cascading to update the object.
9
+ *
10
+ * However, we currently only consider consecutive scopes for
11
+ * merging, so we first see the `a` scope, then the `b` scope,
12
+ * and see that the output of the `a` scope is used later -
13
+ * so we don't merge these scopes, and so on.
14
+ *
15
+ * The more optimal thing would be to build a dependency graph
16
+ * of scopes so that we can see the data flow is along the lines
17
+ * of:
18
+ *
19
+ * config
20
+ * / \
21
+ * [a] [b]
22
+ * \ /
23
+ * [object]
24
+ *
25
+ * All the scopes (shown in []) are transitively dependent on
26
+ * `config`, so they can be merged.
27
+ */
28
+ const object = useMemo(() => {
29
+ const a = (event) => {
30
+ config?.onA?.(event);
31
+ };
32
+
33
+ const b = (event) => {
34
+ config?.onB?.(event);
35
+ };
36
+
37
+ return {
38
+ b,
39
+ a,
40
+ };
41
+ }, [config]);
42
+
43
+ return <Stringify value={object} />;
44
+}