Skip to content

Commit 7293d70

Browse files
committed
[compiler] Support method-call version of macro functions
ghstack-source-id: c01f45b Pull Request resolved: #29899
1 parent a07f5a3 commit 7293d70

File tree

6 files changed

+233
-5
lines changed

6 files changed

+233
-5
lines changed

compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ function* runWithEnvironment(
248248
memoizeFbtOperandsInSameScope(hir);
249249
yield log({
250250
kind: "hir",
251-
name: "MemoizeFbtOperandsInSameScope",
251+
name: "MemoizeFbtAndMacroOperandsInSameScope",
252252
value: hir,
253253
});
254254

compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MemoizeFbtAndMacroOperandsInSameScope.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {
1515
import { eachReactiveValueOperand } from "./visitors";
1616

1717
/**
18-
* This pass supports the
1918
* This pass supports the `fbt` translation system (https://facebook.github.io/fbt/)
2019
* as well as similar user-configurable macro-like APIs where it's important that
2120
* the name of the function not be changed, and it's literal arguments not be turned
@@ -75,7 +74,7 @@ function visit(
7574
for (const instruction of block.instructions) {
7675
const { lvalue, value } = instruction;
7776
if (lvalue === null) {
78-
return;
77+
continue;
7978
}
8079
if (
8180
value.kind === "Primitive" &&
@@ -96,7 +95,7 @@ function visit(
9695
} else if (isFbtCallExpression(fbtValues, value)) {
9796
const fbtScope = lvalue.identifier.scope;
9897
if (fbtScope === null) {
99-
return;
98+
continue;
10099
}
101100

102101
/*
@@ -121,7 +120,7 @@ function visit(
121120
) {
122121
const fbtScope = lvalue.identifier.scope;
123122
if (fbtScope === null) {
124-
return;
123+
continue;
125124
}
126125

127126
/*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
2+
## Input
3+
4+
```javascript
5+
// @compilationMode(infer) @enableAssumeHooksFollowRulesOfReact:false @customMacros(cx)
6+
import { identity } from "shared-runtime";
7+
8+
const DARK = "dark";
9+
10+
function Component() {
11+
const theme = useTheme();
12+
return (
13+
<div
14+
className={cx.foo({
15+
"styles/light": true,
16+
"styles/dark": identity([theme.getTheme()]),
17+
})}
18+
/>
19+
);
20+
}
21+
22+
function cx(obj) {
23+
const classes = [];
24+
for (const [key, value] of Object.entries(obj)) {
25+
if (value) {
26+
classes.push(key);
27+
}
28+
}
29+
return classes.join(" ");
30+
}
31+
32+
function useTheme() {
33+
return {
34+
getTheme() {
35+
return DARK;
36+
},
37+
};
38+
}
39+
40+
export const FIXTURE_ENTRYPOINT = {
41+
fn: Component,
42+
params: [{}],
43+
};
44+
45+
```
46+
47+
## Code
48+
49+
```javascript
50+
import { c as _c } from "react/compiler-runtime"; // @compilationMode(infer) @enableAssumeHooksFollowRulesOfReact:false @customMacros(cx)
51+
import { identity } from "shared-runtime";
52+
53+
const DARK = "dark";
54+
55+
function Component() {
56+
const $ = _c(2);
57+
const theme = useTheme();
58+
59+
const t0 = cx.foo({
60+
"styles/light": true,
61+
"styles/dark": identity([theme.getTheme()]),
62+
});
63+
let t1;
64+
if ($[0] !== t0) {
65+
t1 = <div className={t0} />;
66+
$[0] = t0;
67+
$[1] = t1;
68+
} else {
69+
t1 = $[1];
70+
}
71+
return t1;
72+
}
73+
74+
function cx(obj) {
75+
const classes = [];
76+
for (const [key, value] of Object.entries(obj)) {
77+
if (value) {
78+
classes.push(key);
79+
}
80+
}
81+
return classes.join(" ");
82+
}
83+
84+
function useTheme() {
85+
return {
86+
getTheme() {
87+
return DARK;
88+
},
89+
};
90+
}
91+
92+
export const FIXTURE_ENTRYPOINT = {
93+
fn: Component,
94+
params: [{}],
95+
};
96+
97+
```
98+
99+
### Eval output
100+
(kind: exception) cx.foo is not a function
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// @compilationMode(infer) @enableAssumeHooksFollowRulesOfReact:false @customMacros(cx)
2+
import { identity } from "shared-runtime";
3+
4+
const DARK = "dark";
5+
6+
function Component() {
7+
const theme = useTheme();
8+
return (
9+
<div
10+
className={cx.foo({
11+
"styles/light": true,
12+
"styles/dark": identity([theme.getTheme()]),
13+
})}
14+
/>
15+
);
16+
}
17+
18+
function cx(obj) {
19+
const classes = [];
20+
for (const [key, value] of Object.entries(obj)) {
21+
if (value) {
22+
classes.push(key);
23+
}
24+
}
25+
return classes.join(" ");
26+
}
27+
28+
function useTheme() {
29+
return {
30+
getTheme() {
31+
return DARK;
32+
},
33+
};
34+
}
35+
36+
export const FIXTURE_ENTRYPOINT = {
37+
fn: Component,
38+
params: [{}],
39+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
2+
## Input
3+
4+
```javascript
5+
import { makeArray } from "shared-runtime";
6+
7+
function Component() {
8+
const items = makeArray("foo", "bar", "", null, "baz", false, "merp");
9+
const classname = cx.namespace(...items.filter(isNonEmptyString));
10+
return <div className={classname}>Ok</div>;
11+
}
12+
13+
function isNonEmptyString(s) {
14+
return typeof s === "string" && s.trim().length !== 0;
15+
}
16+
17+
const cx = {
18+
namespace(...items) {
19+
return items.join(" ");
20+
},
21+
};
22+
23+
export const FIXTURE_ENTRYPOINT = {
24+
fn: Component,
25+
params: [{}],
26+
};
27+
28+
```
29+
30+
## Code
31+
32+
```javascript
33+
import { c as _c } from "react/compiler-runtime";
34+
import { makeArray } from "shared-runtime";
35+
36+
function Component() {
37+
const $ = _c(1);
38+
let t0;
39+
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
40+
const items = makeArray("foo", "bar", "", null, "baz", false, "merp");
41+
const classname = cx.namespace(...items.filter(isNonEmptyString));
42+
t0 = <div className={classname}>Ok</div>;
43+
$[0] = t0;
44+
} else {
45+
t0 = $[0];
46+
}
47+
return t0;
48+
}
49+
50+
function isNonEmptyString(s) {
51+
return typeof s === "string" && s.trim().length !== 0;
52+
}
53+
54+
const cx = {
55+
namespace(...items) {
56+
return items.join(" ");
57+
},
58+
};
59+
60+
export const FIXTURE_ENTRYPOINT = {
61+
fn: Component,
62+
params: [{}],
63+
};
64+
65+
```
66+
67+
### Eval output
68+
(kind: ok) <div class="foo bar baz merp">Ok</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { makeArray } from "shared-runtime";
2+
3+
function Component() {
4+
const items = makeArray("foo", "bar", "", null, "baz", false, "merp");
5+
const classname = cx.namespace(...items.filter(isNonEmptyString));
6+
return <div className={classname}>Ok</div>;
7+
}
8+
9+
function isNonEmptyString(s) {
10+
return typeof s === "string" && s.trim().length !== 0;
11+
}
12+
13+
const cx = {
14+
namespace(...items) {
15+
return items.join(" ");
16+
},
17+
};
18+
19+
export const FIXTURE_ENTRYPOINT = {
20+
fn: Component,
21+
params: [{}],
22+
};

0 commit comments

Comments
 (0)