Skip to content

Commit c45a10b

Browse files
authored
Merge pull request #17851 from slavapestov/protocol-superclass-part-4
Protocol superclass constraints part 4
2 parents d16d798 + eeb5c95 commit c45a10b

16 files changed

+366
-26
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1833,6 +1833,10 @@ WARNING(protocol_composition_with_postfix,none,
18331833
"protocol-constrained type with postfix '%0' is ambiguous "
18341834
"and will be rejected in future version of Swift", (StringRef))
18351835

1836+
ERROR(protocol_where_clause_self_requirement,none,
1837+
"constraint with subject type of 'Self' is not supported; "
1838+
"consider adding requirement to protocol inheritance clause instead", ())
1839+
18361840
ERROR(invalid_protocol_composition_member,none,
18371841
"non-protocol, non-class type %0 cannot be used within a "
18381842
"protocol-constrained type", (Type))
@@ -2128,6 +2132,8 @@ ERROR(duplicate_inheritance,none,
21282132
"duplicate inheritance from %0", (Type))
21292133
WARNING(duplicate_anyobject_class_inheritance,none,
21302134
"redundant inheritance from 'AnyObject' and Swift 3 'class' keyword", ())
2135+
ERROR(objc_protocol_with_superclass,none,
2136+
"protocol %0 is '@objc' and cannot have a superclass constraint", (Identifier))
21312137
ERROR(multiple_inheritance,none,
21322138
"multiple inheritance from classes %0 and %1", (Type, Type))
21332139
ERROR(non_class_inheritance,none,

lib/IRGen/ClassMetadataVisitor.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ template <class Impl> class ClassMetadataVisitor
6161
// isn't necessary.
6262
// FIXME: Figure out what can be removed altogether in non-objc-interop
6363
// mode and remove it. rdar://problem/18801263
64-
asImpl().addSuperClass();
64+
asImpl().addSuperclass();
6565
asImpl().addClassCacheData();
6666
asImpl().addClassDataPointer();
6767

@@ -171,7 +171,7 @@ class ClassMetadataScanner : public ClassMetadataVisitor<Impl> {
171171
void addIVarDestroyer() { addPointer(); }
172172
void addValueWitnessTable() { addPointer(); }
173173
void addDestructorFunction() { addPointer(); }
174-
void addSuperClass() { addPointer(); }
174+
void addSuperclass() { addPointer(); }
175175
void addClassFlags() { addInt32(); }
176176
void addInstanceAddressPoint() { addInt32(); }
177177
void addInstanceSize() { addInt32(); }

lib/IRGen/ForeignClassMetadataVisitor.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class ForeignClassMetadataVisitor
3838
super::layout();
3939
asImpl().addNominalTypeDescriptor();
4040
asImpl().noteStartOfSuperClass();
41-
asImpl().addSuperClass();
41+
asImpl().addSuperclass();
4242
asImpl().addReservedWord();
4343
asImpl().addReservedWord();
4444
asImpl().addReservedWord();
@@ -70,7 +70,7 @@ class ForeignClassMetadataScanner : public ForeignClassMetadataVisitor<Impl> {
7070
void addMetadataFlags() { addPointer(); }
7171
void addValueWitnessTable() { addPointer(); }
7272
void addNominalTypeDescriptor() { addPointer(); }
73-
void addSuperClass() { addPointer(); }
73+
void addSuperclass() { addPointer(); }
7474
void addReservedWord() { addPointer(); }
7575

7676
private:

lib/IRGen/GenCast.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ void irgen::emitScalarExistentialDowncast(IRGenFunction &IGF,
522522
bool hasClassConstraint = layout.requiresClass();
523523
bool hasClassConstraintByProtocol = false;
524524

525-
bool hasSuperclassConstraint = bool(layout.getSuperclass());
525+
bool hasSuperclassConstraint = bool(layout.explicitSuperclass);
526526

527527
for (auto protoTy : layout.getProtocols()) {
528528
auto *protoDecl = protoTy->getDecl();
@@ -581,9 +581,17 @@ void irgen::emitScalarExistentialDowncast(IRGenFunction &IGF,
581581
// Note that destInstanceType is always an existential type, so calling
582582
// getSuperclass() returns the superclass constraint of the existential,
583583
// not the superclass of some concrete class.
584-
bool checkSuperclassConstraint =
585-
hasSuperclassConstraint &&
586-
!destInstanceType->getSuperclass()->isExactSuperclassOf(srcInstanceType);
584+
bool checkSuperclassConstraint = false;
585+
if (hasSuperclassConstraint) {
586+
Type srcSuperclassType = srcInstanceType;
587+
if (srcSuperclassType->isExistentialType())
588+
srcSuperclassType = srcSuperclassType->getSuperclass();
589+
if (srcSuperclassType) {
590+
checkSuperclassConstraint =
591+
!destInstanceType->getSuperclass()->isExactSuperclassOf(
592+
srcSuperclassType);
593+
}
594+
}
587595

588596
if (checkSuperclassConstraint)
589597
checkClassConstraint = true;
@@ -739,7 +747,7 @@ void irgen::emitScalarExistentialDowncast(IRGenFunction &IGF,
739747
args.push_back(metadataValue);
740748

741749
if (checkSuperclassConstraint)
742-
args.push_back(IGF.emitTypeMetadataRef(CanType(layout.getSuperclass())));
750+
args.push_back(IGF.emitTypeMetadataRef(CanType(layout.explicitSuperclass)));
743751

744752
for (auto proto : witnessTableProtos)
745753
args.push_back(proto);

lib/IRGen/GenMeta.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,7 +2041,7 @@ namespace {
20412041
AddressPoint = B.getNextOffsetFromGlobal();
20422042
}
20432043

2044-
void addSuperClass() {
2044+
void addSuperclass() {
20452045
// If this is a root class, use SwiftObject as our formal parent.
20462046
if (!Target->hasSuperclass()) {
20472047
// This is only required for ObjC interoperation.
@@ -3246,7 +3246,7 @@ namespace {
32463246

32473247
void noteStartOfSuperClass() { }
32483248

3249-
void addSuperClass() {
3249+
void addSuperclass() {
32503250
auto superclassDecl = Target->getSuperclassDecl();
32513251
if (!superclassDecl || !superclassDecl->isForeign()) {
32523252
B.addNullPointer(IGM.TypeMetadataPtrTy);

lib/Sema/TypeCheckDecl.cpp

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,8 @@ void TypeChecker::validateWhereClauses(ProtocolDecl *protocol,
214214
GenericTypeResolver *resolver) {
215215
TypeResolutionOptions options;
216216

217+
options |= TypeResolutionFlags::ProtocolWhereClause;
218+
217219
if (auto whereClause = protocol->getTrailingWhereClause()) {
218220
revertGenericRequirements(whereClause->getRequirements());
219221
validateRequirements(whereClause->getWhereLoc(),
@@ -288,9 +290,7 @@ void TypeChecker::checkInheritanceClause(Decl *decl,
288290
inheritedClause = type->getInherited();
289291
} else {
290292
auto ext = cast<ExtensionDecl>(decl);
291-
292-
validateExtension(ext);
293-
if (ext->isInvalid())
293+
if (!ext->getExtendedType())
294294
return;
295295

296296
inheritedClause = ext->getInherited();
@@ -408,17 +408,27 @@ void TypeChecker::checkInheritanceClause(Decl *decl,
408408
}
409409
inheritedTypes[inheritedCanTy] = { i, inherited.getSourceRange() };
410410

411-
// If this is a protocol or protocol composition type, record the
412-
// protocols.
413411
if (inheritedTy->isExistentialType()) {
414412
auto layout = inheritedTy->getExistentialLayout();
415413

414+
// @objc protocols cannot have superclass constraints.
415+
if (layout.explicitSuperclass) {
416+
if (auto *protoDecl = dyn_cast<ProtocolDecl>(decl)) {
417+
if (protoDecl->isObjC()) {
418+
diagnose(protoDecl,
419+
diag::objc_protocol_with_superclass,
420+
protoDecl->getName());
421+
continue;
422+
}
423+
}
424+
}
425+
416426
// Protocols, generic parameters and associated types can inherit
417427
// from subclass existentials, which are "exploded" into their
418428
// corresponding requirements.
419429
//
420-
// Classes can only inherit from subclass existentials that do not
421-
// have a superclass term.
430+
// Extensions, structs and enums can only inherit from protocol
431+
// compositions that do not contain AnyObject or class members.
422432
if (isa<ProtocolDecl>(decl) ||
423433
isa<AbstractTypeParamDecl>(decl) ||
424434
(!layout.hasExplicitAnyObject &&
@@ -494,6 +504,16 @@ void TypeChecker::checkInheritanceClause(Decl *decl,
494504
continue;
495505
}
496506

507+
// @objc protocols cannot have superclass constraints.
508+
if (auto *protoDecl = dyn_cast<ProtocolDecl>(decl)) {
509+
if (protoDecl->isObjC()) {
510+
diagnose(protoDecl,
511+
diag::objc_protocol_with_superclass,
512+
protoDecl->getName());
513+
continue;
514+
}
515+
}
516+
497517
// If the declaration we're looking at doesn't allow a superclass,
498518
// complain.
499519
if (isa<StructDecl>(decl) || isa<ExtensionDecl>(decl)) {

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,31 @@ bool TypeChecker::validateRequirement(SourceLoc whereLoc, RequirementRepr &req,
310310
// Note that we are resolving within a requirement.
311311
options |= TypeResolutionFlags::GenericRequirement;
312312

313+
// Protocol where clauses cannot add conformance and superclass constraints
314+
// to 'Self', because we need to be able to resolve inherited protocols and
315+
// protocol superclasses before computing the protocol requirement signature.
316+
if (options & TypeResolutionFlags::ProtocolWhereClause) {
317+
if (req.getKind() == RequirementReprKind::TypeConstraint ||
318+
req.getKind() == RequirementReprKind::LayoutConstraint) {
319+
if (auto *subjectTyR = req.getSubjectLoc().getTypeRepr()) {
320+
if (auto *componentTyR = dyn_cast<ComponentIdentTypeRepr>(subjectTyR)) {
321+
if (componentTyR->getIdentifier() == Context.Id_Self) {
322+
diagnose(req.getSubjectLoc().getLoc(),
323+
diag::protocol_where_clause_self_requirement);
324+
325+
req.getSubjectLoc().setType(ErrorType::get(Context));
326+
327+
if (req.getKind() == RequirementReprKind::TypeConstraint)
328+
req.getConstraintLoc().setType(ErrorType::get(Context));
329+
330+
req.setInvalid();
331+
return true;
332+
}
333+
}
334+
}
335+
}
336+
}
337+
313338
switch (req.getKind()) {
314339
case RequirementReprKind::TypeConstraint: {
315340
// Validate the types.

lib/Sema/TypeChecker.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,9 @@ enum class TypeResolutionFlags : unsigned {
552552

553553
/// Whether we are in a requirement of a generic declaration
554554
GenericRequirement = 1 << 26,
555+
556+
/// Whether we are in a protocol's where clause
557+
ProtocolWhereClause = 1 << 27,
555558
};
556559

557560
/// Option set describing how type resolution should work.

test/IDE/print_ast_tc_decls.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,11 +1352,11 @@ extension ProtocolToExtend where Self.Assoc == Int {}
13521352

13531353
// Protocol with where clauses
13541354

1355-
protocol ProtocolWithWhereClause : QuxProtocol where Qux == Int, Self : FooProtocol {}
1356-
// PREFER_TYPE_REPR_PRINTING: protocol ProtocolWithWhereClause : FooProtocol, QuxProtocol where Self.Qux == Int {
1355+
protocol ProtocolWithWhereClause : QuxProtocol where Qux == Int {}
1356+
// PREFER_TYPE_REPR_PRINTING: protocol ProtocolWithWhereClause : QuxProtocol where Self.Qux == Int {
13571357

1358-
protocol ProtocolWithWhereClauseAndAssoc : QuxProtocol where Qux == Int, Self : FooProtocol {
1359-
// PREFER_TYPE_REPR_PRINTING-DAG: protocol ProtocolWithWhereClauseAndAssoc : FooProtocol, QuxProtocol where Self.Qux == Int {
1358+
protocol ProtocolWithWhereClauseAndAssoc : QuxProtocol where Qux == Int {
1359+
// PREFER_TYPE_REPR_PRINTING-DAG: protocol ProtocolWithWhereClauseAndAssoc : QuxProtocol where Self.Qux == Int {
13601360
associatedtype A1 : QuxProtocol where A1 : FooProtocol, A1.Qux : QuxProtocol, Int == A1.Qux.Qux
13611361
// PREFER_TYPE_REPR_PRINTING-DAG: {{^}} associatedtype A1 : FooProtocol, QuxProtocol where Self.A1.Qux : QuxProtocol, Self.A1.Qux.Qux == Int{{$}}
13621362

0 commit comments

Comments
 (0)