Skip to content

Commit 10bd2c2

Browse files
committed
[Macros] Initial implementation of conformance macros.
1 parent f6c3aaa commit 10bd2c2

27 files changed

+261
-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

@@ -9808,6 +9823,9 @@ StringRef swift::getMacroRoleString(MacroRole role) {
98089823

98099824
case MacroRole::Peer:
98109825
return "peer";
9826+
9827+
case MacroRole::Conformance:
9828+
return "conformance";
98119829
}
98129830
}
98139831

@@ -9854,7 +9872,8 @@ static MacroRoles attachedMacroRoles = (MacroRoles() |
98549872
MacroRole::Accessor |
98559873
MacroRole::MemberAttribute |
98569874
MacroRole::Member |
9857-
MacroRole::Peer);
9875+
MacroRole::Peer |
9876+
MacroRole::Conformance);
98589877

98599878
bool swift::isFreestandingMacro(MacroRoles contexts) {
98609879
return bool(contexts & freestandingMacroRoles);
@@ -10033,6 +10052,7 @@ MacroDiscriminatorContext MacroDiscriminatorContext::getParentOf(
1003310052
case GeneratedSourceInfo::MemberAttributeMacroExpansion:
1003410053
case GeneratedSourceInfo::MemberMacroExpansion:
1003510054
case GeneratedSourceInfo::PeerMacroExpansion:
10055+
case GeneratedSourceInfo::ConformanceMacroExpansion:
1003610056
case GeneratedSourceInfo::PrettyPrinted:
1003710057
case GeneratedSourceInfo::ReplacedFunctionBody:
1003810058
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: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ enum MacroRole: UInt8 {
3939
case MemberAttribute = 0x08
4040
case Member = 0x10
4141
case Peer = 0x20
42+
case Conformance = 0x40
4243
}
4344

4445
/// Resolve a reference to type metadata into a macro, if posible.
@@ -457,6 +458,37 @@ func expandAttachedMacro(
457458
$0.trimmedDescription
458459
}.joined(separator: "\n\n")
459460

461+
case (let attachedMacro as ConformanceMacro.Type, .Conformance):
462+
guard let declGroup = declarationNode.asProtocol(DeclGroupSyntax.self),
463+
let identified = declarationNode.asProtocol(IdentifiedDeclSyntax.self) else {
464+
return 1
465+
}
466+
467+
// Local function to expand a conformance macro once we've opened up
468+
// the existential.
469+
func expandConformanceMacro<Node: DeclGroupSyntax>(
470+
_ node: Node
471+
) throws -> [(TypeSyntax, WhereClauseSyntax?)] {
472+
return try attachedMacro.expansion(
473+
of: sourceManager.detach(
474+
customAttrNode,
475+
foldingWith: OperatorTable.standardOperators
476+
),
477+
providingConformancesOf: sourceManager.detach(node),
478+
in: context
479+
)
480+
}
481+
482+
let conformances = try expandConformanceMacro(declGroup)
483+
484+
// Form a buffer of extension declarations to return to the caller.
485+
evaluatedSyntaxStr = conformances.map { typeSyntax, whereClause in
486+
let typeName = identified.identifier.trimmedDescription
487+
let protocolName = typeSyntax.trimmedDescription
488+
let whereClause = whereClause?.trimmedDescription ?? ""
489+
return "extension \(typeName) : \(protocolName) \(whereClause) {}"
490+
}.joined(separator: "\n\n")
491+
460492
default:
461493
print("\(macroPtr) does not conform to any known attached macro protocol")
462494
return 1

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
@@ -3900,7 +3900,8 @@ static bool isMacroExpansionNodeKind(Node::Kind kind) {
39003900
kind == Node::Kind::MemberAttributeAttachedMacroExpansion ||
39013901
kind == Node::Kind::FreestandingMacroExpansion ||
39023902
kind == Node::Kind::MemberAttachedMacroExpansion ||
3903-
kind == Node::Kind::PeerAttachedMacroExpansion;
3903+
kind == Node::Kind::PeerAttachedMacroExpansion ||
3904+
kind == Node::Kind::ConformanceAttachedMacroExpansion;
39043905
}
39053906

39063907
NodePointer Demangler::demangleMacroExpansion() {
@@ -3926,6 +3927,10 @@ NodePointer Demangler::demangleMacroExpansion() {
39263927
kind = Node::Kind::PeerAttachedMacroExpansion;
39273928
break;
39283929

3930+
case 'c':
3931+
kind = Node::Kind::ConformanceAttachedMacroExpansion;
3932+
break;
3933+
39293934
case 'u':
39303935
kind = Node::Kind::MacroExpansionUniqueName;
39313936
break;

lib/Demangling/NodePrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ class NodePrinter {
354354
case Node::Kind::ClangType:
355355
case Node::Kind::ClassMetadataBaseOffset:
356356
case Node::Kind::CFunctionPointer:
357+
case Node::Kind::ConformanceAttachedMacroExpansion:
357358
case Node::Kind::Constructor:
358359
case Node::Kind::CoroutineContinuationPrototype:
359360
case Node::Kind::CurryThunk:
@@ -1362,6 +1363,10 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth,
13621363
return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
13631364
/*hasName*/true, "peer macro expansion #",
13641365
(int)Node->getChild(2)->getIndex() + 1);
1366+
case Node::Kind::ConformanceAttachedMacroExpansion:
1367+
return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
1368+
/*hasName*/true, "conformance macro expansion #",
1369+
(int)Node->getChild(2)->getIndex() + 1);
13651370
case Node::Kind::MacroExpansionUniqueName:
13661371
return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
13671372
/*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
@@ -2912,6 +2912,14 @@ ManglingError Remangler::manglePeerAttachedMacroExpansion(
29122912
return mangleChildNode(node, 2, depth + 1);
29132913
}
29142914

2915+
ManglingError Remangler::mangleConformanceAttachedMacroExpansion(
2916+
Node *node, unsigned depth) {
2917+
RETURN_IF_ERROR(mangleChildNode(node, 0, depth + 1));
2918+
RETURN_IF_ERROR(mangleChildNode(node, 1, depth + 1));
2919+
Buffer << "fMc";
2920+
return mangleChildNode(node, 2, depth + 1);
2921+
}
2922+
29152923
ManglingError Remangler::mangleMacroExpansionUniqueName(
29162924
Node *node, unsigned depth) {
29172925
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
@@ -8624,7 +8624,8 @@ static StringRef adjustMacroExpansionWhitespace(
86248624
return scratch;
86258625

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

0 commit comments

Comments
 (0)