@@ -728,6 +728,16 @@ GenericEnvironment *CanGenericSignature::getGenericEnvironment(
728
728
module );
729
729
}
730
730
731
+ // / Remove all of the associated type declarations from the given type
732
+ // / parameter, producing \c DependentMemberTypes with names alone.
733
+ static Type eraseAssociatedTypes (Type type) {
734
+ if (auto depMemTy = type->getAs <DependentMemberType>())
735
+ return DependentMemberType::get (eraseAssociatedTypes (depMemTy->getBase ()),
736
+ depMemTy->getName ());
737
+
738
+ return type;
739
+ }
740
+
731
741
ConformanceAccessPath GenericSignature::getConformanceAccessPath (
732
742
Type type,
733
743
ProtocolDecl *protocol,
@@ -770,42 +780,82 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
770
780
#endif
771
781
772
782
// Local function to construct the conformance access path from the
773
- // requirement
774
- std::function<void (const RequirementSource *, ProtocolDecl *)> buildPath;
775
- buildPath = [&](const RequirementSource *source,
783
+ // requirement.
784
+ std::function<void (GenericSignature *, const RequirementSource *,
785
+ ProtocolDecl *)> buildPath;
786
+ buildPath = [&](GenericSignature *sig, const RequirementSource *source,
776
787
ProtocolDecl *conformingProto) {
777
788
// Each protocol requirement is a step along the path.
778
789
if (source->kind == RequirementSource::ProtocolRequirement) {
779
790
// Follow the rest of the path to derive the conformance into which
780
791
// this particular protocol requirement step would look.
781
792
auto inProtocol = source->getProtocolDecl ();
782
- buildPath (source->parent , inProtocol);
793
+ buildPath (sig, source->parent , inProtocol);
794
+ assert (path.path .back ().second == inProtocol &&
795
+ " path produces incorrect conformance" );
796
+
797
+ // If this step was computed via the requirement signature, add it
798
+ // directly.
799
+ if (source->usesRequirementSignature ) {
800
+ // Add this step along the path, which involes looking for the
801
+ // conformance we want (\c conformingProto) within the protocol
802
+ // described by this source.
803
+
804
+ // Canonicalize the subject type within the protocol's requirement
805
+ // signature.
806
+ // FIXME: We might be able to guarantee this when building from a
807
+ // requirement signature.
808
+ Type subjectType = source->getStoredType ();
809
+ subjectType = inProtocol->getRequirementSignature ()
810
+ ->getCanonicalTypeInContext (subjectType,
811
+ *inProtocol->getParentModule ());
812
+
813
+ assert (hasConformanceInSignature (inProtocol->getRequirementSignature (),
814
+ subjectType, conformingProto) &&
815
+ " missing explicit conformance in requirement signature" );
816
+
817
+ // Record this step.
818
+ path.path .push_back ({subjectType, conformingProto});
819
+ return ;
820
+ }
783
821
784
- // Add this step along the path, which involes looking for the
785
- // conformance we want (\c conformingProto) within the protocol
786
- // described by this source.
822
+ // Canonicalize this step with respect to the requirement signature.
823
+ if (!inProtocol->isRequirementSignatureComputed ()) {
824
+ inProtocol->computeRequirementSignature ();
825
+ assert (inProtocol->isRequirementSignatureComputed () &&
826
+ " missing signature" );
827
+ }
828
+
829
+ // Get a generic signature builder for the requirement signature. This has
830
+ // the requirement we need.
831
+ auto reqSig = inProtocol->getRequirementSignature ();
832
+ auto &reqSigBuilder = *reqSig->getGenericSignatureBuilder (
833
+ *inProtocol->getModuleContext ());
787
834
788
- // Canonicalize the subject type within the protocol's requirement
789
- // signature.
790
- Type subjectType = source->getStoredType ();
791
- subjectType = inProtocol->getRequirementSignature ()
792
- ->getCanonicalTypeInContext (subjectType,
793
- *inProtocol->getParentModule ());
835
+ // Retrieve the stored type, but erase all of the specific associated
836
+ // type declarations; we don't want any details of the enclosing context
837
+ // to sneak in here.
838
+ Type storedType = eraseAssociatedTypes (source->getStoredType ());
794
839
795
- assert ( hasConformanceInSignature (inProtocol-> getRequirementSignature (),
796
- subjectType, conformingProto) &&
797
- " missing explicit conformance in requirement signature " );
840
+ // Dig out the potential archetype for this stored type.
841
+ auto pa = reqSigBuilder. resolveArchetype (storedType);
842
+ auto rep = pa-> getRepresentative ( );
798
843
799
- // Record this step.
800
- path.path .push_back ({subjectType, conformingProto});
844
+ // Find the conformance of this potential archetype to the protocol in
845
+ // question.
846
+ auto knownConforms = rep->getConformsTo ().find (conformingProto);
847
+ assert (knownConforms != rep->getConformsTo ().end ());
848
+
849
+ // Build the path according to the requirement signature.
850
+ buildPath (reqSig, knownConforms->second , conformingProto);
801
851
802
852
// We're done.
803
853
return ;
804
854
}
805
855
806
856
// If we still have a parent, keep going.
807
857
if (source->parent ) {
808
- buildPath (source->parent , conformingProto);
858
+ buildPath (sig, source->parent , conformingProto);
809
859
return ;
810
860
}
811
861
@@ -815,17 +865,24 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
815
865
816
866
// Retrieve the subject type, which is the archetype anchor for the root
817
867
// of this requirement.
818
- auto anchor =
819
- source->getRootPotentialArchetype ()->getArchetypeAnchor (builder);
820
- Type subjectType = anchor->getDependentType (getGenericParams (), false );
868
+ auto subjectPA = source->getRootPotentialArchetype ();
869
+ subjectPA = subjectPA->getArchetypeAnchor (*subjectPA->getBuilder ());
870
+ Type subjectType = subjectPA->getDependentType (sig->getGenericParams (),
871
+ false );
872
+
873
+ // Skip trivial path elements. These occur when querying a requirement
874
+ // signature.
875
+ if (!path.path .empty () && conformingProto == path.path .back ().second &&
876
+ subjectType->isEqual (conformingProto->getSelfInterfaceType ()))
877
+ return ;
821
878
822
- assert (hasConformanceInSignature (this , subjectType, conformingProto) &&
879
+ assert (hasConformanceInSignature (sig , subjectType, conformingProto) &&
823
880
" missing explicit conformance in signature" );
824
881
825
882
// Add the root of the path, which starts at this explicit requirement.
826
883
path.path .push_back ({subjectType, conformingProto});
827
884
};
828
- buildPath (conforms->second , protocol);
885
+ buildPath (this , conforms->second , protocol);
829
886
830
887
// Return the path; we're done!
831
888
return path;
0 commit comments