@samitouri / QOS-React / commits / 704c34e21f

[compiler] Bail out on local variables named 'fbt'

ghstack-source-id: c4e2b802a029b9dd7941ebcdeaaf471ddd95f868 Pull Request resolved: https://github.com/facebook/react/pull/30524

Mofei Zhang committed Jul 29, 2024 at 21:24 UTC 704c34e21f7468fc72c33aa843051c7949ebeccd
7 files changed +76 -144
compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts
+4 -3
@@ -2133,9 +2133,10 @@ function lowerExpression(
2133 const tagIdentifier = openingIdentifier.isJSXIdentifier()
2134 ? builder.resolveIdentifier(openingIdentifier)
2135 : null;
2136 - if (tagIdentifier != null && tagIdentifier.kind === 'Identifier') {
2137 - CompilerError.throwTodo({
2138 - reason: `Support <${tagName}> tags where '${tagName}' is a local variable instead of a global`,
2136 + if (tagIdentifier != null) {
2137 + // This is already checked in builder.resolveIdentifier
2138 + CompilerError.invariant(tagIdentifier.kind !== 'Identifier', {
2139 + reason: `<${tagName}> tags should be module-level imports`,
2140 loc: openingIdentifier.node.loc ?? GeneratedSource,
2141 description: null,
2142 suggestions: null,
compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts
+6
@@ -311,6 +311,12 @@ export default class HIRBuilder {
311 }
312
313 resolveBinding(node: t.Identifier): Identifier {
314 + if (node.name === 'fbt') {
315 + CompilerError.throwTodo({
316 + reason: 'Support local variables named "fbt"',
317 + loc: node.loc ?? null,
318 + });
319 + }
320 const originalName = node.name;
321 let name = originalName;
322 let index = 0;
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-fbt-as-local.expect.md new
+62
@@ -0,0 +1,62 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +import fbt from 'fbt';
6 +import {identity} from 'shared-runtime';
7 +
8 +/**
9 + * Note that the fbt transform looks for callsites with a `fbt`-named callee.
10 + * This is incompatible with react-compiler as we rename local variables in
11 + * HIRBuilder + RenameVariables.
12 + *
13 + * See evaluator error:
14 + * Found differences in evaluator results
15 + * Non-forget (expected):
16 + * (kind: ok) <div>Hello, Sathya!Goodbye, Sathya!</div>
17 + * Forget:
18 + * (kind: exception) fbt$0.param is not a function
19 + */
20 +
21 +function Foo(props) {
22 + const getText1 = fbt =>
23 + fbt(
24 + `Hello, ${fbt.param('(key) name', identity(props.name))}!`,
25 + '(description) Greeting'
26 + );
27 +
28 + const getText2 = fbt =>
29 + fbt(
30 + `Goodbye, ${fbt.param('(key) name', identity(props.name))}!`,
31 + '(description) Greeting2'
32 + );
33 +
34 + return (
35 + <div>
36 + {getText1(fbt)}
37 + {getText2(fbt)}
38 + </div>
39 + );
40 +}
41 +
42 +export const FIXTURE_ENTRYPOINT = {
43 + fn: Foo,
44 + params: [{name: 'Sathya'}],
45 +};
46 +
47 +```
48 +
49 +
50 +## Error
51 +
52 +```
53 + 16 |
54 + 17 | function Foo(props) {
55 +> 18 | const getText1 = fbt =>
56 + | ^^^ Todo: Support local variables named "fbt" (18:18)
57 + 19 | fbt(
58 + 20 | `Hello, ${fbt.param('(key) name', identity(props.name))}!`,
59 + 21 | '(description) Greeting'
60 +```
61 +
62 +
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-fbt-as-local.js renamed
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-locally-require-fbt.expect.md
+4 -4
@@ -14,12 +14,12 @@ function Component(props) {
14 ## Error
15
16 ```
17 - 2 | const fbt = require('fbt');
17 + 1 | function Component(props) {
18 +> 2 | const fbt = require('fbt');
19 + | ^^^ Todo: Support local variables named "fbt" (2:2)
20 3 |
19 -> 4 | return <fbt desc="Description">{'Text'}</fbt>;
20 - | ^^^ Todo: Support <fbt> tags where 'fbt' is a local variable instead of a global (4:4)
21 + 4 | return <fbt desc="Description">{'Text'}</fbt>;
22 5 | }
22 - 6 |
23 ```
24
25
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/todo-fbt-as-local.expect.md deleted
-136
@@ -1,136 +0,0 @@
1 -
2 -## Input
3 -
4 -```javascript
5 -import fbt from 'fbt';
6 -import {identity} from 'shared-runtime';
7 -
8 -/**
9 - * Note that the fbt transform looks for callsites with a `fbt`-named callee.
10 - * This is incompatible with react-compiler as we rename local variables in
11 - * HIRBuilder + RenameVariables.
12 - *
13 - * See evaluator error:
14 - * Found differences in evaluator results
15 - * Non-forget (expected):
16 - * (kind: ok) <div>Hello, Sathya!Goodbye, Sathya!</div>
17 - * Forget:
18 - * (kind: exception) fbt$0.param is not a function
19 - */
20 -
21 -function Foo(props) {
22 - const getText1 = fbt =>
23 - fbt(
24 - `Hello, ${fbt.param('(key) name', identity(props.name))}!`,
25 - '(description) Greeting'
26 - );
27 -
28 - const getText2 = fbt =>
29 - fbt(
30 - `Goodbye, ${fbt.param('(key) name', identity(props.name))}!`,
31 - '(description) Greeting2'
32 - );
33 -
34 - return (
35 - <div>
36 - {getText1(fbt)}
37 - {getText2(fbt)}
38 - </div>
39 - );
40 -}
41 -
42 -export const FIXTURE_ENTRYPOINT = {
43 - fn: Foo,
44 - params: [{name: 'Sathya'}],
45 -};
46 -
47 -```
48 -
49 -## Code
50 -
51 -```javascript
52 -import { c as _c } from "react/compiler-runtime";
53 -import fbt from "fbt";
54 -import { identity } from "shared-runtime";
55 -
56 -/**
57 - * Note that the fbt transform looks for callsites with a `fbt`-named callee.
58 - * This is incompatible with react-compiler as we rename local variables in
59 - * HIRBuilder + RenameVariables.
60 - *
61 - * See evaluator error:
62 - * Found differences in evaluator results
63 - * Non-forget (expected):
64 - * (kind: ok) <div>Hello, Sathya!Goodbye, Sathya!</div>
65 - * Forget:
66 - * (kind: exception) fbt$0.param is not a function
67 - */
68 -
69 -function Foo(props) {
70 - const $ = _c(11);
71 - let t0;
72 - if ($[0] !== props.name) {
73 - t0 = (fbt$0) =>
74 - fbt$0(
75 - `Hello, ${fbt$0.param("(key) name", identity(props.name))}!`,
76 - "(description) Greeting",
77 - );
78 - $[0] = props.name;
79 - $[1] = t0;
80 - } else {
81 - t0 = $[1];
82 - }
83 - const getText1 = t0;
84 - let t1;
85 - if ($[2] !== props.name) {
86 - t1 = (fbt_0) =>
87 - fbt_0(
88 - `Goodbye, ${fbt_0.param("(key) name", identity(props.name))}!`,
89 - "(description) Greeting2",
90 - );
91 - $[2] = props.name;
92 - $[3] = t1;
93 - } else {
94 - t1 = $[3];
95 - }
96 - const getText2 = t1;
97 - let t2;
98 - if ($[4] !== getText1) {
99 - t2 = getText1(fbt);
100 - $[4] = getText1;
101 - $[5] = t2;
102 - } else {
103 - t2 = $[5];
104 - }
105 - let t3;
106 - if ($[6] !== getText2) {
107 - t3 = getText2(fbt);
108 - $[6] = getText2;
109 - $[7] = t3;
110 - } else {
111 - t3 = $[7];
112 - }
113 - let t4;
114 - if ($[8] !== t2 || $[9] !== t3) {
115 - t4 = (
116 - <div>
117 - {t2}
118 - {t3}
119 - </div>
120 - );
121 - $[8] = t2;
122 - $[9] = t3;
123 - $[10] = t4;
124 - } else {
125 - t4 = $[10];
126 - }
127 - return t4;
128 -}
129 -
130 -export const FIXTURE_ENTRYPOINT = {
131 - fn: Foo,
132 - params: [{ name: "Sathya" }],
133 -};
134 -
135 -```
136 -
\ No newline at end of file
compiler/packages/snap/src/SproutTodoFilter.ts
-1
@@ -484,7 +484,6 @@ const skipFilter = new Set([
484 'rules-of-hooks/rules-of-hooks-69521d94fa03',
485
486 // bugs
487 - 'fbt/todo-fbt-as-local',
487 'bug-invalid-hoisting-functionexpr',
488 'original-reactive-scopes-fork/bug-nonmutating-capture-in-unsplittable-memo-block',
489 'original-reactive-scopes-fork/bug-hoisted-declaration-with-scope',