|
21 | 21 | #include "swift/AST/GenericEnvironment.h"
|
22 | 22 | #include "swift/AST/Module.h"
|
23 | 23 | #include "swift/AST/Types.h"
|
| 24 | +#include "swift/Basic/STLExtras.h" |
| 25 | +#include <functional> |
24 | 26 |
|
25 | 27 | using namespace swift;
|
26 | 28 |
|
| 29 | +void ConformanceAccessPath::print(raw_ostream &out) const { |
| 30 | + interleave(begin(), end(), |
| 31 | + [&](const Entry &entry) { |
| 32 | + entry.first.print(out); |
| 33 | + out << ": " << entry.second->getName(); |
| 34 | + }, [&] { |
| 35 | + out << " -> "; |
| 36 | + }); |
| 37 | +} |
| 38 | + |
| 39 | +void ConformanceAccessPath::dump() const { |
| 40 | + print(llvm::errs()); |
| 41 | + llvm::errs() << "\n"; |
| 42 | +} |
| 43 | + |
27 | 44 | GenericSignature::GenericSignature(ArrayRef<GenericTypeParamType *> params,
|
28 | 45 | ArrayRef<Requirement> requirements,
|
29 | 46 | bool isKnownCanonical)
|
@@ -719,6 +736,109 @@ GenericEnvironment *CanGenericSignature::getGenericEnvironment(
|
719 | 736 | module);
|
720 | 737 | }
|
721 | 738 |
|
| 739 | +ConformanceAccessPath GenericSignature::getConformanceAccessPath( |
| 740 | + Type type, |
| 741 | + ProtocolDecl *protocol, |
| 742 | + ModuleDecl &mod) { |
| 743 | + assert(type->isTypeParameter() && "not a type parameter"); |
| 744 | + |
| 745 | + // Resolve this type to a potential archetype. |
| 746 | + auto &builder = *getGenericSignatureBuilder(mod); |
| 747 | + auto pa = builder.resolveArchetype(type); |
| 748 | + auto rep = pa->getRepresentative(); |
| 749 | + |
| 750 | + // Dig out the conformance of this type to the given protocol, because we |
| 751 | + // want its requirement source. |
| 752 | + auto conforms = rep->getConformsTo().find(protocol); |
| 753 | + assert(conforms != rep->getConformsTo().end()); |
| 754 | + |
| 755 | + // Follow the requirement source to form the conformance access path. |
| 756 | + typedef GenericSignatureBuilder::RequirementSource RequirementSource; |
| 757 | + ConformanceAccessPath path; |
| 758 | + |
| 759 | +#ifndef NDEBUG |
| 760 | + // Local function to determine whether there is a conformance of the given |
| 761 | + // subject type to the given protocol within the given generic signature's |
| 762 | + // explicit requirements. |
| 763 | + auto hasConformanceInSignature = [&](const GenericSignature *genericSig, |
| 764 | + Type subjectType, |
| 765 | + ProtocolDecl *proto) -> bool { |
| 766 | + // Make sure this requirement exists in the requirement signature. |
| 767 | + for (const auto& req: genericSig->getRequirements()) { |
| 768 | + if (req.getKind() == RequirementKind::Conformance && |
| 769 | + req.getFirstType()->isEqual(subjectType) && |
| 770 | + req.getSecondType()->castTo<ProtocolType>()->getDecl() |
| 771 | + == proto) { |
| 772 | + return true; |
| 773 | + } |
| 774 | + } |
| 775 | + |
| 776 | + return false; |
| 777 | + }; |
| 778 | +#endif |
| 779 | + |
| 780 | + // Local function to construct the conformance access path from the |
| 781 | + // requirement |
| 782 | + std::function<void(const RequirementSource *, ProtocolDecl *)> buildPath; |
| 783 | + buildPath = [&](const RequirementSource *source, |
| 784 | + ProtocolDecl *conformingProto) { |
| 785 | + // Each protocol requirement is a step along the path. |
| 786 | + if (source->kind == RequirementSource::ProtocolRequirement) { |
| 787 | + // Follow the rest of the path to derive the conformance into which |
| 788 | + // this particular protocol requirement step would look. |
| 789 | + auto inProtocol = source->getProtocolDecl(); |
| 790 | + buildPath(source->parent, inProtocol); |
| 791 | + |
| 792 | + // Add this step along the path, which involes looking for the |
| 793 | + // conformance we want (\c conformingProto) within the protocol |
| 794 | + // described by this source. |
| 795 | + |
| 796 | + // Canonicalize the subject type within the protocol's requirement |
| 797 | + // signature. |
| 798 | + Type subjectType = source->getStoredType(); |
| 799 | + subjectType = inProtocol->getRequirementSignature() |
| 800 | + ->getCanonicalTypeInContext(subjectType, |
| 801 | + *inProtocol->getParentModule()); |
| 802 | + |
| 803 | + assert(hasConformanceInSignature(inProtocol->getRequirementSignature(), |
| 804 | + subjectType, conformingProto) && |
| 805 | + "missing explicit conformance in requirement signature"); |
| 806 | + |
| 807 | + // Record this step. |
| 808 | + path.path.push_back({subjectType, conformingProto}); |
| 809 | + |
| 810 | + // We're done. |
| 811 | + return; |
| 812 | + } |
| 813 | + |
| 814 | + // If we still have a parent, keep going. |
| 815 | + if (source->parent) { |
| 816 | + buildPath(source->parent, conformingProto); |
| 817 | + return; |
| 818 | + } |
| 819 | + |
| 820 | + // We are at an explicit or inferred requirement. |
| 821 | + assert(source->kind == RequirementSource::Explicit || |
| 822 | + source->kind == RequirementSource::Inferred); |
| 823 | + |
| 824 | + // Retrieve the subject type, which is the archetype anchor for the root |
| 825 | + // of this requirement. |
| 826 | + auto anchor = |
| 827 | + source->getRootPotentialArchetype()->getArchetypeAnchor(builder); |
| 828 | + Type subjectType = anchor->getDependentType(getGenericParams(), false); |
| 829 | + |
| 830 | + assert(hasConformanceInSignature(this, subjectType, conformingProto) && |
| 831 | + "missing explicit conformance in signature"); |
| 832 | + |
| 833 | + // Add the root of the path, which starts at this explicit requirement. |
| 834 | + path.path.push_back({subjectType, conformingProto}); |
| 835 | + }; |
| 836 | + buildPath(conforms->second, protocol); |
| 837 | + |
| 838 | + // Return the path; we're done! |
| 839 | + return path; |
| 840 | +} |
| 841 | + |
722 | 842 | unsigned GenericParamKey::findIndexIn(
|
723 | 843 | llvm::ArrayRef<GenericTypeParamType *> genericParams) const {
|
724 | 844 | // For depth 0, we have random access. We perform the extra checking so that
|
|
0 commit comments