@@ -900,12 +900,70 @@ namespace {
900
900
using GSBConstraint = GenericSignatureBuilder::Constraint<T>;
901
901
} // end anonymous namespace
902
902
903
+ // / Determine whether there is a conformance of the given
904
+ // / subject type to the given protocol within the given set of explicit
905
+ // / requirements.
906
+ static bool hasConformanceInSignature (ArrayRef<Requirement> requirements,
907
+ Type subjectType,
908
+ ProtocolDecl *proto) {
909
+ // Make sure this requirement exists in the requirement signature.
910
+ for (const auto & req: requirements) {
911
+ if (req.getKind () == RequirementKind::Conformance &&
912
+ req.getFirstType ()->isEqual (subjectType) &&
913
+ req.getSecondType ()->castTo <ProtocolType>()->getDecl ()
914
+ == proto) {
915
+ return true ;
916
+ }
917
+ }
918
+
919
+ return false ;
920
+ }
921
+
922
+ // / Check whether the given requirement source has any non-canonical protocol
923
+ // / requirements in it.
924
+ static bool hasNonCanonicalSelfProtocolRequirement (
925
+ const RequirementSource *source,
926
+ ProtocolDecl *conformingProto) {
927
+ for (; source; source = source->parent ) {
928
+ // Only look at protocol requirements.
929
+ if (!source->isProtocolRequirement ())
930
+ continue ;
931
+
932
+ // If we don't already have a requirement signature for this protocol,
933
+ // build one now.
934
+ auto inProto = source->getProtocolDecl ();
935
+ if (!inProto->isRequirementSignatureComputed ()) {
936
+ inProto->computeRequirementSignature ();
937
+ assert (inProto->isRequirementSignatureComputed () &&
938
+ " couldn't compute requirement signature?" );
939
+ }
940
+
941
+ // Check whether the given requirement is in the requirement signature.
942
+ if (!hasConformanceInSignature (inProto->getRequirementSignature (),
943
+ source->getStoredType (), conformingProto))
944
+ return true ;
945
+
946
+ // Update the conforming protocol for the rest of the search.
947
+ conformingProto = inProto;
948
+ }
949
+
950
+ return false ;
951
+ }
952
+
903
953
// / Retrieve the best requirement source from the list
904
954
static const RequirementSource *
905
- getBestRequirementSource (ArrayRef<GSBConstraint<ProtocolDecl *>> constraints) {
955
+ getBestCanonicalRequirementSource (
956
+ ArrayRef<GSBConstraint<ProtocolDecl *>> constraints) {
906
957
const RequirementSource *bestSource = nullptr ;
907
958
for (const auto &constraint : constraints) {
908
959
auto source = constraint.source ;
960
+
961
+ // If there is a non-canonical protocol requirement next to the root,
962
+ // skip this requirement source.
963
+ if (hasNonCanonicalSelfProtocolRequirement (source, constraint.value ))
964
+ continue ;
965
+
966
+ // Check whether this is better than our best source.
909
967
if (!bestSource || source->compare (bestSource) < 0 )
910
968
bestSource = source;
911
969
}
@@ -934,27 +992,6 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
934
992
typedef GenericSignatureBuilder::RequirementSource RequirementSource;
935
993
ConformanceAccessPath path;
936
994
937
- #ifndef NDEBUG
938
- // Local function to determine whether there is a conformance of the given
939
- // subject type to the given protocol within the given set of explicit
940
- // requirements.
941
- auto hasConformanceInSignature = [&](ArrayRef<Requirement> requirements,
942
- Type subjectType,
943
- ProtocolDecl *proto) -> bool {
944
- // Make sure this requirement exists in the requirement signature.
945
- for (const auto & req: requirements) {
946
- if (req.getKind () == RequirementKind::Conformance &&
947
- req.getFirstType ()->isEqual (subjectType) &&
948
- req.getSecondType ()->castTo <ProtocolType>()->getDecl ()
949
- == proto) {
950
- return true ;
951
- }
952
- }
953
-
954
- return false ;
955
- };
956
- #endif
957
-
958
995
// Local function to construct the conformance access path from the
959
996
// requirement.
960
997
std::function<void (ArrayRef<Requirement>, const RequirementSource *,
@@ -1003,13 +1040,6 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
1003
1040
return ;
1004
1041
}
1005
1042
1006
- // Canonicalize this step with respect to the requirement signature.
1007
- if (!inProtocol->isRequirementSignatureComputed ()) {
1008
- inProtocol->computeRequirementSignature ();
1009
- assert (inProtocol->isRequirementSignatureComputed () &&
1010
- " missing signature" );
1011
- }
1012
-
1013
1043
// Get a generic signature for the protocol's signature.
1014
1044
auto inProtoSig = inProtocol->getGenericSignature ();
1015
1045
auto &inProtoSigBuilder = *inProtoSig->getGenericSignatureBuilder ();
@@ -1031,7 +1061,7 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
1031
1061
assert (conforms != equivClass->conformsTo .end ());
1032
1062
1033
1063
// Compute the root type, canonicalizing it w.r.t. the protocol context.
1034
- auto conformsSource = getBestRequirementSource (conforms->second );
1064
+ auto conformsSource = getBestCanonicalRequirementSource (conforms->second );
1035
1065
assert (conformsSource != source || !requirementSignatureProto);
1036
1066
Type localRootType = conformsSource->getRootType ();
1037
1067
localRootType = inProtoSig->getCanonicalTypeInContext (localRootType);
@@ -1079,7 +1109,7 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
1079
1109
};
1080
1110
1081
1111
// Canonicalize the root type.
1082
- auto source = getBestRequirementSource (conforms->second );
1112
+ auto source = getBestCanonicalRequirementSource (conforms->second );
1083
1113
Type rootType = source->getRootType ()->getCanonicalType (this );
1084
1114
1085
1115
// Build the path.
0 commit comments