Skip to content

Commit 7ad9d89

Browse files
authored
Merge pull request #41640 from slavapestov/primary-associated-type-syntax
New syntax for declaring primary associated types
2 parents f93bc64 + 20ccd05 commit 7ad9d89

21 files changed

+313
-42
lines changed

include/swift/AST/Attr.def

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -661,10 +661,7 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(distributed, DistributedActor,
661661
APIBreakingToAdd | APIBreakingToRemove,
662662
118)
663663

664-
SIMPLE_DECL_ATTR(_primaryAssociatedType,
665-
PrimaryAssociatedType, OnAssociatedType | UserInaccessible |
666-
APIStableToAdd | ABIStableToAdd | APIBreakingToRemove | ABIStableToRemove,
667-
119)
664+
// 119 is unused
668665

669666
SIMPLE_DECL_ATTR(_assemblyVision, EmitAssemblyVisionRemarks,
670667
OnFunc | UserInaccessible | NotSerialized | OnNominalType |

include/swift/AST/Decl.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,11 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
505505
IsOpaqueType : 1
506506
);
507507

508+
SWIFT_INLINE_BITFIELD_FULL(AssociatedTypeDecl, AbstractTypeParamDecl, 1,
509+
/// Whether this is a primary associated type.
510+
IsPrimary : 1
511+
);
512+
508513
SWIFT_INLINE_BITFIELD_EMPTY(GenericTypeDecl, TypeDecl);
509514

