Skip to content

Commit 7dca692

Browse files
authored
Merge pull request #64840 from DougGregor/macro-lookup-in-types
2 parents 25f26e2 + 706b3e1 commit 7dca692

10 files changed

+215
-66
lines changed

include/swift/AST/TypeOrExtensionDecl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323

2424
namespace swift {
2525

26+
class DeclContext;
27+
class IterableDeclContext;
28+
2629
/// Describes either a nominal type declaration or an extension
2730
/// declaration.
2831
struct TypeOrExtensionDecl {
@@ -38,6 +41,8 @@ struct TypeOrExtensionDecl {
3841
class Decl *getAsDecl() const;
3942
/// Return the contained *Decl as the DeclContext superclass.
4043
DeclContext *getAsDeclContext() const;
44+
/// Return the contained *Decl as the DeclContext superclass.
45+
IterableDeclContext *getAsIterableDeclContext() const;
4146
/// Return the contained NominalTypeDecl or that of the extended type
4247
/// in the ExtensionDecl.
4348
NominalTypeDecl *getBaseNominal() const;

lib/AST/Decl.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9895,6 +9895,14 @@ Decl *TypeOrExtensionDecl::getAsDecl() const {
98959895
DeclContext *TypeOrExtensionDecl::getAsDeclContext() const {
98969896
return getAsDecl()->getInnermostDeclContext();
98979897
}
9898+
9899+
IterableDeclContext *TypeOrExtensionDecl::getAsIterableDeclContext() const {
9900+
if (auto nominal = Decl.dyn_cast<NominalTypeDecl *>())
9901+
return nominal;
9902+
9903+
return Decl.get<ExtensionDecl *>();
9904+
}
9905+
98989906
NominalTypeDecl *TypeOrExtensionDecl::getBaseNominal() const {
98999907
return getAsDeclContext()->getSelfNominalTypeDecl();
99009908
}

lib/AST/NameLookup.cpp

Lines changed: 111 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1534,75 +1534,129 @@ 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.getBaseName());
1605+
}
1606+
1607+
bool shouldExpandForName(DeclName name) const {
1608+
return introducesArbitraryNames ||
1609+
allIntroducedNames.contains(name.getBaseName());
1610+
}
1611+
};
1612+
}
1613+
15371614
static void
15381615
populateLookupTableEntryFromMacroExpansions(ASTContext &ctx,
15391616
MemberLookupTable &table,
15401617
DeclName name,
1541-
NominalTypeDecl *dc) {
1542-
auto *moduleScopeCtx = dc->getModuleScopeContext();
1543-
auto *module = dc->getModuleContext();
1544-
for (auto *member : dc->getCurrentMembersWithoutLoading()) {
1618+
TypeOrExtensionDecl container) {
1619+
1620+
// Trigger the expansion of member macros on the container, if any of the
1621+
// names match.
1622+
{
1623+
MacroIntroducedNameTracker nameTracker;
1624+
auto decl = container.getAsDecl();
1625+
forEachPotentialAttachedMacro(decl, MacroRole::Member, nameTracker);
1626+
if (nameTracker.shouldExpandForName(name)) {
1627+
(void)evaluateOrDefault(
1628+
ctx.evaluator,
1629+
ExpandSynthesizedMemberMacroRequest{decl},
1630+
false);
1631+
}
1632+
}
1633+
1634+
auto dc = container.getAsDeclContext();
1635+
auto *module = dc->getParentModule();
1636+
auto idc = container.getAsIterableDeclContext();
1637+
for (auto *member : idc->getCurrentMembersWithoutLoading()) {
15451638
// Collect all macro introduced names, along with its corresponding macro
15461639
// reference. We need the macro reference to prevent adding auxiliary decls
15471640
// that weren't introduced by the macro.
1548-
llvm::SmallSet<DeclName, 4> allIntroducedNames;
1549-
bool introducesArbitraryNames = false;
1641+
MacroIntroducedNameTracker nameTracker;
15501642
if (auto *med = dyn_cast<MacroExpansionDecl>(member)) {
1551-
auto declRef = evaluateOrDefault(
1552-
ctx.evaluator, ResolveMacroRequest{med, dc},
1553-
nullptr);
1554-
if (!declRef)
1555-
continue;
1556-
auto *macro = dyn_cast<MacroDecl>(declRef.getDecl());
1557-
if (macro->getMacroRoleAttr(MacroRole::Declaration)
1558-
->hasNameKind(MacroIntroducedDeclNameKind::Arbitrary))
1559-
introducesArbitraryNames = true;
1560-
else {
1561-
SmallVector<DeclName, 4> introducedNames;
1562-
macro->getIntroducedNames(MacroRole::Declaration, nullptr,
1563-
introducedNames);
1564-
for (auto name : introducedNames)
1565-
allIntroducedNames.insert(name);
1566-
}
1643+
forEachPotentialResolvedMacro(
1644+
member->getModuleContext(), med->getMacroName(),
1645+
MacroRole::Declaration, nameTracker);
15671646
} else if (auto *vd = dyn_cast<ValueDecl>(member)) {
1568-
// We intentionally avoid calling `forEachAttachedMacro` in order to avoid
1569-
// a request cycle.
1570-
for (auto attrConst : member->getSemanticAttrs().getAttributes<CustomAttr>()) {
1571-
auto *attr = const_cast<CustomAttr *>(attrConst);
1572-
UnresolvedMacroReference macroRef(attr);
1573-
auto macroName = macroRef.getMacroName();
1574-
UnqualifiedLookupDescriptor lookupDesc{macroName, moduleScopeCtx};
1575-
auto lookup = evaluateOrDefault(
1576-
ctx.evaluator, UnqualifiedLookupRequest{lookupDesc}, {});
1577-
for (auto result : lookup.allResults()) {
1578-
auto *vd = result.getValueDecl();
1579-
auto *macro = dyn_cast<MacroDecl>(vd);
1580-
if (!macro)
1581-
continue;
1582-
auto *macroRoleAttr = macro->getMacroRoleAttr(MacroRole::Peer);
1583-
if (!macroRoleAttr)
1584-
continue;
1585-
if (macroRoleAttr->hasNameKind(
1586-
MacroIntroducedDeclNameKind::Arbitrary))
1587-
introducesArbitraryNames = true;
1588-
else {
1589-
SmallVector<DeclName, 4> introducedNames;
1590-
macro->getIntroducedNames(
1591-
MacroRole::Peer, dyn_cast<ValueDecl>(member), introducedNames);
1592-
for (auto name : introducedNames)
1593-
allIntroducedNames.insert(name);
1594-
}
1595-
}
1596-
}
1647+
nameTracker.attachedTo = dyn_cast<ValueDecl>(member);
1648+
forEachPotentialAttachedMacro(member, MacroRole::Peer, nameTracker);
15971649
}
1598-
// Expand macros based on the name.
1599-
if (introducesArbitraryNames || allIntroducedNames.contains(name))
1650+
1651+
// Expand macros on this member.
1652+
if (nameTracker.shouldExpandForName(name)) {
16001653
member->visitAuxiliaryDecls([&](Decl *decl) {
16011654
auto *sf = module->getSourceFileContainingLocation(decl->getLoc());
16021655
// Bail out if the auxiliary decl was not produced by a macro.
16031656
if (!sf || sf->Kind != SourceFileKind::MacroExpansion) return;
16041657
table.addMember(decl);
16051658
});
1659+
}
16061660
}
16071661
}
16081662

@@ -1773,6 +1827,10 @@ DirectLookupRequest::evaluate(Evaluator &evaluator,
17731827
if (!Table.isLazilyCompleteForMacroExpansion(macroExpansionKey)) {
17741828
populateLookupTableEntryFromMacroExpansions(
17751829
ctx, Table, macroExpansionKey, decl);
1830+
for (auto ext : decl->getExtensions()) {
1831+
populateLookupTableEntryFromMacroExpansions(
1832+
ctx, Table, macroExpansionKey, ext);
1833+
}
17761834
Table.markLazilyCompleteForMacroExpansion(macroExpansionKey);
17771835
}
17781836

@@ -2134,12 +2192,6 @@ QualifiedLookupRequest::evaluate(Evaluator &eval, const DeclContext *DC,
21342192
// Make sure we've resolved property wrappers, if we need them.
21352193
installPropertyWrapperMembersIfNeeded(current, member);
21362194

2137-
// Expand synthesized member macros.
2138-
auto &ctx = current->getASTContext();
2139-
(void)evaluateOrDefault(ctx.evaluator,
2140-
ExpandSynthesizedMemberMacroRequest{current},
2141-
false);
2142-
21432195
// Look for results within the current nominal type and its extensions.
21442196
bool currentIsProtocol = isa<ProtocolDecl>(current);
21452197
auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();

lib/Sema/LookupVisibleDecls.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,21 @@ static void doGlobalExtensionLookup(Type BaseType,
253253

254254
synthesizePropertyWrapperVariables(extension);
255255

256+
// Expand member macros.
257+
ASTContext &ctx = nominal->getASTContext();
258+
(void)evaluateOrDefault(
259+
ctx.evaluator,
260+
ExpandSynthesizedMemberMacroRequest{extension},
261+
false);
262+
263+
// Expand peer macros.
264+
for (auto *member : extension->getMembers()) {
265+
(void)evaluateOrDefault(
266+
ctx.evaluator,
267+
ExpandPeerMacroRequest{member},
268+
{});
269+
}
270+
256271
collectVisibleMemberDecls(CurrDC, LS, BaseType, extension, FoundDecls);
257272
}
258273

lib/Sema/TypeCheckMacros.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1258,7 +1258,7 @@ evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo, CustomAttr *attr,
12581258
if (auto nominal = dyn_cast<NominalTypeDecl>(attachedTo)) {
12591259
rightBraceLoc = nominal->getBraces().End;
12601260
} else {
1261-
auto ext = cast<ExtensionDecl>(parentDecl);
1261+
auto ext = cast<ExtensionDecl>(attachedTo);
12621262
rightBraceLoc = ext->getBraces().End;
12631263
}
12641264

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,37 @@ public struct AddMembers: MemberMacro {
554554
}
555555
}
556556

557+
public struct AddExtMembers: MemberMacro {
558+
public static func expansion(
559+
of node: AttributeSyntax,
560+
providingMembersOf decl: some DeclGroupSyntax,
561+
in context: some MacroExpansionContext
562+
) throws -> [DeclSyntax] {
563+
let uniqueClassName = context.createUniqueName("uniqueClass")
564+
565+
let instanceMethod: DeclSyntax =
566+
"""
567+
func extInstanceMethod() {}
568+
"""
569+
570+
let staticMethod: DeclSyntax =
571+
"""
572+
static func extStaticMethod() {}
573+
"""
574+
575+
let classDecl: DeclSyntax =
576+
"""
577+
class \(uniqueClassName) { }
578+
"""
579+
580+
return [
581+
instanceMethod,
582+
staticMethod,
583+
classDecl,
584+
]
585+
}
586+
}
587+
557588
public struct AddArbitraryMembers: MemberMacro {
558589
public static func expansion(
559590
of node: AttributeSyntax,

test/Macros/macro_expand.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,12 @@ func testFreestandingMacroExpansion() {
335335
}
336336
testFreestandingMacroExpansion()
337337

338+
// Explicit structs to force macros to be parsed as decl.
339+
struct ContainerOfNumberedStructs {
340+
#bitwidthNumberedStructs("MyIntOne")
341+
#bitwidthNumberedStructs("MyIntTwo")
342+
}
343+
338344
// Avoid re-type-checking declaration macro arguments.
339345
@freestanding(declaration)
340346
macro freestandingWithClosure<T>(_ value: T, body: (T) -> T) = #externalMacro(module: "MacroDefinition", type: "EmptyDeclarationMacro")

test/Macros/macro_expand_peers.swift

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,26 @@ struct S {
3636
}
3737
}
3838

39-
// CHECK-DUMP: @__swiftmacro_18macro_expand_peers1f1a3for_SSSi_SSSdtYaF20addCompletionHandlerfMp_.swift
40-
// CHECK-DUMP: func f(a: Int, for b: String, _ value: Double, completionHandler: @escaping (String) -> Void) {
41-
// CHECK-DUMP: Task {
42-
// CHECK-DUMP: completionHandler(await f(a: a, for: b, value))
43-
// CHECK-DUMP: }
44-
// CHECK-DUMP: }
39+
extension S {
40+
@addCompletionHandler
41+
func g(a: Int, for b: String, _ value: Double) async -> String {
42+
return b
43+
}
44+
45+
// CHECK-DUMP: @__swiftmacro_18macro_expand_peers1SV1g1a3for_SSSi_SSSdtYaF20addCompletionHandlerfMp_.swift
46+
// CHECK-DUMP: func f(a: Int, for b: String, _ value: Double, completionHandler: @escaping (String) -> Void) {
47+
// CHECK-DUMP: Task {
48+
// CHECK-DUMP: completionHandler(await f(a: a, for: b, value))
49+
// CHECK-DUMP: }
50+
// CHECK-DUMP: }
51+
52+
}
53+
54+
func useCompletionHandlerG(s: S, _ body: @escaping (String) -> Void) {
55+
s.g(a: 1, for: "hahaha local", 2.0) {
56+
body($0)
57+
}
58+
}
4559

4660
@addCompletionHandler
4761
func f(a: Int, for b: String, _ value: Double) async -> String {

test/Macros/macro_expand_synthesized_members.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,25 @@ struct S {
2323
}
2424
}
2525

26+
@attached(
27+
member,
28+
names: named(extInstanceMethod), named(extStaticMethod)
29+
)
30+
macro addExtMembers() = #externalMacro(module: "MacroDefinition", type: "AddExtMembers")
31+
32+
@addExtMembers
33+
extension S { }
34+
2635
let s = S()
2736

2837
// CHECK: synthesized method
2938
// CHECK: Storage
3039
s.useSynthesized()
3140

41+
// Members added via extension.
42+
s.extInstanceMethod()
43+
S.extStaticMethod()
44+
3245
@attached(member, names: arbitrary)
3346
macro addArbitraryMembers() = #externalMacro(module: "MacroDefinition", type: "AddArbitraryMembers")
3447

test/Macros/top_level_freestanding.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,8 @@ macro freestandingWithClosure<T>(_ value: T, body: (T) -> T) = #externalMacro(mo
5050
let x = $0
5151
return x
5252
}
53+
54+
struct HasInnerClosure {
55+
#freestandingWithClosure(0) { x in x }
56+
#freestandingWithClosure(1) { x in x }
57+
}

0 commit comments

Comments
 (0)