Skip to content

Commit 9af2de4

Browse files
committed
[Macros] Only expand member macros that can affect qualified name lookup.
Rather than eagerly expanding all member macros when doing any name lookup into a type, use the same introduced-name-tracking logic we apply to peer macros to only expand those member macros that can produce the requested name. This makes the compiler lazier.
1 parent 5e4118a commit 9af2de4

File tree

1 file changed

+99
-55
lines changed

1 file changed

+99
-55
lines changed

lib/AST/NameLookup.cpp

Lines changed: 99 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1534,77 +1534,132 @@ static DeclName adjustLazyMacroExpansionNameKey(
15341534
return name;
15351535
}
15361536

1537+
/// Call the given function body with each macro declaration and its associated
1538+
/// role attribute for the given role.
1539+
///
1540+
/// This routine intentionally avoids calling `forEachAttachedMacro`, which
1541+
/// triggers request cycles.
1542+
static void forEachPotentialResolvedMacro(
1543+
DeclContext *moduleScopeCtx, DeclNameRef macroName, MacroRole role,
1544+
llvm::function_ref<void(MacroDecl *, const MacroRoleAttr *)> body
1545+
) {
1546+
ASTContext &ctx = moduleScopeCtx->getASTContext();
1547+
UnqualifiedLookupDescriptor lookupDesc{macroName, moduleScopeCtx};
1548+
auto lookup = evaluateOrDefault(
1549+
ctx.evaluator, UnqualifiedLookupRequest{lookupDesc}, {});
1550+
for (auto result : lookup.allResults()) {
1551+
auto *vd = result.getValueDecl();
1552+
auto *macro = dyn_cast<MacroDecl>(vd);
1553+
if (!macro)
1554+
continue;
1555+
1556+
auto *macroRoleAttr = macro->getMacroRoleAttr(role);
1557+
if (!macroRoleAttr)
1558+
continue;
1559+
1560+
body(macro, macroRoleAttr);
1561+
}
1562+
}
1563+
1564+
/// For each macro with the given role that might be attached to the given
1565+
/// declaration, call the body.
1566+
static void forEachPotentialAttachedMacro(
1567+
Decl *decl, MacroRole role,
1568+
llvm::function_ref<void(MacroDecl *macro, const MacroRoleAttr *)> body
1569+
) {
1570+
// We intentionally avoid calling `forEachAttachedMacro` in order to avoid
1571+
// a request cycle.
1572+
auto moduleScopeCtx = decl->getDeclContext()->getModuleScopeContext();
1573+
for (auto attrConst : decl->getSemanticAttrs().getAttributes<CustomAttr>()) {
1574+
auto *attr = const_cast<CustomAttr *>(attrConst);
1575+
UnresolvedMacroReference macroRef(attr);
1576+
auto macroName = macroRef.getMacroName();
1577+
forEachPotentialResolvedMacro(moduleScopeCtx, macroName, role, body);
1578+
}
1579+
}
1580+
1581+
namespace {
1582+
/// Function object that tracks macro-introduced names.
1583+
struct MacroIntroducedNameTracker {
1584+
ValueDecl *attachedTo = nullptr;
1585+
1586+
llvm::SmallSet<DeclName, 4> allIntroducedNames;
1587+
bool introducesArbitraryNames = false;
1588+
1589+
/// Augment the set of names with those introduced by the given macro.
1590+
void operator()(MacroDecl *macro, const MacroRoleAttr *attr) {
1591+
// First check for arbitrary names.
1592+
if (attr->hasNameKind(MacroIntroducedDeclNameKind::Arbitrary)) {
1593+
introducesArbitraryNames = true;
1594+
}
1595+
1596+
// If this introduces arbitrary names, there's nothing more to do.
1597+
if (introducesArbitraryNames)
1598+
return;
1599+
1600+
SmallVector<DeclName, 4> introducedNames;
1601+
macro->getIntroducedNames(
1602+
attr->getMacroRole(), attachedTo, introducedNames);
1603+
for (auto name : introducedNames)
1604+
allIntroducedNames.insert(name);
1605+
}
1606+
1607+
bool shouldExpandForName(DeclName name) const {
1608+
return introducesArbitraryNames || allIntroducedNames.contains(name);
1609+
}
1610+
};
1611+
}
1612+
15371613
static void
15381614
populateLookupTableEntryFromMacroExpansions(ASTContext &ctx,
15391615
MemberLookupTable &table,
15401616
DeclName name,
15411617
TypeOrExtensionDecl container) {
1618+
1619+
// Trigger the expansion of member macros on the container, if any of the
1620+
// names match.
1621+
{
1622+
MacroIntroducedNameTracker nameTracker;
1623+
auto decl = container.getAsDecl();
1624+
forEachPotentialAttachedMacro(decl, MacroRole::Member, nameTracker);
1625+
if (nameTracker.shouldExpandForName(name)) {
1626+
(void)evaluateOrDefault(
1627+
ctx.evaluator,
1628+
ExpandSynthesizedMemberMacroRequest{decl},
1629+
false);
1630+
}
1631+
}
1632+
15421633
auto dc = container.getAsDeclContext();
1543-
auto *moduleScopeCtx = dc->getModuleScopeContext();
15441634
auto *module = dc->getParentModule();
15451635
auto idc = container.getAsIterableDeclContext();
15461636
for (auto *member : idc->getCurrentMembersWithoutLoading()) {
15471637
// Collect all macro introduced names, along with its corresponding macro
15481638
// reference. We need the macro reference to prevent adding auxiliary decls
15491639
// that weren't introduced by the macro.
1550-
llvm::SmallSet<DeclName, 4> allIntroducedNames;
1551-
bool introducesArbitraryNames = false;
1640+
MacroIntroducedNameTracker nameTracker;
15521641
if (auto *med = dyn_cast<MacroExpansionDecl>(member)) {
15531642
auto declRef = evaluateOrDefault(
15541643
ctx.evaluator, ResolveMacroRequest{med, dc},
15551644
nullptr);
15561645
if (!declRef)
15571646
continue;
15581647
auto *macro = dyn_cast<MacroDecl>(declRef.getDecl());
1559-
if (macro->getMacroRoleAttr(MacroRole::Declaration)
1560-
->hasNameKind(MacroIntroducedDeclNameKind::Arbitrary))
1561-
introducesArbitraryNames = true;
1562-
else {
1563-
SmallVector<DeclName, 4> introducedNames;
1564-
macro->getIntroducedNames(MacroRole::Declaration, nullptr,
1565-
introducedNames);
1566-
for (auto name : introducedNames)
1567-
allIntroducedNames.insert(name);
1568-
}
1648+
nameTracker(macro, macro->getMacroRoleAttr(MacroRole::Declaration));
15691649
} else if (auto *vd = dyn_cast<ValueDecl>(member)) {
1570-
// We intentionally avoid calling `forEachAttachedMacro` in order to avoid
1571-
// a request cycle.
1572-
for (auto attrConst : member->getSemanticAttrs().getAttributes<CustomAttr>()) {
1573-
auto *attr = const_cast<CustomAttr *>(attrConst);
1574-
UnresolvedMacroReference macroRef(attr);
1575-
auto macroName = macroRef.getMacroName();
1576-
UnqualifiedLookupDescriptor lookupDesc{macroName, moduleScopeCtx};
1577-
auto lookup = evaluateOrDefault(
1578-
ctx.evaluator, UnqualifiedLookupRequest{lookupDesc}, {});
1579-
for (auto result : lookup.allResults()) {
1580-
auto *vd = result.getValueDecl();
1581-
auto *macro = dyn_cast<MacroDecl>(vd);
1582-
if (!macro)
1583-
continue;
1584-
auto *macroRoleAttr = macro->getMacroRoleAttr(MacroRole::Peer);
1585-
if (!macroRoleAttr)
1586-
continue;
1587-
if (macroRoleAttr->hasNameKind(
1588-
MacroIntroducedDeclNameKind::Arbitrary))
1589-
introducesArbitraryNames = true;
1590-
else {
1591-
SmallVector<DeclName, 4> introducedNames;
1592-
macro->getIntroducedNames(
1593-
MacroRole::Peer, dyn_cast<ValueDecl>(member), introducedNames);
1594-
for (auto name : introducedNames)
1595-
allIntroducedNames.insert(name);
1596-
}
1597-
}
1598-
}
1650+
nameTracker.attachedTo = dyn_cast<ValueDecl>(member);
1651+
forEachPotentialAttachedMacro(member, MacroRole::Peer, nameTracker);
15991652
}
1600-
// Expand macros based on the name.
1601-
if (introducesArbitraryNames || allIntroducedNames.contains(name))
1653+
1654+
// Expand macros on this member.
1655+
if (nameTracker.shouldExpandForName(name)) {
16021656
member->visitAuxiliaryDecls([&](Decl *decl) {
16031657
auto *sf = module->getSourceFileContainingLocation(decl->getLoc());
16041658
// Bail out if the auxiliary decl was not produced by a macro.
16051659
if (!sf || sf->Kind != SourceFileKind::MacroExpansion) return;
16061660
table.addMember(decl);
16071661
});
1662+
}
16081663
}
16091664
}
16101665

@@ -2140,17 +2195,6 @@ QualifiedLookupRequest::evaluate(Evaluator &eval, const DeclContext *DC,
21402195
// Make sure we've resolved property wrappers, if we need them.
21412196
installPropertyWrapperMembersIfNeeded(current, member);
21422197

2143-
// Expand synthesized member macros.
2144-
auto &ctx = current->getASTContext();
2145-
(void)evaluateOrDefault(ctx.evaluator,
2146-
ExpandSynthesizedMemberMacroRequest{current},
2147-
false);
2148-
for (auto ext : current->getExtensions()) {
2149-
(void)evaluateOrDefault(ctx.evaluator,
2150-
ExpandSynthesizedMemberMacroRequest{ext},
2151-
false);
2152-
}
2153-
21542198
// Look for results within the current nominal type and its extensions.
21552199
bool currentIsProtocol = isa<ProtocolDecl>(current);
21562200
auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();

0 commit comments

Comments
 (0)