510515
SWIFT_INLINE_BITFIELD(TypeAliasDecl, GenericTypeDecl, 1+1,
@@ -3206,6 +3211,14 @@ class AssociatedTypeDecl : public AbstractTypeParamDecl {
32063211
LazyMemberLoader *definitionResolver,
32073212
uint64_t resolverData);
32083213

3214+
bool isPrimary() const {
3215+
return Bits.AssociatedTypeDecl.IsPrimary;
3216+
}
3217+
3218+
void setPrimary() {
3219+
Bits.AssociatedTypeDecl.IsPrimary = true;
3220+
}
3221+
32093222
/// Get the protocol in which this associated type is declared.
32103223
ProtocolDecl *getProtocol() const {
32113224
return cast<ProtocolDecl>(getDeclContext());

include/swift/AST/DiagnosticsParse.def

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1797,8 +1797,14 @@ ERROR(redundant_class_requirement,none,
17971797
ERROR(late_class_requirement,none,
17981798
"'class' must come first in the requirement list", ())
17991799
ERROR(where_inside_brackets,none,
1800-
"'where' clause next to generic parameters is obsolete, "
1801-
"must be written following the declaration's type", ())
1800+
"'where' clause next to generic parameters is obsolete, "
1801+
"must be written following the declaration's type", ())
1802+
1803+
1804+
ERROR(expected_rangle_primary_associated_type_list,PointsToFirstBadToken,
1805+
"expected '>' to complete primary associated type list", ())
1806+
ERROR(expected_primary_associated_type_name,PointsToFirstBadToken,
1807+
"expected an identifier to name primary associated type", ())
18021808

18031809
//------------------------------------------------------------------------------
18041810
// MARK: Conditional compilation parsing diagnostics

include/swift/AST/PrintOptions.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,12 @@ struct PrintOptions {
511511
QualifyNestedDeclarations ShouldQualifyNestedDeclarations =
512512
QualifyNestedDeclarations::Never;
513513

514+
/// If true, we print a protocol's primary associated types using the
515+
/// primary associated type syntax: protocol Foo<Type1, ...>.
516+
///
517+
/// If false, we print them as ordinary associated types.
518+
bool PrintPrimaryAssociatedTypes = true;
519+
514520
/// If this is not \c nullptr then function bodies (including accessors
515521
/// and constructors) will be printed by this function.
516522
std::function<void(const ValueDecl *, ASTPrinter &)> FunctionBody;

include/swift/Basic/Features.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,6 @@ LANGUAGE_FEATURE(BuiltinStackAlloc, 0, "Builtin.stackAlloc", true)
7474
SUPPRESSIBLE_LANGUAGE_FEATURE(SpecializeAttributeWithAvailability, 0, "@_specialize attribute with availability", true)
7575
LANGUAGE_FEATURE(BuiltinAssumeAlignment, 0, "Builtin.assumeAlignment", true)
7676
SUPPRESSIBLE_LANGUAGE_FEATURE(UnsafeInheritExecutor, 0, "@_unsafeInheritExecutor", true)
77-
77+
SUPPRESSIBLE_LANGUAGE_FEATURE(PrimaryAssociatedTypes, 0, "Primary associated types", true)
7878
#undef SUPPRESSIBLE_LANGUAGE_FEATURE
7979
#undef LANGUAGE_FEATURE

include/swift/Parse/Parser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,9 @@ class Parser {
11991199
void parseAbstractFunctionBody(AbstractFunctionDecl *AFD);
12001200
BodyAndFingerprint
12011201
parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD);
1202+
1203+
ParserStatus parsePrimaryAssociatedTypes(
1204+
SmallVectorImpl<AssociatedTypeDecl *> &AssocTypes);
12021205
ParserResult<ProtocolDecl> parseDeclProtocol(ParseDeclOptions Flags,
12031206
DeclAttributes &Attributes);
12041207

lib/AST/ASTPrinter.cpp

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,7 @@ class PrintAST : public ASTVisitor<PrintAST> {
892892
bool openBracket = true, bool closeBracket = true);
893893
void printGenericDeclGenericParams(GenericContext *decl);
894894
void printDeclGenericRequirements(GenericContext *decl);
895+
void printPrimaryAssociatedTypes(ProtocolDecl *decl);
895896
void printBodyIfNecessary(const AbstractFunctionDecl *decl);
896897

897898
void printEnumElement(EnumElementDecl *elt);
@@ -1380,7 +1381,8 @@ struct RequirementPrintLocation {
13801381
/// function does: asking "where should this requirement be printed?" and then
13811382
/// callers check if the location is the ATD.
13821383
static RequirementPrintLocation
1383-
bestRequirementPrintLocation(ProtocolDecl *proto, const Requirement &req) {
1384+
bestRequirementPrintLocation(ProtocolDecl *proto, const Requirement &req,
1385+
PrintOptions opts, bool inheritanceClause) {
13841386
auto protoSelf = proto->getProtocolSelfType();
13851387
// Returns the most relevant decl within proto connected to outerType (or null
13861388
// if one doesn't exist), and whether the type is an "direct use",
@@ -1397,6 +1399,7 @@ bestRequirementPrintLocation(ProtocolDecl *proto, const Requirement &req) {
13971399
return true;
13981400
} else if (auto DMT = t->getAs<DependentMemberType>()) {
13991401
auto assocType = DMT->getAssocType();
1402+
14001403
if (assocType && assocType->getProtocol() == proto) {
14011404
relevantDecl = assocType;
14021405
foundType = t;
@@ -1411,6 +1414,17 @@ bestRequirementPrintLocation(ProtocolDecl *proto, const Requirement &req) {
14111414
// If we didn't find anything, relevantDecl and foundType will be null, as
14121415
// desired.
14131416
auto directUse = foundType && outerType->isEqual(foundType);
1417+
1418+
// Prefer to attach requirements to associated type declarations,
1419+
// unless the associated type is a primary associated type and
1420+
// we're printing primary associated types using the new syntax.
1421+
if (!directUse &&
1422+
relevantDecl &&
1423+
opts.PrintPrimaryAssociatedTypes &&
1424+
isa<AssociatedTypeDecl>(relevantDecl) &&
1425+
cast<AssociatedTypeDecl>(relevantDecl)->isPrimary())
1426+
relevantDecl = proto;
1427+
14141428
return std::make_pair(relevantDecl, directUse);
14151429
};
14161430

@@ -1481,7 +1495,8 @@ void PrintAST::printInheritedFromRequirementSignature(ProtocolDecl *proto,
14811495
return false;
14821496
}
14831497

1484-
auto location = bestRequirementPrintLocation(proto, req);
1498+
auto location = bestRequirementPrintLocation(proto, req, Options,
1499+
/*inheritanceClause=*/true);
14851500
return location.AttachedTo == attachingTo && !location.InWhereClause;
14861501
});
14871502
}
@@ -1496,7 +1511,8 @@ void PrintAST::printWhereClauseFromRequirementSignature(ProtocolDecl *proto,
14961511
proto->getRequirementSignature().getRequirements()),
14971512
flags,
14981513
[&](const Requirement &req) {
1499-
auto location = bestRequirementPrintLocation(proto, req);
1514+
auto location = bestRequirementPrintLocation(proto, req, Options,
1515+
/*inheritanceClause=*/false);
15001516
return location.AttachedTo == attachingTo && location.InWhereClause;
15011517
});
15021518
}
@@ -2969,6 +2985,22 @@ static void suppressingFeatureUnsafeInheritExecutor(PrintOptions &options,
29692985
options.ExcludeAttrList.resize(originalExcludeAttrCount);
29702986
}
29712987

2988+
static bool usesFeaturePrimaryAssociatedTypes(Decl *decl) {
2989+
if (auto *protoDecl = dyn_cast<ProtocolDecl>(decl)) {
2990+
if (protoDecl->getPrimaryAssociatedTypes().size() > 0)
2991+
return true;
2992+
}
2993+
2994+
return false;
2995+
}
2996+
2997+
static void suppressingFeaturePrimaryAssociatedTypes(PrintOptions &options,
2998+
llvm::function_ref<void()> action) {
2999+
bool originalPrintPrimaryAssociatedTypes = options.PrintPrimaryAssociatedTypes;
3000+
options.PrintPrimaryAssociatedTypes = false;
3001+
action();
3002+
options.PrintPrimaryAssociatedTypes = originalPrintPrimaryAssociatedTypes;
3003+
}
29723004

29733005
/// Suppress the printing of a particular feature.
29743006
static void suppressingFeature(PrintOptions &options, Feature feature,
@@ -3485,6 +3517,38 @@ void PrintAST::visitClassDecl(ClassDecl *decl) {
34853517
}
34863518
}
34873519

3520+
void PrintAST::printPrimaryAssociatedTypes(ProtocolDecl *decl) {
3521+
auto primaryAssocTypes = decl->getPrimaryAssociatedTypes();
3522+
if (primaryAssocTypes.empty())
3523+
return;
3524+
3525+
Printer.printStructurePre(PrintStructureKind::DeclGenericParameterClause);
3526+
3527+
Printer << "<";
3528+
llvm::interleave(
3529+
primaryAssocTypes,
3530+
[&](AssociatedTypeDecl *assocType) {
3531+
Printer.callPrintStructurePre(PrintStructureKind::GenericParameter,
3532+
assocType);
3533+
Printer.printName(assocType->getName(),
3534+
PrintNameContext::GenericParameter);
3535+
3536+
printInheritedFromRequirementSignature(decl, assocType);
3537+
3538+
if (assocType->hasDefaultDefinitionType()) {
3539+
Printer << " = ";
3540+
assocType->getDefaultDefinitionType().print(Printer, Options);
3541+
}
3542+
3543+
Printer.printStructurePost(PrintStructureKind::GenericParameter,
3544+
assocType);
3545+
},
3546+
[&] { Printer << ", "; });
3547+
Printer << ">";
3548+
3549+
Printer.printStructurePost(PrintStructureKind::DeclGenericParameterClause);
3550+
}
3551+
34883552
void PrintAST::visitProtocolDecl(ProtocolDecl *decl) {
34893553
printDocumentationComment(decl);
34903554
printAttributes(decl);
@@ -3502,6 +3566,10 @@ void PrintAST::visitProtocolDecl(ProtocolDecl *decl) {
35023566
Printer.printName(decl->getName());
35033567
});
35043568

3569+
if (Options.PrintPrimaryAssociatedTypes) {
3570+
printPrimaryAssociatedTypes(decl);
3571+
}
3572+
35053573
printInheritedFromRequirementSignature(decl, decl);
35063574

35073575
// The trailing where clause is a syntactic thing, which isn't serialized
@@ -4997,6 +5065,14 @@ bool Decl::shouldPrintInContext(const PrintOptions &PO) const {
49975065
return PO.PrintIfConfig;
49985066
}
49995067

5068+
if (auto *ATD = dyn_cast<AssociatedTypeDecl>(this)) {
5069+
// If PO.PrintPrimaryAssociatedTypes is on, primary associated
5070+
// types are printed as part of the protocol declaration itself,
5071+
// so skip them here.
5072+
if (ATD->isPrimary() && PO.PrintPrimaryAssociatedTypes)
5073+
return false;
5074+
}
5075+
50005076
// Print everything else.
50015077
return true;
50025078
}

lib/AST/Decl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4539,6 +4539,7 @@ AssociatedTypeDecl::AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc,
45394539
: AbstractTypeParamDecl(DeclKind::AssociatedType, dc, name, nameLoc),
45404540
KeywordLoc(keywordLoc), DefaultDefinition(defaultDefinition),
45414541
TrailingWhere(trailingWhere) {
4542+
Bits.AssociatedTypeDecl.IsPrimary = 0;
45424543
}
45434544

45444545
AssociatedTypeDecl::AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc,

0 commit comments

Comments
 (0)