compiler: fix for calls on builtin jsx/function types
When I added new builtin types for jsx and functions, i forget to add a shape definition. This meant that attempting to accesss a property or method on these types would cause an internal error with an unresolved shape. That wasn't obvious because we rarely call methods on these types. I confirmed that the new fixtures here fail without the fix. ghstack-source-id: aa8f8d75a302bb5bac126d3e963594545e71ec74 Pull Request resolved: https://github.com/facebook/react/pull/29624
Joe Savona committed
May 28, 2024 at 15:09 UTC
bd4bb32fe708bace6fa927834220f571ff583f39
7 files changed
+261
compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts
+3
@@ -431,6 +431,9 @@ addObject(BUILTIN_SHAPES, BuiltInMixedReadonlyId, [
431
["*", { kind: "Object", shapeId: BuiltInMixedReadonlyId }],
432
]);
433
434
+addObject(BUILTIN_SHAPES, BuiltInJsxId, []);
435
+addObject(BUILTIN_SHAPES, BuiltInFunctionId, []);
436
+
437
export const DefaultMutatingHook = addHook(
438
BUILTIN_SHAPES,
439
{
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-to-string.expect.md
new
+61
@@ -0,0 +1,61 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+import fbt from "fbt";
6
+
7
+function Component(props) {
8
+ const element = (
9
+ <fbt desc={"Dialog to show to user"}>
10
+ Hello <fbt:param name="user name">{props.name}</fbt:param>
11
+ </fbt>
12
+ );
13
+ return element.toString();
14
+}
15
+
16
+export const FIXTURE_ENTRYPOINT = {
17
+ fn: Component,
18
+ params: [{ name: "Jason" }],
19
+};
20
+
21
+```
22
+
23
+## Code
24
+
25
+```javascript
26
+import { c as _c } from "react/compiler-runtime";
27
+import fbt from "fbt";
28
+
29
+function Component(props) {
30
+ const $ = _c(4);
31
+ let t0;
32
+ if ($[0] !== props.name) {
33
+ t0 = fbt._("Hello {user name}", [fbt._param("user name", props.name)], {
34
+ hk: "2zEDKF",
35
+ });
36
+ $[0] = props.name;
37
+ $[1] = t0;
38
+ } else {
39
+ t0 = $[1];
40
+ }
41
+ const element = t0;
42
+ let t1;
43
+ if ($[2] !== element) {
44
+ t1 = element.toString();
45
+ $[2] = element;
46
+ $[3] = t1;
47
+ } else {
48
+ t1 = $[3];
49
+ }
50
+ return t1;
51
+}
52
+
53
+export const FIXTURE_ENTRYPOINT = {
54
+ fn: Component,
55
+ params: [{ name: "Jason" }],
56
+};
57
+
58
+```
59
+
60
+### Eval output
61
+(kind: ok) "Hello Jason"
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-to-string.js
new
+15
@@ -0,0 +1,15 @@
1
+import fbt from "fbt";
2
+
3
+function Component(props) {
4
+ const element = (
5
+ <fbt desc={"Dialog to show to user"}>
6
+ Hello <fbt:param name="user name">{props.name}</fbt:param>
7
+ </fbt>
8
+ );
9
+ return element.toString();
10
+}
11
+
12
+export const FIXTURE_ENTRYPOINT = {
13
+ fn: Component,
14
+ params: [{ name: "Jason" }],
15
+};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-prototype-call-mutating.expect.md
new
+92
@@ -0,0 +1,92 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+import { useMemo } from "react";
6
+import { ValidateMemoization } from "shared-runtime";
7
+
8
+function Component(props) {
9
+ const a = useMemo(() => {
10
+ const a = [];
11
+ const f = function () {
12
+ a.push(props.name);
13
+ };
14
+ f.call();
15
+ return a;
16
+ }, [props.name]);
17
+ return <ValidateMemoization inputs={[props.name]} output={a} />;
18
+}
19
+
20
+export const FIXTURE_ENTRYPOINT = {
21
+ fn: Component,
22
+ params: [{ name: "Jason" }],
23
+ sequentialRenders: [
24
+ { name: "Lauren" },
25
+ { name: "Lauren" },
26
+ { name: "Jason" },
27
+ ],
28
+};
29
+
30
+```
31
+
32
+## Code
33
+
34
+```javascript
35
+import { c as _c } from "react/compiler-runtime";
36
+import { useMemo } from "react";
37
+import { ValidateMemoization } from "shared-runtime";
38
+
39
+function Component(props) {
40
+ const $ = _c(7);
41
+ let t0;
42
+ let a;
43
+ if ($[0] !== props.name) {
44
+ a = [];
45
+ const f = function () {
46
+ a.push(props.name);
47
+ };
48
+
49
+ f.call();
50
+ $[0] = props.name;
51
+ $[1] = a;
52
+ } else {
53
+ a = $[1];
54
+ }
55
+ t0 = a;
56
+ const a_0 = t0;
57
+ let t1;
58
+ if ($[2] !== props.name) {
59
+ t1 = [props.name];
60
+ $[2] = props.name;
61
+ $[3] = t1;
62
+ } else {
63
+ t1 = $[3];
64
+ }
65
+ let t2;
66
+ if ($[4] !== t1 || $[5] !== a_0) {
67
+ t2 = <ValidateMemoization inputs={t1} output={a_0} />;
68
+ $[4] = t1;
69
+ $[5] = a_0;
70
+ $[6] = t2;
71
+ } else {
72
+ t2 = $[6];
73
+ }
74
+ return t2;
75
+}
76
+
77
+export const FIXTURE_ENTRYPOINT = {
78
+ fn: Component,
79
+ params: [{ name: "Jason" }],
80
+ sequentialRenders: [
81
+ { name: "Lauren" },
82
+ { name: "Lauren" },
83
+ { name: "Jason" },
84
+ ],
85
+};
86
+
87
+```
88
+
89
+### Eval output
90
+(kind: ok) <div>{"inputs":["Lauren"],"output":["Lauren"]}</div>
91
+<div>{"inputs":["Lauren"],"output":["Lauren"]}</div>
92
+<div>{"inputs":["Jason"],"output":["Jason"]}</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-prototype-call-mutating.js
new
+24
@@ -0,0 +1,24 @@
1
+import { useMemo } from "react";
2
+import { ValidateMemoization } from "shared-runtime";
3
+
4
+function Component(props) {
5
+ const a = useMemo(() => {
6
+ const a = [];
7
+ const f = function () {
8
+ a.push(props.name);
9
+ };
10
+ f.call();
11
+ return a;
12
+ }, [props.name]);
13
+ return <ValidateMemoization inputs={[props.name]} output={a} />;
14
+}
15
+
16
+export const FIXTURE_ENTRYPOINT = {
17
+ fn: Component,
18
+ params: [{ name: "Jason" }],
19
+ sequentialRenders: [
20
+ { name: "Lauren" },
21
+ { name: "Lauren" },
22
+ { name: "Jason" },
23
+ ],
24
+};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-prototype-call.expect.md
new
+55
@@ -0,0 +1,55 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ const f = function () {
7
+ return <div>{props.name}</div>;
8
+ };
9
+ return f.call();
10
+}
11
+
12
+export const FIXTURE_ENTRYPOINT = {
13
+ fn: Component,
14
+ params: [{ name: "Jason" }],
15
+};
16
+
17
+```
18
+
19
+## Code
20
+
21
+```javascript
22
+import { c as _c } from "react/compiler-runtime";
23
+function Component(props) {
24
+ const $ = _c(4);
25
+ let t0;
26
+ if ($[0] !== props.name) {
27
+ t0 = function () {
28
+ return <div>{props.name}</div>;
29
+ };
30
+ $[0] = props.name;
31
+ $[1] = t0;
32
+ } else {
33
+ t0 = $[1];
34
+ }
35
+ const f = t0;
36
+ let t1;
37
+ if ($[2] !== f) {
38
+ t1 = f.call();
39
+ $[2] = f;
40
+ $[3] = t1;
41
+ } else {
42
+ t1 = $[3];
43
+ }
44
+ return t1;
45
+}
46
+
47
+export const FIXTURE_ENTRYPOINT = {
48
+ fn: Component,
49
+ params: [{ name: "Jason" }],
50
+};
51
+
52
+```
53
+
54
+### Eval output
55
+(kind: ok) <div>Jason</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-prototype-call.js
new
+11
@@ -0,0 +1,11 @@
1
+function Component(props) {
2
+ const f = function () {
3
+ return <div>{props.name}</div>;
4
+ };
5
+ return f.call();
6
+}
7
+
8
+export const FIXTURE_ENTRYPOINT = {
9
+ fn: Component,
10
+ params: [{ name: "Jason" }],
11
+};