Skip to content

Commit a5c079a

Browse files
committed
Replace the class_protocol attribute with a "class" requirement.
This only tackles the protocol case (<rdar://problem/17510790>); it does not yet generalize to an arbitrary "class" requirement on either existentials or generics. Swift SVN r19896
1 parent fd2c4dd commit a5c079a

File tree

71 files changed

+306
-197
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+306
-197
lines changed

include/swift/AST/Decl.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ class alignas(8) Decl {
447447
/// Whether the \c RequiresClass bit is valid.
448448
unsigned RequiresClassValid : 1;
449449

450-
/// Whether this is a [class_bounded] protocol.
450+
/// Whether this is a class-bounded protocol.
451451
unsigned RequiresClass : 1;
452452

453453
/// Whether the \c ExistentialConformsToSelf bit is valid.
@@ -3038,6 +3038,13 @@ class ProtocolDecl : public NominalTypeDecl {
30383038
return requiresClassSlow();
30393039
}
30403040

3041+
/// Specify that this protocol is class-bounded, e.g., because it was
3042+
/// annotated with the 'class' keyword.
3043+
void setRequiresClass() {
3044+
ProtocolDeclBits.RequiresClassValid = true;
3045+
ProtocolDeclBits.RequiresClass = true;
3046+
}
3047+
30413048
/// Determine whether an existential value conforming to just this protocol
30423049
/// conforms to the protocol itself.
30433050
///

include/swift/AST/DiagnosticsParse.def

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,15 @@ ERROR(requires_single_equal,parsing,none,
10161016
ERROR(expected_requirement_delim,parsing,none,
10171017
"expected ':' or '==' to indicate a conformance or same-type requirement",
10181018
())
1019+
ERROR(invalid_class_requirement,decl_parsing,none,
1020+
"'class' requirement only applies to protocols", ())
1021+
ERROR(redundant_class_requirement,decl_parsing,none,
1022+
"redundant 'class' requirement", ())
1023+
ERROR(late_class_requirement,decl_parsing,none,
1024+
"'class' must come first in the requirement list", ())
1025+
ERROR(class_protocol_removed,decl_class,none,
1026+
"the 'class_protocol' attribute has been replaced with a 'class' "
1027+
"requirement", ())
10191028

10201029
//------------------------------------------------------------------------------
10211030
// Build configuration parsing diagnostics

include/swift/Parse/Parser.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,15 @@ class Parser {
385385
consumeToken(K);
386386
return true;
387387
}
388-
388+
389+
/// \brief If the current token is the specified kind, consume it and
390+
/// return true. Otherwise, return false without consuming it.
391+
bool consumeIf(tok K, SourceLoc &consumedLoc) {
392+
if (Tok.isNot(K)) return false;
393+
consumedLoc = consumeToken(K);
394+
return true;
395+
}
396+
389397
bool consumeIfNotAtStartOfLine(tok K) {
390398
if (Tok.isAtStartOfLine()) return false;
391399
return consumeIf(K);
@@ -660,7 +668,8 @@ class Parser {
660668

661669
ParserResult<ImportDecl> parseDeclImport(ParseDeclOptions Flags,
662670
DeclAttributes &Attributes);
663-
ParserStatus parseInheritance(SmallVectorImpl<TypeLoc> &Inherited);
671+
ParserStatus parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,
672+
SourceLoc *classRequirementLoc);
664673
ParserResult<ExtensionDecl> parseDeclExtension(ParseDeclOptions Flags,
665674
DeclAttributes &Attributes);
666675
ParserResult<EnumDecl> parseDeclEnum(ParseDeclOptions Flags,

include/swift/Serialization/ModuleFormat.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ const uint16_t VERSION_MAJOR = 0;
4040
/// Serialized module format minor version number.
4141
///
4242
/// When the format changes IN ANY WAY, this number should be incremented.
43-
const uint16_t VERSION_MINOR = 116;
43+
const uint16_t VERSION_MINOR = 117;
4444

4545
using DeclID = Fixnum<31>;
4646
using DeclIDField = BCFixed<31>;
@@ -669,6 +669,7 @@ namespace decls_block {
669669
IdentifierIDField, // name
670670
DeclIDField, // context decl
671671
BCFixed<1>, // implicit flag
672+
BCFixed<1>, // class-bounded?
672673
BCFixed<1>, // objc?
673674
AccessibilityKindField, // accessibility
674675
BCArray<DeclIDField> // protocols

lib/AST/ASTPrinter.cpp

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,13 @@ class PrintAST : public ASTVisitor<PrintAST> {
292292
ArrayRef<TypeLoc> inherited,
293293
ArrayRef<ProtocolDecl *> protos,
294294
Type superclass = {},
295+
bool explicitClass = false,
295296
bool PrintAsProtocolComposition = false);
296297

297298
template <typename DeclWithSuperclass>
298299
void printInheritedWithSuperclass(DeclWithSuperclass *decl);
299300

300-
void printInherited(const TypeDecl *decl);
301+
void printInherited(const TypeDecl *decl, bool explicitClass = false);
301302
void printInherited(const EnumDecl *D);
302303
void printInherited(const ExtensionDecl *decl);
303304
void printInherited(const GenericTypeParamDecl *D);
@@ -660,8 +661,9 @@ void PrintAST::printInherited(const Decl *decl,
660661
ArrayRef<TypeLoc> inherited,
661662
ArrayRef<ProtocolDecl *> protos,
662663
Type superclass,
664+
bool explicitClass,
663665
bool PrintAsProtocolComposition) {
664-
if (inherited.empty() && superclass.isNull()) {
666+
if (inherited.empty() && superclass.isNull() && !explicitClass) {
665667
if (protos.empty())
666668
return;
667669
// If only conforms to AnyObject protocol, nothing to print.
@@ -675,7 +677,10 @@ void PrintAST::printInherited(const Decl *decl,
675677
bool PrintedColon = false;
676678
bool PrintedInherited = false;
677679

678-
if (superclass) {
680+
if (explicitClass) {
681+
Printer << " : class";
682+
PrintedInherited = true;
683+
} else if (superclass) {
679684
bool ShouldPrintSuper = true;
680685
if (auto NTD = superclass->getAnyNominal()) {
681686
ShouldPrintSuper = shouldPrint(NTD);
@@ -736,6 +741,9 @@ void PrintAST::printInherited(const Decl *decl,
736741

737742
Printer << " : ";
738743

744+
if (explicitClass)
745+
Printer << " class, ";
746+
739747
interleave(TypesToPrint, [&](TypeLoc TL) {
740748
printTypeLoc(TL);
741749
}, [&]() {
@@ -750,8 +758,9 @@ void PrintAST::printInheritedWithSuperclass(DeclWithSuperclass *decl) {
750758
decl->getSuperclass());
751759
}
752760

753-
void PrintAST::printInherited(const TypeDecl *decl) {
754-
printInherited(decl, decl->getInherited(), decl->getProtocols());
761+
void PrintAST::printInherited(const TypeDecl *decl, bool explicitClass) {
762+
printInherited(decl, decl->getInherited(), decl->getProtocols(), nullptr,
763+
explicitClass);
755764
}
756765

757766
void PrintAST::printInherited(const EnumDecl *D) {
@@ -764,7 +773,7 @@ void PrintAST::printInherited(const ExtensionDecl *decl) {
764773

765774
void PrintAST::printInherited(const GenericTypeParamDecl *D) {
766775
printInherited(D, D->getInherited(), D->getProtocols(), D->getSuperclass(),
767-
true);
776+
false, true);
768777
}
769778

770779
void PrintAST::visitImportDecl(ImportDecl *decl) {
@@ -946,7 +955,23 @@ void PrintAST::visitProtocolDecl(ProtocolDecl *decl) {
946955
Printer << "protocol ";
947956
recordDeclLoc(decl);
948957
printNominalDeclName(decl);
949-
printInherited(decl);
958+
959+
// Figure out whether we need an explicit 'class' in the inheritance.
960+
bool explicitClass = false;
961+
if (decl->requiresClass() && !decl->isObjC()) {
962+
bool inheritsRequiresClass = false;
963+
for (auto proto : decl->getProtocols()) {
964+
if (proto->requiresClass()) {
965+
inheritsRequiresClass = true;
966+
break;
967+
}
968+
}
969+
970+
if (!inheritsRequiresClass)
971+
explicitClass = true;
972+
}
973+
974+
printInherited(decl, explicitClass);
950975
if (Options.TypeDefinitions) {
951976
printMembers(decl->getMembers());
952977
}

lib/AST/Decl.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1819,8 +1819,7 @@ bool ProtocolDecl::requiresClassSlow() {
18191819
// Ensure that the result can not change in future.
18201820
assert(isProtocolsValid());
18211821

1822-
if (getAttrs().hasAttribute<ClassProtocolAttr>() ||
1823-
getAttrs().hasAttribute<ObjCAttr>() || isObjC()) {
1822+
if (getAttrs().hasAttribute<ObjCAttr>() || isObjC()) {
18241823
ProtocolDeclBits.RequiresClass = true;
18251824
return true;
18261825
}

lib/Parse/ParseDecl.cpp

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,13 +1742,55 @@ ParserResult<ImportDecl> Parser::parseDeclImport(ParseDeclOptions Flags,
17421742
///
17431743
/// \verbatim
17441744
/// inheritance:
1745-
/// ':' type-identifier (',' type-identifier)*
1745+
/// ':' inherited (',' inherited)*
1746+
///
1747+
/// inherited:
1748+
/// 'class'
1749+
/// type-identifier
17461750
/// \endverbatim
1747-
ParserStatus Parser::parseInheritance(SmallVectorImpl<TypeLoc> &Inherited) {
1751+
ParserStatus Parser::parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,
1752+
SourceLoc *classRequirementLoc) {
17481753
consumeToken(tok::colon);
17491754

1755+
// Clear out the class requirement location.
1756+
if (classRequirementLoc)
1757+
*classRequirementLoc = SourceLoc();
1758+
17501759
ParserStatus Status;
1760+
SourceLoc prevComma;
17511761
do {
1762+
// Parse the 'class' keyword for a class requirement.
1763+
if (Tok.is(tok::kw_class)) {
1764+
// If we aren't allowed to have a class requirement here, complain.
1765+
auto classLoc = consumeToken();
1766+
if (!classRequirementLoc) {
1767+
SourceLoc endLoc = Tok.is(tok::comma) ? Tok.getLoc() : classLoc;
1768+
diagnose(classLoc, diag::invalid_class_requirement)
1769+
.fixItRemove(SourceRange(classLoc, endLoc));
1770+
continue;
1771+
}
1772+
1773+
// If we already saw a class requirement, complain.
1774+
if (classRequirementLoc->isValid()) {
1775+
diagnose(classLoc, diag::redundant_class_requirement)
1776+
.highlight(*classRequirementLoc)
1777+
.fixItRemove(SourceRange(prevComma, classLoc));
1778+
continue;
1779+
}
1780+
1781+
// If the class requirement was not the first requirement, complain.
1782+
if (!Inherited.empty()) {
1783+
SourceLoc properLoc = Inherited[0].getSourceRange().Start;
1784+
diagnose(classLoc, diag::late_class_requirement)
1785+
.fixItInsert(properLoc, "class, ")
1786+
.fixItRemove(SourceRange(prevComma, classLoc));
1787+
}
1788+
1789+
// Record the location of the 'class' keyword.
1790+
*classRequirementLoc = classLoc;
1791+
continue;
1792+
}
1793+
17521794
// Parse the inherited type (which must be a protocol).
17531795
ParserResult<TypeRepr> Ty = parseTypeIdentifier();
17541796
Status |= Ty;
@@ -1758,7 +1800,7 @@ ParserStatus Parser::parseInheritance(SmallVectorImpl<TypeLoc> &Inherited) {
17581800
Inherited.push_back(Ty.get());
17591801

17601802
// Check for a ',', which indicates that there are more protocols coming.
1761-
} while (consumeIf(tok::comma));
1803+
} while (consumeIf(tok::comma, prevComma));
17621804

17631805
return Status;
17641806
}
@@ -1881,7 +1923,7 @@ Parser::parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes) {
18811923
// Parse optional inheritance clause.
18821924
SmallVector<TypeLoc, 2> Inherited;
18831925
if (Tok.is(tok::colon))
1884-
Status |= parseInheritance(Inherited);
1926+
Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
18851927

18861928
ExtensionDecl *ED
18871929
= new (Context) ExtensionDecl(ExtensionLoc, Ty.get(),
@@ -2093,9 +2135,10 @@ ParserResult<TypeDecl> Parser::parseDeclTypeAlias(bool WantDefinition,
20932135
DebuggerContextChange DCC(*this, Id, DeclKind::TypeAlias);
20942136

20952137
// Parse optional inheritance clause.
2138+
// FIXME: Allow class requirements here.
20962139
SmallVector<TypeLoc, 2> Inherited;
20972140
if (isAssociatedType && Tok.is(tok::colon))
2098-
Status |= parseInheritance(Inherited);
2141+
Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
20992142

21002143
ParserResult<TypeRepr> UnderlyingTy;
21012144
if (WantDefinition || Tok.is(tok::equal)) {
@@ -3271,7 +3314,7 @@ ParserResult<EnumDecl> Parser::parseDeclEnum(ParseDeclOptions Flags,
32713314
if (Tok.is(tok::colon)) {
32723315
ContextChange CC(*this, UD);
32733316
SmallVector<TypeLoc, 2> Inherited;
3274-
Status |= parseInheritance(Inherited);
3317+
Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
32753318
UD->setInherited(Context.AllocateCopy(Inherited));
32763319
}
32773320

@@ -3527,7 +3570,7 @@ ParserResult<StructDecl> Parser::parseDeclStruct(ParseDeclOptions Flags,
35273570
if (Tok.is(tok::colon)) {
35283571
ContextChange CC(*this, SD);
35293572
SmallVector<TypeLoc, 2> Inherited;
3530-
Status |= parseInheritance(Inherited);
3573+
Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
35313574
SD->setInherited(Context.AllocateCopy(Inherited));
35323575
}
35333576

@@ -3606,7 +3649,7 @@ ParserResult<ClassDecl> Parser::parseDeclClass(SourceLoc ClassLoc,
36063649
if (Tok.is(tok::colon)) {
36073650
ContextChange CC(*this, CD);
36083651
SmallVector<TypeLoc, 2> Inherited;
3609-
Status |= parseInheritance(Inherited);
3652+
Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
36103653
CD->setInherited(Context.AllocateCopy(Inherited));
36113654
}
36123655

@@ -3678,15 +3721,51 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) {
36783721

36793722
// Parse optional inheritance clause.
36803723
SmallVector<TypeLoc, 4> InheritedProtocols;
3681-
if (Tok.is(tok::colon))
3682-
Status |= parseInheritance(InheritedProtocols);
3724+
SourceLoc classRequirementLoc;
3725+
SourceLoc colonLoc;
3726+
if (Tok.is(tok::colon)) {
3727+
colonLoc = Tok.getLoc();
3728+
Status |= parseInheritance(InheritedProtocols, &classRequirementLoc);
3729+
}
36833730

36843731
ProtocolDecl *Proto
36853732
= new (Context) ProtocolDecl(CurDeclContext, ProtocolLoc, NameLoc,
36863733
ProtocolName,
36873734
Context.AllocateCopy(InheritedProtocols));
36883735
// No need to setLocalDiscriminator: protocols can't appear in local contexts.
36893736

3737+
// If there was a 'class' requirement, mark this as a class-bounded protocol.
3738+
if (classRequirementLoc.isValid())
3739+
Proto->setRequiresClass();
3740+
3741+
// If the "class_protocol" attribute was provided, replace it with a 'class'
3742+
// requirement.
3743+
if (auto classProto = Attributes.getAttribute<ClassProtocolAttr>()) {
3744+
StringRef addString;
3745+
SourceLoc insertLoc;
3746+
if (InheritedProtocols.empty()) {
3747+
insertLoc = Lexer::getLocForEndOfToken(SourceMgr, NameLoc);
3748+
addString = " : class";
3749+
} else {
3750+
insertLoc = InheritedProtocols[0].getSourceRange().Start;
3751+
addString = "class, ";
3752+
}
3753+
3754+
// Remove @class_protocol and the character following it.
3755+
SourceLoc removeEndLoc = Lexer::getLocForEndOfToken(SourceMgr,
3756+
classProto->Range.End)
3757+
.getAdvancedLoc(1);
3758+
diagnose(classProto->AtLoc, diag::class_protocol_removed)
3759+
.fixItRemoveChars(classProto->AtLoc, removeEndLoc)
3760+
.fixItInsert(insertLoc, addString);
3761+
3762+
// Act as if we saw a 'class' requirement.
3763+
Proto->setRequiresClass();
3764+
3765+
// Drop the attribute.
3766+
Attributes.removeAttribute(classProto);
3767+
}
3768+
36903769
if (Attributes.shouldSaveInAST())
36913770
Proto->getMutableAttrs() = Attributes;
36923771

lib/Sema/TypeCheckAttr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,8 @@ void AttributeChecker::visitAssignmentAttr(AssignmentAttr *attr) {
566566
}
567567

568568
void AttributeChecker::visitClassProtocolAttr(ClassProtocolAttr *attr) {
569-
// Only protocols can have the @class_protocol attribute.
569+
// FIXME: The @class_protocol attribute is dead. Retain this code so that we
570+
// diagnose uses of @class_protocol for non-protocols.
570571
if (!isa<ProtocolDecl>(D)) {
571572
TC.diagnose(attr->getLocation(),
572573
diag::class_protocol_not_protocol);
@@ -585,7 +586,6 @@ void AttributeChecker::visitUnsafeNoObjCTaggedPointerAttr(
585586
}
586587

587588
if (!proto->requiresClass()
588-
&& !proto->getAttrs().hasAttribute<ClassProtocolAttr>()
589589
&& !proto->getAttrs().hasAttribute<ObjCAttr>()) {
590590
TC.diagnose(attr->getLocation(),
591591
diag::no_objc_tagged_pointer_not_class_protocol);

0 commit comments

Comments
 (0)