@samitouri / QOS-React-2 / commits / b2ec0445b4

[compiler][patch] Don't wrap non-ascii fbt operands in JSXExpressionContainer

ghstack-source-id: 4b5505aa5e58d1bcc0813452762e9921c74417d7 Pull Request resolved: https://github.com/facebook/react/pull/30389

Mofei Zhang committed Jul 18, 2024 at 15:33 UTC b2ec0445b4801e067f624adb2a29afcd06d1de55
12 files changed +227 -102
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts
+5 -2
@@ -262,7 +262,7 @@ function* runWithEnvironment(
262 value: hir,
263 });
264
265 - memoizeFbtOperandsInSameScope(hir);
265 + const fbtOperands = memoizeFbtOperandsInSameScope(hir);
266 yield log({
267 kind: "hir",
268 name: "MemoizeFbtAndMacroOperandsInSameScope",
@@ -484,7 +484,10 @@ function* runWithEnvironment(
484 validatePreservedManualMemoization(reactiveFunction);
485 }
486
487 - const ast = codegenFunction(reactiveFunction, uniqueIdentifiers).unwrap();
487 + const ast = codegenFunction(reactiveFunction, {
488 + uniqueIdentifiers,
489 + fbtOperands,
490 + }).unwrap();
491 yield log({ kind: "ast", name: "Codegen", value: ast });
492 for (const outlined of ast.outlined) {
493 yield log({ kind: "ast", name: "Codegen (outlined)", value: outlined.fn });
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts
+19 -3
@@ -100,12 +100,19 @@ export type CodegenFunction = {
100
101 export function codegenFunction(
102 fn: ReactiveFunction,
103 - uniqueIdentifiers: Set<string>
103 + {
104 + uniqueIdentifiers,
105 + fbtOperands,
106 + }: {
107 + uniqueIdentifiers: Set<string>;
108 + fbtOperands: Set<IdentifierId>;
109 + }
110 ): Result<CodegenFunction, CompilerError> {
111 const cx = new Context(
112 fn.env,
113 fn.id ?? "[[ anonymous ]]",
114 uniqueIdentifiers,
115 + fbtOperands,
116 null
117 );
118
@@ -281,7 +288,8 @@ export function codegenFunction(
288 new Context(
289 cx.env,
290 reactiveFunction.id ?? "[[ anonymous ]]",
284 - identifiers
291 + identifiers,
292 + cx.fbtOperands
293 ),
294 reactiveFunction
295 );
@@ -391,17 +399,20 @@ class Context {
399 errors: CompilerError = new CompilerError();
400 objectMethods: Map<IdentifierId, ObjectMethod> = new Map();
401 uniqueIdentifiers: Set<string>;
402 + fbtOperands: Set<IdentifierId>;
403 synthesizedNames: Map<string, ValidIdentifierName> = new Map();
404
405 constructor(
406 env: Environment,
407 fnName: string,
408 uniqueIdentifiers: Set<string>,
409 + fbtOperands: Set<IdentifierId>,
410 temporaries: Temporaries | null = null
411 ) {
412 this.env = env;
413 this.fnName = fnName;
414 this.uniqueIdentifiers = uniqueIdentifiers;
415 + this.fbtOperands = fbtOperands;
416 this.temp = temporaries !== null ? new Map(temporaries) : new Map();
417 }
418 get nextCacheIndex(): number {
@@ -1776,6 +1787,7 @@ function codegenInstructionValue(
1787 cx.env,
1788 reactiveFunction.id ?? "[[ anonymous ]]",
1789 cx.uniqueIdentifiers,
1790 + cx.fbtOperands,
1791 cx.temp
1792 ),
1793 reactiveFunction
@@ -1979,6 +1991,7 @@ function codegenInstructionValue(
1991 cx.env,
1992 reactiveFunction.id ?? "[[ anonymous ]]",
1993 cx.uniqueIdentifiers,
1994 + cx.fbtOperands,
1995 cx.temp
1996 ),
1997 reactiveFunction
@@ -2229,7 +2242,10 @@ function codegenJsxAttribute(
2242 switch (innerValue.type) {
2243 case "StringLiteral": {
2244 value = innerValue;
2232 - if (STRING_REQUIRES_EXPR_CONTAINER_PATTERN.test(value.value)) {
2245 + if (
2246 + STRING_REQUIRES_EXPR_CONTAINER_PATTERN.test(value.value) &&
2247 + !cx.fbtOperands.has(attribute.place.identifier.id)
2248 + ) {
2249 value = createJsxExpressionContainer(value.loc, value);
2250 }
2251 break;
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MemoizeFbtAndMacroOperandsInSameScope.ts
+4 -1
@@ -39,7 +39,9 @@ import { eachReactiveValueOperand } from "./visitors";
39 * Users can also specify their own functions to be treated similarly to fbt via the
40 * `customMacros` environment configuration.
41 */
42 -export function memoizeFbtAndMacroOperandsInSameScope(fn: HIRFunction): void {
42 +export function memoizeFbtAndMacroOperandsInSameScope(
43 + fn: HIRFunction
44 +): Set<IdentifierId> {
45 const fbtMacroTags = new Set([
46 ...FBT_TAGS,
47 ...(fn.env.config.customMacros ?? []),
@@ -52,6 +54,7 @@ export function memoizeFbtAndMacroOperandsInSameScope(fn: HIRFunction): void {
54 break;
55 }
56 }
57 + return fbtValues;
58 }
59
60 export const FBT_TAGS: Set<string> = new Set([
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-fbt-param-with-newline.expect.md deleted
-36
@@ -1,36 +0,0 @@
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{" "}
11 - <fbt:param
12 - name="a really long description
13 - that got split into multiple lines"
14 - >
15 - {props.name}
16 - </fbt:param>
17 - </fbt>
18 - );
19 - return element.toString();
20 -}
21 -
22 -export const FIXTURE_ENTRYPOINT = {
23 - fn: Component,
24 - params: [{ name: "Jason" }],
25 -};
26 -
27 -```
28 -
29 -
30 -## Error
31 -
32 -```
33 -Cannot read properties of undefined (reading 'replace')
34 -```
35 -
36 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-fbt-param-with-quotes.expect.md deleted
-30
@@ -1,30 +0,0 @@
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 -
24 -## Error
25 -
26 -```
27 -Property arguments[0] of CallExpression expected node to be of a type ["Expression","SpreadElement","JSXNamespacedName","ArgumentPlaceholder"] but instead got "JSXExpressionContainer"
28 -```
29 -
30 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/error.todo-fbt-param-with-unicode.expect.md deleted
-30
@@ -1,30 +0,0 @@
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 -
24 -## Error
25 -
26 -```
27 -Property arguments[0] of CallExpression expected node to be of a type ["Expression","SpreadElement","JSXNamespacedName","ArgumentPlaceholder"] but instead got "JSXExpressionContainer"
28 -```
29 -
30 -
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-param-with-newline.expect.md new
+75
@@ -0,0 +1,75 @@
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{" "}
11 + <fbt:param
12 + name="a really long description
13 + that got split into multiple lines"
14 + >
15 + {props.name}
16 + </fbt:param>
17 + </fbt>
18 + );
19 + return element.toString();
20 +}
21 +
22 +export const FIXTURE_ENTRYPOINT = {
23 + fn: Component,
24 + params: [{ name: "Jason" }],
25 +};
26 +
27 +```
28 +
29 +## Code
30 +
31 +```javascript
32 +import { c as _c } from "react/compiler-runtime";
33 +import fbt from "fbt";
34 +
35 +function Component(props) {
36 + const $ = _c(4);
37 + let t0;
38 + if ($[0] !== props.name) {
39 + t0 = fbt._(
40 + "Hello {a really long description that got split into multiple lines}",
41 + [
42 + fbt._param(
43 + "a really long description that got split into multiple lines",
44 +
45 + props.name,
46 + ),
47 + ],
48 + { hk: "1euPUp" },
49 + );
50 + $[0] = props.name;
51 + $[1] = t0;
52 + } else {
53 + t0 = $[1];
54 + }
55 + const element = t0;
56 + let t1;
57 + if ($[2] !== element) {
58 + t1 = element.toString();
59 + $[2] = element;
60 + $[3] = t1;
61 + } else {
62 + t1 = $[3];
63 + }
64 + return t1;
65 +}
66 +
67 +export const FIXTURE_ENTRYPOINT = {
68 + fn: Component,
69 + params: [{ name: "Jason" }],
70 +};
71 +
72 +```
73 +
74 +### Eval output
75 +(kind: ok) "Hello Jason"
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-param-with-newline.js renamed
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-param-with-quotes.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: "S0vMe",
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-param-with-quotes.js renamed
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-param-with-unicode.expect.md new
+63
@@ -0,0 +1,63 @@
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._(
34 + "Hello {user name ☺}",
35 + [fbt._param("user name \u263A", props.name)],
36 + { hk: "1En1lp" },
37 + );
38 + $[0] = props.name;
39 + $[1] = t0;
40 + } else {
41 + t0 = $[1];
42 + }
43 + const element = t0;
44 + let t1;
45 + if ($[2] !== element) {
46 + t1 = element.toString();
47 + $[2] = element;
48 + $[3] = t1;
49 + } else {
50 + t1 = $[3];
51 + }
52 + return t1;
53 +}
54 +
55 +export const FIXTURE_ENTRYPOINT = {
56 + fn: Component,
57 + params: [{ name: "Jason" }],
58 +};
59 +
60 +```
61 +
62 +### Eval output
63 +(kind: ok) "Hello Jason"
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-param-with-unicode.js renamed