@@ -1002,7 +1002,82 @@ bool TypeChecker::conformsToProtocol(Type T, ProtocolDecl *Proto,
1002
1002
// For explicit conformance, force the check again.
1003
1003
Context.ConformsTo .erase (Known);
1004
1004
}
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
+
1006
1081
// Assume that the type does not conform to this protocol while checking
1007
1082
// whether it does in fact conform. This eliminates both infinite recursion
1008
1083
// (if the protocol hierarchies are circular) as well as tautologies.
0 commit comments