@@ -233,6 +233,17 @@ struct RequirementMachine::Implementation {
233
233
CanGenericSignature Sig;
234
234
bool Complete = false ;
235
235
236
+ // / All conformance access paths computed so far.
237
+ llvm::DenseMap<std::pair<CanType, ProtocolDecl *>,
238
+ ConformanceAccessPath> ConformanceAccessPaths;
239
+
240
+ // / Conformance access paths computed during the last round. All elements
241
+ // / have the same length. If a conformance access path of greater length
242
+ // / is requested, we refill CurrentConformanceAccessPaths with all paths of
243
+ // / length N+1, and add them to the ConformanceAccessPaths map.
244
+ std::vector<std::pair<CanType, ConformanceAccessPath>>
245
+ CurrentConformanceAccessPaths;
246
+
236
247
explicit Implementation (ASTContext &ctx)
237
248
: Context(ctx),
238
249
System(Context),
@@ -748,6 +759,154 @@ Type RequirementMachine::getCanonicalTypeInContext(
748
759
});
749
760
}
750
761
762
+ // / Replace 'Self' in the given dependent type (\c depTy) with the given
763
+ // / dependent type, producing a type that refers to
764
+ // / the nested type. This limited operation makes sure that it does not
765
+ // / create any new potential archetypes along the way, so it should only be
766
+ // / used in cases where we're reconstructing something that we know exists.
767
+ static Type replaceSelfWithType (Type selfType, Type depTy) {
768
+ if (auto depMemTy = depTy->getAs <DependentMemberType>()) {
769
+ Type baseType = replaceSelfWithType (selfType, depMemTy->getBase ());
770
+ assert (depMemTy->getAssocType () && " Missing associated type" );
771
+ return DependentMemberType::get (baseType, depMemTy->getAssocType ());
772
+ }
773
+
774
+ assert (depTy->is <GenericTypeParamType>() && " missing Self?" );
775
+ return selfType;
776
+ }
777
+
778
+ // / Retrieve the conformance access path used to extract the conformance of
779
+ // / interface \c type to the given \c protocol.
780
+ // /
781
+ // / \param type The interface type whose conformance access path is to be
782
+ // / queried.
783
+ // / \param protocol A protocol to which \c type conforms.
784
+ // /
785
+ // / \returns the conformance access path that starts at a requirement of
786
+ // / this generic signature and ends at the conformance that makes \c type
787
+ // / conform to \c protocol.
788
+ // /
789
+ // / \seealso ConformanceAccessPath
790
+ ConformanceAccessPath
791
+ RequirementMachine::getConformanceAccessPath (Type type,
792
+ ProtocolDecl *protocol) {
793
+ auto canType = getCanonicalTypeInContext (type, { })->getCanonicalType ();
794
+ assert (canType->isTypeParameter ());
795
+
796
+ // Check if we've already cached the result before doing anything else.
797
+ auto found = Impl->ConformanceAccessPaths .find (
798
+ std::make_pair (canType, protocol));
799
+ if (found != Impl->ConformanceAccessPaths .end ()) {
800
+ return found->second ;
801
+ }
802
+
803
+ auto *Stats = Context.Stats ;
804
+
805
+ FrontendStatsTracer tracer (Stats, " get-conformance-access-path" );
806
+
807
+ auto recordPath = [&](CanType type, ProtocolDecl *proto,
808
+ ConformanceAccessPath path) {
809
+ // Add the path to the buffer.
810
+ Impl->CurrentConformanceAccessPaths .emplace_back (type, path);
811
+
812
+ // Add the path to the map.
813
+ auto key = std::make_pair (type, proto);
814
+ auto inserted = Impl->ConformanceAccessPaths .insert (
815
+ std::make_pair (key, path));
816
+ assert (inserted.second );
817
+ (void ) inserted;
818
+
819
+ if (Stats)
820
+ ++Stats->getFrontendCounters ().NumConformanceAccessPathsRecorded ;
821
+ };
822
+
823
+ // If this is the first time we're asked to look up a conformance access path,
824
+ // visit all of the root conformance requirements in our generic signature and
825
+ // add them to the buffer.
826
+ if (Impl->ConformanceAccessPaths .empty ()) {
827
+ for (const auto &req : Impl->Sig ->getRequirements ()) {
828
+ // We only care about conformance requirements.
829
+ if (req.getKind () != RequirementKind::Conformance)
830
+ continue ;
831
+
832
+ auto rootType = CanType (req.getFirstType ());
833
+ auto *rootProto = req.getProtocolDecl ();
834
+
835
+ ConformanceAccessPath::Entry root (rootType, rootProto);
836
+ ArrayRef<ConformanceAccessPath::Entry> path (root);
837
+ ConformanceAccessPath result (Context.AllocateCopy (path));
838
+
839
+ recordPath (rootType, rootProto, result);
840
+ }
841
+ }
842
+
843
+ // We enumerate conformance access paths in lexshort order until we find the
844
+ // path whose corresponding type canonicalizes to the one we are looking for.
845
+ while (true ) {
846
+ auto found = Impl->ConformanceAccessPaths .find (
847
+ std::make_pair (canType, protocol));
848
+ if (found != Impl->ConformanceAccessPaths .end ()) {
849
+ return found->second ;
850
+ }
851
+
852
+ assert (Impl->CurrentConformanceAccessPaths .size () > 0 );
853
+
854
+ // The buffer consists of all conformance access paths of length N.
855
+ // Swap it out with an empty buffer, and fill it with all paths of
856
+ // length N+1.
857
+ std::vector<std::pair<CanType, ConformanceAccessPath>> oldPaths;
858
+ std::swap (Impl->CurrentConformanceAccessPaths , oldPaths);
859
+
860
+ for (const auto &pair : oldPaths) {
861
+ const auto &lastElt = pair.second .back ();
862
+ auto *lastProto = lastElt.second ;
863
+
864
+ // A copy of the current path, populated as needed.
865
+ SmallVector<ConformanceAccessPath::Entry, 4 > entries;
866
+
867
+ for (const auto &req : lastProto->getRequirementSignature ()) {
868
+ // We only care about conformance requirements.
869
+ if (req.getKind () != RequirementKind::Conformance)
870
+ continue ;
871
+
872
+ auto nextSubjectType = req.getFirstType ()->getCanonicalType ();
873
+ auto *nextProto = req.getProtocolDecl ();
874
+
875
+ // Compute the canonical anchor for this conformance requirement.
876
+ auto nextType = replaceSelfWithType (pair.first , nextSubjectType);
877
+ auto nextCanType = getCanonicalTypeInContext (nextType, { })
878
+ ->getCanonicalType ();
879
+
880
+ // Skip "derived via concrete" sources.
881
+ if (!nextCanType->isTypeParameter ())
882
+ continue ;
883
+
884
+ // If we've already seen a path for this conformance, skip it and
885
+ // don't add it to the buffer. Note that because we iterate over
886
+ // conformance access paths in lexshort order, the existing
887
+ // conformance access path is shorter than the one we found just now.
888
+ if (Impl->ConformanceAccessPaths .count (
889
+ std::make_pair (nextCanType, nextProto)))
890
+ continue ;
891
+
892
+ if (entries.empty ()) {
893
+ // Fill our temporary vector.
894
+ entries.insert (entries.begin (),
895
+ pair.second .begin (),
896
+ pair.second .end ());
897
+ }
898
+
899
+ // Add the next entry.
900
+ entries.emplace_back (nextSubjectType, nextProto);
901
+ ConformanceAccessPath result = Context.AllocateCopy (entries);
902
+ entries.pop_back ();
903
+
904
+ recordPath (nextCanType, nextProto, result);
905
+ }
906
+ }
907
+ }
908
+ }
909
+
751
910
// / Compare two associated types.
752
911
static int compareAssociatedTypes (AssociatedTypeDecl *assocType1,
753
912
AssociatedTypeDecl *assocType2) {
0 commit comments