Skip to content

Commit a3caacd

Browse files
committed
[Macros] Initial implementation of conformance macros.
1 parent fedf86f commit a3caacd

27 files changed

+265
-8
lines changed

include/swift/AST/MacroDeclaration.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ enum class MacroRole: uint32_t {
5252
/// An attached macro that generates declarations that are peers
5353
/// of the declaration the macro is attached to.
5454
Peer = 0x20,
55+
/// An attached macro that adds conformances to the declaration the
56+
/// macro is attached to.
57+
Conformance = 0x40,
5558
};
5659

5760
/// The contexts in which a particular macro declaration can be used.

include/swift/AST/TypeCheckRequests.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3848,6 +3848,26 @@ class ExpandAccessorMacros
38483848
bool isCached() const { return true; }
38493849
};
38503850

3851+
/// Expand all conformance macros attached to the given declaration.
3852+
///
3853+
/// Produces the set of macro expansion buffer IDs.
3854+
class ExpandConformanceMacros
3855+
: public SimpleRequest<ExpandConformanceMacros,
3856+
ArrayRef<unsigned>(NominalTypeDecl *),
3857+
RequestFlags::Cached> {
3858+
public:
3859+
using SimpleRequest::SimpleRequest;
3860+
3861+
private:
3862+
friend SimpleRequest;
3863+
3864+
ArrayRef<unsigned> evaluate(Evaluator &evaluator,
3865+
NominalTypeDecl *nominal) const;
3866+
3867+
public:
3868+
bool isCached() const { return true; }
3869+
};
3870+
38513871
/// Expand all member attribute macros attached to the given
38523872
/// declaration.
38533873
///

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,9 @@ SWIFT_REQUEST(TypeChecker, ExpandMemberAttributeMacros,
437437
SWIFT_REQUEST(TypeChecker, ExpandAccessorMacros,
438438
ArrayRef<unsigned>(AbstractStorageDecl *),
439439
Cached, NoLocationInfo)
440+
SWIFT_REQUEST(TypeChecker, ExpandConformanceMacros,
441+
ArrayRef<unsigned>(NominalTypeDecl *),
442+
Cached, NoLocationInfo)
440443
SWIFT_REQUEST(TypeChecker, ExpandSynthesizedMemberMacroRequest,
441444
ArrayRef<unsigned>(Decl *),
442445
Cached, NoLocationInfo)

include/swift/Basic/SourceManager.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ class GeneratedSourceInfo {
5050
/// The expansion of an attached peer macro.
5151
PeerMacroExpansion,
5252

53+
/// The expansion of an attached conformance macro.
54+
ConformanceMacroExpansion,
55+
5356
/// A new function body that is replacing an existing function body.
5457
ReplacedFunctionBody,
5558

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ NODE(ClangType)
4949
CONTEXT_NODE(Class)
5050
NODE(ClassMetadataBaseOffset)
5151
NODE(ConcreteProtocolConformance)
52+
NODE(ConformanceAttachedMacroExpansion)
5253
CONTEXT_NODE(Constructor)
5354
NODE(CoroutineContinuationPrototype)
5455
CONTEXT_NODE(Deallocator)

lib/AST/ASTMangler.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3771,7 +3771,8 @@ void ASTMangler::appendMacroExpansionContext(
37713771
case GeneratedSourceInfo::AccessorMacroExpansion:
37723772
case GeneratedSourceInfo::MemberAttributeMacroExpansion:
37733773
case GeneratedSourceInfo::MemberMacroExpansion:
3774-
case GeneratedSourceInfo::PeerMacroExpansion: {
3774+
case GeneratedSourceInfo::PeerMacroExpansion:
3775+
case GeneratedSourceInfo::ConformanceMacroExpansion: {
37753776
auto decl = ASTNode::getFromOpaqueValue(generatedSourceInfo->astNode)
37763777
.get<Decl *>();
37773778
auto attr = generatedSourceInfo->attachedMacroCustomAttr;
@@ -3793,6 +3794,10 @@ void ASTMangler::appendMacroExpansionContext(
37933794
role = MacroRole::Peer;
37943795
break;
37953796

3797+
case GeneratedSourceInfo::ConformanceMacroExpansion:
3798+
role = MacroRole::Conformance;
3799+
break;
3800+
37963801
default:
37973802
llvm_unreachable("Unhandled macro role");
37983803
}
@@ -3851,6 +3856,10 @@ void ASTMangler::appendMacroExpansionOperator(
38513856
case MacroRole::Peer:
38523857
appendOperator("fMp", Index(discriminator));
38533858
break;
3859+
3860+
case MacroRole::Conformance:
3861+
appendOperator("fMc", Index(discriminator));
3862+
break;
38543863
}
38553864
}
38563865

lib/AST/ASTScopeCreation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ ASTSourceFileScope::ASTSourceFileScope(SourceFile *SF,
259259
case MacroRole::Accessor:
260260
case MacroRole::MemberAttribute:
261261
case MacroRole::Peer:
262+
case MacroRole::Conformance:
262263
parentLoc = expansion.getStartLoc();
263264
break;
264265
case MacroRole::Member: {

lib/AST/Decl.cpp

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -383,13 +383,14 @@ DeclAttributes Decl::getSemanticAttrs() const {
383383
void Decl::visitAuxiliaryDecls(AuxiliaryDeclCallback callback) const {
384384
auto &ctx = getASTContext();
385385
auto *mutableThis = const_cast<Decl *>(this);
386+
SourceManager &sourceMgr = ctx.SourceMgr;
387+
auto *moduleDecl = getModuleContext();
388+
386389
auto peerBuffers =
387390
evaluateOrDefault(ctx.evaluator,
388391
ExpandPeerMacroRequest{mutableThis},
389392
{});
390393

391-
SourceManager &sourceMgr = ctx.SourceMgr;
392-
auto *moduleDecl = getModuleContext();
393394
for (auto bufferID : peerBuffers) {
394395
auto startLoc = sourceMgr.getLocForBufferStart(bufferID);
395396
auto *sourceFile = moduleDecl->getSourceFileContainingLocation(startLoc);
@@ -398,6 +399,20 @@ void Decl::visitAuxiliaryDecls(AuxiliaryDeclCallback callback) const {
398399
}
399400
}
400401

402+
if (auto *nominal = dyn_cast<NominalTypeDecl>(mutableThis)) {
403+
auto conformanceBuffers =
404+
evaluateOrDefault(ctx.evaluator,
405+
ExpandConformanceMacros{nominal},
406+
{});
407+
for (auto bufferID : conformanceBuffers) {
408+
auto startLoc = sourceMgr.getLocForBufferStart(bufferID);
409+
auto *sourceFile = moduleDecl->getSourceFileContainingLocation(startLoc);
410+
for (auto *extension : sourceFile->getTopLevelDecls()) {
411+
callback(extension);
412+
}
413+
}
414+
}
415+
401416
// FIXME: fold VarDecl::visitAuxiliaryDecls into this.
402417
}
403418

@@ -9810,6 +9825,9 @@ StringRef swift::getMacroRoleString(MacroRole role) {
98109825

98119826
case MacroRole::Peer:
98129827
return "peer";
9828+
9829+
case MacroRole::Conformance:
9830+
return "conformance";
98139831
}
98149832
}
98159833

@@ -9856,7 +9874,8 @@ static MacroRoles attachedMacroRoles = (MacroRoles() |
98569874
MacroRole::Accessor |
98579875
MacroRole::MemberAttribute |
98589876
MacroRole::Member |
9859-
MacroRole::Peer);
9877+
MacroRole::Peer |
9878+
MacroRole::Conformance);
98609879

98619880
bool swift::isFreestandingMacro(MacroRoles contexts) {
98629881
return bool(contexts & freestandingMacroRoles);
@@ -10035,6 +10054,7 @@ MacroDiscriminatorContext MacroDiscriminatorContext::getParentOf(
1003510054
case GeneratedSourceInfo::MemberAttributeMacroExpansion:
1003610055
case GeneratedSourceInfo::MemberMacroExpansion:
1003710056
case GeneratedSourceInfo::PeerMacroExpansion:
10057+
case GeneratedSourceInfo::ConformanceMacroExpansion:
1003810058
case GeneratedSourceInfo::PrettyPrinted:
1003910059
case GeneratedSourceInfo::ReplacedFunctionBody:
1004010060
return origDC;

lib/AST/DiagnosticEngine.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1313,7 +1313,8 @@ std::vector<Diagnostic> DiagnosticEngine::getGeneratedSourceBufferNotes(
13131313
case GeneratedSourceInfo::AccessorMacroExpansion:
13141314
case GeneratedSourceInfo::MemberAttributeMacroExpansion:
13151315
case GeneratedSourceInfo::MemberMacroExpansion:
1316-
case GeneratedSourceInfo::PeerMacroExpansion: {
1316+
case GeneratedSourceInfo::PeerMacroExpansion:
1317+
case GeneratedSourceInfo::ConformanceMacroExpansion: {
13171318
SourceRange origRange = expansionNode.getSourceRange();
13181319
DeclName macroName;
13191320
if (auto customAttr = generatedInfo->attachedMacroCustomAttr) {

lib/AST/Module.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,9 @@ Optional<MacroRole> SourceFile::getFulfilledMacroRole() const {
931931
case GeneratedSourceInfo::PeerMacroExpansion:
932932
return MacroRole::Peer;
933933

934+
case GeneratedSourceInfo::ConformanceMacroExpansion:
935+
return MacroRole::Conformance;
936+
934937
case GeneratedSourceInfo::ReplacedFunctionBody:
935938
case GeneratedSourceInfo::PrettyPrinted:
936939
return None;

lib/ASTGen/Sources/ASTGen/Macros.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ enum MacroRole: UInt8 {
6262
case MemberAttribute = 0x08
6363
case Member = 0x10
6464
case Peer = 0x20
65+
case Conformance = 0x40
6566
}
6667

6768
extension String {
@@ -514,6 +515,8 @@ func expandAttachedMacro(
514515
expandedSource = expandedSources.joined(separator: " ")
515516
case .Peer:
516517
expandedSource = expandedSources.joined(separator: "\n\n")
518+
case .Conformance:
519+
expandedSource = expandedSources.joined(separator: "\n\n")
517520
case .Expression,
518521
.FreestandingDeclaration:
519522
fatalError("unreachable")
@@ -739,6 +742,39 @@ func expandAttachedMacroInProcess(
739742
$0.trimmedDescription
740743
}
741744

745+
case (let attachedMacro as ConformanceMacro.Type, .Conformance):
746+
guard let declGroup = declarationNode.asProtocol(DeclGroupSyntax.self),
747+
let identified = declarationNode.asProtocol(IdentifiedDeclSyntax.self) else {
748+
return nil
749+
}
750+
751+
// Local function to expand a conformance macro once we've opened up
752+
// the existential.
753+
func expandConformanceMacro<Node: DeclGroupSyntax>(
754+
_ node: Node
755+
) throws -> [(TypeSyntax, WhereClauseSyntax?)] {
756+
return try attachedMacro.expansion(
757+
of: sourceManager.detach(
758+
customAttrNode,
759+
foldingWith: OperatorTable.standardOperators
760+
),
761+
providingConformancesOf: sourceManager.detach(node),
762+
in: context
763+
)
764+
}
765+
766+
let conformances = try _openExistential(
767+
declGroup, do: expandConformanceMacro
768+
)
769+
770+
// Form a buffer of extension declarations to return to the caller.
771+
expandedSources = conformances.map { typeSyntax, whereClause in
772+
let typeName = identified.identifier.trimmedDescription
773+
let protocolName = typeSyntax.trimmedDescription
774+
let whereClause = whereClause?.trimmedDescription ?? ""
775+
return "extension \(typeName) : \(protocolName) \(whereClause) {}"
776+
}
777+
742778
default:
743779
print("\(macroPtr) does not conform to any known attached macro protocol")
744780
return nil

lib/Basic/SourceLoc.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ void SourceManager::setGeneratedSourceInfo(
379379
case GeneratedSourceInfo::MemberAttributeMacroExpansion:
380380
case GeneratedSourceInfo::MemberMacroExpansion:
381381
case GeneratedSourceInfo::PeerMacroExpansion:
382+
case GeneratedSourceInfo::ConformanceMacroExpansion:
382383
case GeneratedSourceInfo::PrettyPrinted:
383384
break;
384385

lib/Demangling/Demangler.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3934,7 +3934,8 @@ static bool isMacroExpansionNodeKind(Node::Kind kind) {
39343934
kind == Node::Kind::MemberAttributeAttachedMacroExpansion ||
39353935
kind == Node::Kind::FreestandingMacroExpansion ||
39363936
kind == Node::Kind::MemberAttachedMacroExpansion ||
3937-
kind == Node::Kind::PeerAttachedMacroExpansion;
3937+
kind == Node::Kind::PeerAttachedMacroExpansion ||
3938+
kind == Node::Kind::ConformanceAttachedMacroExpansion;
39383939
}
39393940

39403941
NodePointer Demangler::demangleMacroExpansion() {
@@ -3960,6 +3961,10 @@ NodePointer Demangler::demangleMacroExpansion() {
39603961
kind = Node::Kind::PeerAttachedMacroExpansion;
39613962
break;
39623963

3964+
case 'c':
3965+
kind = Node::Kind::ConformanceAttachedMacroExpansion;
3966+
break;
3967+
39633968
case 'u':
39643969
kind = Node::Kind::MacroExpansionUniqueName;
39653970
break;

lib/Demangling/NodePrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ class NodePrinter {
356356
case Node::Kind::ClangType:
357357
case Node::Kind::ClassMetadataBaseOffset:
358358
case Node::Kind::CFunctionPointer:
359+
case Node::Kind::ConformanceAttachedMacroExpansion:
359360
case Node::Kind::Constructor:
360361
case Node::Kind::CoroutineContinuationPrototype:
361362
case Node::Kind::CurryThunk:
@@ -1364,6 +1365,10 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth,
13641365
return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
13651366
/*hasName*/true, "peer macro expansion #",
13661367
(int)Node->getChild(2)->getIndex() + 1);
1368+
case Node::Kind::ConformanceAttachedMacroExpansion:
1369+
return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
1370+
/*hasName*/true, "conformance macro expansion #",
1371+
(int)Node->getChild(2)->getIndex() + 1);
13671372
case Node::Kind::MacroExpansionUniqueName:
13681373
return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
13691374
/*hasName*/true, "unique name #",

lib/Demangling/OldRemangler.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,13 @@ ManglingError Remangler::manglePeerAttachedMacroExpansion(
10981098
return mangleChildNodes(node, depth + 1);
10991099
}
11001100

1101+
ManglingError Remangler::mangleConformanceAttachedMacroExpansion(
1102+
Node *node, unsigned depth) {
1103+
Buffer << "fMc";
1104+
RETURN_IF_ERROR(mangleIndex(node, depth + 1));
1105+
return mangleChildNodes(node, depth + 1);
1106+
}
1107+
11011108
ManglingError Remangler::mangleMacroExpansionUniqueName(
11021109
Node *node, unsigned depth) {
11031110
Buffer << "fMu";

lib/Demangling/Remangler.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2924,6 +2924,14 @@ ManglingError Remangler::manglePeerAttachedMacroExpansion(
29242924
return mangleChildNode(node, 2, depth + 1);
29252925
}
29262926

2927+
ManglingError Remangler::mangleConformanceAttachedMacroExpansion(
2928+
Node *node, unsigned depth) {
2929+
RETURN_IF_ERROR(mangleChildNode(node, 0, depth + 1));
2930+
RETURN_IF_ERROR(mangleChildNode(node, 1, depth + 1));
2931+
Buffer << "fMc";
2932+
return mangleChildNode(node, 2, depth + 1);
2933+
}
2934+
29272935
ManglingError Remangler::mangleMacroExpansionUniqueName(
29282936
Node *node, unsigned depth) {
29292937
RETURN_IF_ERROR(mangleChildNode(node, 0, depth + 1));

lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2198,6 +2198,7 @@ static Optional<MacroRole> getMacroRole(
21982198
.Case("memberAttribute", MacroRole::MemberAttribute)
21992199
.Case("member", MacroRole::Member)
22002200
.Case("peer", MacroRole::Peer)
2201+
.Case("conformance", MacroRole::Conformance)
22012202
.Default(None);
22022203

22032204
if (!role) {

lib/Parse/ParseRequests.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,10 @@ SourceFileParsingResult ParseSourceFileRequest::evaluate(Evaluator &evaluator,
205205
} else {
206206
parser.parseTopLevelItems(items);
207207
}
208+
}
208209

210+
case GeneratedSourceInfo::ConformanceMacroExpansion: {
211+
parser.parseTopLevelItems(items);
209212
break;
210213
}
211214
}

lib/Parse/ParseStmt.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/AST/ASTWalker.h"
1818
#include "swift/AST/Attr.h"
1919
#include "swift/AST/Decl.h"
20+
#include "swift/AST/FileUnit.h"
2021
#include "swift/Basic/Defer.h"
2122
#include "swift/Basic/Version.h"
2223
#include "swift/Parse/IDEInspectionCallbacks.h"
@@ -299,7 +300,9 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
299300
BraceItemListKind ConditionalBlockKind,
300301
bool &IsFollowingGuard) {
301302
bool IsTopLevel = (Kind == BraceItemListKind::TopLevelCode) ||
302-
(Kind == BraceItemListKind::TopLevelLibrary);
303+
(Kind == BraceItemListKind::TopLevelLibrary ||
304+
(Kind == BraceItemListKind::MacroExpansion &&
305+
isa<FileUnit>(CurDeclContext)));
303306
bool isActiveConditionalBlock =
304307
ConditionalBlockKind == BraceItemListKind::ActiveConditionalBlock;
305308
bool isConditionalBlock = isActiveConditionalBlock ||

lib/Refactoring/Refactoring.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8625,7 +8625,8 @@ static StringRef adjustMacroExpansionWhitespace(
86258625
return scratch;
86268626

86278627
case GeneratedSourceInfo::PeerMacroExpansion:
8628-
// For peers, add a newline to create some separation.
8628+
case GeneratedSourceInfo::ConformanceMacroExpansion:
8629+
// For peers and conformances, add a newline to create some separation.
86298630
scratch += "\n";
86308631
LLVM_FALLTHROUGH;
86318632

0 commit comments

Comments
 (0)