Skip to content

Commit 7d181c1

Browse files
authored
Merge pull request #68372 from DougGregor/member-macro-conformances-5.9
2 parents e105aca + 61a975c commit 7d181c1

11 files changed

+148
-29
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
_**Note:** This is in reverse chronological order, so newer entries are added to the top._
44

5+
## Swift 5.9.2
6+
7+
* [SE-0407][]:
8+
9+
Member macros can specify a list of protocols via the `conformances` argument to the macro role. The macro implementation will be provided with those protocols that are listed but have not already been implemented by the type to which the member macro is attached, in the same manner as extension macros.
10+
11+
```swift
12+
@attached(member, conformances: Decodable, Encodable, names: named(init(from:), encode(to:)))
13+
@attached(extension, conformances: Decodable, Encodable, names: named(init(from:), encode(to:)))
14+
macro Codable() = #externalMacro(module: "MyMacros", type: "CodableMacro")
15+
```
16+
517
## Swift 5.9
618

719
* [SE-0382][], [SE-0389][], [SE-0394][], [SE-0397][]:
@@ -9830,6 +9842,7 @@ using the `.dynamicType` member to retrieve the type of an expression should mig
98309842
[SE-0389]: https://github.com/apple/swift-evolution/blob/main/proposals/0389-attached-macros.md
98319843
[SE-0394]: https://github.com/apple/swift-evolution/blob/main/proposals/0394-swiftpm-expression-macros.md
98329844
[SE-0397]: https://github.com/apple/swift-evolution/blob/main/proposals/0397-freestanding-declaration-macros.md
9845+
[SE-0407]: https://github.com/apple/swift-evolution/blob/main/proposals/0407-member-macro-conformances.md
98339846
[#64927]: <https://github.com/apple/swift/issues/64927>
98349847
[#42697]: <https://github.com/apple/swift/issues/42697>
98359848
[#42728]: <https://github.com/apple/swift/issues/42728>

include/swift/AST/Decl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8621,6 +8621,7 @@ class MacroDecl : public GenericContext, public ValueDecl {
86218621
/// be added if this macro does not contain an extension role.
86228622
void getIntroducedConformances(
86238623
NominalTypeDecl *attachedTo,
8624+
MacroRole role,
86248625
SmallVectorImpl<ProtocolDecl *> &conformances) const;
86258626

86268627
/// Returns a DeclName that represents arbitrary names.

include/swift/AST/TypeCheckRequests.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3337,10 +3337,10 @@ class ResolveMacroRequest
33373337
void noteCycleStep(DiagnosticEngine &diags) const;
33383338
};
33393339

3340-
/// Returns the resolved constraint types that an extension macro
3341-
/// adds conformances to.
3342-
class ResolveExtensionMacroConformances
3343-
: public SimpleRequest<ResolveExtensionMacroConformances,
3340+
/// Returns the resolved constraint types that a macro references conformances
3341+
/// to.
3342+
class ResolveMacroConformances
3343+
: public SimpleRequest<ResolveMacroConformances,
33443344
ArrayRef<Type>(const MacroRoleAttr *, const Decl *),
33453345
RequestFlags::Cached> {
33463346
public:

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ SWIFT_REQUEST(TypeChecker, ResolveImplicitMemberRequest,
360360
SWIFT_REQUEST(TypeChecker, ResolveMacroRequest,
361361
ConcreteDeclRef(UnresolvedMacroReference, const Decl *),
362362
Cached, NoLocationInfo)
363-
SWIFT_REQUEST(TypeChecker, ResolveExtensionMacroConformances,
363+
SWIFT_REQUEST(TypeChecker, ResolveMacroConformances,
364364
ArrayRef<Type>(const MacroRoleAttr *, const Decl *),
365365
Cached, NoLocationInfo)
366366
SWIFT_REQUEST(TypeChecker, ResolveTypeEraserTypeRequest,

lib/AST/Attr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1387,7 +1387,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
13871387
// Print conformances, if present.
13881388
auto conformances = evaluateOrDefault(
13891389
D->getASTContext().evaluator,
1390-
ResolveExtensionMacroConformances{Attr, D},
1390+
ResolveMacroConformances{Attr, D},
13911391
{});
13921392
if (!conformances.empty()) {
13931393
Printer << ", conformances: ";

lib/AST/ConformanceLookupTable.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,8 @@ void ConformanceLookupTable::addMacroGeneratedProtocols(
503503
MacroRole::Extension,
504504
[&](CustomAttr *attr, MacroDecl *macro) {
505505
SmallVector<ProtocolDecl *, 2> conformances;
506-
macro->getIntroducedConformances(nominal, conformances);
506+
macro->getIntroducedConformances(
507+
nominal, MacroRole::Extension, conformances);
507508

508509
for (auto *protocol : conformances) {
509510
addProtocol(protocol, attr->getLocation(), source);

lib/AST/Decl.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10826,15 +10826,16 @@ void MacroDecl::getIntroducedNames(MacroRole role, ValueDecl *attachedTo,
1082610826

1082710827
void MacroDecl::getIntroducedConformances(
1082810828
NominalTypeDecl *attachedTo,
10829+
MacroRole role,
1082910830
SmallVectorImpl<ProtocolDecl *> &conformances) const {
10830-
auto *attr = getMacroRoleAttr(MacroRole::Extension);
10831+
auto *attr = getMacroRoleAttr(role);
1083110832
if (!attr)
1083210833
return;
1083310834

1083410835
auto &ctx = getASTContext();
1083510836
auto constraintTypes = evaluateOrDefault(
1083610837
ctx.evaluator,
10837-
ResolveExtensionMacroConformances{attr, this},
10838+
ResolveMacroConformances{attr, this},
1083810839
{});
1083910840

1084010841
for (auto constraint : constraintTypes) {

lib/Sema/TypeCheckAttr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7151,7 +7151,7 @@ void AttributeChecker::visitMacroRoleAttr(MacroRoleAttr *attr) {
71517151

71527152
(void)evaluateOrDefault(
71537153
Ctx.evaluator,
7154-
ResolveExtensionMacroConformances{attr, D},
7154+
ResolveMacroConformances{attr, D},
71557155
{});
71567156
}
71577157

lib/Sema/TypeCheckMacros.cpp

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,12 +1538,56 @@ swift::expandAttributes(CustomAttr *attr, MacroDecl *macro, Decl *member) {
15381538
return macroSourceFile->getBufferID();
15391539
}
15401540

1541+
// Collect the protocol conformances that the macro asked about but were
1542+
// not already present on the declaration.
1543+
static TinyPtrVector<ProtocolDecl *> getIntroducedConformances(
1544+
NominalTypeDecl *nominal, MacroRole role, MacroDecl *macro,
1545+
SmallVectorImpl<ProtocolDecl *> *potentialConformances = nullptr) {
1546+
SmallVector<ProtocolDecl *, 2> potentialConformancesBuffer;
1547+
if (!potentialConformances)
1548+
potentialConformances = &potentialConformancesBuffer;
1549+
macro->getIntroducedConformances(nominal, role, *potentialConformances);
1550+
1551+
TinyPtrVector<ProtocolDecl *> introducedConformances;
1552+
for (auto protocol : *potentialConformances) {
1553+
SmallVector<ProtocolConformance *, 2> existingConformances;
1554+
nominal->lookupConformance(protocol, existingConformances);
1555+
1556+
bool hasExistingConformance = llvm::any_of(
1557+
existingConformances,
1558+
[&](ProtocolConformance *conformance) {
1559+
return conformance->getSourceKind() !=
1560+
ConformanceEntryKind::PreMacroExpansion;
1561+
});
1562+
1563+
if (!hasExistingConformance) {
1564+
introducedConformances.push_back(protocol);
1565+
}
1566+
}
1567+
1568+
return introducedConformances;
1569+
}
1570+
15411571
llvm::Optional<unsigned> swift::expandMembers(CustomAttr *attr,
15421572
MacroDecl *macro, Decl *decl) {
1573+
auto nominal = dyn_cast<NominalTypeDecl>(decl);
1574+
if (!nominal) {
1575+
auto ext = dyn_cast<ExtensionDecl>(decl);
1576+
if (!ext)
1577+
return llvm::None;
1578+
1579+
nominal = ext->getExtendedNominal();
1580+
if (!nominal)
1581+
return llvm::None;
1582+
}
1583+
auto introducedConformances = getIntroducedConformances(
1584+
nominal, MacroRole::Member, macro);
1585+
15431586
// Evaluate the macro.
15441587
auto macroSourceFile =
15451588
::evaluateAttachedMacro(macro, decl, attr,
1546-
/*passParentContext=*/false, MacroRole::Member);
1589+
/*passParentContext=*/false, MacroRole::Member,
1590+
introducedConformances);
15471591
if (!macroSourceFile)
15481592
return llvm::None;
15491593

@@ -1616,22 +1660,9 @@ llvm::Optional<unsigned> swift::expandExtensions(CustomAttr *attr,
16161660
return llvm::None;
16171661
}
16181662

1619-
// Collect the protocol conformances that the macro can add. The
1620-
// macro should not add conformances that are already stated in
1621-
// the original source.
1622-
16231663
SmallVector<ProtocolDecl *, 2> potentialConformances;
1624-
macro->getIntroducedConformances(nominal, potentialConformances);
1625-
1626-
SmallVector<ProtocolDecl *, 2> introducedConformances;
1627-
for (auto protocol : potentialConformances) {
1628-
SmallVector<ProtocolConformance *, 2> existingConformances;
1629-
nominal->lookupConformance(protocol, existingConformances);
1630-
if (existingConformances.empty()) {
1631-
introducedConformances.push_back(protocol);
1632-
}
1633-
}
1634-
1664+
auto introducedConformances = getIntroducedConformances(
1665+
nominal, MacroRole::Extension, macro, &potentialConformances);
16351666
auto macroSourceFile = ::evaluateAttachedMacro(macro, nominal, attr,
16361667
/*passParentContext=*/false,
16371668
role, introducedConformances);
@@ -1820,9 +1851,9 @@ ConcreteDeclRef ResolveMacroRequest::evaluate(Evaluator &evaluator,
18201851
}
18211852

18221853
ArrayRef<Type>
1823-
ResolveExtensionMacroConformances::evaluate(Evaluator &evaluator,
1824-
const MacroRoleAttr *attr,
1825-
const Decl *decl) const {
1854+
ResolveMacroConformances::evaluate(Evaluator &evaluator,
1855+
const MacroRoleAttr *attr,
1856+
const Decl *decl) const {
18261857
auto *dc = decl->getDeclContext();
18271858
auto &ctx = dc->getASTContext();
18281859

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2018,3 +2018,53 @@ public struct InitWithProjectedValueWrapperMacro: PeerMacro {
20182018
]
20192019
}
20202020
}
2021+
2022+
public struct RequiredDefaultInitMacro: ExtensionMacro {
2023+
public static func expansion(
2024+
of node: AttributeSyntax,
2025+
attachedTo decl: some DeclGroupSyntax,
2026+
providingExtensionsOf type: some TypeSyntaxProtocol,
2027+
conformingTo protocols: [TypeSyntax],
2028+
in context: some MacroExpansionContext
2029+
) throws -> [ExtensionDeclSyntax] {
2030+
if protocols.isEmpty {
2031+
return []
2032+
}
2033+
2034+
let decl: DeclSyntax =
2035+
"""
2036+
extension \(type.trimmed): DefaultInit {
2037+
}
2038+
2039+
"""
2040+
2041+
return [
2042+
decl.cast(ExtensionDeclSyntax.self)
2043+
]
2044+
}
2045+
}
2046+
2047+
extension RequiredDefaultInitMacro: MemberMacro {
2048+
public static func expansion(
2049+
of node: AttributeSyntax,
2050+
providingMembersOf declaration: some DeclGroupSyntax,
2051+
in context: some MacroExpansionContext
2052+
) throws -> [DeclSyntax] {
2053+
fatalError("old swift-syntax")
2054+
}
2055+
2056+
public static func expansion(
2057+
of node: AttributeSyntax,
2058+
providingMembersOf declaration: some DeclGroupSyntax,
2059+
conformingTo protocols: [TypeSyntax],
2060+
in context: some MacroExpansionContext
2061+
) throws -> [DeclSyntax] {
2062+
let decl: DeclSyntax
2063+
if declaration.is(ClassDeclSyntax.self) && protocols.isEmpty {
2064+
decl = "required init() { }"
2065+
} else {
2066+
decl = "init() { }"
2067+
}
2068+
return [ decl ]
2069+
}
2070+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// REQUIRES: swift_swift_parser
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath
5+
6+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature ExtensionMacros -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) -module-name MacroUser -DTEST_DIAGNOSTICS -swift-version 5 -I %t
7+
protocol DefaultInit {
8+
init()
9+
}
10+
11+
@attached(extension, conformances: DefaultInit)
12+
@attached(member, conformances: DefaultInit, names: named(init()))
13+
macro DefaultInit() = #externalMacro(module: "MacroDefinition", type: "RequiredDefaultInitMacro")
14+
15+
@DefaultInit
16+
class C { }
17+
18+
@DefaultInit
19+
class D: C { }
20+
21+
@DefaultInit
22+
struct E { }

0 commit comments

Comments
 (0)