Skip to content

Commit 4c7381c

Browse files
committed
Remove implicit conformance to protocols.
Conformance is now entirely explicit. Fixes <rdar://problem/13380989>. Swift SVN r6725
1 parent 5aef7a6 commit 4c7381c

File tree

3 files changed

+98
-1
lines changed

3 files changed

+98
-1
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,6 +1175,18 @@ void TypeChecker::typeCheckDecl(Decl *D, bool isFirstPass) {
11751175
DeclChecker(*this, isFirstPass, isSecondPass).visit(D);
11761176
}
11771177

1178+
ArrayRef<ProtocolDecl *>
1179+
TypeChecker::getDirectConformsTo(NominalTypeDecl *nominal) {
1180+
checkInheritanceClause(*this, nominal);
1181+
return nominal->getProtocols();
1182+
}
1183+
1184+
ArrayRef<ProtocolDecl *>
1185+
TypeChecker::getDirectConformsTo(ExtensionDecl *ext) {
1186+
checkInheritanceClause(*this, ext);
1187+
return ext->getProtocols();
1188+
}
1189+
11781190
/// \brief Create an implicit struct constructor.
11791191
///
11801192
/// \param structDecl The struct for which a constructor will be created.

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1002,7 +1002,82 @@ bool TypeChecker::conformsToProtocol(Type T, ProtocolDecl *Proto,
10021002
// For explicit conformance, force the check again.
10031003
Context.ConformsTo.erase(Known);
10041004
}
1005-
1005+
1006+
// If we're checking for conformance (rather than stating it),
1007+
// look for the explicit declaration of conformance in the list of protocols.
1008+
if (!Explicit) {
1009+
// Look through the metatype.
1010+
// FIXME: This feels like a hack to work around bugs in the solver.
1011+
auto instanceT = T;
1012+
if (auto metaT = T->getAs<MetaTypeType>()) {
1013+
instanceT = metaT->getInstanceType();
1014+
}
1015+
1016+
// Only nominal types conform to protocols.
1017+
auto nominal = instanceT->getAnyNominal();
1018+
if (!nominal)
1019+
return nullptr;
1020+
1021+
// Walk the nominal type, its extensions, superclasses, and so on.
1022+
llvm::SmallPtrSet<ProtocolDecl *, 4> visitedProtocols;
1023+
SmallVector<NominalTypeDecl *, 4> stack;
1024+
bool foundExplicitConformance = false;
1025+
1026+
// Local function that checks for our protocol in the given array of
1027+
// protocols.
1028+
auto isProtocolInList = [&](ArrayRef<ProtocolDecl *> protocols) -> bool {
1029+
for (auto testProto : protocols) {
1030+
if (testProto == Proto) {
1031+
foundExplicitConformance = true;
1032+
return true;
1033+
}
1034+
1035+
if (visitedProtocols.insert(testProto))
1036+
stack.push_back(testProto);
1037+
}
1038+
1039+
return false;
1040+
};
1041+
1042+
// Walk the stack of types.
1043+
stack.push_back(nominal);
1044+
while (!stack.empty()) {
1045+
auto current = stack.back();
1046+
stack.pop_back();
1047+
1048+
// Visit the superclass of a class.
1049+
if (auto classDecl = dyn_cast<ClassDecl>(current)) {
1050+
if (auto superclassTy = classDecl->getSuperclass())
1051+
stack.push_back(superclassTy->getAnyNominal());
1052+
}
1053+
1054+
// Visit the protocols this type conforms to directly.
1055+
if (isProtocolInList(getDirectConformsTo(current)))
1056+
break;
1057+
1058+
// Visit the extensions of this type.
1059+
for (auto ext : current->getExtensions()) {
1060+
if (isProtocolInList(getDirectConformsTo(ext)))
1061+
break;
1062+
}
1063+
}
1064+
1065+
// If we did not find explicit conformance, we're done.
1066+
if (!foundExplicitConformance) {
1067+
// FIXME: Check whether the type *implicitly* conforms. If so, produce
1068+
// a cleaner diagnostic along with a Fix-It that adds the explicit
1069+
// conformance either via a new extension or onto an existing extension.
1070+
if (ComplainLoc.isValid()) {
1071+
diagnose(ComplainLoc, diag::type_does_not_conform,
1072+
T, Proto->getDeclaredType());
1073+
}
1074+
1075+
return nullptr;
1076+
}
1077+
1078+
// We found explicit conformance. Compute and record the conformance below.
1079+
}
1080+
10061081
// Assume that the type does not conform to this protocol while checking
10071082
// whether it does in fact conform. This eliminates both infinite recursion
10081083
// (if the protocol hierarchies are circular) as well as tautologies.

lib/Sema/TypeChecker.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,16 @@ class TypeChecker : public ASTMutationListener {
349349

350350
void typeCheckDecl(Decl *D, bool isFirstPass);
351351

352+
/// Retrieve the set of protocols to which this nominal type declaration
353+
/// directly conforms, i.e., as specified in its own inheritance clause.
354+
///
355+
/// Protocols to which this nominal type declaration conforms via extensions
356+
/// or superclasses need to be extracted separately.
357+
ArrayRef<ProtocolDecl *> getDirectConformsTo(NominalTypeDecl *nominal);
358+
359+
/// Retrieve the set of protocols to which this extension directly conforms.
360+
ArrayRef<ProtocolDecl *> getDirectConformsTo(ExtensionDecl *extension);
361+
352362
/// \brief Add any implicitly-defined constructors required for the given
353363
/// struct.
354364
void addImplicitConstructors(StructDecl *structDecl);

0 commit comments

Comments
 (0)