Skip to content

Commit 01e4c8d

Browse files
authored
[Macros] Use name lookup for lazy declaration macro expansion (swiftlang#63411)
- Use the name lookup table instead of adding members from a macro expansion to the parent decl context. - Require declaration macros to specify introduced names and used the declared names to guide macro expansions lazily.
1 parent 5d684fb commit 01e4c8d

19 files changed

+215
-67
lines changed

include/swift/AST/Attr.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2314,25 +2314,31 @@ class MacroRoleAttr final
23142314
MacroSyntax syntax;
23152315
MacroRole role;
23162316
unsigned numNames;
2317+
SourceLoc lParenLoc, rParenLoc;
23172318

23182319
MacroRoleAttr(SourceLoc atLoc, SourceRange range, MacroSyntax syntax,
2319-
MacroRole role, ArrayRef<MacroIntroducedDeclName> names,
2320-
bool implicit);
2320+
SourceLoc lParenLoc, MacroRole role,
2321+
ArrayRef<MacroIntroducedDeclName> names,
2322+
SourceLoc rParenLoc, bool implicit);
23212323

23222324
public:
23232325
static MacroRoleAttr *create(ASTContext &ctx, SourceLoc atLoc,
23242326
SourceRange range, MacroSyntax syntax,
2325-
MacroRole role,
2327+
SourceLoc lParenLoc, MacroRole role,
23262328
ArrayRef<MacroIntroducedDeclName> names,
2327-
bool implicit);
2329+
SourceLoc rParenLoc, bool implicit);
23282330

23292331
size_t numTrailingObjects(OverloadToken<MacroIntroducedDeclName>) const {
23302332
return numNames;
23312333
}
23322334

2335+
SourceLoc getLParenLoc() const { return lParenLoc; }
2336+
SourceLoc getRParenLoc() const { return rParenLoc; }
2337+
23332338
MacroSyntax getMacroSyntax() const { return syntax; }
23342339
MacroRole getMacroRole() const { return role; }
23352340
ArrayRef<MacroIntroducedDeclName> getNames() const;
2341+
bool hasNameKind(MacroIntroducedDeclNameKind kind) const;
23362342

