Skip to content

Commit 05c9bf1

Browse files
committed
[compiler] Fix fbt for the ∞th time (facebook#34865)
We now do a single pass over the HIR, building up two data structures: * One tracks values that are known macro tags or macro calls. * One tracks operands of macro-related instructions so that we can later group them. After building up these data structures, we do a pass over the latter structure. For each macro call instruction, we recursively traverse its operands to ensure they're in the same scope. Thus, something like `fbt('hello' + fbt.param(foo(), "..."))` will correctly merge the fbt call, the `+` binary expression, the `fbt.param()` call, and `foo()` into a single scope. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34865). * facebook#34855 * __->__ facebook#34865 DiffTrain build for [85f415e](facebook@85f415e)
1 parent b101334 commit 05c9bf1

35 files changed

+152
-138
lines changed

compiled/eslint-plugin-react-hooks/index.js

Lines changed: 66 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -37178,30 +37178,49 @@ function memoizeFbtAndMacroOperandsInSameScope(fn) {
3717837178
...Array.from(FBT_TAGS).map((tag) => [tag, []]),
3717937179
...((_a = fn.env.config.customMacros) !== null && _a !== void 0 ? _a : []),
3718037180
]);
37181-
const fbtValues = new Set();
37181+
const macroTagsCalls = new Set();
37182+
const macroValues = new Map();
3718237183
const macroMethods = new Map();
37183-
while (true) {
37184-
let vsize = fbtValues.size;
37185-
let msize = macroMethods.size;
37186-
visit$1(fn, fbtMacroTags, fbtValues, macroMethods);
37187-
if (vsize === fbtValues.size && msize === macroMethods.size) {
37188-
break;
37184+
visit$1(fn, fbtMacroTags, macroTagsCalls, macroMethods, macroValues);
37185+
for (const root of macroValues.keys()) {
37186+
const scope = root.scope;
37187+
if (scope == null) {
37188+
continue;
3718937189
}
37190+
if (!macroTagsCalls.has(root.id)) {
37191+
continue;
37192+
}
37193+
mergeScopes(root, scope, macroValues, macroTagsCalls);
3719037194
}
37191-
return fbtValues;
37195+
return macroTagsCalls;
3719237196
}
3719337197
const FBT_TAGS = new Set([
3719437198
'fbt',
3719537199
'fbt:param',
37200+
'fbt:enum',
37201+
'fbt:plural',
3719637202
'fbs',
3719737203
'fbs:param',
37204+
'fbs:enum',
37205+
'fbs:plural',
3719837206
]);
3719937207
const SINGLE_CHILD_FBT_TAGS = new Set([
3720037208
'fbt:param',
3720137209
'fbs:param',
3720237210
]);
37203-
function visit$1(fn, fbtMacroTags, fbtValues, macroMethods) {
37211+
function visit$1(fn, fbtMacroTags, macroTagsCalls, macroMethods, macroValues) {
3720437212
for (const [, block] of fn.body.blocks) {
37213+
for (const phi of block.phis) {
37214+
const macroOperands = [];
37215+
for (const operand of phi.operands.values()) {
37216+
if (macroValues.has(operand.identifier)) {
37217+
macroOperands.push(operand.identifier);
37218+
}
37219+
}
37220+
if (macroOperands.length !== 0) {
37221+
macroValues.set(phi.place.identifier, macroOperands);
37222+
}
37223+
}
3720537224
for (const instruction of block.instructions) {
3720637225
const { lvalue, value } = instruction;
3720737226
if (lvalue === null) {
@@ -37210,11 +37229,11 @@ function visit$1(fn, fbtMacroTags, fbtValues, macroMethods) {
3721037229
if (value.kind === 'Primitive' &&
3721137230
typeof value.value === 'string' &&
3721237231
matchesExactTag(value.value, fbtMacroTags)) {
37213-
fbtValues.add(lvalue.identifier.id);
37232+
macroTagsCalls.add(lvalue.identifier.id);
3721437233
}
3721537234
else if (value.kind === 'LoadGlobal' &&
3721637235
matchesExactTag(value.binding.name, fbtMacroTags)) {
37217-
fbtValues.add(lvalue.identifier.id);
37236+
macroTagsCalls.add(lvalue.identifier.id);
3721837237
}
3721937238
else if (value.kind === 'LoadGlobal' &&
3722037239
matchTagRoot(value.binding.name, fbtMacroTags) !== null) {
@@ -37233,54 +37252,48 @@ function visit$1(fn, fbtMacroTags, fbtValues, macroMethods) {
3723337252
newMethods.push(method.slice(1));
3723437253
}
3723537254
else {
37236-
fbtValues.add(lvalue.identifier.id);
37255+
macroTagsCalls.add(lvalue.identifier.id);
3723737256
}
3723837257
}
3723937258
}
3724037259
if (newMethods.length > 0) {
3724137260
macroMethods.set(lvalue.identifier.id, newMethods);
3724237261
}
3724337262
}
37244-
else if (isFbtCallExpression(fbtValues, value)) {
37245-
const fbtScope = lvalue.identifier.scope;
37246-
if (fbtScope === null) {
37247-
continue;
37248-
}
37249-
for (const operand of eachReactiveValueOperand(value)) {
37250-
operand.identifier.scope = fbtScope;
37251-
expandFbtScopeRange(fbtScope.range, operand.identifier.mutableRange);
37252-
fbtValues.add(operand.identifier.id);
37253-
}
37263+
else if (value.kind === 'PropertyLoad' &&
37264+
macroTagsCalls.has(value.object.identifier.id)) {
37265+
macroTagsCalls.add(lvalue.identifier.id);
3725437266
}
37255-
else if (isFbtJsxExpression(fbtMacroTags, fbtValues, value) ||
37256-
isFbtJsxChild(fbtValues, lvalue, value)) {
37257-
const fbtScope = lvalue.identifier.scope;
37258-
if (fbtScope === null) {
37259-
continue;
37260-
}
37261-
for (const operand of eachReactiveValueOperand(value)) {
37262-
operand.identifier.scope = fbtScope;
37263-
expandFbtScopeRange(fbtScope.range, operand.identifier.mutableRange);
37264-
fbtValues.add(operand.identifier.id);
37265-
}
37267+
else if (isFbtJsxExpression(fbtMacroTags, macroTagsCalls, value) ||
37268+
isFbtJsxChild(macroTagsCalls, lvalue, value) ||
37269+
isFbtCallExpression(macroTagsCalls, value)) {
37270+
macroTagsCalls.add(lvalue.identifier.id);
37271+
macroValues.set(lvalue.identifier, Array.from(eachInstructionValueOperand(value), operand => operand.identifier));
3726637272
}
37267-
else if (fbtValues.has(lvalue.identifier.id)) {
37268-
const fbtScope = lvalue.identifier.scope;
37269-
if (fbtScope === null) {
37270-
return;
37271-
}
37272-
for (const operand of eachReactiveValueOperand(value)) {
37273-
if (operand.identifier.name !== null &&
37274-
operand.identifier.name.kind === 'named') {
37275-
continue;
37273+
else if (Iterable_some(eachInstructionValueOperand(value), operand => macroValues.has(operand.identifier))) {
37274+
const macroOperands = [];
37275+
for (const operand of eachInstructionValueOperand(value)) {
37276+
if (macroValues.has(operand.identifier)) {
37277+
macroOperands.push(operand.identifier);
3727637278
}
37277-
operand.identifier.scope = fbtScope;
37278-
expandFbtScopeRange(fbtScope.range, operand.identifier.mutableRange);
3727937279
}
37280+
macroValues.set(lvalue.identifier, macroOperands);
3728037281
}
3728137282
}
3728237283
}
3728337284
}
37285+
function mergeScopes(root, scope, macroValues, macroTagsCalls) {
37286+
const operands = macroValues.get(root);
37287+
if (operands == null) {
37288+
return;
37289+
}
37290+
for (const operand of operands) {
37291+
operand.scope = scope;
37292+
expandFbtScopeRange(scope.range, operand.mutableRange);
37293+
macroTagsCalls.add(operand.id);
37294+
mergeScopes(operand, scope, macroValues, macroTagsCalls);
37295+
}
37296+
}
3728437297
function matchesExactTag(s, tags) {
3728537298
return Array.from(tags).some(macro => typeof macro === 'string'
3728637299
? s === macro
@@ -37304,22 +37317,23 @@ function matchTagRoot(s, tags) {
3730437317
return null;
3730537318
}
3730637319
}
37307-
function isFbtCallExpression(fbtValues, value) {
37320+
function isFbtCallExpression(macroTagsCalls, value) {
3730837321
return ((value.kind === 'CallExpression' &&
37309-
fbtValues.has(value.callee.identifier.id)) ||
37310-
(value.kind === 'MethodCall' && fbtValues.has(value.property.identifier.id)));
37322+
macroTagsCalls.has(value.callee.identifier.id)) ||
37323+
(value.kind === 'MethodCall' &&
37324+
macroTagsCalls.has(value.property.identifier.id)));
3731137325
}
37312-
function isFbtJsxExpression(fbtMacroTags, fbtValues, value) {
37326+
function isFbtJsxExpression(fbtMacroTags, macroTagsCalls, value) {
3731337327
return (value.kind === 'JsxExpression' &&
3731437328
((value.tag.kind === 'Identifier' &&
37315-
fbtValues.has(value.tag.identifier.id)) ||
37329+
macroTagsCalls.has(value.tag.identifier.id)) ||
3731637330
(value.tag.kind === 'BuiltinTag' &&
3731737331
matchesExactTag(value.tag.name, fbtMacroTags))));
3731837332
}
37319-
function isFbtJsxChild(fbtValues, lvalue, value) {
37333+
function isFbtJsxChild(macroTagsCalls, lvalue, value) {
3732037334
return ((value.kind === 'JsxExpression' || value.kind === 'JsxFragment') &&
3732137335
lvalue !== null &&
37322-
fbtValues.has(lvalue.identifier.id));
37336+
macroTagsCalls.has(lvalue.identifier.id));
3732337337
}
3732437338
function expandFbtScopeRange(fbtRange, extendWith) {
3732537339
if (extendWith.start !== 0) {
@@ -48172,7 +48186,7 @@ function* generateInstructionTypes(env, names, instr) {
4817248186
});
4817348187
}
4817448188
else {
48175-
break;
48189+
continue;
4817648190
}
4817748191
}
4817848192
}

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
b9ec735de248f46da181afbc12aa906422be0dba
1+
85f415e33b95d65aaa29f92268b31d33060628ac
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
b9ec735de248f46da181afbc12aa906422be0dba
1+
85f415e33b95d65aaa29f92268b31d33060628ac

compiled/facebook-www/React-dev.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1460,7 +1460,7 @@ __DEV__ &&
14601460
exports.useTransition = function () {
14611461
return resolveDispatcher().useTransition();
14621462
};
1463-
exports.version = "19.3.0-www-classic-b9ec735d-20251013";
1463+
exports.version = "19.3.0-www-classic-85f415e3-20251015";
14641464
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
14651465
"function" ===
14661466
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-dev.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1460,7 +1460,7 @@ __DEV__ &&
14601460
exports.useTransition = function () {
14611461
return resolveDispatcher().useTransition();
14621462
};
1463-
exports.version = "19.3.0-www-modern-b9ec735d-20251013";
1463+
exports.version = "19.3.0-www-modern-85f415e3-20251015";
14641464
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
14651465
"function" ===
14661466
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-prod.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,4 +606,4 @@ exports.useSyncExternalStore = function (
606606
exports.useTransition = function () {
607607
return ReactSharedInternals.H.useTransition();
608608
};
609-
exports.version = "19.3.0-www-classic-b9ec735d-20251013";
609+
exports.version = "19.3.0-www-classic-85f415e3-20251015";

compiled/facebook-www/React-prod.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,4 +606,4 @@ exports.useSyncExternalStore = function (
606606
exports.useTransition = function () {
607607
return ReactSharedInternals.H.useTransition();
608608
};
609-
exports.version = "19.3.0-www-modern-b9ec735d-20251013";
609+
exports.version = "19.3.0-www-modern-85f415e3-20251015";

compiled/facebook-www/React-profiling.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ exports.useSyncExternalStore = function (
610610
exports.useTransition = function () {
611611
return ReactSharedInternals.H.useTransition();
612612
};
613-
exports.version = "19.3.0-www-classic-b9ec735d-20251013";
613+
exports.version = "19.3.0-www-classic-85f415e3-20251015";
614614
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
615615
"function" ===
616616
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-profiling.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ exports.useSyncExternalStore = function (
610610
exports.useTransition = function () {
611611
return ReactSharedInternals.H.useTransition();
612612
};
613-
exports.version = "19.3.0-www-modern-b9ec735d-20251013";
613+
exports.version = "19.3.0-www-modern-85f415e3-20251015";
614614
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
615615
"function" ===
616616
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/ReactART-dev.classic.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20371,10 +20371,10 @@ __DEV__ &&
2037120371
(function () {
2037220372
var internals = {
2037320373
bundleType: 1,
20374-
version: "19.3.0-www-classic-b9ec735d-20251013",
20374+
version: "19.3.0-www-classic-85f415e3-20251015",
2037520375
rendererPackageName: "react-art",
2037620376
currentDispatcherRef: ReactSharedInternals,
20377-
reconcilerVersion: "19.3.0-www-classic-b9ec735d-20251013"
20377+
reconcilerVersion: "19.3.0-www-classic-85f415e3-20251015"
2037820378
};
2037920379
internals.overrideHookState = overrideHookState;
2038020380
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -20409,7 +20409,7 @@ __DEV__ &&
2040920409
exports.Shape = Shape;
2041020410
exports.Surface = Surface;
2041120411
exports.Text = Text;
20412-
exports.version = "19.3.0-www-classic-b9ec735d-20251013";
20412+
exports.version = "19.3.0-www-classic-85f415e3-20251015";
2041320413
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
2041420414
"function" ===
2041520415
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

0 commit comments

Comments
 (0)