Skip to content

Commit 8f1f6bf

Browse files
committed
[Macros] Allow extension macros to specify conformances in the attached
attribute. (cherry picked from commit c867c7c)
1 parent 92fed81 commit 8f1f6bf

File tree

12 files changed

+132
-17
lines changed

12 files changed

+132
-17
lines changed

include/swift/AST/Attr.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2368,36 +2368,45 @@ class ObjCImplementationAttr final : public DeclAttribute {
23682368
/// which declares one of the roles that a given macro can inhabit.
23692369
class MacroRoleAttr final
23702370
: public DeclAttribute,
2371-
private llvm::TrailingObjects<MacroRoleAttr, MacroIntroducedDeclName> {
2371+
private llvm::TrailingObjects<MacroRoleAttr, MacroIntroducedDeclName,
2372+
TypeExpr *> {
23722373
friend TrailingObjects;
23732374

23742375
MacroSyntax syntax;
23752376
MacroRole role;
23762377
unsigned numNames;
2378+
unsigned numConformances;
23772379
SourceLoc lParenLoc, rParenLoc;
23782380

23792381
MacroRoleAttr(SourceLoc atLoc, SourceRange range, MacroSyntax syntax,
23802382
SourceLoc lParenLoc, MacroRole role,
23812383
ArrayRef<MacroIntroducedDeclName> names,
2384+
ArrayRef<TypeExpr *> conformances,
23822385
SourceLoc rParenLoc, bool implicit);
23832386

23842387
public:
23852388
static MacroRoleAttr *create(ASTContext &ctx, SourceLoc atLoc,
23862389
SourceRange range, MacroSyntax syntax,
23872390
SourceLoc lParenLoc, MacroRole role,
23882391
ArrayRef<MacroIntroducedDeclName> names,
2392+
ArrayRef<TypeExpr *> conformances,
23892393
SourceLoc rParenLoc, bool implicit);
23902394

23912395
size_t numTrailingObjects(OverloadToken<MacroIntroducedDeclName>) const {
23922396
return numNames;
23932397
}
23942398

2399+
size_t numTrailingObjects(OverloadToken<TypeExpr *>) const {
2400+
return numConformances;
2401+
}
2402+
23952403
SourceLoc getLParenLoc() const { return lParenLoc; }
23962404
SourceLoc getRParenLoc() const { return rParenLoc; }
23972405

23982406
MacroSyntax getMacroSyntax() const { return syntax; }
23992407
MacroRole getMacroRole() const { return role; }
24002408
ArrayRef<MacroIntroducedDeclName> getNames() const;
2409+
ArrayRef<TypeExpr *> getConformances() const;
24012410
bool hasNameKind(MacroIntroducedDeclNameKind kind) const;
24022411

24032412
static bool classof(const DeclAttribute *DA) {

lib/AST/Attr.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2480,23 +2480,32 @@ MacroRoleAttr::MacroRoleAttr(SourceLoc atLoc, SourceRange range,
24802480
MacroSyntax syntax, SourceLoc lParenLoc,
24812481
MacroRole role,
24822482
ArrayRef<MacroIntroducedDeclName> names,
2483+
ArrayRef<TypeExpr *> conformances,
24832484
SourceLoc rParenLoc, bool implicit)
24842485
: DeclAttribute(DAK_MacroRole, atLoc, range, implicit),
2485-
syntax(syntax), role(role), numNames(names.size()), lParenLoc(lParenLoc),
2486+
syntax(syntax), role(role), numNames(names.size()),
2487+
numConformances(conformances.size()), lParenLoc(lParenLoc),
24862488
rParenLoc(rParenLoc) {
24872489
auto *trailingNamesBuffer = getTrailingObjects<MacroIntroducedDeclName>();
24882490
std::uninitialized_copy(names.begin(), names.end(), trailingNamesBuffer);
2491+
2492+
auto *trailingConformancesBuffer = getTrailingObjects<TypeExpr *>();
2493+
std::uninitialized_copy(conformances.begin(), conformances.end(),
2494+
trailingConformancesBuffer);
24892495
}
24902496

24912497
MacroRoleAttr *
24922498
MacroRoleAttr::create(ASTContext &ctx, SourceLoc atLoc, SourceRange range,
24932499
MacroSyntax syntax, SourceLoc lParenLoc, MacroRole role,
24942500
ArrayRef<MacroIntroducedDeclName> names,
2501+
ArrayRef<TypeExpr *> conformances,
24952502
SourceLoc rParenLoc, bool implicit) {
2496-
unsigned size = totalSizeToAlloc<MacroIntroducedDeclName>(names.size());
2503+
unsigned size =
2504+
totalSizeToAlloc<MacroIntroducedDeclName, TypeExpr *>(
2505+
names.size(), conformances.size());
24972506
auto *mem = ctx.Allocate(size, alignof(MacroRoleAttr));
24982507
return new (mem) MacroRoleAttr(atLoc, range, syntax, lParenLoc, role, names,
2499-
rParenLoc, implicit);
2508+
conformances, rParenLoc, implicit);
25002509
}
25012510

25022511
ArrayRef<MacroIntroducedDeclName> MacroRoleAttr::getNames() const {
@@ -2506,6 +2515,13 @@ ArrayRef<MacroIntroducedDeclName> MacroRoleAttr::getNames() const {
25062515
};
25072516
}
25082517

2518+
ArrayRef<TypeExpr *> MacroRoleAttr::getConformances() const {
2519+
return {
2520+
getTrailingObjects<TypeExpr *>(),
2521+
numConformances
2522+
};
2523+
}
2524+
25092525
bool MacroRoleAttr::hasNameKind(MacroIntroducedDeclNameKind kind) const {
25102526
return llvm::find_if(getNames(), [kind](MacroIntroducedDeclName name) {
25112527
return name.getKind() == kind;

lib/IDETool/SyntacticMacroExpansion.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ MacroDecl *SyntacticMacroExpansionInstance::getSynthesizedMacroDecl(
163163

164164
auto *attr = MacroRoleAttr::create(ctx, /*atLoc=*/{}, /*range=*/{}, syntax,
165165
/*lParenLoc=*/{}, role, /*names=*/{},
166+
/*conformances=*/{},
166167
/*rParenLoc=*/{}, /*implicit=*/true);
167168
macro->getAttrs().add(attr);
168169
}

lib/Parse/ParseDecl.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2262,8 +2262,10 @@ Parser::parseMacroRoleAttribute(
22622262
SourceLoc rParenLoc;
22632263
Optional<MacroRole> role;
22642264
bool sawRole = false;
2265+
bool sawConformances = false;
22652266
bool sawNames = false;
22662267
SmallVector<MacroIntroducedDeclName, 2> names;
2268+
SmallVector<TypeExpr *, 2> conformances;
22672269
auto argumentsStatus = parseList(tok::r_paren, lParenLoc, rParenLoc,
22682270
/*AllowSepAfterLast=*/false,
22692271
diag::expected_rparen_expr_list,
@@ -2292,7 +2294,8 @@ Parser::parseMacroRoleAttribute(
22922294
parseOptionalArgumentLabel(fieldName, fieldNameLoc);
22932295

22942296
// If there is a field name, it better be 'names'.
2295-
if (!(fieldName.empty() || fieldName.is("names"))) {
2297+
if (!(fieldName.empty() || fieldName.is("names") ||
2298+
fieldName.is("conformances"))) {
22962299
diagnose(
22972300
fieldNameLoc, diag::macro_attribute_unknown_label, isAttached,
22982301
fieldName);
@@ -2302,7 +2305,7 @@ Parser::parseMacroRoleAttribute(
23022305

23032306
// If there is no field name and we haven't seen either names or the role,
23042307
// this is the role.
2305-
if (fieldName.empty() && !sawNames && !sawRole) {
2308+
if (fieldName.empty() && !sawConformances && !sawNames && !sawRole) {
23062309
// Whether we saw anything we tried to treat as a role.
23072310
sawRole = true;
23082311

@@ -2347,6 +2350,25 @@ Parser::parseMacroRoleAttribute(
23472350
return status;
23482351
}
23492352

2353+
if (fieldName.is("conformances") ||
2354+
(fieldName.empty() && sawConformances && !sawNames)) {
2355+
if (fieldName.is("conformances") && sawConformances) {
2356+
diagnose(fieldNameLoc.isValid() ? fieldNameLoc : Tok.getLoc(),
2357+
diag::macro_attribute_duplicate_label,
2358+
isAttached,
2359+
"conformances");
2360+
}
2361+
2362+
sawConformances = true;
2363+
2364+
// Parse the introduced conformances
2365+
auto type = parseType();
2366+
auto *typeExpr = new (Context) TypeExpr(type.get());
2367+
conformances.push_back(typeExpr);
2368+
2369+
return status;
2370+
}
2371+
23502372
// If the field name is empty and we haved seen "names", or the field name
23512373
// is "names" but we've already seen the argument label, complain.
23522374
if (fieldName.empty() != sawNames) {
@@ -2450,7 +2472,7 @@ Parser::parseMacroRoleAttribute(
24502472
SourceRange range(Loc, rParenLoc);
24512473
return makeParserResult(MacroRoleAttr::create(
24522474
Context, AtLoc, range, syntax, lParenLoc, *role, names,
2453-
rParenLoc, /*isImplicit*/ false));
2475+
conformances, rParenLoc, /*isImplicit*/ false));
24542476
}
24552477

24562478
/// Guts of \c parseSingleAttrOption and \c parseSingleAttrOptionIdentifier.
@@ -3822,7 +3844,7 @@ ParserStatus Parser::parseDeclAttribute(
38223844
auto attr = MacroRoleAttr::create(
38233845
Context, AtLoc, SourceRange(AtLoc, attrLoc),
38243846
MacroSyntax::Freestanding, SourceLoc(), MacroRole::Expression, { },
3825-
SourceLoc(), /*isImplicit*/ false);
3847+
/*conformances=*/{}, SourceLoc(), /*isImplicit*/ false);
38263848
Attributes.add(attr);
38273849
return makeParserSuccess();
38283850
}

lib/Sema/TypeCheckAttr.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7110,6 +7110,25 @@ void AttributeChecker::visitMacroRoleAttr(MacroRoleAttr *attr) {
71107110
break;
71117111
}
71127112
}
7113+
7114+
for (auto *typeExpr : attr->getConformances()) {
7115+
if (auto *typeRepr = typeExpr->getTypeRepr()) {
7116+
auto *dc = D->getDeclContext();
7117+
auto resolved =
7118+
TypeResolution::forInterface(
7119+
dc, TypeResolverContext::GenericRequirement,
7120+
/*unboundTyOpener*/ nullptr,
7121+
/*placeholderHandler*/ nullptr,
7122+
/*packElementOpener*/ nullptr)
7123+
.resolveType(typeRepr);
7124+
7125+
if (resolved->is<ErrorType>()) {
7126+
attr->setInvalid();
7127+
} else {
7128+
typeExpr->setType(MetatypeType::get(resolved));
7129+
}
7130+
}
7131+
}
71137132
}
71147133

71157134
namespace {

lib/Serialization/Deserialization.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2752,6 +2752,7 @@ getActualMacroRole(uint8_t context) {
27522752
CASE(Peer)
27532753
CASE(Conformance)
27542754
CASE(CodeItem)
2755+
CASE(Extension)
27552756
#undef CASE
27562757
}
27572758
return None;
@@ -5623,14 +5624,15 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() {
56235624
uint8_t rawMacroSyntax;
56245625
uint8_t rawMacroRole;
56255626
uint64_t numNames;
5627+
uint64_t numConformances;
56265628
ArrayRef<uint64_t> introducedDeclNames;
56275629
serialization::decls_block::MacroRoleDeclAttrLayout::
56285630
readRecord(scratch, isImplicit, rawMacroSyntax, rawMacroRole,
5629-
numNames, introducedDeclNames);
5631+
numNames, numConformances, introducedDeclNames);
56305632
auto role = *getActualMacroRole(rawMacroRole);
56315633
SmallVector<MacroIntroducedDeclName, 1> names;
56325634
unsigned nameIdx = 0;
5633-
while (nameIdx < introducedDeclNames.size()) {
5635+
while (nameIdx < numNames) {
56345636
auto kind = getActualMacroIntroducedDeclNameKind(
56355637
(uint8_t)introducedDeclNames[nameIdx++]);
56365638
auto baseName =
@@ -5655,10 +5657,22 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() {
56555657
names.push_back(MacroIntroducedDeclName(*kind, name));
56565658
}
56575659

5660+
introducedDeclNames = introducedDeclNames.slice(numNames);
5661+
SmallVector<TypeExpr *, 1> conformances;
5662+
for (TypeID conformanceID : introducedDeclNames) {
5663+
auto conformance = MF.getTypeChecked(conformanceID);
5664+
if (!conformance) {
5665+
return conformance.takeError();
5666+
}
5667+
5668+
conformances.push_back(
5669+
TypeExpr::createImplicit(conformance.get(), ctx));
5670+
}
5671+
56585672
Attr = MacroRoleAttr::create(
56595673
ctx, SourceLoc(), SourceRange(),
56605674
static_cast<MacroSyntax>(rawMacroSyntax), SourceLoc(), role, names,
5661-
SourceLoc(), isImplicit);
5675+
conformances, SourceLoc(), isImplicit);
56625676
break;
56635677
}
56645678

lib/Serialization/ModuleFormat.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 788; // PluginSearchOption
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 789; // extension macros
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///
@@ -638,7 +638,7 @@ enum class MacroRole : uint8_t {
638638
CodeItem,
639639
Extension,
640640
};
641-
using MacroRoleField = BCFixed<3>;
641+
using MacroRoleField = BCFixed<4>;
642642

643643
// These IDs must \em not be renumbered or reordered without incrementing
644644
// the module version.
@@ -2317,11 +2317,13 @@ namespace decls_block {
23172317
BCFixed<1>, // macro syntax
23182318
MacroRoleField, // macro role
23192319
BCVBR<5>, // number of names
2320+
BCVBR<5>, // number of conformances
23202321
BCArray<IdentifierIDField> // introduced names, where each is encoded as
23212322
// - introduced kind
23222323
// - base name
23232324
// - # of argument labels + 1 (or 0 if none)
23242325
// - argument labels
2326+
// trialed by introduced conformances
23252327
>;
23262328

23272329
#undef SYNTAX_SUGAR_TYPE_LAYOUT

lib/Serialization/Serialization.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3137,10 +3137,19 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
31373137
introducedDeclNames.push_back(S.addDeclBaseNameRef(label));
31383138
}
31393139

3140+
unsigned numNames = introducedDeclNames.size();
3141+
3142+
unsigned numConformances = 0;
3143+
for (auto conformance : theAttr->getConformances()) {
3144+
introducedDeclNames.push_back(
3145+
S.addTypeRef(conformance->getInstanceType()));
3146+
++numConformances;
3147+
}
3148+
31403149
MacroRoleDeclAttrLayout::emitRecord(
31413150
S.Out, S.ScratchRecord, abbrCode, theAttr->isImplicit(),
31423151
static_cast<uint8_t>(theAttr->getMacroSyntax()),
3143-
rawMacroRole, introducedDeclNames.size(),
3152+
rawMacroRole, numNames, numConformances,
31443153
introducedDeclNames);
31453154
return;
31463155
}

test/Macros/macro_expand_extensions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
// RUN: %target-codesign %t/main
1111
// RUN: %target-run %t/main | %FileCheck %s
1212

13-
@attached(extension, names: named(requirement))
13+
@attached(extension, conformances: P, names: named(requirement))
1414
macro DelegatedConformance() = #externalMacro(module: "MacroDefinition", type: "DelegatedConformanceMacro")
1515

1616
protocol P {

test/Serialization/Inputs/def_macro_plugin.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,23 @@ public struct ArbitraryMembersMacro: MemberMacro {
5151
]
5252
}
5353
}
54+
55+
public struct SendableMacro: ExtensionMacro {
56+
public static func expansion(
57+
of node: AttributeSyntax,
58+
attachedTo: some DeclGroupSyntax,
59+
providingExtensionsOf type: some TypeSyntaxProtocol,
60+
in context: some MacroExpansionContext
61+
) throws -> [ExtensionDeclSyntax] {
62+
let sendableExtension: DeclSyntax =
63+
"""
64+
extension \(type.trimmed): Sendable {}
65+
"""
66+
67+
guard let extensionDecl = sendableExtension.as(ExtensionDeclSyntax.self) else {
68+
return []
69+
}
70+
71+
return [extensionDecl]
72+
}
73+
}

0 commit comments

Comments
 (0)