23372343
static bool classof(const DeclAttribute *DA) {
23382344
return DA->getKind() == DAK_MacroRole;

include/swift/AST/Decl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8440,6 +8440,9 @@ class MacroDecl : public GenericContext, public ValueDecl {
84408440
/// Determine the contexts in which this macro can be applied.
84418441
MacroRoles getMacroRoles() const;
84428442

8443+
/// Retrieve the attribute that declared the given macro role.
8444+
const MacroRoleAttr *getMacroRoleAttr(MacroRole role) const;
8445+
84438446
/// Retrieve the definition of this macro.
84448447
MacroDefinition getDefinition() const;
84458448

include/swift/AST/DiagnosticsSema.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6918,7 +6918,7 @@ ERROR(macro_definition_unsupported,none,
69186918
"macro definitions other than '#externalMacro(...)' are unsupported", ())
69196919
ERROR(external_macro_arg_not_type_name,none,
69206920
"argument to `#externalMacro` must be a string literal naming "
6921-
"the external macro's %select{module|type}", (unsigned))
6921+
"the external macro's %select{module|type}0", (unsigned))
69226922
ERROR(attached_declaration_macro_not_supported,none,
69236923
"attached declaration macros are not yet supported", ())
69246924

lib/AST/Attr.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2390,23 +2390,26 @@ bool CustomAttr::isAttachedMacro(const Decl *decl) const {
23902390
}
23912391

23922392
MacroRoleAttr::MacroRoleAttr(SourceLoc atLoc, SourceRange range,
2393-
MacroSyntax syntax, MacroRole role,
2393+
MacroSyntax syntax, SourceLoc lParenLoc,
2394+
MacroRole role,
23942395
ArrayRef<MacroIntroducedDeclName> names,
2395-
bool implicit)
2396+
SourceLoc rParenLoc, bool implicit)
23962397
: DeclAttribute(DAK_MacroRole, atLoc, range, implicit),
2397-
syntax(syntax), role(role), numNames(names.size()) {
2398+
syntax(syntax), role(role), numNames(names.size()), lParenLoc(lParenLoc),
2399+
rParenLoc(rParenLoc) {
23982400
auto *trailingNamesBuffer = getTrailingObjects<MacroIntroducedDeclName>();
23992401
std::uninitialized_copy(names.begin(), names.end(), trailingNamesBuffer);
24002402
}
24012403

24022404
MacroRoleAttr *
24032405
MacroRoleAttr::create(ASTContext &ctx, SourceLoc atLoc, SourceRange range,
2404-
MacroSyntax syntax, MacroRole role,
2406+
MacroSyntax syntax, SourceLoc lParenLoc, MacroRole role,
24052407
ArrayRef<MacroIntroducedDeclName> names,
2406-
bool implicit) {
2408+
SourceLoc rParenLoc, bool implicit) {
24072409
unsigned size = totalSizeToAlloc<MacroIntroducedDeclName>(names.size());
24082410
auto *mem = ctx.Allocate(size, alignof(MacroRoleAttr));
2409-
return new (mem) MacroRoleAttr(atLoc, range, syntax, role, names, implicit);
2411+
return new (mem) MacroRoleAttr(atLoc, range, syntax, lParenLoc, role, names,
2412+
rParenLoc, implicit);
24102413
}
24112414

24122415
ArrayRef<MacroIntroducedDeclName> MacroRoleAttr::getNames() const {
@@ -2416,6 +2419,11 @@ ArrayRef<MacroIntroducedDeclName> MacroRoleAttr::getNames() const {
24162419
};
24172420
}
24182421

2422+
bool MacroRoleAttr::hasNameKind(MacroIntroducedDeclNameKind kind) const {
2423+
return llvm::find_if(getNames(), [kind](MacroIntroducedDeclName name) {
2424+
return name.getKind() == kind;
2425+
}) != getNames().end();
2426+
}
24192427

24202428
const DeclAttribute *
24212429
DeclAttributes::getEffectiveSendableAttr() const {

lib/AST/Decl.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9866,6 +9866,13 @@ MacroRoles MacroDecl::getMacroRoles() const {
98669866
return contexts;
98679867
}
98689868

9869+
const MacroRoleAttr *MacroDecl::getMacroRoleAttr(MacroRole role) const {
9870+
for (auto attr : getAttrs().getAttributes<MacroRoleAttr>())
9871+
if (attr->getMacroRole() == role)
9872+
return attr;
9873+
llvm_unreachable("Macro role not declared for this MacroDecl");
9874+
}
9875+
98699876
MacroDefinition MacroDecl::getDefinition() const {
98709877
return evaluateOrDefault(
98719878
getASTContext().evaluator,

lib/AST/NameLookup.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,6 +1206,10 @@ class swift::MemberLookupTable : public ASTAllocated<swift::MemberLookupTable> {
12061206
/// parent nominal type.
12071207
llvm::DenseSet<DeclBaseName> LazilyCompleteNames;
12081208

1209+
/// The set of names for which we have expanded relevant macros for in the
1210+
/// parent nominal type.
1211+
llvm::DenseSet<DeclName> LazilyCompleteNamesForMacroExpansion;
1212+
12091213
public:
12101214
/// Create a new member lookup table.
12111215
explicit MemberLookupTable(ASTContext &ctx);
@@ -1234,6 +1238,23 @@ class swift::MemberLookupTable : public ASTAllocated<swift::MemberLookupTable> {
12341238
LazilyCompleteNames.clear();
12351239
}
12361240

1241+
bool isLazilyCompleteForMacroExpansion(DeclName name) const {
1242+
// If we've already expanded macros for a simple name, we must have expanded
1243+
// all macros that produce names with the same base identifier.
1244+
bool isBaseNameComplete = name.isCompoundName() &&
1245+
isLazilyCompleteForMacroExpansion(DeclName(name.getBaseName()));
1246+
return isBaseNameComplete ||
1247+
LazilyCompleteNamesForMacroExpansion.contains(name);
1248+
}
1249+
1250+
void markLazilyCompleteForMacroExpansion(DeclName name) {
1251+
LazilyCompleteNamesForMacroExpansion.insert(name);
1252+
}
1253+
1254+
void clearLazilyCompleteForMacroExpansionCache() {
1255+
LazilyCompleteNamesForMacroExpansion.clear();
1256+
}
1257+
12371258
/// Iterator into the lookup table.
12381259
typedef LookupTable::iterator iterator;
12391260

@@ -1356,6 +1377,7 @@ void NominalTypeDecl::addedExtension(ExtensionDecl *ext) {
13561377
if (ext->hasLazyMembers()) {
13571378
table->addMembers(ext->getCurrentMembersWithoutLoading());
13581379
table->clearLazilyCompleteCache();
1380+
table->clearLazilyCompleteForMacroExpansionCache();
13591381
} else {
13601382
table->addMembers(ext->getMembers());
13611383
}
@@ -1483,6 +1505,55 @@ populateLookupTableEntryFromExtensions(ASTContext &ctx,
14831505
}
14841506
}
14851507

1508+
static void
1509+
populateLookupTableEntryFromMacroExpansions(ASTContext &ctx,
1510+
MemberLookupTable &table,
1511+
DeclName name,
1512+
NominalTypeDecl *dc) {
1513+
auto expandAndPopulate = [&](MacroExpansionDecl *med) {
1514+
auto expanded = evaluateOrDefault(med->getASTContext().evaluator,
1515+
ExpandMacroExpansionDeclRequest{med},
1516+
nullptr);
1517+
for (auto *decl : expanded)
1518+
table.addMember(decl);
1519+
};
1520+
1521+
for (auto *member : dc->getCurrentMembersWithoutLoading()) {
1522+
auto *med = dyn_cast<MacroExpansionDecl>(member);
1523+
if (!med)
1524+
continue;
1525+
auto macro = evaluateOrDefault(
1526+
ctx.evaluator, ResolveMacroRequest{med, MacroRole::Declaration, dc},
1527+
nullptr);
1528+
if (!macro)
1529+
continue;
1530+
auto *attr = macro->getMacroRoleAttr(MacroRole::Declaration);
1531+
// If a macro produces arbitrary names, we have to expand it to factor its
1532+
// expansion results into name lookup.
1533+
if (attr->hasNameKind(MacroIntroducedDeclNameKind::Arbitrary)) {
1534+
expandAndPopulate(med);
1535+
}
1536+
// Otherwise, we expand the macro if it has the same decl base name being
1537+
// looked for.
1538+
else {
1539+
auto it = llvm::find_if(attr->getNames(),
1540+
[&](const MacroIntroducedDeclName &introName) {
1541+
// FIXME: The `Named` kind of `MacroIntroducedDeclName` should store a
1542+
// `DeclName` instead of `Identifier`. This is so that we can compare
1543+
// base identifiers when the macro specifies a compound name.
1544+
// Currently only simple names are allowed in a `MacroRoleAttr`.
1545+
if (!name.isSpecial())
1546+
return introName.getIdentifier() == name.getBaseIdentifier();
1547+
else
1548+
return introName.getIdentifier().str() ==
1549+
name.getBaseName().userFacingName();
1550+
});
1551+
if (it != attr->getNames().end())
1552+
expandAndPopulate(med);
1553+
}
1554+
}
1555+
}
1556+
14861557
MemberLookupTable *NominalTypeDecl::getLookupTable() {
14871558
if (!LookupTable.getPointer()) {
14881559
auto &ctx = getASTContext();
@@ -1646,6 +1717,11 @@ DirectLookupRequest::evaluate(Evaluator &evaluator,
16461717
Table.markLazilyComplete(baseName);
16471718
}
16481719

1720+
if (!Table.isLazilyCompleteForMacroExpansion(name)) {
1721+
populateLookupTableEntryFromMacroExpansions(ctx, Table, name, decl);
1722+
Table.markLazilyCompleteForMacroExpansion(name);
1723+
}
1724+
16491725
// Look for a declaration with this name.
16501726
auto known = Table.find(name);
16511727
if (known == Table.end()) {

lib/IRGen/GenClass.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,11 +1776,6 @@ namespace {
17761776
llvm_unreachable("should not IRGen classes with missing members");
17771777
}
17781778

1779-
void visitMacroExpansionDecl(MacroExpansionDecl *med) {
1780-
for (auto *rewritten : med->getRewritten())
1781-
visit(rewritten);
1782-
}
1783-
17841779
void addIVarInitializer() {
17851780
if (auto fn = IGM.getAddrOfIVarInitDestroy(getClass(),
17861781
/*destroy*/ false,

lib/Parse/ParseDecl.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2391,7 +2391,8 @@ Parser::parseMacroRoleAttribute(
23912391

23922392
SourceRange range(Loc, argList->getEndLoc());
23932393
return makeParserResult(MacroRoleAttr::create(
2394-
Context, AtLoc, range, syntax, *role, names, /*isImplicit*/ false));
2394+
Context, AtLoc, range, syntax, argList->getLParenLoc(), *role, names,
2395+
argList->getRParenLoc(), /*isImplicit*/ false));
23952396
}
23962397

23972398
/// Guts of \c parseSingleAttrOption and \c parseSingleAttrOptionIdentifier.
@@ -3750,8 +3751,8 @@ ParserStatus Parser::parseDeclAttribute(
37503751
.fixItReplace(SourceRange(AtLoc, attrLoc), "@freestanding(expression)");
37513752
auto attr = MacroRoleAttr::create(
37523753
Context, AtLoc, SourceRange(AtLoc, attrLoc),
3753-
MacroSyntax::Freestanding, MacroRole::Expression, { },
3754-
/*isImplicit*/ false);
3754+
MacroSyntax::Freestanding, SourceLoc(), MacroRole::Expression, { },
3755+
SourceLoc(), /*isImplicit*/ false);
37553756
Attributes.add(attr);
37563757
return makeParserSuccess();
37573758
}

lib/SILGen/SILGenType.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,11 +1237,6 @@ class SILGenType : public TypeMemberVisitor<SILGenType> {
12371237
void visitMacroDecl(MacroDecl *md) {
12381238
llvm_unreachable("macros aren't allowed in types");
12391239
}
1240-
1241-
void visitMacroExpansionDecl(MacroExpansionDecl *med) {
1242-
for (auto *rewritten : med->getRewritten())
1243-
visit(rewritten);
1244-
}
12451240
};
12461241

12471242
} // end anonymous namespace
@@ -1415,11 +1410,6 @@ class SILGenExtension : public TypeMemberVisitor<SILGenExtension> {
14151410
void visitMacroDecl(MacroDecl *md) {
14161411
llvm_unreachable("macros aren't allowed in extensions");
14171412
}
1418-
1419-
void visitMacroExpansionDecl(MacroExpansionDecl *med) {
1420-
for (auto *rewritten : med->getRewritten())
1421-
visit(rewritten);
1422-
}
14231413
};
14241414

14251415
void SILGenModule::visitExtensionDecl(ExtensionDecl *ed) {

lib/Sema/TypeCheckDecl.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,10 +1609,13 @@ TypeChecker::lookupMacros(DeclContext *dc, DeclNameRef macroName,
16091609
UnqualifiedLookupDescriptor descriptor(macroName, moduleScopeDC);
16101610
auto lookup = evaluateOrDefault(
16111611
ctx.evaluator, UnqualifiedLookupRequest{descriptor}, {});
1612-
for (const auto &found : lookup.allResults())
1613-
if (auto macro = dyn_cast<MacroDecl>(found.getValueDecl()))
1614-
if (roles.contains(macro->getMacroRoles()))
1612+
for (const auto &found : lookup.allResults()) {
1613+
if (auto macro = dyn_cast<MacroDecl>(found.getValueDecl())) {
1614+
auto foundRoles = macro->getMacroRoles();
1615+
if (foundRoles && roles.contains(foundRoles))
16151616
choices.push_back(macro);
1617+
}
1618+
}
16161619
return choices;
16171620
}
16181621

0 commit comments

Comments
 (0)