@samitouri / QOS-React-1 / commits / 88b1a069c0

Add examples for phi type inference

Adds test cases that would demonstrate different output if we were to update InferTypes to infer the types of phi identifiers when their operands have the same type. We currently do infer such types, but attach them to phi.type instead of phi.id.type, so the type doesn't effect inference. Fixing that would cause the output on these examples to change — however, per the discussion on #2079, we'd also incorrectly set the mutable ranges in some cases and cause incorrect compilation. I did a thorough review of InferReferenceEffects and can't figure out how to trigger the bug in our current implementation — the bug only kicks in when phi operands would be mutated as a store instead of a mutate, and that cannot happen given our currently imprecise types on phi identifiers.

Joe Savona committed Sep 14, 2023 at 11:56 UTC 88b1a069c04631009cf64e3ff18cc8f463626f38
4 files changed +202
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/phi-type-inference-array-push.expect.md new
+76
@@ -0,0 +1,76 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +// @debug
6 +function Component(props) {
7 + const x = {};
8 + let y;
9 + if (props.cond) {
10 + y = [props.value];
11 + } else {
12 + y = [];
13 + }
14 + // This should be inferred as `<store> y` s.t. `x` can still
15 + // be independently memoized. *But* this also must properly
16 + // extend the mutable range of the array literals in the
17 + // if/else branches
18 + y.push(x);
19 +
20 + return [x, y];
21 +}
22 +
23 +export const FIXTURE_ENTRYPOINT = {
24 + fn: Component,
25 + params: [{ cond: true, value: 42 }],
26 +};
27 +
28 +```
29 +
30 +## Code
31 +
32 +```javascript
33 +import { unstable_useMemoCache as useMemoCache } from "react"; // @debug
34 +function Component(props) {
35 + const $ = useMemoCache(6);
36 + const c_0 = $[0] !== props;
37 + let x;
38 + let y;
39 + if (c_0) {
40 + x = {};
41 + y = undefined;
42 + if (props.cond) {
43 + y = [props.value];
44 + } else {
45 + y = [];
46 + }
47 +
48 + y.push(x);
49 + $[0] = props;
50 + $[1] = x;
51 + $[2] = y;
52 + } else {
53 + x = $[1];
54 + y = $[2];
55 + }
56 + const c_3 = $[3] !== x;
57 + const c_4 = $[4] !== y;
58 + let t0;
59 + if (c_3 || c_4) {
60 + t0 = [x, y];
61 + $[3] = x;
62 + $[4] = y;
63 + $[5] = t0;
64 + } else {
65 + t0 = $[5];
66 + }
67 + return t0;
68 +}
69 +
70 +export const FIXTURE_ENTRYPOINT = {
71 + fn: Component,
72 + params: [{ cond: true, value: 42 }],
73 +};
74 +
75 +```
76 +
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/phi-type-inference-array-push.js new
+22
@@ -0,0 +1,22 @@
1 +// @debug
2 +function Component(props) {
3 + const x = {};
4 + let y;
5 + if (props.cond) {
6 + y = [props.value];
7 + } else {
8 + y = [];
9 + }
10 + // This should be inferred as `<store> y` s.t. `x` can still
11 + // be independently memoized. *But* this also must properly
12 + // extend the mutable range of the array literals in the
13 + // if/else branches
14 + y.push(x);
15 +
16 + return [x, y];
17 +}
18 +
19 +export const FIXTURE_ENTRYPOINT = {
20 + fn: Component,
21 + params: [{ cond: true, value: 42 }],
22 +};
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/phi-type-inference-property-store.expect.md new
+82
@@ -0,0 +1,82 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +// @debug
6 +function Component(props) {
7 + const x = {};
8 + let y;
9 + if (props.cond) {
10 + y = {};
11 + } else {
12 + y = { a: props.a };
13 + }
14 + // This should be inferred as `<store> y` s.t. `x` can still
15 + // be independently memoized. *But* this also must properly
16 + // extend the mutable range of the object literals in the
17 + // if/else branches
18 + y.x = x;
19 +
20 + return [x, y];
21 +}
22 +
23 +export const FIXTURE_ENTRYPOINT = {
24 + fn: Component,
25 + params: [{ cond: false, a: "a!" }],
26 +};
27 +
28 +```
29 +
30 +## Code
31 +
32 +```javascript
33 +import { unstable_useMemoCache as useMemoCache } from "react"; // @debug
34 +function Component(props) {
35 + const $ = useMemoCache(7);
36 + let t0;
37 + if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
38 + t0 = {};
39 + $[0] = t0;
40 + } else {
41 + t0 = $[0];
42 + }
43 + const x = t0;
44 + const c_1 = $[1] !== props;
45 + const c_2 = $[2] !== x;
46 + let y;
47 + if (c_1 || c_2) {
48 + y = undefined;
49 + if (props.cond) {
50 + y = {};
51 + } else {
52 + y = { a: props.a };
53 + }
54 +
55 + y.x = x;
56 + $[1] = props;
57 + $[2] = x;
58 + $[3] = y;
59 + } else {
60 + y = $[3];
61 + }
62 + const c_4 = $[4] !== x;
63 + const c_5 = $[5] !== y;
64 + let t1;
65 + if (c_4 || c_5) {
66 + t1 = [x, y];
67 + $[4] = x;
68 + $[5] = y;
69 + $[6] = t1;
70 + } else {
71 + t1 = $[6];
72 + }
73 + return t1;
74 +}
75 +
76 +export const FIXTURE_ENTRYPOINT = {
77 + fn: Component,
78 + params: [{ cond: false, a: "a!" }],
79 +};
80 +
81 +```
82 +
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/phi-type-inference-property-store.js new
+22
@@ -0,0 +1,22 @@
1 +// @debug
2 +function Component(props) {
3 + const x = {};
4 + let y;
5 + if (props.cond) {
6 + y = {};
7 + } else {
8 + y = { a: props.a };
9 + }
10 + // This should be inferred as `<store> y` s.t. `x` can still
11 + // be independently memoized. *But* this also must properly
12 + // extend the mutable range of the object literals in the
13 + // if/else branches
14 + y.x = x;
15 +
16 + return [x, y];
17 +}
18 +
19 +export const FIXTURE_ENTRYPOINT = {
20 + fn: Component,
21 + params: [{ cond: false, a: "a!" }],
22 +};