//===--- GenericSignatureBuilder.cpp - Generic Requirement Builder --------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // Support for collecting a set of generic requirements, both explicitly stated // and inferred, and computing the archetypes and required witness tables from // those requirements. // //===----------------------------------------------------------------------===// #include "GenericSignatureBuilderImpl.h" #include "GenericSignatureBuilder.h" #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericParamList.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/TypeMatcher.h" #include "swift/AST/TypeRepr.h" #include "swift/AST/TypeWalker.h" #include "swift/Basic/Debug.h" #include "swift/Basic/Defer.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/Statistic.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/GraphWriter.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/SaveAndRestore.h" #include using namespace swift; using llvm::DenseMap; #define DEBUG_TYPE "Serialization" STATISTIC(NumLazyRequirementSignaturesLoaded, "# of lazily-deserialized requirement signatures loaded"); #undef DEBUG_TYPE namespace { typedef GenericSignatureBuilder::RequirementSource RequirementSource; typedef GenericSignatureBuilder::FloatingRequirementSource FloatingRequirementSource; typedef GenericSignatureBuilder::ConstraintResult ConstraintResult; typedef GenericSignatureBuilder::PotentialArchetype PotentialArchetype; typedef GenericSignatureBuilder::ConcreteConstraint ConcreteConstraint; template using Constraint = GenericSignatureBuilder::Constraint; typedef GenericSignatureBuilder::EquivalenceClass EquivalenceClass; typedef EquivalenceClass::DerivedSameTypeComponent DerivedSameTypeComponent; typedef GenericSignatureBuilder::DelayedRequirement DelayedRequirement; typedef GenericSignatureBuilder::ResolvedType ResolvedType; typedef GenericSignatureBuilder::RequirementRHS RequirementRHS; typedef GenericSignatureBuilder::ExplicitRequirement ExplicitRequirement; } // end anonymous namespace namespace llvm { // Equivalence classes are bump-ptr-allocated. template <> struct ilist_alloc_traits { static void deleteNode(EquivalenceClass *ptr) { ptr->~EquivalenceClass(); } }; } #define DEBUG_TYPE "Generic signature builder" STATISTIC(NumPotentialArchetypes, "# of potential archetypes"); STATISTIC(NumEquivalenceClassesAllocated, "# of equivalence classes allocated"); STATISTIC(NumEquivalenceClassesFreed, "# of equivalence classes freed"); STATISTIC(NumConformances, "# of conformances tracked"); STATISTIC(NumConformanceConstraints, "# of conformance constraints tracked"); STATISTIC(NumSameTypeConstraints, "# of same-type constraints tracked"); STATISTIC(NumConcreteTypeConstraints, "# of same-type-to-concrete constraints tracked"); STATISTIC(NumSuperclassConstraints, "# of superclass constraints tracked"); STATISTIC(NumSuperclassConstraintsExtra, "# of superclass constraints that add no information"); STATISTIC(NumLayoutConstraints, "# of layout constraints tracked"); STATISTIC(NumLayoutConstraintsExtra, "# of layout constraints that add no information"); STATISTIC(NumSelfDerived, "# of self-derived constraints removed"); STATISTIC(NumArchetypeAnchorCacheHits, "# of hits in the archetype anchor cache"); STATISTIC(NumArchetypeAnchorCacheMisses, "# of misses in the archetype anchor cache"); STATISTIC(NumNestedTypeCacheHits, "# of hits in the equivalence class nested type cache"); STATISTIC(NumNestedTypeCacheMisses, "# of misses in the equivalence class nested type cache"); STATISTIC(NumProcessDelayedRequirements, "# of times we process delayed requirements"); STATISTIC(NumProcessDelayedRequirementsUnchanged, "# of times we process delayed requirements without change"); STATISTIC(NumDelayedRequirementConcrete, "Delayed requirements resolved as concrete"); STATISTIC(NumDelayedRequirementResolved, "Delayed requirements resolved"); STATISTIC(NumDelayedRequirementUnresolved, "Delayed requirements left unresolved"); STATISTIC(NumConditionalRequirementsAdded, "# of conditional requirements added"); STATISTIC(NumRewriteMinimizations, "# of rewrite system minimizations performed"); STATISTIC(NumRewriteRhsSimplified, "# of rewrite rule right-hand sides simplified"); STATISTIC(NumRewriteRhsSimplifiedToLhs, "# of rewrite rule right-hand sides simplified to lhs (and removed)"); STATISTIC(NumRewriteRulesRedundant, "# of rewrite rules that are redundant (and removed)"); STATISTIC(NumSignaturesRebuiltWithoutRedundantRequirements, "# of generic signatures which had a concretized conformance requirement"); namespace { /// A purely-relative rewrite path consisting of a (possibly empty) /// sequence of associated type references. using RelativeRewritePath = ArrayRef; class AnchorPathCache; /// Describes a rewrite path, which contains an optional base (generic /// parameter) followed by a sequence of associated type references. class RewritePath { Optional base; TinyPtrVector path; public: RewritePath() { } enum PathOrder { Forward, Reverse, }; /// Form a rewrite path given an optional base and a relative rewrite path. RewritePath(Optional base, RelativeRewritePath path, PathOrder order); /// Retrieve the base of the given rewrite path. /// /// When present, it indicates that the entire path will be rebased on /// the given base generic parameter. This is required for describing /// rewrites on type parameters themselves, e.g., T == U. /// /// When absent, the path is relative to the root of the tree from which /// the search began. Optional getBase() const { return base; } /// Retrieve the sequence of associated type references that describes /// the path. ArrayRef getPath() const { return path; } /// Whether this path is completely empty. bool isEmpty() const { return getBase() == None && getPath().empty(); } /// whether this describes a valid path. explicit operator bool() const { return !isEmpty(); } /// Decompose a type into a path. /// /// \returns the path, or None if it contained unresolved dependent member /// types. static RewritePath createPath(Type type); /// Decompose a type into a path. /// /// \param path Will be filled in with the components of the path, in /// reverse order. /// /// \returns the generic parameter at the start of the path. static GenericParamKey createPath( Type type, SmallVectorImpl &path); /// Compute the longer common prefix between this path and \c other. RewritePath commonPath(const RewritePath &other) const; /// Form a canonical, dependent type. /// /// This requires that either the rewrite path have a base, or the /// \c baseEquivClass to be non-null (which substitutes in a base). CanType formDependentType(ASTContext &ctx, AnchorPathCache *anchorPathCache = nullptr) const; /// Compare the given rewrite paths. int compare(const RewritePath &other) const; /// Print this path. void print(llvm::raw_ostream &out) const; SWIFT_DEBUG_DUMP { print(llvm::errs()); } friend bool operator==(const RewritePath &lhs, const RewritePath &rhs) { return lhs.getBase() == rhs.getBase() && lhs.getPath() == rhs.getPath(); } }; /// A cache that lazily computes the anchor path for the given equivalence /// class. class AnchorPathCache { GenericSignatureBuilder &builder; EquivalenceClass &equivClass; Optional anchorPath; public: AnchorPathCache(GenericSignatureBuilder &builder, EquivalenceClass &equivClass) : builder(builder), equivClass(equivClass) { } const RewritePath &getAnchorPath() { if (anchorPath) return *anchorPath; anchorPath = RewritePath::createPath(equivClass.getAnchor(builder, { })); return *anchorPath; } }; /// A node within the prefix tree that is used to match associated type /// references. class RewriteTreeNode { /// The associated type that leads to this node. /// /// The bit indicates whether there is a rewrite rule for this particular /// node. If the bit is not set, \c rewrite is invalid. llvm::PointerIntPair assocTypeAndHasRewrite; /// The sequence of associated types to which a reference to this associated /// type (from the equivalence class root) can be rewritten. This field is /// only valid when the bit of \c assocTypeAndHasRewrite is set. /// /// Consider a requirement "Self.A.B.C == C". This will be encoded as /// a prefix tree starting at the equivalence class for Self with /// the following nodes: /// /// (assocType: A, /// children: [ /// (assocType: B, /// children: [ /// (assocType: C, rewrite: [C], children: []) /// ]) /// ]) RewritePath rewrite; /// The child nodes, which extend the sequence to be matched. /// /// The child nodes are sorted by the associated type declaration /// pointers, so we can perform binary searches quickly. llvm::TinyPtrVector children; public: ~RewriteTreeNode(); RewriteTreeNode(AssociatedTypeDecl *assocType) : assocTypeAndHasRewrite(assocType, false) { } /// Retrieve the associated type declaration one must match to use this /// node, which may the AssociatedTypeDecl *getMatch() const { return assocTypeAndHasRewrite.getPointer(); } /// Determine whether this particular node has a rewrite rule. bool hasRewriteRule() const { return assocTypeAndHasRewrite.getInt(); } /// Set a new rewrite rule for this particular node. This can only be /// performed once. void setRewriteRule(RewritePath replacementPath) { assert(!hasRewriteRule()); assocTypeAndHasRewrite.setInt(true); rewrite = replacementPath; } /// Remove the rewrite rule. void removeRewriteRule() { assert(hasRewriteRule()); assocTypeAndHasRewrite.setInt(false); } /// Retrieve the path to which this node will be rewritten. const RewritePath &getRewriteRule() const & { assert(hasRewriteRule()); return rewrite; } /// Retrieve the path to which this node will be rewritten. RewritePath &&getRewriteRule() && { assert(hasRewriteRule()); return std::move(rewrite); } /// Add a new rewrite rule to this tree node. /// /// \param matchPath The path of associated type declarations that must /// be matched to produce a rewrite. /// /// \param replacementPath The sequence of associated type declarations /// with which a match will be replaced. /// /// \returns true if a rewrite rule was added, and false if it already /// existed. bool addRewriteRule(RelativeRewritePath matchPath, RewritePath replacementPath); /// Enumerate all of the paths to which the given matched path can be /// rewritten. /// /// \param matchPath The path to match. /// /// \param callback A callback that will be invoked with (prefix, rewrite) /// pairs, where \c prefix is the length of the matching prefix of /// \c matchPath that matched and \c rewrite is the path to which it can /// be rewritten. void enumerateRewritePaths( RelativeRewritePath matchPath, llvm::function_ref callback) const { return enumerateRewritePathsImpl(matchPath, callback, /*depth=*/0); } private: void enumerateRewritePathsImpl( RelativeRewritePath matchPath, llvm::function_ref callback, unsigned depth) const; public: /// Find the best rewrite rule to match the given path. /// /// \param path The path to match. /// \param prefixLength The length of the prefix leading up to \c path. Optional> bestRewritePath(GenericParamKey base, RelativeRewritePath path, unsigned prefixLength); /// Merge the given rewrite tree into \c other. /// /// \returns true if any rules were created by this merge. bool mergeInto(RewriteTreeNode *other); /// An action to perform for the given rule class RuleAction { enum Kind { /// No action; continue traversal. None, /// Stop traversal. Stop, /// Remove the given rule completely. Remove, /// Replace the right-hand side of the rule with the given new path. Replace, } kind; RewritePath path; RuleAction(Kind kind, RewritePath path = {}) : kind(kind), path(path) { } friend class RewriteTreeNode; public: static RuleAction none() { return RuleAction(None); } static RuleAction stop() { return RuleAction(Stop); } static RuleAction remove() { return RuleAction(Remove); } static RuleAction replace(RewritePath path) { return RuleAction(Replace, std::move(path)); } operator Kind() const { return kind; } }; /// Callback function for enumerating rules in a tree. using EnumerateCallback = RuleAction(RelativeRewritePath lhs, const RewritePath &rhs); /// Enumerate all of the rewrite rules, calling \c fn with the left and /// right-hand sides of each rule. /// /// \returns true if the action function returned \c Stop at any point. bool enumerateRules(llvm::function_ref fn, bool temporarilyDisableVisitedRule = false) { SmallVector lhs; return enumerateRulesRec(fn, temporarilyDisableVisitedRule, lhs); } SWIFT_DEBUG_DUMP; /// Dump the tree. void dump(llvm::raw_ostream &out, bool lastChild = true) const; private: /// Enumerate all of the rewrite rules, calling \c fn with the left and /// right-hand sides of each rule. /// /// \returns true if the action function returned \c Stop at any point. bool enumerateRulesRec(llvm::function_ref &fn, bool temporarilyDisableVisitedRule, llvm::SmallVectorImpl &lhs); }; } /// A representation of an explicit requirement, used for diagnosing redundant /// requirements. /// /// Just like the Requirement data type, this stores the requirement kind and /// a right hand side (either another type, a protocol, or a layout constraint). /// /// However, instead of a subject type, we store an explicit requirement source, /// from which the subject type can be obtained. class GenericSignatureBuilder::ExplicitRequirement { llvm::PointerIntPair sourceAndKind; RequirementRHS rhs; public: ExplicitRequirement(RequirementKind kind, const RequirementSource *source, RequirementRHS rhs) : sourceAndKind(source, kind), rhs(rhs) { if (auto type = rhs.dyn_cast()) this->rhs = type->getCanonicalType(); } static std::pair getKindAndRHS(const RequirementSource *source, ASTContext &ctx) { switch (source->kind) { // If we have a protocol requirement source whose parent is the root, then // we have an implied constraint coming from a protocol's requirement // signature: // // Explicit: T -> ProtocolRequirement: Self.Iterator (in Sequence) // // The root's subject type (T) is the subject of the constraint. The next // innermost child -- the ProtocolRequirement source -- stores the // conformed-to protocol declaration. // // Therefore the original constraint was 'T : Sequence'. case RequirementSource::ProtocolRequirement: case RequirementSource::InferredProtocolRequirement: { auto *proto = source->getProtocolDecl(); return std::make_pair(RequirementKind::Conformance, proto); } // If we have a superclass or concrete source whose parent is the root, then // we have an implied conformance constraint -- either this: // // Explicit: T -> Superclass: [MyClass : P] // // or this: // // Explicit: T -> Concrete: [MyStruct : P] // // The original constraint was either 'T : MyClass' or 'T == MyStruct', // respectively. case RequirementSource::Superclass: case RequirementSource::Concrete: { Type conformingType = source->getStoredType(); if (conformingType) { // A concrete requirement source for a self-conforming exitential type // stores the original type, and not the conformance, because there is // no way to recover the original type from the conformance. assert(conformingType->isExistentialType()); } else { auto conformance = source->getProtocolConformance(); if (conformance.isConcrete()) conformingType = conformance.getConcrete()->getType(); else { // If the conformance was abstract or invalid, we're dealing with // invalid code. We have no way to recover the superclass type, so // just stick an ErrorType in there. conformingType = ErrorType::get(ctx); } } auto kind = (source->kind == RequirementSource::Superclass ? RequirementKind::Superclass : RequirementKind::SameType); return std::make_pair(kind, conformingType); } // If we have a layout source whose parent is the root, then // we have an implied layout constraint: // // Explicit: T -> Layout: MyClass // // The original constraint was the superclass constraint 'T : MyClass' // (*not* a layout constraint -- this is the layout constraint *implied* // by a superclass constraint, ensuring that it supercedes an explicit // 'T : AnyObject' constraint). case RequirementSource::Layout: { auto type = source->getStoredType(); return std::make_pair(RequirementKind::Superclass, type); } case RequirementSource::RequirementSignatureSelf: return std::make_pair(RequirementKind::Conformance, source->getProtocolDecl()); default: { source->dump(llvm::errs(), &ctx.SourceMgr, 0); llvm::errs() << "\n"; llvm_unreachable("Unhandled source kind"); } } } RequirementKind getKind() const { return sourceAndKind.getInt(); } Type getSubjectType() const { return getSource()->getStoredType(); } const RequirementSource *getSource() const { return sourceAndKind.getPointer(); } RequirementRHS getRHS() const { return rhs; } void dump(llvm::raw_ostream &out, SourceManager *SM) const; static ExplicitRequirement getEmptyKey() { return ExplicitRequirement(RequirementKind::Conformance, nullptr, nullptr); } static ExplicitRequirement getTombstoneKey() { return ExplicitRequirement(RequirementKind::Superclass, nullptr, Type()); } friend llvm::hash_code hash_value(const ExplicitRequirement &req) { using llvm::hash_value; llvm::hash_code first = hash_value(req.sourceAndKind.getOpaqueValue()); llvm::hash_code second = hash_value(req.rhs.getOpaqueValue()); return llvm::hash_combine(first, second); } friend bool operator==(const ExplicitRequirement &lhs, const ExplicitRequirement &rhs) { if (lhs.sourceAndKind.getOpaqueValue() != rhs.sourceAndKind.getOpaqueValue()) return false; if (lhs.rhs.getOpaqueValue() != rhs.rhs.getOpaqueValue()) return false; return true; } friend bool operator!=(const ExplicitRequirement &lhs, const ExplicitRequirement &rhs) { return !(lhs == rhs); } }; namespace llvm { template<> struct DenseMapInfo { static swift::GenericSignatureBuilder::ExplicitRequirement getEmptyKey() { return swift::GenericSignatureBuilder::ExplicitRequirement::getEmptyKey(); } static swift::GenericSignatureBuilder::ExplicitRequirement getTombstoneKey() { return swift::GenericSignatureBuilder::ExplicitRequirement::getTombstoneKey(); } static unsigned getHashValue( const swift::GenericSignatureBuilder::ExplicitRequirement &req) { return hash_value(req); } static bool isEqual(const swift::GenericSignatureBuilder::ExplicitRequirement &lhs, const swift::GenericSignatureBuilder::ExplicitRequirement &rhs) { return lhs == rhs; } }; } namespace { struct ConflictingConcreteTypeRequirement { ExplicitRequirement otherRequirement; Type resolvedConcreteType; RequirementRHS otherRHS; }; } struct GenericSignatureBuilder::Implementation { /// Allocator. llvm::BumpPtrAllocator Allocator; /// The generic parameters that this generic signature builder is working /// with. SmallVector GenericParams; /// The potential archetypes for the generic parameters in \c GenericParams. SmallVector PotentialArchetypes; /// The requirement sources used in this generic signature builder. llvm::FoldingSet RequirementSources; /// The set of requirements that have been delayed for some reason. SmallVector DelayedRequirements; /// The set of equivalence classes. llvm::iplist EquivalenceClasses; /// Equivalence classes that are not currently being used. std::vector FreeEquivalenceClasses; /// The roots of the rewrite tree, keyed on the canonical, dependent /// types. DenseMap> RewriteTreeRoots; /// The generation number for the term-rewriting system, which is /// increased every time a new rule gets added. unsigned RewriteGeneration = 0; /// The generation at which the term-rewriting system was last minimized. unsigned LastRewriteMinimizedGeneration = 0; /// The generation number, which is incremented whenever we successfully /// introduce a new constraint. unsigned Generation = 0; /// The generation at which we last processed all of the delayed requirements. unsigned LastProcessedGeneration = 0; /// Whether we are currently processing delayed requirements. bool ProcessingDelayedRequirements = false; /// Whether we are currently minimizing the term-rewriting system. bool MinimizingRewriteSystem = false; /// Whether there were any errors. bool HadAnyError = false; /// Set this to true to get some debug output. bool DebugRedundantRequirements = false; /// All explicit non-same type requirements that were added to the builder. SmallSetVector ExplicitRequirements; /// All explicit same-type requirements that were added to the builder. SmallVector ExplicitSameTypeRequirements; /// Whether we are rebuilding a signature without redundant conformance /// requirements. bool RebuildingWithoutRedundantConformances = false; /// Whether we are building a protocol requirement signature. bool BuildingProtocolRequirementSignature = false; /// A mapping of redundant explicit requirements to the best root requirement /// that implies them. Built by computeRedundantRequirements(). using RedundantRequirementMap = llvm::DenseMap>; RedundantRequirementMap RedundantRequirements; /// Requirements which conflict with other requirements, for example if a /// there are two unrelated superclass requirements on the same type, /// the second one is recorded here. Built by computeRedundantRequirements(). llvm::DenseMap ConflictingRequirements; /// Pairs of conflicting concrete type vs. superclass/layout/conformance /// requirements. std::vector ConflictingConcreteTypeRequirements; llvm::DenseSet ExplicitConformancesImpliedByConcrete; llvm::DenseMap, ConformanceAccessPath> ConformanceAccessPaths; std::vector> CurrentConformanceAccessPaths; #ifndef NDEBUG /// Whether we've already computed redundant requiremnts. bool computedRedundantRequirements = false; /// Whether we've already finalized the builder. bool finalized = false; #endif /// Tear down an implementation. ~Implementation(); /// Allocate a new equivalence class with the given representative. EquivalenceClass *allocateEquivalenceClass( PotentialArchetype *representative); /// Deallocate the given equivalence class, returning it to the free list. void deallocateEquivalenceClass(EquivalenceClass *equivClass); /// Retrieve the rewrite tree root for the given anchor type. RewriteTreeNode *getRewriteTreeRootIfPresent(CanType anchor); /// Retrieve the rewrite tree root for the given anchor type, /// creating it if needed. RewriteTreeNode *getOrCreateRewriteTreeRoot(CanType anchor); /// Minimize the rewrite tree by minimizing the right-hand sides and /// removing redundant rules. void minimizeRewriteTree(GenericSignatureBuilder &builder); private: /// Minimize the right-hand sides of the rewrite tree, simplifying them /// as far as possible and removing any changes that result in trivial /// rules. void minimizeRewriteTreeRhs(GenericSignatureBuilder &builder); /// Minimize the right-hand sides of the rewrite tree, simplifying them /// as far as possible and removing any changes that result in trivial /// rules. void removeRewriteTreeRedundancies(GenericSignatureBuilder &builder); }; #pragma mark Memory management GenericSignatureBuilder::Implementation::~Implementation() { for (auto pa : PotentialArchetypes) pa->~PotentialArchetype(); } EquivalenceClass * GenericSignatureBuilder::Implementation::allocateEquivalenceClass( PotentialArchetype *representative) { void *mem; if (FreeEquivalenceClasses.empty()) { // Allocate a new equivalence class. mem = Allocator.Allocate(); } else { // Take an equivalence class from the free list. mem = FreeEquivalenceClasses.back(); FreeEquivalenceClasses.pop_back(); } auto equivClass = new (mem) EquivalenceClass(representative); EquivalenceClasses.push_back(equivClass); ++NumEquivalenceClassesAllocated; return equivClass; } void GenericSignatureBuilder::Implementation::deallocateEquivalenceClass( EquivalenceClass *equivClass) { EquivalenceClasses.erase(equivClass); FreeEquivalenceClasses.push_back(equivClass); ++NumEquivalenceClassesFreed; } #pragma mark Requirement sources #ifndef NDEBUG bool RequirementSource::isAcceptableStorageKind(Kind kind, StorageKind storageKind) { switch (kind) { case Explicit: case Inferred: case RequirementSignatureSelf: case NestedTypeNameMatch: case EquivalentType: case Layout: switch (storageKind) { case StorageKind::StoredType: return true; case StorageKind::ProtocolConformance: case StorageKind::AssociatedTypeDecl: case StorageKind::None: return false; } case Parent: switch (storageKind) { case StorageKind::AssociatedTypeDecl: return true; case StorageKind::StoredType: case StorageKind::ProtocolConformance: case StorageKind::None: return false; } case ProtocolRequirement: case InferredProtocolRequirement: switch (storageKind) { case StorageKind::StoredType: return true; case StorageKind::ProtocolConformance: case StorageKind::AssociatedTypeDecl: case StorageKind::None: return false; } case Superclass: case Concrete: switch (storageKind) { case StorageKind::StoredType: case StorageKind::ProtocolConformance: return true; case StorageKind::AssociatedTypeDecl: case StorageKind::None: return false; } } llvm_unreachable("Unhandled RequirementSourceKind in switch."); } #endif const void *RequirementSource::getOpaqueStorage1() const { switch (storageKind) { case StorageKind::None: return nullptr; case StorageKind::ProtocolConformance: return storage.conformance; case StorageKind::StoredType: return storage.type; case StorageKind::AssociatedTypeDecl: return storage.assocType; } llvm_unreachable("Unhandled StorageKind in switch."); } const void *RequirementSource::getOpaqueStorage2() const { if (numTrailingObjects(OverloadToken()) == 1) return getTrailingObjects()[0]; if (numTrailingObjects(OverloadToken()) == 1) return getTrailingObjects()[0].getOpaquePointerValue(); return nullptr; } const void *RequirementSource::getOpaqueStorage3() const { if (numTrailingObjects(OverloadToken()) == 1 && numTrailingObjects(OverloadToken()) == 1) return getTrailingObjects()[0].getOpaquePointerValue(); return nullptr; } bool RequirementSource::isInferredRequirement() const { for (auto source = this; source; source = source->parent) { switch (source->kind) { case Inferred: case InferredProtocolRequirement: case NestedTypeNameMatch: return true; case EquivalentType: return false; case Concrete: case Explicit: case Parent: case ProtocolRequirement: case RequirementSignatureSelf: case Superclass: case Layout: break; } } return false; } unsigned RequirementSource::classifyDiagKind() const { if (isInferredRequirement()) return 2; if (isDerivedRequirement()) return 1; return 0; } bool RequirementSource::isDerivedRequirement() const { switch (kind) { case Explicit: case Inferred: return false; case NestedTypeNameMatch: case Parent: case Superclass: case Concrete: case RequirementSignatureSelf: case Layout: case EquivalentType: return true; case ProtocolRequirement: case InferredProtocolRequirement: // Requirements based on protocol requirements are derived unless they are // direct children of the requirement-signature source, in which case we // need to keep them for the requirement signature. return parent->kind != RequirementSignatureSelf; } llvm_unreachable("Unhandled RequirementSourceKind in switch."); } bool RequirementSource::isDerivedNonRootRequirement() const { return (isDerivedRequirement() && kind != RequirementSource::RequirementSignatureSelf); } bool RequirementSource::shouldDiagnoseRedundancy(bool primary) const { return !isInferredRequirement() && getLoc().isValid() && (!primary || !isDerivedRequirement()); } bool RequirementSource::isSelfDerivedSource(GenericSignatureBuilder &builder, Type type) const { return getMinimalConformanceSource(builder, type, /*proto=*/nullptr) != this; } /// Replace 'Self' in the given dependent type (\c depTy) with the given /// dependent type, producing a type that refers to /// the nested type. This limited operation makes sure that it does not /// create any new potential archetypes along the way, so it should only be /// used in cases where we're reconstructing something that we know exists. static Type replaceSelfWithType(Type selfType, Type depTy) { if (auto depMemTy = depTy->getAs()) { Type baseType = replaceSelfWithType(selfType, depMemTy->getBase()); assert(depMemTy->getAssocType() && "Missing associated type"); return DependentMemberType::get(baseType, depMemTy->getAssocType()); } assert(depTy->is() && "missing Self?"); return selfType; } /// Determine whether the given protocol requirement is self-derived when it /// occurs within the requirement signature of its own protocol. static bool isSelfDerivedProtocolRequirementInProtocol( const RequirementSource *source, const ProtocolDecl *selfProto, GenericSignatureBuilder &builder) { assert(source->isProtocolRequirement()); // This can only happen if the requirement points comes from the protocol // itself. if (source->getProtocolDecl() != selfProto) return false; // This only applies if the parent is not the anchor for computing the // requirement signature. Anywhere else, we can use the protocol requirement. if (source->parent->kind == RequirementSource::RequirementSignatureSelf) return false; // If the relative type of the protocol requirement itself is in the // same equivalence class as what we've proven with this requirement, // it's a self-derived requirement. return builder.resolveEquivalenceClass(source->getAffectedType(), ArchetypeResolutionKind::WellFormed) == builder.resolveEquivalenceClass(source->getStoredType(), ArchetypeResolutionKind::AlreadyKnown); } const RequirementSource *RequirementSource::getMinimalConformanceSource( GenericSignatureBuilder &builder, Type currentType, ProtocolDecl *proto) const { // If it's not a derived requirement, it's not self-derived. if (!isDerivedRequirement()) return this; /// Keep track of all of the requirements we've seen along the way. If /// we see the same requirement twice, we have found a shorter path. llvm::DenseMap, const RequirementSource *> constraintsSeen; /// Note that we've now seen a new constraint (described on an equivalence /// class). auto addConstraint = [&](EquivalenceClass *equivClass, ProtocolDecl *proto, const RequirementSource *source) -> const RequirementSource * { auto &storedSource = constraintsSeen[{equivClass, proto}]; if (storedSource) return storedSource; storedSource = source; return nullptr; }; // Note that we've now seen a new constraint, returning true if we've seen // it before. auto addTypeConstraint = [&](Type type, ProtocolDecl *proto, const RequirementSource *source) -> const RequirementSource * { auto equivClass = builder.resolveEquivalenceClass(type, ArchetypeResolutionKind::WellFormed); assert(equivClass && "Not a well-formed type?"); return addConstraint(equivClass, proto, source); }; const ProtocolDecl *requirementSignatureSelfProto = nullptr; Optional> redundantSubpath; bool isSelfDerived = visitPotentialArchetypesAlongPath( [&](Type parentType, const RequirementSource *source) { switch (source->kind) { case ProtocolRequirement: case InferredProtocolRequirement: { // If the base has been made concrete, note it. auto parentEquivClass = builder.resolveEquivalenceClass(parentType, ArchetypeResolutionKind::WellFormed); assert(parentEquivClass && "Not a well-formed type?"); // The parent potential archetype must conform to the protocol in which // this requirement resides. Add this constraint. if (auto startOfPath = addConstraint(parentEquivClass, source->getProtocolDecl(), source->parent)) { // We found a redundant subpath; record it and stop the algorithm. assert(startOfPath != source->parent); redundantSubpath = { startOfPath, source->parent }; return true; } // If this is a self-derived protocol requirement, fail. if (requirementSignatureSelfProto && isSelfDerivedProtocolRequirementInProtocol( source, requirementSignatureSelfProto, builder)) { redundantSubpath = { source->getRoot(), source->parent }; return true; } // No redundancy thus far. return false; } case Parent: // FIXME: Ad hoc detection of recursive same-type constraints. return !proto && builder.areInSameEquivalenceClass(parentType, currentType); case Concrete: case Superclass: case Layout: case EquivalentType: return false; case RequirementSignatureSelf: // Note the protocol whose requirement signature the requirement is // based on. requirementSignatureSelfProto = source->getProtocolDecl(); LLVM_FALLTHROUGH; case Explicit: case Inferred: case NestedTypeNameMatch: return false; } llvm_unreachable("unhandled kind"); }).isNull(); // If we didn't already find a redundancy, check our end state. if (!redundantSubpath && proto) { if (auto startOfPath = addTypeConstraint(currentType, proto, this)) { redundantSubpath = { startOfPath, this }; assert(startOfPath != this); isSelfDerived = true; } } // If we saw a constraint twice, it's self-derived. if (redundantSubpath) { assert(isSelfDerived && "Not considered self-derived?"); auto shorterSource = withoutRedundantSubpath(builder, redundantSubpath->first, redundantSubpath->second); return shorterSource ->getMinimalConformanceSource(builder, currentType, proto); } // It's self-derived but we don't have a redundant subpath to eliminate. if (isSelfDerived) return nullptr; return this; } #define REQUIREMENT_SOURCE_FACTORY_BODY(ProfileArgs, ConstructorArgs, \ NumProtocolDecls, WrittenReq) \ llvm::FoldingSetNodeID nodeID; \ Profile ProfileArgs; \ \ void *insertPos = nullptr; \ if (auto known = \ builder.Impl->RequirementSources.FindNodeOrInsertPos(nodeID, \ insertPos)) \ return known; \ \ unsigned size = \ totalSizeToAlloc( \ NumProtocolDecls, \ WrittenReq.isValid()? 1 : 0); \ void *mem = \ builder.Impl->Allocator.Allocate(size, alignof(RequirementSource)); \ auto result = new (mem) RequirementSource ConstructorArgs; \ builder.Impl->RequirementSources.InsertNode(result, insertPos); \ return result const RequirementSource *RequirementSource::forAbstract( GenericSignatureBuilder &builder, Type rootType) { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, Explicit, nullptr, rootType.getPointer(), nullptr, nullptr), (Explicit, rootType, nullptr, SourceLoc()), 0, SourceLoc()); } const RequirementSource *RequirementSource::forExplicit( GenericSignatureBuilder &builder, Type rootType, SourceLoc writtenLoc) { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, Explicit, nullptr, rootType.getPointer(), writtenLoc.getOpaquePointerValue(), nullptr), (Explicit, rootType, nullptr, writtenLoc), 0, writtenLoc); } const RequirementSource *RequirementSource::forInferred( GenericSignatureBuilder &builder, Type rootType, SourceLoc writtenLoc) { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, Inferred, nullptr, rootType.getPointer(), writtenLoc.getOpaquePointerValue(), nullptr), (Inferred, rootType, nullptr, writtenLoc), 0, writtenLoc); } const RequirementSource *RequirementSource::forRequirementSignature( GenericSignatureBuilder &builder, Type rootType, ProtocolDecl *protocol) { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, RequirementSignatureSelf, nullptr, rootType.getPointer(), protocol, nullptr), (RequirementSignatureSelf, rootType, protocol, SourceLoc()), 1, SourceLoc()); } const RequirementSource *RequirementSource::forNestedTypeNameMatch( GenericSignatureBuilder &builder, Type rootType) { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, NestedTypeNameMatch, nullptr, rootType.getPointer(), nullptr, nullptr), (NestedTypeNameMatch, rootType, nullptr, SourceLoc()), 0, SourceLoc()); } const RequirementSource *RequirementSource::viaProtocolRequirement( GenericSignatureBuilder &builder, Type dependentType, ProtocolDecl *protocol, bool inferred, SourceLoc writtenLoc) const { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, inferred ? InferredProtocolRequirement : ProtocolRequirement, this, dependentType.getPointer(), protocol, writtenLoc.getOpaquePointerValue()), (inferred ? InferredProtocolRequirement : ProtocolRequirement, this, dependentType, protocol, writtenLoc), 1, writtenLoc); } const RequirementSource *RequirementSource::viaSuperclass( GenericSignatureBuilder &builder, ProtocolConformanceRef conformance) const { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, Superclass, this, conformance.getOpaqueValue(), nullptr, nullptr), (Superclass, this, conformance), 0, SourceLoc()); } const RequirementSource *RequirementSource::viaConcrete( GenericSignatureBuilder &builder, ProtocolConformanceRef conformance) const { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, Concrete, this, conformance.getOpaqueValue(), nullptr, nullptr), (Concrete, this, conformance), 0, SourceLoc()); } const RequirementSource *RequirementSource::viaConcrete( GenericSignatureBuilder &builder, Type existentialType) const { assert(existentialType->isExistentialType()); REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, Concrete, this, existentialType.getPointer(), nullptr, nullptr), (Concrete, this, existentialType), 0, SourceLoc()); } const RequirementSource *RequirementSource::viaParent( GenericSignatureBuilder &builder, AssociatedTypeDecl *assocType) const { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, Parent, this, assocType, nullptr, nullptr), (Parent, this, assocType), 0, SourceLoc()); } const RequirementSource *RequirementSource::viaLayout( GenericSignatureBuilder &builder, Type superclass) const { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, Layout, this, superclass.getPointer(), nullptr, nullptr), (Layout, this, superclass), 0, SourceLoc()); } const RequirementSource *RequirementSource::viaEquivalentType( GenericSignatureBuilder &builder, Type newType) const { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, EquivalentType, this, newType.getPointer(), nullptr, nullptr), (EquivalentType, this, newType), 0, SourceLoc()); } #undef REQUIREMENT_SOURCE_FACTORY_BODY const RequirementSource *RequirementSource::withoutRedundantSubpath( GenericSignatureBuilder &builder, const RequirementSource *start, const RequirementSource *end) const { // Replace the end with the start; the caller has guaranteed that they // produce the same thing. if (this == end) { #ifndef NDEBUG // Sanity check: make sure the 'start' precedes the 'end'. bool foundStart = false; for (auto source = this; source; source = source->parent) { if (source == start) { foundStart = true; break; } } assert(foundStart && "Start doesn't precede end!"); #endif return start; } switch (kind) { case Explicit: case Inferred: case RequirementSignatureSelf: case NestedTypeNameMatch: llvm_unreachable("Subpath end doesn't occur within path"); case ProtocolRequirement: return parent->withoutRedundantSubpath(builder, start, end) ->viaProtocolRequirement(builder, getStoredType(), getProtocolDecl(), /*inferred=*/false, getSourceLoc()); case InferredProtocolRequirement: return parent->withoutRedundantSubpath(builder, start, end) ->viaProtocolRequirement(builder, getStoredType(), getProtocolDecl(), /*inferred=*/true, getSourceLoc()); case Concrete: if (auto existentialType = getStoredType()) { assert(existentialType->isExistentialType()); return parent->withoutRedundantSubpath(builder, start, end) ->viaConcrete(builder, existentialType); } else { return parent->withoutRedundantSubpath(builder, start, end) ->viaConcrete(builder, getProtocolConformance()); } case Layout: return parent->withoutRedundantSubpath(builder, start, end) ->viaLayout(builder, getStoredType()); case EquivalentType: return parent->withoutRedundantSubpath(builder, start, end) ->viaEquivalentType(builder, Type(storage.type)); case Parent: return parent->withoutRedundantSubpath(builder, start, end) ->viaParent(builder, getAssociatedType()); case Superclass: return parent->withoutRedundantSubpath(builder, start, end) ->viaSuperclass(builder, getProtocolConformance()); } llvm_unreachable("unhandled kind"); } const RequirementSource *RequirementSource::getRoot() const { auto root = this; while (auto parent = root->parent) root = parent; return root; } Type RequirementSource::getRootType() const { /// Find the root. auto root = getRoot(); // We're at the root, so it's in the inline storage. assert(root->storageKind == StorageKind::StoredType); return Type(root->storage.type); } Type RequirementSource::getAffectedType() const { return visitPotentialArchetypesAlongPath( [](Type, const RequirementSource *) { return false; }); } Type RequirementSource::visitPotentialArchetypesAlongPath( llvm::function_ref visitor) const { switch (kind) { case RequirementSource::Parent: { Type parentType = parent->visitPotentialArchetypesAlongPath(visitor); if (!parentType) return nullptr; if (visitor(parentType, this)) return nullptr; return replaceSelfWithType(parentType, getAssociatedType()->getDeclaredInterfaceType()); } case RequirementSource::NestedTypeNameMatch: case RequirementSource::Explicit: case RequirementSource::Inferred: case RequirementSource::RequirementSignatureSelf: { Type rootType = getRootType(); if (visitor(rootType, this)) return nullptr; return rootType; } case RequirementSource::Concrete: case RequirementSource::Superclass: case RequirementSource::Layout: return parent->visitPotentialArchetypesAlongPath(visitor); case RequirementSource::EquivalentType: { auto parentType = parent->visitPotentialArchetypesAlongPath(visitor); if (!parentType) return nullptr; if (visitor(parentType, this)) return nullptr; return Type(storage.type); } case RequirementSource::ProtocolRequirement: case RequirementSource::InferredProtocolRequirement: { Type parentType = parent->visitPotentialArchetypesAlongPath(visitor); if (!parentType) return nullptr; if (visitor(parentType, this)) return nullptr; return replaceSelfWithType(parentType, getStoredType()); } } llvm_unreachable("unhandled kind"); } Type RequirementSource::getStoredType() const { switch (storageKind) { case StorageKind::None: case StorageKind::ProtocolConformance: case StorageKind::AssociatedTypeDecl: return Type(); case StorageKind::StoredType: return storage.type; } llvm_unreachable("Unhandled StorageKind in switch."); } ProtocolDecl *RequirementSource::getProtocolDecl() const { switch (storageKind) { case StorageKind::None: return nullptr; case StorageKind::StoredType: if (isProtocolRequirement() || kind == RequirementSignatureSelf) return getTrailingObjects()[0]; return nullptr; case StorageKind::ProtocolConformance: return getProtocolConformance().getRequirement(); case StorageKind::AssociatedTypeDecl: return storage.assocType->getProtocol(); } llvm_unreachable("Unhandled StorageKind in switch."); } SourceLoc RequirementSource::getLoc() const { // Don't produce locations for protocol requirements unless the parent is // the protocol self. // FIXME: We should have a better notion of when to emit diagnostics // for a particular requirement, rather than turning on/off location info. // Locations that fall into this category should be advisory, emitted via // notes rather than as the normal location. if (isProtocolRequirement() && parent && parent->kind != RequirementSignatureSelf) return parent->getLoc(); auto loc = getSourceLoc(); if (loc.isValid()) return loc; if (parent) return parent->getLoc(); if (kind == RequirementSignatureSelf) return getProtocolDecl()->getLoc(); return SourceLoc(); } /// Compute the path length of a requirement source, counting only the number /// of \c ProtocolRequirement elements. static unsigned sourcePathLength(const RequirementSource *source) { unsigned count = 0; for (; source; source = source->parent) { if (source->isProtocolRequirement()) ++count; } return count; } int RequirementSource::compare(const RequirementSource *other) const { // Prefer the derived option, if there is one. bool thisIsDerived = this->isDerivedRequirement(); bool otherIsDerived = other->isDerivedRequirement(); if (thisIsDerived != otherIsDerived) return thisIsDerived ? -1 : +1; // Prefer the shorter path. unsigned thisLength = sourcePathLength(this); unsigned otherLength = sourcePathLength(other); if (thisLength != otherLength) return thisLength < otherLength ? -1 : +1; // FIXME: Arbitrary hack to allow later requirement sources to stomp on // earlier ones. We need a proper ordering here. return +1; } void RequirementSource::dump() const { dump(llvm::errs(), nullptr, 0); llvm::errs() << "\n"; } /// Dump the constraint source. void RequirementSource::dump(llvm::raw_ostream &out, SourceManager *srcMgr, unsigned indent) const { // FIXME: Implement for real, so we actually dump the structure. out.indent(indent); print(out, srcMgr); } void RequirementSource::print() const { print(llvm::errs(), nullptr); } void RequirementSource::print(llvm::raw_ostream &out, SourceManager *srcMgr) const { if (parent) { parent->print(out, srcMgr); out << " -> "; } else { out << getRootType().getString() << ": "; } switch (kind) { case Concrete: out << "Concrete"; break; case Explicit: out << "Explicit"; break; case Inferred: out << "Inferred"; break; case NestedTypeNameMatch: out << "Nested type match"; break; case Parent: out << "Parent"; break; case ProtocolRequirement: out << "Protocol requirement"; break; case InferredProtocolRequirement: out << "Inferred protocol requirement"; break; case RequirementSignatureSelf: out << "Requirement signature self"; break; case Superclass: out << "Superclass"; break; case Layout: out << "Layout"; break; case EquivalentType: out << "Equivalent type"; break; } // Local function to dump a source location, if we can. auto dumpSourceLoc = [&](SourceLoc loc) { if (!srcMgr) return; if (loc.isInvalid()) return; unsigned bufferID = srcMgr->findBufferContainingLoc(loc); auto lineAndCol = srcMgr->getPresumedLineAndColumnForLoc(loc, bufferID); out << " @ " << lineAndCol.first << ':' << lineAndCol.second; }; switch (storageKind) { case StorageKind::None: break; case StorageKind::StoredType: if (auto proto = getProtocolDecl()) { out << " (via " << storage.type->getString() << " in " << proto->getName() << ")"; } break; case StorageKind::ProtocolConformance: { auto conformance = getProtocolConformance(); if (conformance.isConcrete()) { out << " (" << conformance.getConcrete()->getType()->getString() << ": " << conformance.getConcrete()->getProtocol()->getName() << ")"; } else { out << " (abstract " << conformance.getRequirement()->getName() << ")"; } break; } case StorageKind::AssociatedTypeDecl: out << " (" << storage.assocType->getProtocol()->getName() << "::" << storage.assocType->getName() << ")"; break; } if (auto loc = getLoc()) { dumpSourceLoc(loc); } } /// Form the dependent type such that the given protocol's \c Self can be /// replaced by \c baseType to reach \c type. static Type formProtocolRelativeType(ProtocolDecl *proto, Type baseType, Type type) { // Error case: hand back the erroneous type. if (type->hasError()) return type; // Basis case: we've hit the base potential archetype. if (baseType->isEqual(type)) return proto->getSelfInterfaceType(); // Recursive case: form a dependent member type. auto depMemTy = type->castTo(); Type newBaseType = formProtocolRelativeType(proto, baseType, depMemTy->getBase()); auto assocType = depMemTy->getAssocType(); return DependentMemberType::get(newBaseType, assocType); } const RequirementSource *FloatingRequirementSource::getSource( GenericSignatureBuilder &builder, ResolvedType type) const { switch (kind) { case Resolved: return source; case Explicit: { auto depType = type.getDependentType(builder); return RequirementSource::forExplicit(builder, depType, loc); } case Inferred: { auto depType = type.getDependentType(builder); return RequirementSource::forInferred(builder, depType, loc); } case ProtocolRequirement: case InferredProtocolRequirement: { auto depType = type.getDependentType(); // Derive the dependent type on which this requirement was written. It is // the path from the requirement source on which this requirement is based // to the potential archetype on which the requirement is being placed. auto baseSourceType = source->getAffectedType(); auto dependentType = formProtocolRelativeType(protocol, baseSourceType, depType); return source ->viaProtocolRequirement(builder, dependentType, protocol, kind == InferredProtocolRequirement, loc); } case NestedTypeNameMatch: { auto depType = type.getDependentType(builder); return RequirementSource::forNestedTypeNameMatch(builder, depType); } } llvm_unreachable("unhandled kind"); } SourceLoc FloatingRequirementSource::getLoc() const { if (kind == Inferred || isExplicit()) { if (loc.isValid()) return loc; } if (source) return source->getLoc(); return SourceLoc(); } bool FloatingRequirementSource::isDerived() const { switch (kind) { case Explicit: case Inferred: case NestedTypeNameMatch: return false; case ProtocolRequirement: case InferredProtocolRequirement: switch (source->kind) { case RequirementSource::RequirementSignatureSelf: return false; case RequirementSource::Concrete: case RequirementSource::Explicit: case RequirementSource::Inferred: case RequirementSource::NestedTypeNameMatch: case RequirementSource::Parent: case RequirementSource::ProtocolRequirement: case RequirementSource::InferredProtocolRequirement: case RequirementSource::Superclass: case RequirementSource::Layout: case RequirementSource::EquivalentType: return true; } case Resolved: return source->isDerivedRequirement(); } llvm_unreachable("unhandled kind"); } bool FloatingRequirementSource::isExplicit() const { switch (kind) { case Explicit: return true; case Inferred: case NestedTypeNameMatch: return false; case ProtocolRequirement: // Requirements implied by other protocol conformance requirements are // implicit, except when computing a requirement signature, where // non-inferred ones are explicit, to allow flagging of redundant // requirements. switch (source->kind) { case RequirementSource::RequirementSignatureSelf: return true; case RequirementSource::Concrete: case RequirementSource::Explicit: case RequirementSource::Inferred: case RequirementSource::NestedTypeNameMatch: case RequirementSource::Parent: case RequirementSource::ProtocolRequirement: case RequirementSource::InferredProtocolRequirement: case RequirementSource::Superclass: case RequirementSource::Layout: case RequirementSource::EquivalentType: return false; } case InferredProtocolRequirement: return false; case Resolved: switch (source->kind) { case RequirementSource::Explicit: return true; case RequirementSource::ProtocolRequirement: return source->parent->kind == RequirementSource::RequirementSignatureSelf; case RequirementSource::Inferred: case RequirementSource::InferredProtocolRequirement: case RequirementSource::RequirementSignatureSelf: case RequirementSource::Concrete: case RequirementSource::NestedTypeNameMatch: case RequirementSource::Parent: case RequirementSource::Superclass: case RequirementSource::Layout: case RequirementSource::EquivalentType: return false; } } llvm_unreachable("unhandled kind"); } FloatingRequirementSource FloatingRequirementSource::asInferred( const TypeRepr *typeRepr) const { auto loc = typeRepr ? typeRepr->getStartLoc() : SourceLoc(); switch (kind) { case Explicit: return forInferred(loc); case Inferred: case Resolved: case NestedTypeNameMatch: return *this; case ProtocolRequirement: case InferredProtocolRequirement: return viaProtocolRequirement(source, protocol, loc, /*inferred=*/true); } llvm_unreachable("unhandled kind"); } bool FloatingRequirementSource::isRecursive( GenericSignatureBuilder &builder) const { llvm::SmallSet, 32> visitedAssocReqs; for (auto storedSource = source; storedSource; storedSource = storedSource->parent) { // FIXME: isRecursive() is completely misnamed if (storedSource->kind == RequirementSource::EquivalentType) return true; if (!storedSource->isProtocolRequirement()) continue; if (!visitedAssocReqs.insert( {storedSource->getStoredType()->getCanonicalType(), storedSource->getProtocolDecl()}).second) return true; } return false; } GenericSignatureBuilder::PotentialArchetype::PotentialArchetype( PotentialArchetype *parent, AssociatedTypeDecl *assocType) : parent(parent) { ++NumPotentialArchetypes; assert(parent != nullptr && "Not a nested type?"); assert(assocType->getOverriddenDecls().empty()); depType = CanDependentMemberType::get(parent->getDependentType(), assocType); } GenericSignatureBuilder::PotentialArchetype::PotentialArchetype( GenericTypeParamType *genericParam) : parent(nullptr) { ++NumPotentialArchetypes; depType = genericParam->getCanonicalType(); } GenericSignatureBuilder::PotentialArchetype::~PotentialArchetype() { for (const auto &nested : NestedTypes) { for (auto pa : nested.second) { pa->~PotentialArchetype(); } } } std::string GenericSignatureBuilder::PotentialArchetype::getDebugName() const { llvm::SmallString<64> result; auto parent = getParent(); if (!parent) { return depType.getString(); } // Nested types. result += parent->getDebugName(); // When building the name for debugging purposes, include the protocol into // which the associated type or type alias was resolved. auto *proto = getResolvedType()->getProtocol(); result.push_back('['); result.push_back('.'); result.append(proto->getName().str()); result.push_back(']'); result.push_back('.'); result.append(getResolvedType()->getName().str()); return result.str().str(); } unsigned GenericSignatureBuilder::PotentialArchetype::getNestingDepth() const { unsigned Depth = 0; for (auto P = getParent(); P; P = P->getParent()) ++Depth; return Depth; } void EquivalenceClass::addMember(PotentialArchetype *pa) { assert(find(members, pa) == members.end() && "Already have this potential archetype!"); members.push_back(pa); if (members.back()->getNestingDepth() < members.front()->getNestingDepth()) { MutableArrayRef mutMembers = members; std::swap(mutMembers.front(), mutMembers.back()); } } bool EquivalenceClass::recordConformanceConstraint( GenericSignatureBuilder &builder, ResolvedType type, ProtocolDecl *proto, const RequirementSource *source) { // If we haven't seen a conformance to this protocol yet, add it. bool inserted = false; auto known = conformsTo.find(proto); if (known == conformsTo.end()) { known = conformsTo.insert({ proto, { }}).first; inserted = true; modified(builder); ++NumConformances; // If there is a concrete type that resolves this conformance requirement, // record the conformance. bool explicitConformance = !source->isDerivedRequirement(); if (!builder.resolveConcreteConformance(type, proto, explicitConformance)) { // Otherwise, determine whether there is a superclass constraint where the // superclass conforms to this protocol. (void)builder.resolveSuperConformance(type, proto, explicitConformance); } } // Record this conformance source. known->second.push_back({type.getUnresolvedType(), proto, source}); ++NumConformanceConstraints; return inserted; } Optional EquivalenceClass::findAnyConcreteConstraintAsWritten(Type preferredType) const { // If we don't have a concrete type, there's no source. if (!concreteType) return None; // Go look for a source with source-location information. Optional result; for (const auto &constraint : concreteTypeConstraints) { if (constraint.source->getLoc().isValid()) { result = constraint; if (!preferredType || constraint.getSubjectDependentType({ })->isEqual(preferredType)) return result; } } return result; } Optional EquivalenceClass::findAnySuperclassConstraintAsWritten( Type preferredType) const { // If we don't have a superclass, there's no source. if (!superclass) return None; // Go look for a source with source-location information. Optional result; for (const auto &constraint : superclassConstraints) { if (constraint.source->getLoc().isValid() && constraint.value->isEqual(superclass)) { result = constraint; if (!preferredType || constraint.getSubjectDependentType({ })->isEqual(preferredType)) return result; } } return result; } bool EquivalenceClass::isConformanceSatisfiedBySuperclass( ProtocolDecl *proto) const { auto known = conformsTo.find(proto); assert(known != conformsTo.end() && "doesn't conform to this protocol"); for (const auto &constraint: known->second) { if (constraint.source->kind == RequirementSource::Superclass) return true; } return false; } static void lookupConcreteNestedType(NominalTypeDecl *decl, Identifier name, SmallVectorImpl &concreteDecls) { SmallVector foundMembers; decl->getParentModule()->lookupQualified( decl, DeclNameRef(name), NL_QualifiedDefault | NL_OnlyTypes | NL_ProtocolMembers, foundMembers); for (auto member : foundMembers) concreteDecls.push_back(cast(member)); } static TypeDecl *findBestConcreteNestedType(SmallVectorImpl &concreteDecls) { return *std::min_element(concreteDecls.begin(), concreteDecls.end(), [](TypeDecl *type1, TypeDecl *type2) { return TypeDecl::compare(type1, type2) < 0; }); } TypeDecl *EquivalenceClass::lookupNestedType( GenericSignatureBuilder &builder, Identifier name) { // If we have a cached value that is up-to-date, use that. auto cached = nestedTypeNameCache.find(name); if (cached != nestedTypeNameCache.end() && cached->second.numConformancesPresent == conformsTo.size() && (!superclass || cached->second.superclassPresent == superclass->getCanonicalType()) && (!concreteType || cached->second.concreteTypePresent == concreteType->getCanonicalType())) { ++NumNestedTypeCacheHits; return cached->second.type; } // Cache miss; go compute the result. ++NumNestedTypeCacheMisses; // Look for types with the given name in protocols that we know about. AssociatedTypeDecl *bestAssocType = nullptr; SmallVector concreteDecls; for (const auto &conforms : conformsTo) { ProtocolDecl *proto = conforms.first; // Look for an associated type and/or concrete type with this name. for (auto member : proto->lookupDirect(name)) { // If this is an associated type, record whether it is the best // associated type we've seen thus far. if (auto assocType = dyn_cast(member)) { // Retrieve the associated type anchor. assocType = assocType->getAssociatedTypeAnchor(); if (!bestAssocType || compareAssociatedTypes(assocType, bestAssocType) < 0) bestAssocType = assocType; continue; } // If this is another type declaration, record it. if (auto type = dyn_cast(member)) { concreteDecls.push_back(type); continue; } } } // If we haven't found anything yet but have a concrete type or a superclass, // look for a type in that. // FIXME: Shouldn't we always look here? if (!bestAssocType && concreteDecls.empty()) { Type typeToSearch = concreteType ? concreteType : superclass; if (typeToSearch) if (auto *decl = typeToSearch->getAnyNominal()) lookupConcreteNestedType(decl, name, concreteDecls); } // Form the new cache entry. CachedNestedType entry; entry.numConformancesPresent = conformsTo.size(); entry.superclassPresent = superclass ? superclass->getCanonicalType() : CanType(); entry.concreteTypePresent = concreteType ? concreteType->getCanonicalType() : CanType(); if (bestAssocType) { entry.type = bestAssocType; assert(bestAssocType->getOverriddenDecls().empty() && "Lookup should never keep a non-anchor associated type"); } else if (!concreteDecls.empty()) { // Find the best concrete type. entry.type = findBestConcreteNestedType(concreteDecls); } nestedTypeNameCache[name] = entry; return entry.type; } static Type getSugaredDependentType(Type type, TypeArrayView params) { if (params.empty()) return type; if (auto *gp = type->getAs()) { unsigned index = GenericParamKey(gp).findIndexIn(params); return Type(params[index]); } auto *dmt = type->castTo(); return DependentMemberType::get(getSugaredDependentType(dmt->getBase(), params), dmt->getAssocType()); } Type EquivalenceClass::getAnchor( GenericSignatureBuilder &builder, TypeArrayView genericParams) { // Substitute into the anchor with the given generic parameters. auto substAnchor = [&] { if (genericParams.empty()) return archetypeAnchorCache.anchor; return getSugaredDependentType(archetypeAnchorCache.anchor, genericParams); }; // Check whether the cache is valid. if (archetypeAnchorCache.anchor && archetypeAnchorCache.lastGeneration == builder.Impl->Generation) { ++NumArchetypeAnchorCacheHits; return substAnchor(); } // Check whether we already have an anchor, in which case we // can simplify it further. if (archetypeAnchorCache.anchor) { // Record the cache miss. ++NumArchetypeAnchorCacheMisses; // Update the anchor by simplifying it further. archetypeAnchorCache.anchor = builder.getCanonicalTypeParameter(archetypeAnchorCache.anchor); archetypeAnchorCache.lastGeneration = builder.Impl->Generation; return substAnchor(); } // Record the cache miss and update the cache. ++NumArchetypeAnchorCacheMisses; archetypeAnchorCache.anchor = builder.getCanonicalTypeParameter( members.front()->getDependentType()); archetypeAnchorCache.lastGeneration = builder.Impl->Generation; #ifndef NDEBUG // All members must produce the same anchor. for (auto member : members) { auto anchorType = builder.getCanonicalTypeParameter( member->getDependentType()); assert(anchorType->isEqual(archetypeAnchorCache.anchor) && "Inconsistent anchor computation"); } #endif return substAnchor(); } void EquivalenceClass::dump(llvm::raw_ostream &out, GenericSignatureBuilder *builder) const { auto dumpSource = [&](const RequirementSource *source) { source->dump(out, &builder->getASTContext().SourceMgr, 4); if (source->isDerivedRequirement()) out << " [derived]"; out << "\n"; }; out << "Equivalence class represented by " << members.front()->getRepresentative()->getDebugName() << ":\n"; out << "Members: "; interleave(members, [&](PotentialArchetype *pa) { out << pa->getDebugName(); }, [&]() { out << ", "; }); out << "\n"; out << "Conformance constraints:\n"; for (auto entry : conformsTo) { out << " " << entry.first->getNameStr() << "\n"; for (auto constraint : entry.second) { dumpSource(constraint.source); } } out << "Same-type constraints:\n"; for (auto constraint : sameTypeConstraints) { out << " " << constraint.getSubjectDependentType({}) << " == " << constraint.value << "\n"; dumpSource(constraint.source); } if (concreteType) { out << "Concrete type: " << concreteType.getString() << "\n"; for (auto constraint : concreteTypeConstraints) { out << " " << constraint.getSubjectDependentType({}) << " == " << constraint.value << "\n"; dumpSource(constraint.source); } } if (superclass) { out << "Superclass: " << superclass.getString() << "\n"; for (auto constraint : superclassConstraints) { out << " " << constraint.getSubjectDependentType({}) << " : " << constraint.value << "\n"; dumpSource(constraint.source); } } if (layout) { out << "Layout: " << layout.getString() << "\n"; for (auto constraint : layoutConstraints) { out << " " << constraint.getSubjectDependentType({}) << " : " << constraint.value << "\n"; dumpSource(constraint.source); } } if (!delayedRequirements.empty()) { out << "Delayed requirements:\n"; for (const auto &req : delayedRequirements) { req.dump(out); out << "\n"; } } out << "\n"; if (builder) { CanType anchorType = const_cast(this)->getAnchor(*builder, { }) ->getCanonicalType(); if (auto rewriteRoot = builder->Impl->getRewriteTreeRootIfPresent(anchorType)) { out << "---Rewrite tree---\n"; rewriteRoot->dump(out); } } } void EquivalenceClass::dump(GenericSignatureBuilder *builder) const { dump(llvm::errs(), builder); } void DelayedRequirement::dump(llvm::raw_ostream &out) const { // Print LHS. if (auto lhsPA = lhs.dyn_cast()) out << lhsPA->getDebugName(); else lhs.get().print(out); switch (kind) { case Type: case Layout: out << ": "; break; case SameType: out << " == "; break; } // Print RHS. if (auto rhsPA = rhs.dyn_cast()) out << rhsPA->getDebugName(); else if (auto rhsType = rhs.dyn_cast()) rhsType.print(out); else rhs.get().print(out); } void DelayedRequirement::dump() const { dump(llvm::errs()); llvm::errs() << "\n"; } ConstraintResult GenericSignatureBuilder::handleUnresolvedRequirement( RequirementKind kind, UnresolvedType lhs, UnresolvedRequirementRHS rhs, FloatingRequirementSource source, EquivalenceClass *unresolvedEquivClass, UnresolvedHandlingKind unresolvedHandling) { // Record the delayed requirement. DelayedRequirement::Kind delayedKind; switch (kind) { case RequirementKind::Conformance: case RequirementKind::Superclass: delayedKind = DelayedRequirement::Type; break; case RequirementKind::Layout: delayedKind = DelayedRequirement::Layout; break; case RequirementKind::SameType: delayedKind = DelayedRequirement::SameType; break; } if (unresolvedEquivClass) { unresolvedEquivClass->delayedRequirements.push_back( {delayedKind, lhs, rhs, source}); } else { Impl->DelayedRequirements.push_back({delayedKind, lhs, rhs, source}); } switch (unresolvedHandling) { case UnresolvedHandlingKind::GenerateConstraints: return ConstraintResult::Resolved; case UnresolvedHandlingKind::GenerateUnresolved: return ConstraintResult::Unresolved; } llvm_unreachable("unhandled handling"); } void GenericSignatureBuilder::addConditionalRequirements( ProtocolConformanceRef conformance, ModuleDecl *inferForModule) { // When rebuilding a signature, don't add requirements inferred from conditional // conformances, since we've already added them to our ExplicitRequirements list. // // FIXME: We need to handle conditional conformances earlier, in the same place // as other forms of requirement inference, to eliminate this bit of state. if (Impl->RebuildingWithoutRedundantConformances) return; // We do not perform requirement inference, including conditional requirement // inference, inside protocols. if (Impl->BuildingProtocolRequirementSignature) return; // Abstract conformances don't have associated decl-contexts/modules, but also // don't have conditional requirements. if (conformance.isConcrete()) { auto source = FloatingRequirementSource::forInferred(SourceLoc()); for (auto requirement : conformance.getConditionalRequirements()) { addRequirement(requirement, source, inferForModule); ++NumConditionalRequirementsAdded; } } } const RequirementSource * GenericSignatureBuilder::resolveConcreteConformance(ResolvedType type, ProtocolDecl *proto, bool explicitConformance) { auto equivClass = type.getEquivalenceClass(*this); auto concrete = equivClass->concreteType; if (!concrete) return nullptr; // Conformance to this protocol is redundant; update the requirement source // appropriately. const RequirementSource *concreteSource; if (auto writtenSource = equivClass->findAnyConcreteConstraintAsWritten(nullptr)) concreteSource = writtenSource->source; else concreteSource = equivClass->concreteTypeConstraints.front().source; // Lookup the conformance of the concrete type to this protocol. auto conformance = lookupConformance(concrete, proto); if (conformance.isInvalid()) { if (!concrete->hasError() && concreteSource->getLoc().isValid()) { Impl->HadAnyError = true; Diags.diagnose(concreteSource->getLoc(), diag::requires_generic_param_same_type_does_not_conform, concrete, proto->getName()); } Impl->HadAnyError = true; equivClass->invalidConcreteType = true; return nullptr; } if (concrete->isExistentialType()) { // If we have an existential type, record the original type, and // not the conformance. // // The conformance must be a self-conformance, and self-conformances // do not record the original type in the case where a derived // protocol self-conforms to a base protocol; for example: // // @objc protocol Base {} // // @objc protocol Derived {} // // struct S {} // // extension S where T == Derived {} assert(isa(conformance.getConcrete())); concreteSource = concreteSource->viaConcrete(*this, concrete); } else { concreteSource = concreteSource->viaConcrete(*this, conformance); } equivClass->recordConformanceConstraint(*this, type, proto, concreteSource); // Only infer conditional requirements from explicit sources. bool explicitConcreteType = llvm::any_of( equivClass->concreteTypeConstraints, [](const ConcreteConstraint &constraint) { return !constraint.source->isDerivedRequirement(); }); if (explicitConformance || explicitConcreteType) { addConditionalRequirements(conformance, /*inferForModule=*/nullptr); } return concreteSource; } const RequirementSource * GenericSignatureBuilder::resolveSuperConformance(ResolvedType type, ProtocolDecl *proto, bool explicitConformance) { // Get the superclass constraint. auto equivClass = type.getEquivalenceClass(*this); Type superclass = equivClass->superclass; if (!superclass) return nullptr; // Lookup the conformance of the superclass to this protocol. auto conformance = lookupConformance(superclass, proto); if (conformance.isInvalid()) return nullptr; assert(!conformance.isAbstract()); // Conformance to this protocol is redundant; update the requirement source // appropriately. const RequirementSource *superclassSource; if (auto writtenSource = equivClass->findAnySuperclassConstraintAsWritten()) superclassSource = writtenSource->source; else superclassSource = equivClass->superclassConstraints.front().source; superclassSource = superclassSource->viaSuperclass(*this, conformance); equivClass->recordConformanceConstraint(*this, type, proto, superclassSource); // Only infer conditional requirements from explicit sources. bool explicitSuperclass = llvm::any_of( equivClass->superclassConstraints, [](const ConcreteConstraint &constraint) { return !constraint.source->isDerivedRequirement(); }); if (explicitConformance || explicitSuperclass) { addConditionalRequirements(conformance, /*inferForModule=*/nullptr); } return superclassSource; } CanType ResolvedType::getDependentType() const { return storage.get() ->getDependentType(); } Type ResolvedType::getDependentType(GenericSignatureBuilder &builder) const { return storage.get() ->getDependentType(builder.getGenericParams()); } auto PotentialArchetype::getOrCreateEquivalenceClass( GenericSignatureBuilder &builder) const -> EquivalenceClass * { // The equivalence class is stored on the representative. auto representative = getRepresentative(); if (representative != this) return representative->getOrCreateEquivalenceClass(builder); // If we already have an equivalence class, return it. if (auto equivClass = getEquivalenceClassIfPresent()) return equivClass; // Create a new equivalence class. auto equivClass = builder.Impl->allocateEquivalenceClass( const_cast(this)); representativeOrEquivClass = equivClass; return equivClass; } auto PotentialArchetype::getRepresentative() const -> PotentialArchetype * { auto representative = representativeOrEquivClass.dyn_cast(); if (!representative) return const_cast(this); // Find the representative. PotentialArchetype *result = representative; while (auto nextRepresentative = result->representativeOrEquivClass.dyn_cast()) result = nextRepresentative; // Perform (full) path compression. const PotentialArchetype *fixUp = this; while (auto nextRepresentative = fixUp->representativeOrEquivClass.dyn_cast()) { fixUp->representativeOrEquivClass = nextRepresentative; fixUp = nextRepresentative; } return result; } /// Compare two dependent paths to determine which is better. static int compareDependentPaths(ArrayRef path1, ArrayRef path2) { // Shorter paths win. if (path1.size() != path2.size()) return path1.size() < path2.size() ? -1 : 1; // The paths are the same length, so order by comparing the associted // types. for (unsigned index : indices(path1)) { if (int result = compareAssociatedTypes(path1[index], path2[index])) return result; } // Identical paths. return 0; } namespace { /// Function object used to suppress conflict diagnoses when we know we'll /// see them again later. struct SameTypeConflictCheckedLater { void operator()(Type type1, Type type2) const { } }; } // end anonymous namespace // Give a nested type the appropriately resolved concrete type, based off a // parent PA that has a concrete type. static void concretizeNestedTypeFromConcreteParent( GenericSignatureBuilder::PotentialArchetype *parent, GenericSignatureBuilder::PotentialArchetype *nestedPA, GenericSignatureBuilder &builder) { auto parentEquiv = parent->getEquivalenceClassIfPresent(); assert(parentEquiv && "can't have a concrete type without an equiv class"); bool isSuperclassConstrained = false; auto concreteParent = parentEquiv->concreteType; if (!concreteParent) { isSuperclassConstrained = true; concreteParent = parentEquiv->superclass; } assert(concreteParent && "attempting to resolve concrete nested type of non-concrete PA"); // These requirements are all implied based on the parent's concrete // conformance. auto assocType = nestedPA->getResolvedType(); if (!assocType) return; auto proto = assocType->getProtocol(); // If we don't already have a conformance of the parent to this protocol, // add it now; it was elided earlier. if (parentEquiv->conformsTo.count(proto) == 0) { auto source = (!isSuperclassConstrained ? parentEquiv->concreteTypeConstraints.front().source : parentEquiv->superclassConstraints.front().source); parentEquiv->recordConformanceConstraint(builder, parent, proto, source); } assert(parentEquiv->conformsTo.count(proto) > 0 && "No conformance requirement"); const RequirementSource *parentConcreteSource = nullptr; for (const auto &constraint : parentEquiv->conformsTo.find(proto)->second) { if (!isSuperclassConstrained) { if (constraint.source->kind == RequirementSource::Concrete) { parentConcreteSource = constraint.source; } } else { if (constraint.source->kind == RequirementSource::Superclass) { parentConcreteSource = constraint.source; } } } // Error condition: parent did not conform to this protocol, so there is no // way to resolve the nested type via concrete conformance. if (!parentConcreteSource) return; auto source = parentConcreteSource->viaParent(builder, assocType); auto conformance = parentConcreteSource->getProtocolConformance(); Type witnessType; if (conformance.isConcrete()) { witnessType = conformance.getConcrete()->getTypeWitness(assocType); if (!witnessType) return; // FIXME: should we delay here? } else { // Otherwise we have an abstract conformance to an opaque result type. assert(conformance.isAbstract()); auto archetype = concreteParent->castTo(); witnessType = archetype->getNestedType(assocType->getName()); } builder.addSameTypeRequirement( nestedPA, witnessType, source, GenericSignatureBuilder::UnresolvedHandlingKind::GenerateConstraints, SameTypeConflictCheckedLater()); } PotentialArchetype *PotentialArchetype::getOrCreateNestedType( GenericSignatureBuilder &builder, AssociatedTypeDecl *assocType, ArchetypeResolutionKind kind) { if (!assocType) return nullptr; // Always refer to the archetype anchor. assocType = assocType->getAssociatedTypeAnchor(); Identifier name = assocType->getName(); SWIFT_DEFER { // If we were asked for a complete, well-formed archetype, make sure we // process delayed requirements if anything changed. if (kind == ArchetypeResolutionKind::CompleteWellFormed) builder.processDelayedRequirements(); }; // Look for a potential archetype with the appropriate associated type. auto knownNestedTypes = NestedTypes.find(name); if (knownNestedTypes != NestedTypes.end()) { for (auto existingPA : knownNestedTypes->second) { // Do we have an associated-type match? if (assocType && existingPA->getResolvedType() == assocType) { return existingPA; } } } if (kind == ArchetypeResolutionKind::AlreadyKnown) return nullptr; // We don't have a result potential archetype, so we need to add one. // Creating a new potential archetype in an equivalence class is a // modification. getOrCreateEquivalenceClass(builder)->modified(builder); void *mem = builder.Impl->Allocator.Allocate(); auto *resultPA = new (mem) PotentialArchetype(this, assocType); NestedTypes[name].push_back(resultPA); builder.addedNestedType(resultPA); // If we know something concrete about the parent PA, we need to propagate // that information to this new archetype. if (auto equivClass = getEquivalenceClassIfPresent()) { if (equivClass->concreteType || equivClass->superclass) concretizeNestedTypeFromConcreteParent(this, resultPA, builder); } return resultPA; } Type GenericSignatureBuilder::PotentialArchetype::getDependentType( TypeArrayView genericParams) const { auto depType = getDependentType(); return getSugaredDependentType(depType, genericParams); } void GenericSignatureBuilder::PotentialArchetype::dump() const { dump(llvm::errs(), nullptr, 0); } void GenericSignatureBuilder::PotentialArchetype::dump(llvm::raw_ostream &Out, SourceManager *SrcMgr, unsigned Indent) const { // Print name. if (Indent == 0 || isGenericParam()) Out << getDebugName(); else Out.indent(Indent) << getResolvedType()->getName(); auto equivClass = getEquivalenceClassIfPresent(); // Print superclass. if (equivClass && equivClass->superclass) { for (const auto &constraint : equivClass->superclassConstraints) { if (!constraint.isSubjectEqualTo(this)) continue; Out << " : "; constraint.value.print(Out); Out << " "; if (!constraint.source->isDerivedRequirement()) Out << "*"; Out << "["; constraint.source->print(Out, SrcMgr); Out << "]"; } } // Print concrete type. if (equivClass && equivClass->concreteType) { for (const auto &constraint : equivClass->concreteTypeConstraints) { if (!constraint.isSubjectEqualTo(this)) continue; Out << " == "; constraint.value.print(Out); Out << " "; if (!constraint.source->isDerivedRequirement()) Out << "*"; Out << "["; constraint.source->print(Out, SrcMgr); Out << "]"; } } // Print requirements. if (equivClass) { bool First = true; for (const auto &entry : equivClass->conformsTo) { for (const auto &constraint : entry.second) { if (!constraint.isSubjectEqualTo(this)) continue; if (First) { First = false; Out << ": "; } else { Out << " & "; } Out << constraint.value->getName().str() << " "; if (!constraint.source->isDerivedRequirement()) Out << "*"; Out << "["; constraint.source->print(Out, SrcMgr); Out << "]"; } } } if (getRepresentative() != this) { Out << " [represented by " << getRepresentative()->getDebugName() << "]"; } if (getEquivalenceClassMembers().size() > 1) { Out << " [equivalence class "; bool isFirst = true; for (auto equiv : getEquivalenceClassMembers()) { if (equiv == this) continue; if (isFirst) isFirst = false; else Out << ", "; Out << equiv->getDebugName(); } Out << "]"; } Out << "\n"; // Print nested types. for (const auto &nestedVec : NestedTypes) { for (auto nested : nestedVec.second) { nested->dump(Out, SrcMgr, Indent + 2); } } } #pragma mark Rewrite tree RewritePath::RewritePath(Optional base, RelativeRewritePath path, PathOrder order) : base(base) { switch (order) { case Forward: this->path.insert(this->path.begin(), path.begin(), path.end()); break; case Reverse: this->path.insert(this->path.begin(), path.rbegin(), path.rend()); break; } } RewritePath RewritePath::createPath(Type type) { SmallVector path; auto genericParam = createPath(type, path); return RewritePath(genericParam, path, Reverse); } GenericParamKey RewritePath::createPath( Type type, SmallVectorImpl &path) { while (auto depMemTy = type->getAs()) { auto assocType = depMemTy->getAssocType(); assert(assocType && "Unresolved dependent member type"); path.push_back(assocType); type = depMemTy->getBase(); } return type->castTo(); } RewritePath RewritePath::commonPath(const RewritePath &other) const { assert(getBase().hasValue() && other.getBase().hasValue()); if (*getBase() != *other.getBase()) return RewritePath(); // Find the longest common prefix. RelativeRewritePath path1 = getPath(); RelativeRewritePath path2 = other.getPath(); if (path1.size() > path2.size()) std::swap(path1, path2); unsigned prefixLength = std::mismatch(path1.begin(), path1.end(), path2.begin()).first - path1.begin(); // Form the common path. return RewritePath(getBase(), path1.slice(0, prefixLength), Forward); } /// Form a dependent type with the given generic parameter, then following the /// path of associated types. static Type formDependentType(GenericTypeParamType *base, RelativeRewritePath path) { return std::accumulate(path.begin(), path.end(), Type(base), [](Type type, AssociatedTypeDecl *assocType) -> Type { return DependentMemberType::get(type, assocType); }); } /// Form a dependent type with the (canonical) generic parameter for the given /// parameter key, then following the path of associated types. static Type formDependentType(ASTContext &ctx, GenericParamKey genericParam, RelativeRewritePath path) { return formDependentType(GenericTypeParamType::get(genericParam.TypeSequence, genericParam.Depth, genericParam.Index, ctx), path); } CanType RewritePath::formDependentType( ASTContext &ctx, AnchorPathCache *anchorPathCache) const { if (auto base = getBase()) return CanType(::formDependentType(ctx, *base, getPath())); assert(anchorPathCache && "Need an anchor path cache"); const RewritePath &anchorPath = anchorPathCache->getAnchorPath(); // Add the relative path to the anchor path. SmallVector absolutePath; absolutePath.append(anchorPath.getPath().begin(), anchorPath.getPath().end()); absolutePath.append(getPath().begin(), getPath().end()); return CanType(::formDependentType(ctx, *anchorPath.getBase(), absolutePath)); } int RewritePath::compare(const RewritePath &other) const { // Prefer relative to absolute paths. if (getBase().hasValue() != other.getBase().hasValue()) { return other.getBase().hasValue() ? -1 : 1; } // Order based on the bases. if (getBase() && *getBase() != *other.getBase()) return (*getBase() < *other.getBase()) ? -1 : 1; // Order based on the path contents. return compareDependentPaths(getPath(), other.getPath()); } void RewritePath::print(llvm::raw_ostream &out) const { out << "["; if (getBase()) { out << "(" << getBase()->Depth << ", " << getBase()->Index << ")"; if (!getPath().empty()) out << " -> "; } llvm::interleave( getPath().begin(), getPath().end(), [&](AssociatedTypeDecl *assocType) { out.changeColor(raw_ostream::BLUE); out << assocType->getProtocol()->getName() << "." << assocType->getName(); out.resetColor(); }, [&] { out << " -> "; }); out << "]"; } RewriteTreeNode::~RewriteTreeNode() { for (auto child : children) delete child; } namespace { /// Function object used to order rewrite tree nodes based on the address /// of the associated type. class OrderTreeRewriteNode { bool compare(AssociatedTypeDecl *lhs, AssociatedTypeDecl *rhs) const { // Make sure null pointers precede everything else. if (static_cast(lhs) != static_cast(rhs)) return static_cast(rhs); // Use std::less to provide a defined ordering. return std::less()(lhs, rhs); } public: bool operator()(RewriteTreeNode *lhs, AssociatedTypeDecl *rhs) const { return compare(lhs->getMatch(), rhs); } bool operator()(AssociatedTypeDecl *lhs, RewriteTreeNode *rhs) const { return compare(lhs, rhs->getMatch()); } bool operator()(RewriteTreeNode *lhs, RewriteTreeNode *rhs) const { return compare(lhs->getMatch(), rhs->getMatch()); } }; } bool RewriteTreeNode::addRewriteRule(RelativeRewritePath matchPath, RewritePath replacementPath) { // If the match path is empty, we're adding the rewrite rule to this node. if (matchPath.empty()) { // If we don't already have a rewrite rule, add it. if (!hasRewriteRule()) { setRewriteRule(replacementPath); return true; } // If we already have this rewrite rule, we're done. if (getRewriteRule() == replacementPath) return false; // Check whether any of the continuation children matches. auto insertPos = children.begin(); while (insertPos != children.end() && !(*insertPos)->getMatch()) { if ((*insertPos)->hasRewriteRule() && (*insertPos)->getRewriteRule() == replacementPath) return false; ++insertPos; } // We already have a rewrite rule, so add a new child with a // null associated type match to hold the rewrite rule. auto newChild = new RewriteTreeNode(nullptr); newChild->setRewriteRule(replacementPath); children.insert(insertPos, newChild); return true; } // Find (or create) a child node describing the next step in the match. auto matchFront = matchPath.front(); auto childPos = std::lower_bound(children.begin(), children.end(), matchFront, OrderTreeRewriteNode()); if (childPos == children.end() || (*childPos)->getMatch() != matchFront) { childPos = children.insert(childPos, new RewriteTreeNode(matchFront)); } // Add the rewrite rule to the child. return (*childPos)->addRewriteRule(matchPath.slice(1), replacementPath); } void RewriteTreeNode::enumerateRewritePathsImpl( RelativeRewritePath matchPath, llvm::function_ref callback, unsigned depth) const { // Determine whether we know anything about the next step in the path. auto childPos = depth < matchPath.size() ? std::lower_bound(children.begin(), children.end(), matchPath[depth], OrderTreeRewriteNode()) : children.end(); if (childPos != children.end() && (*childPos)->getMatch() == matchPath[depth]) { // Try to match the rest of the path. (*childPos)->enumerateRewritePathsImpl(matchPath, callback, depth + 1); } // If we have a rewrite rule at this position, invoke it. if (hasRewriteRule()) { // Invoke the callback with the first result. callback(depth, rewrite); } // Walk any children with NULL associated types; they might have more matches. for (auto otherRewrite : children) { if (otherRewrite->getMatch()) break; otherRewrite->enumerateRewritePathsImpl(matchPath, callback, depth); } } Optional> RewriteTreeNode::bestRewritePath(GenericParamKey base, RelativeRewritePath path, unsigned prefixLength) { Optional> best; unsigned bestAdjustedLength = 0; enumerateRewritePaths(path, [&](unsigned length, RewritePath path) { // Determine how much of the original path will be replaced by the rewrite. unsigned adjustedLength = length; bool changesBase = false; if (auto newBase = path.getBase()) { adjustedLength += prefixLength; // If the base is unchanged, make sure we're reducing the length. changesBase = *newBase != base; if (!changesBase && adjustedLength <= path.getPath().size()) return; } if (adjustedLength == 0 && !changesBase) return; if (adjustedLength > bestAdjustedLength || !best || (adjustedLength == bestAdjustedLength && path.compare(best->second) < 0)) { best = { length, path }; bestAdjustedLength = adjustedLength; } }); return best; } bool RewriteTreeNode::mergeInto(RewriteTreeNode *other) { // FIXME: A destructive version of this operation would be more efficient, // since we generally don't care about \c other after doing this. bool anyAdded = false; (void)enumerateRules([other, &anyAdded](RelativeRewritePath lhs, const RewritePath &rhs) { if (other->addRewriteRule(lhs, rhs)) anyAdded = true; return RuleAction::none(); }); return anyAdded; } bool RewriteTreeNode::enumerateRulesRec( llvm::function_ref &fn, bool temporarilyDisableVisitedRule, llvm::SmallVectorImpl &lhs) { if (auto assocType = getMatch()) lhs.push_back(assocType); SWIFT_DEFER { if (getMatch()) lhs.pop_back(); }; // If there is a rewrite rule, invoke the callback. if (hasRewriteRule()) { // If we're supposed to temporarily disabled the visited rule, do so // now. Optional rewriteRule; if (temporarilyDisableVisitedRule) { rewriteRule = std::move(*this).getRewriteRule(); removeRewriteRule(); } // Make sure that we put the rewrite rule back in place if we moved it // aside. SWIFT_DEFER { if (temporarilyDisableVisitedRule && rewriteRule) setRewriteRule(*std::move(rewriteRule)); }; switch (auto action = fn(lhs, rewriteRule ? *rewriteRule : getRewriteRule())) { case RuleAction::None: break; case RuleAction::Stop: return true; case RuleAction::Remove: if (temporarilyDisableVisitedRule) rewriteRule = None; else removeRewriteRule(); break; case RuleAction::Replace: if (temporarilyDisableVisitedRule) { rewriteRule = std::move(action.path); } else { removeRewriteRule(); setRewriteRule(action.path); } break; } } // Recurse into the child nodes. for (auto child : children) { if (child->enumerateRulesRec(fn, temporarilyDisableVisitedRule, lhs)) return true; } return false; } void RewriteTreeNode::dump() const { dump(llvm::errs()); } void RewriteTreeNode::dump(llvm::raw_ostream &out, bool lastChild) const { std::string prefixStr; std::function print; print = [&](const RewriteTreeNode *node, bool lastChild) { out << prefixStr << " `--"; // Print the node name. out.changeColor(raw_ostream::GREEN); if (auto assoc = node->getMatch()) out << assoc->getProtocol()->getName() << "." << assoc->getName(); else out << "(cont'd)"; out.resetColor(); // Print the rewrite, if there is one. if (node->hasRewriteRule()) { out << " --> "; node->rewrite.print(out); } out << "\n"; // Print children. prefixStr += ' '; prefixStr += (lastChild ? ' ' : '|'); prefixStr += " "; for (auto child : node->children) { print(child, child == node->children.back()); } prefixStr.erase(prefixStr.end() - 4, prefixStr.end()); }; print(this, lastChild); } RewriteTreeNode * GenericSignatureBuilder::Implementation::getRewriteTreeRootIfPresent( CanType anchor) { auto known = RewriteTreeRoots.find(anchor); if (known != RewriteTreeRoots.end()) return known->second.get(); return nullptr; } RewriteTreeNode * GenericSignatureBuilder::Implementation::getOrCreateRewriteTreeRoot( CanType anchor) { if (auto *root = getRewriteTreeRootIfPresent(anchor)) return root; auto &root = RewriteTreeRoots[anchor]; root = std::make_unique(nullptr); return root.get(); } void GenericSignatureBuilder::Implementation::minimizeRewriteTree( GenericSignatureBuilder &builder) { // Only perform minimization if the term-rewriting tree has changed. if (LastRewriteMinimizedGeneration == RewriteGeneration || MinimizingRewriteSystem) return; ++NumRewriteMinimizations; llvm::SaveAndRestore minimizingRewriteSystem(MinimizingRewriteSystem, true); SWIFT_DEFER { LastRewriteMinimizedGeneration = RewriteGeneration; }; minimizeRewriteTreeRhs(builder); removeRewriteTreeRedundancies(builder); } void GenericSignatureBuilder::Implementation::minimizeRewriteTreeRhs( GenericSignatureBuilder &builder) { assert(MinimizingRewriteSystem); // Minimize the right-hand sides of each rule in the tree. for (auto &equivClass : EquivalenceClasses) { CanType anchorType = equivClass.getAnchor(builder, { })->getCanonicalType(); auto root = RewriteTreeRoots.find(anchorType); if (root == RewriteTreeRoots.end()) continue; AnchorPathCache anchorPathCache(builder, equivClass); ASTContext &ctx = builder.getASTContext(); root->second->enumerateRules([&](RelativeRewritePath lhs, const RewritePath &rhs) { // Compute the type of the right-hand side. Type rhsType = rhs.formDependentType(ctx, &anchorPathCache); if (!rhsType) return RewriteTreeNode::RuleAction::none(); // Compute the canonical type for the right-hand side. Type canonicalRhsType = builder.getCanonicalTypeParameter(rhsType); // If the canonicalized result is equivalent to the right-hand side we // had, there's nothing to do. if (rhsType->isEqual(canonicalRhsType)) return RewriteTreeNode::RuleAction::none(); // We have a canonical replacement path. Determine its encoding and // perform the replacement. ++NumRewriteRhsSimplified; // Determine replacement path, which might be relative to the anchor. auto canonicalRhsPath = RewritePath::createPath(canonicalRhsType); auto anchorPath = anchorPathCache.getAnchorPath(); if (auto prefix = anchorPath.commonPath(canonicalRhsPath)) { unsigned prefixLength = prefix.getPath().size(); RelativeRewritePath replacementRhsPath = canonicalRhsPath.getPath().slice(prefixLength); // If the left and right-hand sides are equivalent, just remove the // rule. if (lhs == replacementRhsPath) { ++NumRewriteRhsSimplifiedToLhs; return RewriteTreeNode::RuleAction::remove(); } RewritePath replacementRhs(None, replacementRhsPath, RewritePath::Forward); return RewriteTreeNode::RuleAction::replace(std::move(replacementRhs)); } return RewriteTreeNode::RuleAction::replace(canonicalRhsPath); }); } } void GenericSignatureBuilder::Implementation::removeRewriteTreeRedundancies( GenericSignatureBuilder &builder) { assert(MinimizingRewriteSystem); // Minimize the right-hand sides of each rule in the tree. for (auto &equivClass : EquivalenceClasses) { CanType anchorType = equivClass.getAnchor(builder, { })->getCanonicalType(); auto root = RewriteTreeRoots.find(anchorType); if (root == RewriteTreeRoots.end()) continue; AnchorPathCache anchorPathCache(builder, equivClass); ASTContext &ctx = builder.getASTContext(); root->second->enumerateRules([&](RelativeRewritePath lhs, const RewritePath &rhs) { /// Left-hand side type. Type lhsType = RewritePath(None, lhs, RewritePath::Forward) .formDependentType(ctx, &anchorPathCache); if (!lhsType) return RewriteTreeNode::RuleAction::none(); // Simplify the left-hand type. Type simplifiedLhsType = builder.getCanonicalTypeParameter(lhsType); // Compute the type of the right-hand side. Type rhsType = rhs.formDependentType(ctx, &anchorPathCache); if (!rhsType) return RewriteTreeNode::RuleAction::none(); if (simplifiedLhsType->isEqual(rhsType)) { ++NumRewriteRulesRedundant; return RewriteTreeNode::RuleAction::remove(); } return RewriteTreeNode::RuleAction::none(); }, /*temporarilyDisableVisitedRule=*/true); } } bool GenericSignatureBuilder::addSameTypeRewriteRule(CanType type1, CanType type2) { // We already effectively have this rewrite rule. if (type1 == type2) return false; auto path1 = RewritePath::createPath(type1); auto path2 = RewritePath::createPath(type2); // Look for a common prefix. When we have one, form a rewrite rule using // relative paths. if (auto prefix = path1.commonPath(path2)) { // Find the better relative rewrite path. RelativeRewritePath relPath1 = path1.getPath().slice(prefix.getPath().size()); RelativeRewritePath relPath2 = path2.getPath().slice(prefix.getPath().size()); // Order the paths so that we go to the more-canonical path. if (compareDependentPaths(relPath1, relPath2) < 0) std::swap(relPath1, relPath2); // Find the anchor for the prefix. CanType commonType = prefix.formDependentType(getASTContext()); CanType commonAnchor = getCanonicalTypeParameter(commonType)->getCanonicalType(); // Add the rewrite rule. auto root = Impl->getOrCreateRewriteTreeRoot(commonAnchor); return root->addRewriteRule( relPath1, RewritePath(None, relPath2, RewritePath::Forward)); } // Otherwise, form a rewrite rule with absolute paths. // Find the better path and make sure it's in path2. if (compareDependentTypes(type1, type2) < 0) { std::swap(path1, path2); std::swap(type1, type2); } // Add the rewrite rule. Type firstBase = GenericTypeParamType::get( path1.getBase()->TypeSequence, path1.getBase()->Depth, path1.getBase()->Index, getASTContext()); CanType baseAnchor = getCanonicalTypeParameter(firstBase)->getCanonicalType(); auto root = Impl->getOrCreateRewriteTreeRoot(baseAnchor); return root->addRewriteRule(path1.getPath(), path2); } Type GenericSignatureBuilder::getCanonicalTypeParameter(Type type) { auto initialPath = RewritePath::createPath(type); auto genericParamType = GenericTypeParamType::get( initialPath.getBase()->TypeSequence, initialPath.getBase()->Depth, initialPath.getBase()->Index, getASTContext()); unsigned startIndex = 0; Type currentType = genericParamType; SmallVector path(initialPath.getPath().begin(), initialPath.getPath().end()); bool simplified = false; do { CanType currentAnchor = currentType->getCanonicalType(); if (auto rootNode = Impl->getRewriteTreeRootIfPresent(currentAnchor)) { // Find the best rewrite rule for the path starting at startIndex. auto match = rootNode->bestRewritePath(genericParamType, llvm::makeArrayRef(path).slice(startIndex), startIndex); // If we have a match, replace the matched path with the replacement // path. if (match) { // Determine the range in the path which we'll be replacing. unsigned replaceStartIndex = match->second.getBase() ? 0 : startIndex; unsigned replaceEndIndex = startIndex + match->first; // Overwrite the beginning of the match. auto replacementPath = match->second.getPath(); assert((replaceEndIndex - replaceStartIndex) >= replacementPath.size()); auto replacementStartPos = path.begin() + replaceStartIndex; std::copy(replacementPath.begin(), replacementPath.end(), replacementStartPos); // Erase the rest. path.erase(replacementStartPos + replacementPath.size(), path.begin() + replaceEndIndex); // If this is an absolute path, use the new base. if (auto newBase = match->second.getBase()) { genericParamType = GenericTypeParamType::get(newBase->TypeSequence, newBase->Depth, newBase->Index, getASTContext()); } // Move back to the beginning; we may have opened up other rewrites. simplified = true; startIndex = 0; currentType = genericParamType; continue; } } // If we've hit the end of the path, we're done. if (startIndex >= path.size()) break; currentType = DependentMemberType::get(currentType, path[startIndex++]); } while (true); return formDependentType(genericParamType, path); } #pragma mark Equivalence classes EquivalenceClass::EquivalenceClass(PotentialArchetype *representative) : recursiveConcreteType(false), invalidConcreteType(false), recursiveSuperclassType(false) { members.push_back(representative); } void EquivalenceClass::modified(GenericSignatureBuilder &builder) { ++builder.Impl->Generation; // Transfer any delayed requirements to the primary queue, because they // might be resolvable now. builder.Impl->DelayedRequirements.append(delayedRequirements.begin(), delayedRequirements.end()); delayedRequirements.clear(); } GenericSignatureBuilder::GenericSignatureBuilder( ASTContext &ctx, bool requirementSignature) : Context(ctx), Diags(Context.Diags), Impl(new Implementation) { if (auto *Stats = Context.Stats) ++Stats->getFrontendCounters().NumGenericSignatureBuilders; Impl->BuildingProtocolRequirementSignature = requirementSignature; } GenericSignatureBuilder::GenericSignatureBuilder( GenericSignatureBuilder &&other) : Context(other.Context), Diags(other.Diags), Impl(std::move(other.Impl)) { other.Impl.reset(); if (Impl) { // Update the generic parameters to their canonical types. for (auto &gp : Impl->GenericParams) { gp = gp->getCanonicalType()->castTo(); } } } GenericSignatureBuilder::~GenericSignatureBuilder() = default; auto GenericSignatureBuilder::getLookupConformanceFn() -> LookUpConformanceInBuilder { return LookUpConformanceInBuilder(this); } ProtocolConformanceRef GenericSignatureBuilder::LookUpConformanceInBuilder::operator()( CanType dependentType, Type conformingReplacementType, ProtocolDecl *conformedProtocol) const { // Lookup conformances for opened existential. if (conformingReplacementType->isOpenedExistential()) { return conformedProtocol->getModuleContext()->lookupConformance( conformingReplacementType, conformedProtocol); } return builder->lookupConformance(conformingReplacementType, conformedProtocol); } ProtocolConformanceRef GenericSignatureBuilder::lookupConformance(Type conformingReplacementType, ProtocolDecl *conformedProtocol) { if (conformingReplacementType->isTypeParameter()) return ProtocolConformanceRef(conformedProtocol); // Figure out which module to look into. // FIXME: When lookupConformance() starts respecting modules, we'll need // to do some filtering here. ModuleDecl *searchModule = conformedProtocol->getParentModule(); return searchModule->lookupConformance(conformingReplacementType, conformedProtocol); } /// Resolve any unresolved dependent member types using the given builder. static Type resolveDependentMemberTypes( GenericSignatureBuilder &builder, Type type, ArchetypeResolutionKind resolutionKind) { if (!type->hasTypeParameter()) return type; return type.transformRec([&resolutionKind, &builder](TypeBase *type) -> Optional { if (!type->isTypeParameter()) return None; auto resolved = builder.maybeResolveEquivalenceClass( Type(type), resolutionKind, true); if (!resolved) return ErrorType::get(Type(type)); if (auto concreteType = resolved.getAsConcreteType()) return concreteType; // Map the type parameter to an equivalence class. auto equivClass = resolved.getEquivalenceClassIfPresent(); // If there is a concrete type in this equivalence class, use that. if (equivClass && equivClass->concreteType) { // .. unless it's recursive. if (equivClass->recursiveConcreteType) return ErrorType::get(Type(type)); // Prevent recursive substitution. equivClass->recursiveConcreteType = true; SWIFT_DEFER { equivClass->recursiveConcreteType = false; }; return resolveDependentMemberTypes(builder, equivClass->concreteType, resolutionKind); } return resolved.getDependentType(builder); }); } static Type getStructuralType(TypeDecl *typeDecl, bool keepSugar) { if (auto typealias = dyn_cast(typeDecl)) { if (typealias->getUnderlyingTypeRepr() != nullptr) { auto type = typealias->getStructuralType(); if (!keepSugar) if (auto *aliasTy = cast(type.getPointer())) return aliasTy->getSinglyDesugaredType(); return type; } if (!keepSugar) return typealias->getUnderlyingType(); } return typeDecl->getDeclaredInterfaceType(); } static Type substituteConcreteType(Type parentType, TypeDecl *concreteDecl) { if (parentType->is() || parentType->is()) return parentType; auto *dc = concreteDecl->getDeclContext(); // Form an unsubstituted type referring to the given type declaration, // for use in an inferred same-type requirement. auto type = getStructuralType(concreteDecl, /*keepSugar=*/true); auto subMap = parentType->getContextSubstitutionMap( dc->getParentModule(), dc); // If the type has unresolved DependentMemberTypes, we can't use // Type::subst() if a generic parameter is replaced with a concrete // type. Instead, perform a "shallow" substitution where we replace // generic parameter types but leave DependentMemberTypes as-is. // This means we will end up back in maybeResolveEquivalenceClass(), // where we will perform the name lookup required to resolve any // DependentMemberTypes with a concrete base. if (type->findUnresolvedDependentMemberType()) { return type.transform([&](Type t) { if (t->is()) { return t.subst(subMap); } return t; }); } return type.subst(subMap); } ResolvedType GenericSignatureBuilder::maybeResolveEquivalenceClass( Type type, ArchetypeResolutionKind resolutionKind, bool wantExactPotentialArchetype) { // The equivalence class of a generic type is known directly. if (auto genericParam = type->getAs()) { unsigned index = GenericParamKey(genericParam).findIndexIn( getGenericParams()); if (index < Impl->GenericParams.size()) { return ResolvedType(Impl->PotentialArchetypes[index]); } return ResolvedType::forUnresolved(nullptr); } // The equivalence class of a dependent member type is determined by its // base equivalence class, if there is one. if (auto depMemTy = type->getAs()) { // Find the equivalence class of the base. auto resolvedBase = maybeResolveEquivalenceClass(depMemTy->getBase(), resolutionKind, wantExactPotentialArchetype); if (!resolvedBase) return resolvedBase; // If the base is concrete, so is this member. if (auto parentType = resolvedBase.getAsConcreteType()) { TypeDecl *concreteDecl = depMemTy->getAssocType(); if (!concreteDecl) { // If we have an unresolved dependent member type, perform a // name lookup. if (auto *decl = parentType->getAnyNominal()) { SmallVector concreteDecls; lookupConcreteNestedType(decl, depMemTy->getName(), concreteDecls); if (concreteDecls.empty()) return ResolvedType::forUnresolved(nullptr); concreteDecl = findBestConcreteNestedType(concreteDecls); } } auto concreteType = substituteConcreteType(parentType, concreteDecl); return maybeResolveEquivalenceClass(concreteType, resolutionKind, wantExactPotentialArchetype); } // Find the nested type declaration for this. auto baseEquivClass = resolvedBase.getEquivalenceClass(*this); // Retrieve the "smallest" type in the equivalence class, by depth, and // use that to find a nested potential archetype. We used the smallest // type by depth to limit expansion of the type graph. PotentialArchetype *basePA; if (wantExactPotentialArchetype) { basePA = resolvedBase.getPotentialArchetypeIfKnown(); if (!basePA) return ResolvedType::forUnresolved(baseEquivClass); } else { basePA = baseEquivClass->members.front(); } if (auto assocType = depMemTy->getAssocType()) { // Check whether this associated type references a protocol to which // the base conforms. If not, it's either concrete or unresolved. auto *proto = assocType->getProtocol(); if (baseEquivClass->conformsTo.find(proto) == baseEquivClass->conformsTo.end()) { if (baseEquivClass->concreteType && lookupConformance(baseEquivClass->concreteType, proto)) { // Fall through } else if (baseEquivClass->superclass && lookupConformance(baseEquivClass->superclass, proto)) { // Fall through } else { return ResolvedType::forUnresolved(baseEquivClass); } // FIXME: Instead of falling through, we ought to return a concrete // type here, but then we fail to update a nested PotentialArchetype // if one happens to already exist. It would be cleaner if concrete // types never had nested PotentialArchetypes. } auto nestedPA = basePA->getOrCreateNestedType(*this, assocType, resolutionKind); if (!nestedPA) return ResolvedType::forUnresolved(baseEquivClass); return ResolvedType(nestedPA); } else { auto *concreteDecl = baseEquivClass->lookupNestedType(*this, depMemTy->getName()); if (!concreteDecl) return ResolvedType::forUnresolved(baseEquivClass); Type parentType; auto *proto = concreteDecl->getDeclContext()->getSelfProtocolDecl(); if (!proto) { parentType = (baseEquivClass->concreteType ? baseEquivClass->concreteType : baseEquivClass->superclass); } else { if (baseEquivClass->concreteType && lookupConformance(baseEquivClass->concreteType, proto)) { parentType = baseEquivClass->concreteType; } else if (baseEquivClass->superclass && lookupConformance(baseEquivClass->superclass, proto)) { parentType = baseEquivClass->superclass; } else { parentType = basePA->getDependentType(getGenericParams()); } } auto concreteType = substituteConcreteType(parentType, concreteDecl); return maybeResolveEquivalenceClass(concreteType, resolutionKind, wantExactPotentialArchetype); } } // If it's not a type parameter, it won't directly resolve to one. // FIXME: Generic typealiases contradict the assumption above. // If there is a type parameter somewhere in this type, resolve it. if (type->hasTypeParameter()) { Type resolved = resolveDependentMemberTypes(*this, type, resolutionKind); if (resolved->hasError() && !type->hasError()) return ResolvedType::forUnresolved(nullptr); type = resolved; } return ResolvedType::forConcrete(type); } EquivalenceClass *GenericSignatureBuilder::resolveEquivalenceClass( Type type, ArchetypeResolutionKind resolutionKind) { if (auto resolved = maybeResolveEquivalenceClass(type, resolutionKind, /*wantExactPotentialArchetype=*/false)) return resolved.getEquivalenceClass(*this); return nullptr; } auto GenericSignatureBuilder::resolve(UnresolvedType paOrT, FloatingRequirementSource source) -> ResolvedType { if (auto pa = paOrT.dyn_cast()) return ResolvedType(pa); // Determine what kind of resolution we want. ArchetypeResolutionKind resolutionKind = ArchetypeResolutionKind::WellFormed; if (source.isDerived() && source.isRecursive(*this)) resolutionKind = ArchetypeResolutionKind::AlreadyKnown; Type type = paOrT.get(); return maybeResolveEquivalenceClass(type, resolutionKind, /*wantExactPotentialArchetype=*/true); } bool GenericSignatureBuilder::areInSameEquivalenceClass(Type type1, Type type2) { return resolveEquivalenceClass(type1, ArchetypeResolutionKind::WellFormed) == resolveEquivalenceClass(type2, ArchetypeResolutionKind::WellFormed); } Type GenericSignatureBuilder::getCanonicalTypeInContext(Type type, TypeArrayView genericParams) { // All the contextual canonicality rules apply to type parameters, so if the // type doesn't involve any type parameters, it's already canonical. if (!type->hasTypeParameter()) return type; // Replace non-canonical type parameters. return type.transformRec([&](TypeBase *component) -> Optional { if (!isa(component) && !isa(component)) return None; // Find the equivalence class for this dependent type. auto resolved = maybeResolveEquivalenceClass( Type(component), ArchetypeResolutionKind::CompleteWellFormed, /*wantExactPotentialArchetype=*/false); if (!resolved) return None; if (auto concrete = resolved.getAsConcreteType()) return getCanonicalTypeInContext(concrete, genericParams); auto equivClass = resolved.getEquivalenceClass(*this); if (!equivClass) return None; // If there is a concrete type in this equivalence class, use that. if (auto concrete = equivClass->concreteType) { // .. unless it's recursive. if (equivClass->recursiveConcreteType) return ErrorType::get(Type(type)); // Prevent recursive substitution. equivClass->recursiveConcreteType = true; SWIFT_DEFER { equivClass->recursiveConcreteType = false; }; return getCanonicalTypeInContext(concrete, genericParams); } return equivClass->getAnchor(*this, genericParams); }); } ConformanceAccessPath GenericSignatureBuilder::getConformanceAccessPath(Type type, ProtocolDecl *protocol, GenericSignature sig) { auto canType = getCanonicalTypeInContext(type, { })->getCanonicalType(); assert(canType->isTypeParameter()); // Check if we've already cached the result before doing anything else. auto found = Impl->ConformanceAccessPaths.find( std::make_pair(canType, protocol)); if (found != Impl->ConformanceAccessPaths.end()) { return found->second; } auto *Stats = Context.Stats; FrontendStatsTracer tracer(Stats, "get-conformance-access-path"); auto recordPath = [&](CanType type, ProtocolDecl *proto, ConformanceAccessPath path) { // Add the path to the buffer. Impl->CurrentConformanceAccessPaths.emplace_back(type, path); // Add the path to the map. auto key = std::make_pair(type, proto); auto inserted = Impl->ConformanceAccessPaths.insert( std::make_pair(key, path)); assert(inserted.second); (void) inserted; if (Stats) ++Stats->getFrontendCounters().NumConformanceAccessPathsRecorded; }; // If this is the first time we're asked to look up a conformance access path, // visit all of the root conformance requirements in our generic signature and // add them to the buffer. if (Impl->ConformanceAccessPaths.empty()) { for (const auto &req : sig.getRequirements()) { // We only care about conformance requirements. if (req.getKind() != RequirementKind::Conformance) continue; auto rootType = req.getFirstType()->getCanonicalType(); auto *rootProto = req.getProtocolDecl(); ConformanceAccessPath::Entry root(rootType, rootProto); ArrayRef path(root); ConformanceAccessPath result(Context.AllocateCopy(path)); recordPath(rootType, rootProto, result); } } // We enumerate conformance access paths in lexshort order until we find the // path whose corresponding type canonicalizes to the one we are looking for. while (true) { auto found = Impl->ConformanceAccessPaths.find( std::make_pair(canType, protocol)); if (found != Impl->ConformanceAccessPaths.end()) { return found->second; } assert(Impl->CurrentConformanceAccessPaths.size() > 0); // The buffer consists of all conformance access paths of length N. // Swap it out with an empty buffer, and fill it with all paths of // length N+1. std::vector> oldPaths; std::swap(Impl->CurrentConformanceAccessPaths, oldPaths); for (const auto &pair : oldPaths) { const auto &lastElt = pair.second.back(); auto *lastProto = lastElt.second; // A copy of the current path, populated as needed. SmallVector entries; for (const auto &req : lastProto->getRequirementSignature()) { // We only care about conformance requirements. if (req.getKind() != RequirementKind::Conformance) continue; auto nextSubjectType = req.getFirstType()->getCanonicalType(); auto *nextProto = req.getProtocolDecl(); // Compute the canonical anchor for this conformance requirement. auto nextType = replaceSelfWithType(pair.first, nextSubjectType); auto nextCanType = getCanonicalTypeInContext(nextType, { }) ->getCanonicalType(); // Skip "derived via concrete" sources. if (!nextCanType->isTypeParameter()) continue; // If we've already seen a path for this conformance, skip it and // don't add it to the buffer. Note that because we iterate over // conformance access paths in lexshort order, the existing // conformance access path is shorter than the one we found just now. if (Impl->ConformanceAccessPaths.count( std::make_pair(nextCanType, nextProto))) continue; if (entries.empty()) { // Fill our temporary vector. entries.insert(entries.begin(), pair.second.begin(), pair.second.end()); } // Add the next entry. entries.emplace_back(nextSubjectType, nextProto); ConformanceAccessPath result = Context.AllocateCopy(entries); entries.pop_back(); recordPath(nextCanType, nextProto, result); } } } } TypeArrayView GenericSignatureBuilder::getGenericParams() const { return TypeArrayView(Impl->GenericParams); } void GenericSignatureBuilder::addGenericParameter(GenericTypeParamDecl *GenericParam) { addGenericParameter( GenericParam->getDeclaredInterfaceType()->castTo()); } bool GenericSignatureBuilder::addGenericParameterRequirements( GenericTypeParamDecl *GenericParam) { GenericParamKey Key(GenericParam); auto PA = Impl->PotentialArchetypes[Key.findIndexIn(getGenericParams())]; // Add the requirements from the declaration. return isErrorResult( addInheritedRequirements(GenericParam, PA, nullptr, GenericParam->getModuleContext())); } void GenericSignatureBuilder::addGenericParameter(GenericTypeParamType *GenericParam) { auto params = getGenericParams(); (void)params; #ifndef NDEBUG if (params.empty()) { assert(GenericParam->getDepth() == 0); assert(GenericParam->getIndex() == 0); } else { assert((GenericParam->getDepth() == params.back()->getDepth() && GenericParam->getIndex() == params.back()->getIndex() + 1) || (GenericParam->getDepth() > params.back()->getDepth() && GenericParam->getIndex() == 0)); } #endif // Create a potential archetype for this type parameter. auto PA = new (Impl->Allocator) PotentialArchetype(GenericParam); Impl->GenericParams.push_back(GenericParam); Impl->PotentialArchetypes.push_back(PA); } /// Visit all of the types that show up in the list of inherited /// types. static ConstraintResult visitInherited( llvm::PointerUnion decl, llvm::function_ref visitType) { // Local function that (recursively) adds inherited types. ConstraintResult result = ConstraintResult::Resolved; std::function visitInherited; visitInherited = [&](Type inheritedType, const TypeRepr *typeRepr) { // Decompose explicitly-written protocol compositions. if (auto composition = dyn_cast_or_null(typeRepr)) { if (auto compositionType = inheritedType->getAs()) { unsigned index = 0; for (auto memberType : compositionType->getMembers()) { visitInherited(memberType, composition->getTypes()[index]); ++index; } return; } } auto recursiveResult = visitType(inheritedType, typeRepr); if (isErrorResult(recursiveResult) && !isErrorResult(result)) result = recursiveResult; }; // Visit all of the inherited types. auto typeDecl = decl.dyn_cast(); auto extDecl = decl.dyn_cast(); ASTContext &ctx = typeDecl ? typeDecl->getASTContext() : extDecl->getASTContext(); auto &evaluator = ctx.evaluator; ArrayRef inheritedTypes = typeDecl ? typeDecl->getInherited() : extDecl->getInherited(); for (unsigned index : indices(inheritedTypes)) { Type inheritedType = evaluateOrDefault(evaluator, InheritedTypeRequest{decl, index, TypeResolutionStage::Structural}, Type()); if (!inheritedType) continue; const auto &inherited = inheritedTypes[index]; visitInherited(inheritedType, inherited.getTypeRepr()); } return result; } ConstraintResult GenericSignatureBuilder::expandConformanceRequirement( ResolvedType selfType, ProtocolDecl *proto, const RequirementSource *source, bool onlySameTypeConstraints) { auto protocolSubMap = SubstitutionMap::getProtocolSubstitutions( proto, selfType.getDependentType(*this), ProtocolConformanceRef(proto)); auto result = ConstraintResult::Resolved; // Use the requirement signature to avoid rewalking the entire protocol. This // cannot compute the requirement signature directly, because that may be // infinitely recursive: this code is also used to construct it. if (!proto->isComputingRequirementSignature()) { auto innerSource = FloatingRequirementSource::viaProtocolRequirement(source, proto, /*inferred=*/false); for (const auto &req : proto->getRequirementSignature()) { // If we're only looking at same-type constraints, skip everything else. if (onlySameTypeConstraints && req.getKind() != RequirementKind::SameType) continue; auto substReq = req.subst(protocolSubMap); auto reqResult = substReq ? addRequirement(*substReq, innerSource, nullptr) : ConstraintResult::Conflicting; if (isErrorResult(reqResult) && !isErrorResult(result)) result = reqResult; } return result; } if (!onlySameTypeConstraints) { // Add all of the inherited protocol requirements, recursively. auto inheritedReqResult = addInheritedRequirements(proto, selfType.getUnresolvedType(), source, nullptr); if (isErrorResult(inheritedReqResult) && !isErrorResult(inheritedReqResult)) result = inheritedReqResult; } // Add any requirements in the where clause on the protocol. WhereClauseOwner(proto).visitRequirements(TypeResolutionStage::Structural, [&](const Requirement &req, RequirementRepr *reqRepr) { // If we're only looking at same-type constraints, skip everything else. if (onlySameTypeConstraints && req.getKind() != RequirementKind::SameType) return false; auto innerSource = FloatingRequirementSource::viaProtocolRequirement( source, proto, reqRepr->getSeparatorLoc(), /*inferred=*/false); addRequirement(req, reqRepr, innerSource, &protocolSubMap, nullptr); return false; }); if (proto->isObjC()) { // @objc implies an inferred AnyObject constraint. auto innerSource = FloatingRequirementSource::viaProtocolRequirement(source, proto, /*inferred=*/true); addLayoutRequirementDirect(selfType, LayoutConstraint::getLayoutConstraint( LayoutConstraintKind::Class, getASTContext()), innerSource); return result; } // Remaining logic is not relevant in ObjC protocol cases. // Collect all of the inherited associated types and typealiases in the // inherited protocols (recursively). llvm::MapVector> inheritedTypeDecls; { proto->walkInheritedProtocols( [&](ProtocolDecl *inheritedProto) -> TypeWalker::Action { if (inheritedProto == proto) return TypeWalker::Action::Continue; for (auto req : inheritedProto->getMembers()) { if (auto typeReq = dyn_cast(req)) { // Ignore generic types if (auto genReq = dyn_cast(req)) if (genReq->getGenericParams()) continue; inheritedTypeDecls[typeReq->getName()].push_back(typeReq); } } return TypeWalker::Action::Continue; }); } // Local function to find the insertion point for the protocol's "where" // clause, as well as the string to start the insertion ("where" or ","); auto getProtocolWhereLoc = [&]() -> Located { // Already has a trailing where clause. if (auto trailing = proto->getTrailingWhereClause()) return { ", ", trailing->getRequirements().back().getSourceRange().End }; // Inheritance clause. return { " where ", proto->getInherited().back().getSourceRange().End }; }; // Retrieve the set of requirements that a given associated type declaration // produces, in the form that would be seen in the where clause. const auto getAssociatedTypeReqs = [&](const AssociatedTypeDecl *assocType, const char *start) { std::string result; { llvm::raw_string_ostream out(result); out << start; interleave(assocType->getInherited(), [&](TypeLoc inheritedType) { out << assocType->getName() << ": "; if (auto inheritedTypeRepr = inheritedType.getTypeRepr()) inheritedTypeRepr->print(out); else inheritedType.getType().print(out); }, [&] { out << ", "; }); if (const auto whereClause = assocType->getTrailingWhereClause()) { if (!assocType->getInherited().empty()) out << ", "; whereClause->print(out, /*printWhereKeyword*/false); } } return result; }; // Retrieve the requirement that a given typealias introduces when it // overrides an inherited associated type with the same name, as a string // suitable for use in a where clause. auto getConcreteTypeReq = [&](TypeDecl *type, const char *start) { std::string result; { llvm::raw_string_ostream out(result); out << start; out << type->getName() << " == "; if (auto typealias = dyn_cast(type)) { if (auto underlyingTypeRepr = typealias->getUnderlyingTypeRepr()) underlyingTypeRepr->print(out); else typealias->getUnderlyingType().print(out); } else { type->print(out); } } return result; }; // An inferred same-type requirement between the two type declarations // within this protocol or a protocol it inherits. auto addInferredSameTypeReq = [&](TypeDecl *first, TypeDecl *second) { Type firstType = getStructuralType(first, /*keepSugar=*/false); Type secondType = getStructuralType(second, /*keepSugar=*/false); auto inferredSameTypeSource = FloatingRequirementSource::viaProtocolRequirement( source, proto, SourceLoc(), /*inferred=*/true); auto rawReq = Requirement(RequirementKind::SameType, firstType, secondType); if (auto req = rawReq.subst(protocolSubMap)) addRequirement(*req, inferredSameTypeSource, proto->getParentModule()); }; // Add requirements for each of the associated types. for (auto assocTypeDecl : proto->getAssociatedTypeMembers()) { // Add requirements placed directly on this associated type. Type assocType = DependentMemberType::get(selfType.getDependentType(*this), assocTypeDecl); if (!onlySameTypeConstraints) { (void) resolve(assocType, source); auto assocResult = addInheritedRequirements(assocTypeDecl, assocType, source, /*inferForModule=*/nullptr); if (isErrorResult(assocResult) && !isErrorResult(result)) result = assocResult; } // Add requirements from this associated type's where clause. WhereClauseOwner(assocTypeDecl).visitRequirements( TypeResolutionStage::Structural, [&](const Requirement &req, RequirementRepr *reqRepr) { // If we're only looking at same-type constraints, skip everything else. if (onlySameTypeConstraints && req.getKind() != RequirementKind::SameType) return false; auto innerSource = FloatingRequirementSource::viaProtocolRequirement( source, proto, reqRepr->getSeparatorLoc(), /*inferred=*/false); addRequirement(req, reqRepr, innerSource, &protocolSubMap, /*inferForModule=*/nullptr); return false; }); // Check whether we inherited any types with the same name. auto knownInherited = inheritedTypeDecls.find(assocTypeDecl->getName()); if (knownInherited == inheritedTypeDecls.end()) continue; bool shouldWarnAboutRedeclaration = source->kind == RequirementSource::RequirementSignatureSelf && !assocTypeDecl->getAttrs().hasAttribute() && !assocTypeDecl->getAttrs().hasAttribute() && !assocTypeDecl->hasDefaultDefinitionType() && (!assocTypeDecl->getInherited().empty() || assocTypeDecl->getTrailingWhereClause() || getASTContext().LangOpts.WarnImplicitOverrides); for (auto inheritedType : knownInherited->second) { // If we have inherited associated type... if (auto inheritedAssocTypeDecl = dyn_cast(inheritedType)) { // Complain about the first redeclaration. if (shouldWarnAboutRedeclaration) { auto inheritedFromProto = inheritedAssocTypeDecl->getProtocol(); auto fixItWhere = getProtocolWhereLoc(); Diags.diagnose(assocTypeDecl, diag::inherited_associated_type_redecl, assocTypeDecl->getName(), inheritedFromProto->getDeclaredInterfaceType()) .fixItInsertAfter( fixItWhere.Loc, getAssociatedTypeReqs(assocTypeDecl, fixItWhere.Item)) .fixItRemove(assocTypeDecl->getSourceRange()); Diags.diagnose(inheritedAssocTypeDecl, diag::decl_declared_here, inheritedAssocTypeDecl->getName()); shouldWarnAboutRedeclaration = false; } continue; } // We inherited a type; this associated type will be identical // to that typealias. if (source->kind == RequirementSource::RequirementSignatureSelf) { auto inheritedOwningDecl = inheritedType->getDeclContext()->getSelfNominalTypeDecl(); Diags.diagnose(assocTypeDecl, diag::associated_type_override_typealias, assocTypeDecl->getName(), inheritedOwningDecl->getDescriptiveKind(), inheritedOwningDecl->getDeclaredInterfaceType()); } addInferredSameTypeReq(assocTypeDecl, inheritedType); } inheritedTypeDecls.erase(knownInherited); continue; } // Check all remaining inherited type declarations to determine if // this protocol has a non-associated-type type with the same name. inheritedTypeDecls.remove_if( [&](const std::pair> &inherited) { const auto name = inherited.first; for (auto found : proto->lookupDirect(name)) { // We only want concrete type declarations. auto type = dyn_cast(found); if (!type || isa(type)) continue; // Ignore nominal types. They're always invalid declarations. if (isa(type)) continue; // ... from the same module as the protocol. if (type->getModuleContext() != proto->getModuleContext()) continue; // Ignore types defined in constrained extensions; their equivalence // to the associated type would have to be conditional, which we cannot // model. if (auto ext = dyn_cast(type->getDeclContext())) { if (ext->isConstrainedExtension()) continue; } // We found something. bool shouldWarnAboutRedeclaration = source->kind == RequirementSource::RequirementSignatureSelf; for (auto inheritedType : inherited.second) { // If we have inherited associated type... if (auto inheritedAssocTypeDecl = dyn_cast(inheritedType)) { // Infer a same-type requirement between the typealias' underlying // type and the inherited associated type. addInferredSameTypeReq(inheritedAssocTypeDecl, type); // Warn that one should use where clauses for this. if (shouldWarnAboutRedeclaration) { auto inheritedFromProto = inheritedAssocTypeDecl->getProtocol(); auto fixItWhere = getProtocolWhereLoc(); Diags.diagnose(type, diag::typealias_override_associated_type, name, inheritedFromProto->getDeclaredInterfaceType()) .fixItInsertAfter(fixItWhere.Loc, getConcreteTypeReq(type, fixItWhere.Item)) .fixItRemove(type->getSourceRange()); Diags.diagnose(inheritedAssocTypeDecl, diag::decl_declared_here, inheritedAssocTypeDecl->getName()); shouldWarnAboutRedeclaration = false; } continue; } // Two typealiases that should be the same. addInferredSameTypeReq(inheritedType, type); } // We can remove this entry. return true; } return false; }); // Infer same-type requirements among inherited type declarations. for (auto &entry : inheritedTypeDecls) { if (entry.second.size() < 2) continue; auto firstDecl = entry.second.front(); for (auto otherDecl : ArrayRef(entry.second).slice(1)) { addInferredSameTypeReq(firstDecl, otherDecl); } } return result; } ConstraintResult GenericSignatureBuilder::addConformanceRequirement( ResolvedType type, ProtocolDecl *proto, FloatingRequirementSource source) { auto resolvedSource = source.getSource(*this, type); if (!resolvedSource->isDerivedRequirement()) { Impl->ExplicitRequirements.insert( ExplicitRequirement(RequirementKind::Conformance, resolvedSource, proto)); } // Add the conformance requirement, bailing out earlier if we've already // seen it. auto equivClass = type.getEquivalenceClass(*this); if (!equivClass->recordConformanceConstraint(*this, type, proto, resolvedSource)) return ConstraintResult::Resolved; return expandConformanceRequirement(type, proto, resolvedSource, /*onlySameTypeRequirements=*/false); } ConstraintResult GenericSignatureBuilder::addLayoutRequirementDirect( ResolvedType type, LayoutConstraint layout, FloatingRequirementSource source) { auto resolvedSource = source.getSource(*this, type); if (!resolvedSource->isDerivedRequirement()) { Impl->ExplicitRequirements.insert( ExplicitRequirement(RequirementKind::Layout, resolvedSource, layout)); } // Update the layout in the equivalence class, if we didn't have one already. bool anyChanges = updateLayout(type, layout); // Record this layout constraint. auto equivClass = type.getEquivalenceClass(*this); equivClass->layoutConstraints.push_back({type.getUnresolvedType(), layout, resolvedSource}); equivClass->modified(*this); ++NumLayoutConstraints; if (!anyChanges) ++NumLayoutConstraintsExtra; return ConstraintResult::Resolved; } ConstraintResult GenericSignatureBuilder::addLayoutRequirement( UnresolvedType subject, LayoutConstraint layout, FloatingRequirementSource source, UnresolvedHandlingKind unresolvedHandling) { // Resolve the subject. auto resolvedSubject = resolve(subject, source); if (!resolvedSubject) { return handleUnresolvedRequirement( RequirementKind::Layout, subject, layout, source, resolvedSubject.getUnresolvedEquivClass(), unresolvedHandling); } // If this layout constraint applies to a concrete type, we can fully // resolve it now. if (auto concreteType = resolvedSubject.getAsConcreteType()) { // If a layout requirement was explicitly written on a concrete type, // complain. if (source.isExplicit() && source.getLoc().isValid()) { Impl->HadAnyError = true; Diags.diagnose(source.getLoc(), diag::requires_not_suitable_archetype, concreteType); return ConstraintResult::Concrete; } // FIXME: Check whether the layout constraint makes sense for this // concrete type! return ConstraintResult::Resolved; } return addLayoutRequirementDirect(resolvedSubject, layout, source); } bool GenericSignatureBuilder::updateSuperclass( ResolvedType type, Type superclass, FloatingRequirementSource source) { auto equivClass = type.getEquivalenceClass(*this); // Local function to handle the update of superclass conformances // when the superclass constraint changes. auto updateSuperclassConformances = [&] { for (const auto &conforms : equivClass->conformsTo) { bool explicitConformance = std::find_if( conforms.second.begin(), conforms.second.end(), [](const Constraint &constraint) { return !constraint.source->isDerivedRequirement(); }) != conforms.second.end(); (void)resolveSuperConformance(type, conforms.first, explicitConformance); } // Eagerly resolve any existing nested types to their concrete forms (others // will be "concretized" as they are constructed, in getNestedType). for (auto equivT : equivClass->members) { for (auto nested : equivT->getNestedTypes()) { concretizeNestedTypeFromConcreteParent(equivT, nested.second.front(), *this); } } }; // If we haven't yet recorded a superclass constraint for this equivalence // class, do so now. if (!equivClass->superclass) { equivClass->superclass = superclass; updateSuperclassConformances(); // Presence of a superclass constraint implies a _Class layout // constraint. auto layoutReqSource = source.getSource(*this, type)->viaLayout(*this, superclass); auto layout = LayoutConstraint::getLayoutConstraint( superclass->getClassOrBoundGenericClass()->getLayoutConstraintKind(), getASTContext()); addLayoutRequirementDirect(type, layout, layoutReqSource); return true; } // T already has a superclass; make sure it's related. auto existingSuperclass = equivClass->superclass; // TODO: In principle, this could be isBindableToSuperclassOf instead of // isExactSubclassOf. If you had: // // class Foo // class Bar: Foo // // func foo, U: Bar>(...) { ... } // // then the second constraint should be allowed, constraining U to Bar // and secondarily imposing a T == Int constraint. if (existingSuperclass->isExactSuperclassOf(superclass)) { equivClass->superclass = superclass; // We've strengthened the bound, so update superclass conformances. updateSuperclassConformances(); return true; } return false; } bool GenericSignatureBuilder::updateLayout(ResolvedType type, LayoutConstraint layout) { auto equivClass = type.getEquivalenceClass(*this); if (!equivClass->layout) { equivClass->layout = layout; return true; } // Try to merge layout constraints. auto mergedLayout = equivClass->layout.merge(layout); if (mergedLayout->isKnownLayout() && mergedLayout != equivClass->layout) { equivClass->layout = mergedLayout; return true; } return false; } ConstraintResult GenericSignatureBuilder::addSuperclassRequirementDirect( ResolvedType type, Type superclass, FloatingRequirementSource source) { auto resolvedSource = source.getSource(*this, type); if (!resolvedSource->isDerivedRequirement()) { Impl->ExplicitRequirements.insert( ExplicitRequirement(RequirementKind::Superclass, resolvedSource, superclass)); } // Record the constraint. auto equivClass = type.getEquivalenceClass(*this); equivClass->superclassConstraints.push_back( ConcreteConstraint{type.getUnresolvedType(), superclass, resolvedSource}); equivClass->modified(*this); ++NumSuperclassConstraints; // Update the equivalence class with the constraint. if (!updateSuperclass(type, superclass, resolvedSource)) ++NumSuperclassConstraintsExtra; return ConstraintResult::Resolved; } /// Map an unresolved type to a requirement right-hand-side. static GenericSignatureBuilder::UnresolvedRequirementRHS toUnresolvedRequirementRHS(GenericSignatureBuilder::UnresolvedType unresolved) { if (auto pa = unresolved.dyn_cast()) return pa; return unresolved.dyn_cast(); } ConstraintResult GenericSignatureBuilder::addTypeRequirement( UnresolvedType subject, UnresolvedType constraint, FloatingRequirementSource source, UnresolvedHandlingKind unresolvedHandling, ModuleDecl *inferForModule) { // Resolve the constraint. auto resolvedConstraint = resolve(constraint, source); if (!resolvedConstraint) { return handleUnresolvedRequirement( RequirementKind::Conformance, subject, toUnresolvedRequirementRHS(constraint), source, resolvedConstraint.getUnresolvedEquivClass(), unresolvedHandling); } // The right-hand side needs to be concrete. Type constraintType = resolvedConstraint.getAsConcreteType(); if (!constraintType) { constraintType = resolvedConstraint.getDependentType(*this); assert(constraintType && "No type to express resolved constraint?"); } // Resolve the subject. If we can't, delay the constraint. auto resolvedSubject = resolve(subject, source); if (!resolvedSubject) { auto recordedKind = constraintType->isExistentialType() ? RequirementKind::Conformance : RequirementKind::Superclass; return handleUnresolvedRequirement( recordedKind, subject, constraintType, source, resolvedSubject.getUnresolvedEquivClass(), unresolvedHandling); } // If the resolved subject is concrete, there may be things we can infer (if it // conditionally conforms to the protocol), and we can probably perform // diagnostics here. if (auto subjectType = resolvedSubject.getAsConcreteType()) { if (constraintType->isExistentialType()) { auto layout = constraintType->getExistentialLayout(); for (auto *proto : layout.getProtocols()) { // We have a pure concrete type, and there's no guarantee of dependent // type that makes sense to use here, but, in practice, all // getLookupConformanceFns used in here don't use that parameter anyway. auto dependentType = CanType(); auto conformance = getLookupConformanceFn()(dependentType, subjectType, proto->getDecl()); // FIXME: diagnose if there's no conformance. if (conformance) { // Only infer conditional requirements from explicit sources. if (!source.isDerived()) { addConditionalRequirements(conformance, inferForModule); } } } } // One cannot explicitly write a constraint on a concrete type. if (source.isExplicit()) { if (source.getLoc().isValid() && !subjectType->hasError()) { Impl->HadAnyError = true; Diags.diagnose(source.getLoc(), diag::requires_not_suitable_archetype, subjectType); } return ConstraintResult::Concrete; } return ConstraintResult::Resolved; } // Check whether we have a reasonable constraint type at all. if (!constraintType->isExistentialType() && !constraintType->getClassOrBoundGenericClass()) { if (source.getLoc().isValid() && !constraintType->hasError()) { Impl->HadAnyError = true; auto invalidConstraint = Constraint( {subject, constraintType, source.getSource(*this, resolvedSubject)}); invalidIsaConstraints.push_back(invalidConstraint); } return ConstraintResult::Conflicting; } // Protocol requirements. if (constraintType->isExistentialType()) { bool anyErrors = false; auto layout = constraintType->getExistentialLayout(); if (auto layoutConstraint = layout.getLayoutConstraint()) { if (isErrorResult(addLayoutRequirementDirect(resolvedSubject, layoutConstraint, source))) anyErrors = true; } if (auto superclass = layout.explicitSuperclass) { if (isErrorResult(addSuperclassRequirementDirect(resolvedSubject, superclass, source))) anyErrors = true; } for (auto *proto : layout.getProtocols()) { auto *protoDecl = proto->getDecl(); if (isErrorResult(addConformanceRequirement(resolvedSubject, protoDecl, source))) anyErrors = true; } return anyErrors ? ConstraintResult::Conflicting : ConstraintResult::Resolved; } // Superclass constraint. return addSuperclassRequirementDirect(resolvedSubject, constraintType, source); } void GenericSignatureBuilder::addedNestedType(PotentialArchetype *nestedPA) { // If there was already another type with this name within the parent // potential archetype, equate this type with that one. auto parentPA = nestedPA->getParent(); auto &allNested = parentPA->NestedTypes[nestedPA->getResolvedType()->getName()]; assert(!allNested.empty()); assert(allNested.back() == nestedPA); if (allNested.size() > 1) { auto firstPA = allNested.front(); auto inferredSource = FloatingRequirementSource::forNestedTypeNameMatch( nestedPA->getResolvedType()->getName()); addSameTypeRequirement(firstPA, nestedPA, inferredSource, UnresolvedHandlingKind::GenerateConstraints); return; } // If our parent type is not the representative, equate this nested // potential archetype to the equivalent nested type within the // representative. auto parentRepPA = parentPA->getRepresentative(); if (parentPA == parentRepPA) return; PotentialArchetype *existingPA = parentRepPA->getOrCreateNestedType(*this, nestedPA->getResolvedType(), ArchetypeResolutionKind::WellFormed); auto sameNamedSource = FloatingRequirementSource::forNestedTypeNameMatch( nestedPA->getResolvedType()->getName()); addSameTypeRequirement(existingPA, nestedPA, sameNamedSource, UnresolvedHandlingKind::GenerateConstraints); } ConstraintResult GenericSignatureBuilder::addSameTypeRequirementBetweenTypeParameters( ResolvedType type1, ResolvedType type2, const RequirementSource *source) { ++NumSameTypeConstraints; Type depType1 = type1.getDependentType(*this); Type depType2 = type2.getDependentType(*this); if (!source->isDerivedRequirement()) { Impl->ExplicitSameTypeRequirements.emplace_back(RequirementKind::SameType, source, depType1); } // Record the same-type constraint, and bail out if it was already known. auto equivClass = type1.getEquivalenceClassIfPresent(); auto equivClass2 = type2.getEquivalenceClassIfPresent(); if (depType1->isEqual(depType2) || ((equivClass || equivClass2) && equivClass == equivClass2)) { // Make sure we have an equivalence class in which we can record the // same-type constraint. if (!equivClass) { if (equivClass2) { equivClass = equivClass2; } else { equivClass = type1.getEquivalenceClass(*this); } } // FIXME: We could determine equivalence based on both sides canonicalizing // to the same type. equivClass->sameTypeConstraints.push_back({depType1, depType2, source}); return ConstraintResult::Resolved; } // Both sides are type parameters; equate them. // FIXME: Realizes potential archetypes far too early. auto OrigT1 = type1.getPotentialArchetypeIfKnown(); auto OrigT2 = type2.getPotentialArchetypeIfKnown(); // Operate on the representatives auto T1 = OrigT1->getRepresentative(); auto T2 = OrigT2->getRepresentative(); // Decide which potential archetype is to be considered the representative. // We prefer potential archetypes with lower nesting depths, because it // prevents us from unnecessarily building deeply nested potential archetypes. unsigned nestingDepth1 = T1->getNestingDepth(); unsigned nestingDepth2 = T2->getNestingDepth(); if (nestingDepth2 < nestingDepth1) { std::swap(T1, T2); std::swap(OrigT1, OrigT2); std::swap(equivClass, equivClass2); } // T1 must have an equivalence class; create one if we don't already have // one. if (!equivClass) equivClass = T1->getOrCreateEquivalenceClass(*this); // Record this same-type constraint. // Let's keep type order in the new constraint the same as it's written // in source, which makes it much easier to diagnose later. equivClass->sameTypeConstraints.push_back({depType1, depType2, source}); // Determine the anchor types of the two equivalence classes. CanType anchor1 = equivClass->getAnchor(*this, { })->getCanonicalType(); CanType anchor2 = (equivClass2 ? equivClass2->getAnchor(*this, { }) : getCanonicalTypeParameter(T2->getDependentType())) ->getCanonicalType(); // Merge the equivalence classes. equivClass->modified(*this); auto equivClass1Members = equivClass->members; auto equivClass2Members = T2->getEquivalenceClassMembers(); for (auto equiv : equivClass2Members) equivClass->addMember(equiv); // Grab the old equivalence class, if present. We'll deallocate it at the end. SWIFT_DEFER { if (equivClass2) Impl->deallocateEquivalenceClass(equivClass2); }; // Consider the second equivalence class to be modified. // Transfer Same-type requirements and delayed requirements. if (equivClass2) { // Mark as modified and transfer deplayed requirements to the primary queue. equivClass2->modified(*this); equivClass->sameTypeConstraints.insert( equivClass->sameTypeConstraints.end(), equivClass2->sameTypeConstraints.begin(), equivClass2->sameTypeConstraints.end()); } // Combine the rewrite rules. auto *rewriteRoot1 = Impl->getOrCreateRewriteTreeRoot(anchor1); auto *rewriteRoot2 = Impl->getOrCreateRewriteTreeRoot(anchor2); assert(rewriteRoot1 && rewriteRoot2 && "Couldn't create/retrieve rewrite tree root"); // Merge the second rewrite tree into the first. if (rewriteRoot2->mergeInto(rewriteRoot1)) ++Impl->RewriteGeneration; Impl->RewriteTreeRoots.erase(anchor2); // Add a rewrite rule to map the anchor of T2 down to the anchor of T1. if (addSameTypeRewriteRule(anchor2, anchor1)) ++Impl->RewriteGeneration; // Same-type-to-concrete requirements. bool t1IsConcrete = !equivClass->concreteType.isNull(); bool t2IsConcrete = equivClass2 && !equivClass2->concreteType.isNull(); if (t2IsConcrete) { if (t1IsConcrete) { (void)addSameTypeRequirement(equivClass->concreteType, equivClass2->concreteType, source, UnresolvedHandlingKind::GenerateConstraints, SameTypeConflictCheckedLater()); } else { equivClass->concreteType = equivClass2->concreteType; equivClass->invalidConcreteType = equivClass2->invalidConcreteType; } equivClass->concreteTypeConstraints.insert( equivClass->concreteTypeConstraints.end(), equivClass2->concreteTypeConstraints.begin(), equivClass2->concreteTypeConstraints.end()); for (const auto &conforms : equivClass->conformsTo) { bool explicitConformance = std::find_if( conforms.second.begin(), conforms.second.end(), [](const Constraint &constraint) { return !constraint.source->isDerivedRequirement(); }) != conforms.second.end(); (void)resolveConcreteConformance(T1, conforms.first, explicitConformance); } } // Make T1 the representative of T2, merging the equivalence classes. T2->representativeOrEquivClass = T1; // Layout requirements. if (equivClass2 && equivClass2->layout) { if (!equivClass->layout) { equivClass->layout = equivClass2->layout; equivClass->layoutConstraints = std::move(equivClass2->layoutConstraints); } else { updateLayout(T1, equivClass2->layout); equivClass->layoutConstraints.insert( equivClass->layoutConstraints.end(), equivClass2->layoutConstraints.begin(), equivClass2->layoutConstraints.end()); } } // Superclass requirements. if (equivClass2 && equivClass2->superclass) { const RequirementSource *source2; if (auto existingSource2 = equivClass2->findAnySuperclassConstraintAsWritten( OrigT2->getDependentType())) source2 = existingSource2->source; else source2 = equivClass2->superclassConstraints.front().source; // Add the superclass constraints from the second equivalence class. equivClass->superclassConstraints.insert( equivClass->superclassConstraints.end(), equivClass2->superclassConstraints.begin(), equivClass2->superclassConstraints.end()); (void)updateSuperclass(T1, equivClass2->superclass, source2); } // Add all of the protocol conformance requirements of T2 to T1. if (equivClass2) { for (const auto &entry : equivClass2->conformsTo) { equivClass->recordConformanceConstraint(*this, T1, entry.first, entry.second.front().source); auto &constraints1 = equivClass->conformsTo[entry.first]; // FIXME: Go through recordConformanceConstraint()? constraints1.insert(constraints1.end(), entry.second.begin() + 1, entry.second.end()); } } // Recursively merge the associated types of T2 into T1. auto dependentT1 = T1->getDependentType(getGenericParams()); SmallPtrSet visited; for (auto equivT2 : equivClass2Members) { for (auto T2Nested : equivT2->NestedTypes) { // Only visit each name once. if (!visited.insert(T2Nested.first).second) continue; // If T1 is concrete but T2 is not, concretize the nested types of T2. if (t1IsConcrete && !t2IsConcrete) { concretizeNestedTypeFromConcreteParent(T1, T2Nested.second.front(), *this); continue; } // Otherwise, make the nested types equivalent. AssociatedTypeDecl *assocTypeT2 = nullptr; for (auto T2 : T2Nested.second) { assocTypeT2 = T2->getResolvedType(); if (assocTypeT2) break; } if (!assocTypeT2) continue; Type nestedT1 = DependentMemberType::get(dependentT1, assocTypeT2); if (isErrorResult( addSameTypeRequirement( nestedT1, T2Nested.second.front(), FloatingRequirementSource::forNestedTypeNameMatch( assocTypeT2->getName()), UnresolvedHandlingKind::GenerateConstraints))) return ConstraintResult::Conflicting; } } // If T2 is concrete but T1 was not, concretize the nested types of T1. visited.clear(); if (t2IsConcrete && !t1IsConcrete) { for (auto equivT1 : equivClass1Members) { for (auto T1Nested : equivT1->NestedTypes) { // Only visit each name once. if (!visited.insert(T1Nested.first).second) continue; concretizeNestedTypeFromConcreteParent(T2, T1Nested.second.front(), *this); } } } return ConstraintResult::Resolved; } ConstraintResult GenericSignatureBuilder::addSameTypeRequirementToConcrete( ResolvedType type, Type concrete, const RequirementSource *source) { if (!source->isDerivedRequirement()) { Impl->ExplicitSameTypeRequirements.emplace_back(RequirementKind::SameType, source, concrete); } auto equivClass = type.getEquivalenceClass(*this); // Record the concrete type and its source. equivClass->concreteTypeConstraints.push_back( ConcreteConstraint{type.getUnresolvedType(), concrete, source}); equivClass->modified(*this); ++NumConcreteTypeConstraints; // If we've already been bound to a type, match that type. if (equivClass->concreteType) { return addSameTypeRequirement(equivClass->concreteType, concrete, source, UnresolvedHandlingKind::GenerateConstraints, SameTypeConflictCheckedLater()); } // Record the requirement. equivClass->concreteType = concrete; // Make sure the concrete type fulfills the conformance requirements of // this equivalence class. for (const auto &conforms : equivClass->conformsTo) { bool explicitConformance = std::find_if( conforms.second.begin(), conforms.second.end(), [](const Constraint &constraint) { return !constraint.source->isDerivedRequirement(); }) != conforms.second.end(); if (!resolveConcreteConformance(type, conforms.first, explicitConformance)) return ConstraintResult::Conflicting; } // Eagerly resolve any existing nested types to their concrete forms (others // will be "concretized" as they are constructed, in getNestedType). for (auto equivT : equivClass->members) { for (auto nested : equivT->getNestedTypes()) { concretizeNestedTypeFromConcreteParent(equivT, nested.second.front(), *this); } } return ConstraintResult::Resolved; } ConstraintResult GenericSignatureBuilder::addSameTypeRequirementBetweenConcrete( Type type1, Type type2, FloatingRequirementSource source, llvm::function_ref diagnoseMismatch) { // Local class to handle matching the two sides of the same-type constraint. class ReqTypeMatcher : public TypeMatcher { GenericSignatureBuilder &builder; FloatingRequirementSource source; Type outerType1, outerType2; llvm::function_ref diagnoseMismatch; public: ReqTypeMatcher(GenericSignatureBuilder &builder, FloatingRequirementSource source, Type outerType1, Type outerType2, llvm::function_ref diagnoseMismatch) : builder(builder), source(source), outerType1(outerType1), outerType2(outerType2), diagnoseMismatch(diagnoseMismatch) {} bool mismatch(TypeBase *firstType, TypeBase *secondType, Type sugaredFirstType) { // If the mismatch was in the first layer (i.e. what was fed to // addSameTypeRequirementBetweenConcrete), then this is a fundamental // mismatch, and we need to diagnose it. This is what breaks the mutual // recursion between addSameTypeRequirement and // addSameTypeRequirementBetweenConcrete. if (outerType1->isEqual(firstType) && outerType2->isEqual(secondType)) { diagnoseMismatch(sugaredFirstType, secondType); return false; } auto failed = builder.addSameTypeRequirement( sugaredFirstType, Type(secondType), source, UnresolvedHandlingKind::GenerateConstraints, diagnoseMismatch); return !isErrorResult(failed); } } matcher(*this, source, type1, type2, diagnoseMismatch); if (matcher.match(type1, type2)) { // Warn if neither side of the requirement contains a type parameter. if (source.isTopLevel() && source.getLoc().isValid()) { Diags.diagnose(source.getLoc(), diag::requires_no_same_type_archetype, type1, type2); } return ConstraintResult::Resolved; } return ConstraintResult::Conflicting; } ConstraintResult GenericSignatureBuilder::addSameTypeRequirement( UnresolvedType paOrT1, UnresolvedType paOrT2, FloatingRequirementSource source, UnresolvedHandlingKind unresolvedHandling) { return addSameTypeRequirement(paOrT1, paOrT2, source, unresolvedHandling, [&](Type type1, Type type2) { Impl->HadAnyError = true; if (source.getLoc().isValid() && !type1->hasError() && !type2->hasError()) { Diags.diagnose(source.getLoc(), diag::requires_same_concrete_type, type1, type2); } }); } ConstraintResult GenericSignatureBuilder::addSameTypeRequirement( UnresolvedType paOrT1, UnresolvedType paOrT2, FloatingRequirementSource source, UnresolvedHandlingKind unresolvedHandling, llvm::function_ref diagnoseMismatch) { auto resolved1 = resolve(paOrT1, source); if (!resolved1) { return handleUnresolvedRequirement(RequirementKind::SameType, paOrT1, toUnresolvedRequirementRHS(paOrT2), source, resolved1.getUnresolvedEquivClass(), unresolvedHandling); } auto resolved2 = resolve(paOrT2, source); if (!resolved2) { return handleUnresolvedRequirement(RequirementKind::SameType, paOrT1, toUnresolvedRequirementRHS(paOrT2), source, resolved2.getUnresolvedEquivClass(), unresolvedHandling); } return addSameTypeRequirementDirect(resolved1, resolved2, source, diagnoseMismatch); } ConstraintResult GenericSignatureBuilder::addSameTypeRequirementDirect( ResolvedType type1, ResolvedType type2, FloatingRequirementSource source, llvm::function_ref diagnoseMismatch) { auto concreteType1 = type1.getAsConcreteType(); auto concreteType2 = type2.getAsConcreteType(); // If both sides of the requirement are concrete, equate them. if (concreteType1 && concreteType2) { return addSameTypeRequirementBetweenConcrete(concreteType1, concreteType2, source, diagnoseMismatch); } // If one side is concrete, map the other side to that concrete type. if (concreteType1) { return addSameTypeRequirementToConcrete(type2, concreteType1, source.getSource(*this, type2)); } if (concreteType2) { return addSameTypeRequirementToConcrete(type1, concreteType2, source.getSource(*this, type1)); } return addSameTypeRequirementBetweenTypeParameters( type1, type2, source.getSource(*this, type2)); } ConstraintResult GenericSignatureBuilder::addInheritedRequirements( TypeDecl *decl, UnresolvedType type, const RequirementSource *parentSource, ModuleDecl *inferForModule) { // Local function to get the source. auto getFloatingSource = [&](const TypeRepr *typeRepr, bool forInferred) { auto loc = typeRepr ? typeRepr->getStartLoc() : SourceLoc(); if (parentSource) { ProtocolDecl *proto; if (auto assocType = dyn_cast(decl)) { proto = assocType->getProtocol(); } else { proto = cast(decl); } return FloatingRequirementSource::viaProtocolRequirement( parentSource, proto, loc, forInferred); } // We are inferring requirements. if (forInferred) { return FloatingRequirementSource::forInferred(loc); } // Explicit requirement. return FloatingRequirementSource::forExplicit(loc); }; auto visitType = [&](Type inheritedType, const TypeRepr *typeRepr) { if (inferForModule) { inferRequirements(*inferForModule, inheritedType, getFloatingSource(typeRepr, /*forInferred=*/true)); } return addTypeRequirement( type, inheritedType, getFloatingSource(typeRepr, /*forInferred=*/false), UnresolvedHandlingKind::GenerateConstraints, inferForModule); }; return visitInherited(decl, visitType); } ConstraintResult GenericSignatureBuilder::addRequirement(const Requirement &req, FloatingRequirementSource source, ModuleDecl *inferForModule) { return addRequirement(req, nullptr, source, nullptr, inferForModule); } ConstraintResult GenericSignatureBuilder::addRequirement(const Requirement &req, const RequirementRepr *reqRepr, FloatingRequirementSource source, const SubstitutionMap *subMap, ModuleDecl *inferForModule) { // Local substitution for types in the requirement. auto subst = [&](Type t) { if (subMap) return t.subst(*subMap); return t; }; auto firstType = subst(req.getFirstType()); switch (req.getKind()) { case RequirementKind::Superclass: case RequirementKind::Conformance: { auto secondType = subst(req.getSecondType()); if (inferForModule) { inferRequirements(*inferForModule, firstType, source.asInferred( RequirementRepr::getFirstTypeRepr(reqRepr))); inferRequirements(*inferForModule, secondType, source.asInferred( RequirementRepr::getSecondTypeRepr(reqRepr))); } return addTypeRequirement(firstType, secondType, source, UnresolvedHandlingKind::GenerateConstraints, inferForModule); } case RequirementKind::Layout: { if (inferForModule) { inferRequirements(*inferForModule, firstType, source.asInferred( RequirementRepr::getFirstTypeRepr(reqRepr))); } return addLayoutRequirement(firstType, req.getLayoutConstraint(), source, UnresolvedHandlingKind::GenerateConstraints); } case RequirementKind::SameType: { auto secondType = subst(req.getSecondType()); if (inferForModule) { inferRequirements(*inferForModule, firstType, source.asInferred( RequirementRepr::getFirstTypeRepr(reqRepr))); inferRequirements(*inferForModule, secondType, source.asInferred( RequirementRepr::getSecondTypeRepr(reqRepr))); } return addSameTypeRequirement( firstType, secondType, source, UnresolvedHandlingKind::GenerateConstraints, [&](Type type1, Type type2) { Impl->HadAnyError = true; if (source.getLoc().isValid() && !type1->hasError() && !type2->hasError()) { Diags.diagnose(source.getLoc(), diag::requires_same_concrete_type, type1, type2); } }); } } llvm_unreachable("Unhandled requirement?"); } /// AST walker that infers requirements from type representations. class GenericSignatureBuilder::InferRequirementsWalker : public TypeWalker { ModuleDecl &module; GenericSignatureBuilder &Builder; FloatingRequirementSource source; public: InferRequirementsWalker(ModuleDecl &module, GenericSignatureBuilder &builder, FloatingRequirementSource source) : module(module), Builder(builder), source(source) { } Action walkToTypePre(Type ty) override { // Unbound generic types are the result of recovered-but-invalid code, and // don't have enough info to do any useful substitutions. if (ty->is()) return Action::Stop; return Action::Continue; } Action walkToTypePost(Type ty) override { // Infer from generic typealiases. if (auto TypeAlias = dyn_cast(ty.getPointer())) { auto decl = TypeAlias->getDecl(); auto subMap = TypeAlias->getSubstitutionMap(); for (const auto &rawReq : decl->getGenericSignature().getRequirements()) { if (auto req = rawReq.subst(subMap)) Builder.addRequirement(*req, source, nullptr); } return Action::Continue; } // Infer requirements from `@differentiable` function types. // For all non-`@noDerivative` parameter and result types: // - `@differentiable`, `@differentiable(_forward)`, or // `@differentiable(reverse)`: add `T: Differentiable` requirement. // - `@differentiable(_linear)`: add // `T: Differentiable`, `T == T.TangentVector` requirements. if (auto *fnTy = ty->getAs()) { auto &ctx = Builder.getASTContext(); auto *differentiableProtocol = ctx.getProtocol(KnownProtocolKind::Differentiable); if (differentiableProtocol && fnTy->isDifferentiable()) { auto addConformanceConstraint = [&](Type type, ProtocolDecl *protocol) { Requirement req(RequirementKind::Conformance, type, protocol->getDeclaredInterfaceType()); Builder.addRequirement(req, source, nullptr); }; auto addSameTypeConstraint = [&](Type firstType, AssociatedTypeDecl *assocType) { auto *protocol = assocType->getProtocol(); auto conf = Builder.lookupConformance(firstType, protocol); auto secondType = conf.getAssociatedType( firstType, assocType->getDeclaredInterfaceType()); Requirement req(RequirementKind::SameType, firstType, secondType); Builder.addRequirement(req, source, nullptr); }; auto *tangentVectorAssocType = differentiableProtocol->getAssociatedType(ctx.Id_TangentVector); auto addRequirements = [&](Type type, bool isLinear) { addConformanceConstraint(type, differentiableProtocol); if (isLinear) addSameTypeConstraint(type, tangentVectorAssocType); }; auto constrainParametersAndResult = [&](bool isLinear) { for (auto ¶m : fnTy->getParams()) if (!param.isNoDerivative()) addRequirements(param.getPlainType(), isLinear); addRequirements(fnTy->getResult(), isLinear); }; // Add requirements. constrainParametersAndResult(fnTy->getDifferentiabilityKind() == DifferentiabilityKind::Linear); } } if (!ty->isSpecialized()) return Action::Continue; // Infer from generic nominal types. auto decl = ty->getAnyNominal(); if (!decl) return Action::Continue; // FIXME: The GSB and the request evaluator both detect a cycle here if we // force a recursive generic signature. We should look into moving cycle // detection into the generic signature request(s) - see rdar://55263708 if (!decl->hasComputedGenericSignature()) return Action::Continue; auto genericSig = decl->getGenericSignature(); if (!genericSig) return Action::Continue; /// Retrieve the substitution. auto subMap = ty->getContextSubstitutionMap(&module, decl); // Handle the requirements. // FIXME: Inaccurate TypeReprs. for (const auto &rawReq : genericSig.getRequirements()) { if (auto req = rawReq.subst(subMap)) Builder.addRequirement(*req, source, nullptr); } return Action::Continue; } }; void GenericSignatureBuilder::inferRequirements( ModuleDecl &module, Type type, FloatingRequirementSource source) { if (!type) return; // FIXME: Crummy source-location information. InferRequirementsWalker walker(module, *this, source); type.walk(walker); } void GenericSignatureBuilder::inferRequirements( ModuleDecl &module, ParameterList *params) { for (auto P : *params) { inferRequirements(module, P->getInterfaceType(), FloatingRequirementSource::forInferred( P->getTypeRepr()->getStartLoc())); } } namespace swift { template bool operator<(const Constraint &lhs, const Constraint &rhs) { // FIXME: Awful. auto lhsSource = lhs.getSubjectDependentType({ }); auto rhsSource = rhs.getSubjectDependentType({ }); if (int result = compareDependentTypes(lhsSource, rhsSource)) return result < 0; if (int result = lhs.source->compare(rhs.source)) return result < 0; return false; } template bool operator==(const Constraint &lhs, const Constraint &rhs){ return lhs.hasSameSubjectAs(rhs) && lhs.value == rhs.value && lhs.source == rhs.source; } template<> bool operator==(const Constraint &lhs, const Constraint &rhs){ return lhs.hasSameSubjectAs(rhs) && lhs.value->isEqual(rhs.value) && lhs.source == rhs.source; } } // namespace swift namespace { /// Retrieve the representative constraint that will be used for diagnostics. template Optional> findRepresentativeConstraint( GenericSignatureBuilder &builder, ArrayRef> constraints, RequirementKind kind, llvm::function_ref &)> isSuitableRepresentative) { Optional> fallbackConstraint; // Find a representative constraint. Optional> representativeConstraint; for (const auto &constraint : constraints) { // Make sure we have a constraint to fall back on. if (!fallbackConstraint) fallbackConstraint = constraint; // If this isn't a suitable representative constraint, ignore it. if (!isSuitableRepresentative(constraint)) continue; // Check whether this constraint is better than the best we've seen so far // at being the representative constraint against which others will be // compared. if (!representativeConstraint) { representativeConstraint = constraint; continue; } if (kind != RequirementKind::SameType) { // We prefer non-redundant explicit constraints over everything else. bool thisIsNonRedundantExplicit = (!constraint.source->isDerivedNonRootRequirement() && !builder.isRedundantExplicitRequirement( ExplicitRequirement( kind, constraint.source, constraint.value))); bool representativeIsNonRedundantExplicit = (!representativeConstraint->source->isDerivedNonRootRequirement() && !builder.isRedundantExplicitRequirement( ExplicitRequirement( kind, representativeConstraint->source, representativeConstraint->value))); if (thisIsNonRedundantExplicit != representativeIsNonRedundantExplicit) { if (thisIsNonRedundantExplicit) representativeConstraint = constraint; continue; } } // We prefer derived constraints to non-derived constraints. bool thisIsDerived = constraint.source->isDerivedRequirement(); bool representativeIsDerived = representativeConstraint->source->isDerivedRequirement(); if (thisIsDerived != representativeIsDerived) { if (thisIsDerived) representativeConstraint = constraint; continue; } // We prefer constraints that are explicit to inferred constraints. bool thisIsInferred = constraint.source->isInferredRequirement(); bool representativeIsInferred = representativeConstraint->source->isInferredRequirement(); if (thisIsInferred != representativeIsInferred) { if (thisIsInferred) representativeConstraint = constraint; continue; } // We prefer constraints with locations to constraints without locations. bool thisHasValidSourceLoc = constraint.source->getLoc().isValid(); bool representativeHasValidSourceLoc = representativeConstraint->source->getLoc().isValid(); if (thisHasValidSourceLoc != representativeHasValidSourceLoc) { if (thisHasValidSourceLoc) representativeConstraint = constraint; continue; } // Otherwise, order via the constraint itself. if (constraint < *representativeConstraint) representativeConstraint = constraint; } return representativeConstraint ? representativeConstraint : fallbackConstraint; } } // end anonymous namespace /// For each potential archetype within the given equivalence class that is /// an associated type, expand the protocol requirements for the enclosing /// protocol. static void expandSameTypeConstraints(GenericSignatureBuilder &builder, EquivalenceClass *equivClass) { auto genericParams = builder.getGenericParams(); auto existingMembers = equivClass->members; for (auto pa : existingMembers) { auto dependentType = pa->getDependentType(genericParams); for (const auto &conforms : equivClass->conformsTo) { auto proto = conforms.first; // Check whether we already have a conformance constraint for this // potential archetype. bool alreadyFound = false; const RequirementSource *conformsSource = nullptr; for (const auto &constraint : conforms.second) { auto *minimal = constraint.source->getMinimalConformanceSource( builder, constraint.getSubjectDependentType({ }), proto); if (minimal == nullptr) continue; if (minimal->getAffectedType()->isEqual(dependentType)) { alreadyFound = true; break; } // Capture the source for later use, skipping if (!conformsSource && minimal->kind != RequirementSource::RequirementSignatureSelf) conformsSource = minimal; } if (alreadyFound) continue; if (!conformsSource) continue; // Pick a source at random and reseat it on this potential archetype. auto source = conformsSource->viaEquivalentType(builder, dependentType); // Expand same-type constraints. builder.expandConformanceRequirement(pa, proto, source, /*onlySameTypeConstraints=*/true); } } } void GenericSignatureBuilder::ExplicitRequirement::dump( llvm::raw_ostream &out, SourceManager *SM) const { switch (getKind()) { case RequirementKind::Conformance: out << "conforms_to: "; break; case RequirementKind::Layout: out << "layout: "; break; case RequirementKind::Superclass: out << "superclass: "; break; case RequirementKind::SameType: out << "same_type: "; break; } out << getSubjectType(); if (getKind() == RequirementKind::SameType) out << " == "; else out << " : "; if (auto type = rhs.dyn_cast()) out << type; else if (auto *proto = rhs.dyn_cast()) out << proto->getName(); else out << rhs.get(); out << "(source: "; getSource()->dump(out, SM, 0); out << ")"; } static bool typeImpliesLayoutConstraint(Type t, LayoutConstraint layout) { if (layout->isRefCounted() && t->satisfiesClassConstraint()) return true; return false; } static bool typeConflictsWithLayoutConstraint(Type t, LayoutConstraint layout) { if (layout->isClass() && !t->satisfiesClassConstraint()) return true; return false; } static bool isConcreteConformance(const EquivalenceClass &equivClass, ProtocolDecl *proto, GenericSignatureBuilder &builder) { if (equivClass.concreteType && builder.lookupConformance(equivClass.concreteType, proto)) { return true; } else if (equivClass.superclass && builder.lookupConformance(equivClass.superclass, proto)) { return true; } return false; } void GenericSignatureBuilder::getBaseRequirements( GenericSignatureBuilder::GetKindAndRHS getKindAndRHS, const RequirementSource *source, const ProtocolDecl *requirementSignatureSelfProto, SmallVectorImpl &result) { // If we're building a generic signature, the base requirement is // built from the root of the path. if (source->parent == nullptr) { RequirementKind kind; RequirementRHS rhs; std::tie(kind, rhs) = getKindAndRHS(); result.push_back(ExplicitRequirement(kind, source, rhs)); return; } // If we're building a requirement signature, there can be multiple // base requirements from the same protocol appearing along the path. if (requirementSignatureSelfProto != nullptr && source->isProtocolRequirement() && source->getProtocolDecl() == requirementSignatureSelfProto) { auto *shortSource = source->withoutRedundantSubpath( *this, source->getRoot(), source->parent); RequirementKind kind; RequirementRHS rhs; std::tie(kind, rhs) = getKindAndRHS(); result.push_back(ExplicitRequirement(kind, shortSource, rhs)); } getBaseRequirements( [&]() { return ExplicitRequirement::getKindAndRHS(source, Context); }, source->parent, requirementSignatureSelfProto, result); } Optional GenericSignatureBuilder::isValidRequirementDerivationPath( llvm::SmallDenseSet &visited, RequirementKind otherKind, const RequirementSource *otherSource, RequirementRHS otherRHS, const ProtocolDecl *requirementSignatureSelfProto) { if (auto *Stats = Context.Stats) ++Stats->getFrontendCounters().NumRedundantRequirementSteps; SmallVector result; getBaseRequirements( [&]() { return std::make_pair(otherKind, otherRHS); }, otherSource, requirementSignatureSelfProto, result); assert(result.size() > 0); for (const auto &otherReq : result) { // Don't consider paths that are based on the requirement // itself; such a path doesn't "prove" this requirement, // since if we drop the requirement the path is no longer // valid. if (visited.count(otherReq)) return None; SWIFT_DEFER { visited.erase(otherReq); }; visited.insert(otherReq); auto otherSubjectType = otherReq.getSubjectType(); auto *equivClass = resolveEquivalenceClass(otherSubjectType, ArchetypeResolutionKind::AlreadyKnown); assert(equivClass && "Explicit requirement names an unknown equivalence class?"); // If our requirement is based on a path involving some other // redundant requirement, see if we can derive the redundant // requirement using requirements we haven't visited yet. // If not, we go ahead and drop it from consideration. // // We need to do this because sometimes, we don't record all possible // requirement sources that derive a given requirement. // // For example, when a nested type of a type parameter is concretized by // adding a superclass requirement, we only record the requirement source // for the concrete conformance the first time. A subsequently-added // superclass requirement on the same parent type does not record a // redundant concrete conformance for the child type. if (isRedundantExplicitRequirement(otherReq)) { // If we have a redundant explicit requirement source, it really is // redundant; there's no other derivation that would not be redundant. if (!otherSource->isDerivedNonRootRequirement()) return None; switch (otherReq.getKind()) { case RequirementKind::Conformance: { auto *proto = otherReq.getRHS().get(); auto found = equivClass->conformsTo.find(proto); assert(found != equivClass->conformsTo.end()); bool foundValidDerivation = false; for (const auto &constraint : found->second) { if (isValidRequirementDerivationPath( visited, otherReq.getKind(), constraint.source, proto, requirementSignatureSelfProto)) { foundValidDerivation = true; break; } } if (!foundValidDerivation) return None; break; } case RequirementKind::Superclass: { auto superclass = getCanonicalTypeInContext( otherReq.getRHS().get(), { }); for (const auto &constraint : equivClass->superclassConstraints) { auto otherSuperclass = getCanonicalTypeInContext( constraint.value, { }); if (superclass->isExactSuperclassOf(otherSuperclass)) { bool foundValidDerivation = false; if (isValidRequirementDerivationPath( visited, otherReq.getKind(), constraint.source, otherSuperclass, requirementSignatureSelfProto)) { foundValidDerivation = true; break; } if (!foundValidDerivation) return None; } } break; } case RequirementKind::Layout: { auto layout = otherReq.getRHS().get(); for (const auto &constraint : equivClass->layoutConstraints) { auto otherLayout = constraint.value; if (layout == otherLayout) { bool foundValidDerivation = false; if (isValidRequirementDerivationPath( visited, otherReq.getKind(), constraint.source, otherLayout, requirementSignatureSelfProto)) { foundValidDerivation = true; break; } if (!foundValidDerivation) return None; } } break; } case RequirementKind::SameType: llvm_unreachable("Should not see same type requirements here"); } } auto anchor = equivClass->getAnchor(*this, { }); if (auto *depMemType = anchor->getAs()) { // If 'req' is based on some other conformance requirement // `T.[P.]A : Q', we want to make sure that we have a // non-redundant derivation for 'T : P'. auto baseType = depMemType->getBase(); auto *proto = depMemType->getAssocType()->getProtocol(); auto *baseEquivClass = resolveEquivalenceClass(baseType, ArchetypeResolutionKind::AlreadyKnown); assert(baseEquivClass && "Explicit requirement names an unknown equivalence class?"); auto found = baseEquivClass->conformsTo.find(proto); assert(found != baseEquivClass->conformsTo.end()); bool foundValidDerivation = false; for (const auto &constraint : found->second) { if (isValidRequirementDerivationPath( visited, RequirementKind::Conformance, constraint.source, proto, requirementSignatureSelfProto)) { foundValidDerivation = true; break; } } if (!foundValidDerivation) return None; } } return result.front(); } template void GenericSignatureBuilder::checkIfRequirementCanBeDerived( const ExplicitRequirement &req, const std::vector> &constraints, const ProtocolDecl *requirementSignatureSelfProto, Filter filter) { assert(!constraints.empty()); for (const auto &constraint : constraints) { if (filter(constraint)) continue; // If this requirement can be derived from a set of // non-redundant base requirements, then this requirement // is redundant. llvm::SmallDenseSet visited; visited.insert(req); if (auto representative = isValidRequirementDerivationPath( visited, req.getKind(), constraint.source, constraint.value, requirementSignatureSelfProto)) { Impl->RedundantRequirements[req].insert(*representative); } } } static bool involvesNonSelfSubjectTypes(const RequirementSource *source) { while (source->kind != RequirementSource::RequirementSignatureSelf) { if (source->isProtocolRequirement() && !source->getStoredType()->is()) return true; source = source->parent; } return false; } void GenericSignatureBuilder::computeRedundantRequirements( const ProtocolDecl *requirementSignatureSelfProto) { assert(!Impl->computedRedundantRequirements && "Already computed redundant requirements"); #ifndef NDEBUG Impl->computedRedundantRequirements = true; #endif FrontendStatsTracer tracer(Context.Stats, "compute-redundant-requirements"); // This sort preserves iteration order with the legacy algorithm. SmallVector requirements( Impl->ExplicitRequirements.begin(), Impl->ExplicitRequirements.end()); std::stable_sort(requirements.begin(), requirements.end(), [](const ExplicitRequirement &req1, const ExplicitRequirement &req2) { if (req1.getSource()->isInferredRequirement() && !req2.getSource()->isInferredRequirement()) return true; if (compareDependentTypes(req1.getSubjectType(), req2.getSubjectType()) > 0) return true; return false; }); for (const auto &req : requirements) { auto subjectType = req.getSubjectType(); auto *equivClass = resolveEquivalenceClass(subjectType, ArchetypeResolutionKind::AlreadyKnown); assert(equivClass && "Explicit requirement names an unknown equivalence class?"); Type resolvedConcreteType; if (equivClass->concreteType) { resolvedConcreteType = getCanonicalTypeInContext(equivClass->concreteType, getGenericParams()); } Type resolvedSuperclass; if (equivClass->superclass) { resolvedSuperclass = getCanonicalTypeInContext(equivClass->superclass, getGenericParams()); } switch (req.getKind()) { case RequirementKind::Conformance: { // TODO: conflicts with concrete auto *proto = req.getRHS().get(); auto found = equivClass->conformsTo.find(proto); assert(found != equivClass->conformsTo.end()); // If this is a conformance requirement on 'Self', only consider it // redundant if it can be derived from other sources involving 'Self'. // // What this means in practice is that we will never try to build // a witness table for an inherited conformance from an associated // conformance. // // This is important since witness tables for inherited conformances // are realized eagerly before the witness table for the original // conformance, and allowing more complex requirement sources for // inherited conformances could introduce cycles at runtime. bool isProtocolRefinement = (requirementSignatureSelfProto && equivClass->getAnchor(*this, { })->is()); checkIfRequirementCanBeDerived( req, found->second, requirementSignatureSelfProto, [&](const Constraint &constraint) { if (isProtocolRefinement) return involvesNonSelfSubjectTypes(constraint.source); return false; }); if (isConcreteConformance(*equivClass, proto, *this)) Impl->ExplicitConformancesImpliedByConcrete.insert(req); break; } case RequirementKind::Superclass: { auto superclass = getCanonicalTypeInContext( req.getRHS().get(), { }); if (!superclass->isExactSuperclassOf(resolvedSuperclass)) { // Case 1. We have a requirement 'T : C', and we've // previously resolved the superclass of 'T' to some // class 'D' where 'C' is not a superclass of 'D'. // // This means 'T : C' conflicts with some other // requirement that implies 'T : D'. Impl->ConflictingRequirements[req] = resolvedSuperclass; checkIfRequirementCanBeDerived( req, equivClass->superclassConstraints, requirementSignatureSelfProto, [&](const Constraint &constraint) { auto otherSuperclass = getCanonicalTypeInContext( constraint.value, { }); // Filter out requirements where the superclass // is not equal to the resolved superclass. if (!resolvedSuperclass->isEqual(otherSuperclass)) return true; return false; }); } else { // Case 2. We have a requirement 'T : C', and we've // previously resolved the superclass of 'T' to some // class 'D' where 'C' is a superclass of 'D'. // // This means that 'T : C' is made redundant by any // requirement that implies 'T : B', such that 'C' is a // superclass of 'B'. checkIfRequirementCanBeDerived( req, equivClass->superclassConstraints, requirementSignatureSelfProto, [&](const Constraint &constraint) { auto otherSuperclass = getCanonicalTypeInContext( constraint.value, { }); // Filter out requirements where the superclass is less // specific than the original requirement. if (!superclass->isExactSuperclassOf(otherSuperclass)) return true; return false; }); if (resolvedConcreteType) { // We have a superclass requirement 'T : C' and a same-type // requirement 'T == D'. if (resolvedSuperclass->isExactSuperclassOf(resolvedConcreteType)) { // 'C' is a superclass of 'D', so 'T : C' is redundant. checkIfRequirementCanBeDerived( req, equivClass->concreteTypeConstraints, requirementSignatureSelfProto, [&](const Constraint &constraint) { auto otherType = getCanonicalTypeInContext( constraint.value, { }); if (!resolvedSuperclass->isExactSuperclassOf(otherType)) return true; return false; }); } else { // 'C' is not a superclass of 'D'; we have a conflict. Impl->ConflictingConcreteTypeRequirements.push_back( {req, resolvedConcreteType, resolvedSuperclass}); } } } break; } case RequirementKind::Layout: { // TODO: less-specific constraints // TODO: conflicts with other layout constraints // TODO: conflicts with concrete and superclass auto layout = req.getRHS().get(); if (!layout.merge(equivClass->layout)->isKnownLayout()) { // Case 1. We have a requirement 'T : L1', and we've // previously resolved the layout of 'T' to some // layout constraint 'L2', where 'L1' and 'L2' are not // mergeable. // // This means that 'T : L1' conflicts with some other // requirement that implies 'T : L2'. Impl->ConflictingRequirements[req] = equivClass->layout; checkIfRequirementCanBeDerived( req, equivClass->layoutConstraints, requirementSignatureSelfProto, [&](const Constraint &constraint) { auto otherLayout = constraint.value; // Filter out requirements where the layout is not // equal to the resolved layout. if (equivClass->layout != otherLayout) return true; return false; }); } else if (layout == equivClass->layout) { // Case 2. We have a requirement 'T : L1', and we know // the most specific resolved layout for 'T' is also 'L1'. // // This means that 'T : L1' is made redundant by any // requirement that implies 'T : L1'. checkIfRequirementCanBeDerived( req, equivClass->layoutConstraints, requirementSignatureSelfProto, [&](const Constraint &constraint) { // Filter out requirements where the implied layout is // not equal to the resolved layout. auto otherLayout = constraint.value; if (layout != otherLayout) return true; return false; }); if (resolvedConcreteType) { auto layout = req.getRHS().get(); if (typeImpliesLayoutConstraint(resolvedConcreteType, layout)) { Impl->ExplicitConformancesImpliedByConcrete.insert(req); checkIfRequirementCanBeDerived( req, equivClass->concreteTypeConstraints, requirementSignatureSelfProto, [&](const Constraint &constraint) { // Filter out requirements where the concrete type // does not have the resolved layout. auto otherType = getCanonicalTypeInContext( constraint.value, { }); if (!typeImpliesLayoutConstraint(otherType, layout)) return true; return false; }); } else if (typeConflictsWithLayoutConstraint(resolvedConcreteType, layout)) { // We have a concrete type requirement 'T == C' and 'C' does // not satisfy 'L1'. Impl->ConflictingConcreteTypeRequirements.push_back( {req, resolvedConcreteType, equivClass->layout}); } } } else { // Case 3. We have a requirement 'T : L1', and we know // the most specific resolved layout for 'T' is some other // layout 'L2', such that 'L2' is mergeable with 'L1'. // // This means that 'T : L1' is made redundant by any // requirement that implies 'T : L3', where L3 is // mergeable with L1. checkIfRequirementCanBeDerived( req, equivClass->layoutConstraints, requirementSignatureSelfProto, [&](const Constraint &constraint) { auto otherLayout = constraint.value; // Filter out requirements where the implied layout // is not mergeable with the original requirement's // layout. if (!layout.merge(otherLayout)->isKnownLayout()) return true; return false; }); if (resolvedConcreteType) { auto layout = req.getRHS().get(); if (typeImpliesLayoutConstraint(resolvedConcreteType, layout)) { Impl->ExplicitConformancesImpliedByConcrete.insert(req); checkIfRequirementCanBeDerived( req, equivClass->concreteTypeConstraints, requirementSignatureSelfProto, [&](const Constraint &constraint) { // Filter out requirements where the concrete type // does not have the resolved layout. auto otherType = getCanonicalTypeInContext( constraint.value, { }); if (!typeImpliesLayoutConstraint(otherType, equivClass->layout)) return true; return false; }); } } } break; } case RequirementKind::SameType: llvm_unreachable("Should not see same type requirements here"); } } } void GenericSignatureBuilder::finalize(TypeArrayView genericParams, bool allowConcreteGenericParams, const ProtocolDecl *requirementSignatureSelfProto) { diagnoseProtocolRefinement(requirementSignatureSelfProto); diagnoseRedundantRequirements(); diagnoseConflictingConcreteTypeRequirements(requirementSignatureSelfProto); { // In various places below, we iterate over the list of equivalence classes // and call getMinimalConformanceSource(). Unfortunately, this function // ends up calling maybeResolveEquivalenceClass(), which can delete equivalence // classes. The workaround is to first iterate safely over a copy of the list, // and pre-compute all minimal conformance sources, before proceeding with the // rest of the function. // // FIXME: This is not even correct, because we may not have reached fixed point // after one round of this. getMinimalConformanceSource() should be removed // instead. SmallVector equivalenceClassPAs; for (auto &equivClass : Impl->EquivalenceClasses) { equivalenceClassPAs.push_back(equivClass.members.front()); } for (auto *pa : equivalenceClassPAs) { auto &equivClass = *pa->getOrCreateEquivalenceClass(*this); // Copy the vector and iterate over the copy to avoid iterator invalidation // issues. auto conformsTo = equivClass.conformsTo; for (auto entry : conformsTo) { for (const auto &constraint : entry.second) { (void) constraint.source->getMinimalConformanceSource( *this, constraint.getSubjectDependentType({ }), entry.first); } } } } assert(!Impl->finalized && "Already finalized builder"); #ifndef NDEBUG Impl->finalized = true; #endif // Local function (+ cache) describing the set of equivalence classes // directly referenced by the concrete same-type constraint of the given // equivalence class. llvm::DenseMap> concreteEquivClasses; auto getConcreteReferencedEquivClasses = [&](EquivalenceClass *equivClass) -> SmallPtrSet { auto known = concreteEquivClasses.find(equivClass); if (known != concreteEquivClasses.end()) return known->second; SmallPtrSet referencedEquivClasses; if (!equivClass->concreteType || !equivClass->concreteType->hasTypeParameter()) return referencedEquivClasses; equivClass->concreteType.visit([&](Type type) { if (type->isTypeParameter()) { if (auto referencedEquivClass = resolveEquivalenceClass(type, ArchetypeResolutionKind::AlreadyKnown)) { referencedEquivClasses.insert(referencedEquivClass); } } }); concreteEquivClasses[equivClass] = referencedEquivClasses; return referencedEquivClasses; }; /// Check whether the given type references the archetype. auto isRecursiveConcreteType = [&](EquivalenceClass *equivClass, bool isSuperclass) { SmallPtrSet visited; SmallVector stack; stack.push_back(equivClass); visited.insert(equivClass); // Check whether the specific type introduces recursion. auto checkTypeRecursion = [&](Type type) { if (!type->hasTypeParameter()) return false; return type.findIf([&](Type type) { if (type->isTypeParameter()) { if (auto referencedEquivClass = resolveEquivalenceClass( type, ArchetypeResolutionKind::AlreadyKnown)) { if (referencedEquivClass == equivClass) return true; if (visited.insert(referencedEquivClass).second) stack.push_back(referencedEquivClass); } } return false; }); }; while (!stack.empty()) { auto currentEquivClass = stack.back(); stack.pop_back(); // If we're checking superclasses, do so now. if (isSuperclass && currentEquivClass->superclass && checkTypeRecursion(currentEquivClass->superclass)) { return true; } // Otherwise, look for the equivalence classes referenced by // same-type constraints. for (auto referencedEquivClass : getConcreteReferencedEquivClasses(currentEquivClass)) { // If we found a reference to the original archetype, it's recursive. if (referencedEquivClass == equivClass) return true; if (visited.insert(referencedEquivClass).second) stack.push_back(referencedEquivClass); } } return false; }; // Check for recursive or conflicting same-type bindings and superclass // constraints. for (auto &equivClass : Impl->EquivalenceClasses) { if (equivClass.concreteType) { // Check for recursive same-type bindings. if (isRecursiveConcreteType(&equivClass, /*isSuperclass=*/false)) { if (auto constraint = equivClass.findAnyConcreteConstraintAsWritten()) { Impl->HadAnyError = true; Diags.diagnose(constraint->source->getLoc(), diag::recursive_same_type_constraint, constraint->getSubjectDependentType(genericParams), constraint->value); } equivClass.recursiveConcreteType = true; } else { checkConcreteTypeConstraints(genericParams, &equivClass); } } // Check for recursive superclass bindings. if (equivClass.superclass) { if (isRecursiveConcreteType(&equivClass, /*isSuperclass=*/true)) { if (auto source = equivClass.findAnySuperclassConstraintAsWritten()) { Impl->HadAnyError = true; Diags.diagnose(source->source->getLoc(), diag::recursive_superclass_constraint, source->getSubjectDependentType(genericParams), equivClass.superclass); } equivClass.recursiveSuperclassType = true; } } } if (!Impl->ExplicitSameTypeRequirements.empty()) { // FIXME: Expand all conformance requirements. This is expensive :( for (auto &equivClass : Impl->EquivalenceClasses) { expandSameTypeConstraints(*this, &equivClass); } // Check same-type constraints. for (auto &equivClass : Impl->EquivalenceClasses) { checkSameTypeConstraints(genericParams, &equivClass); } } // Check for generic parameters which have been made concrete or equated // with each other. if (!allowConcreteGenericParams) { SmallPtrSet visited; unsigned depth = 0; for (const auto gp : getGenericParams()) depth = std::max(depth, gp->getDepth()); for (const auto &pa : Impl->PotentialArchetypes) { auto rep = pa->getRepresentative(); if (pa->getDependentType()->getRootGenericParam()->getDepth() < depth) continue; if (!visited.insert(rep).second) continue; // Don't allow a generic parameter to be equivalent to a concrete type, // because then we don't actually have a parameter. auto equivClass = rep->getOrCreateEquivalenceClass(*this); if (equivClass->concreteType && !equivClass->concreteType->is()) { if (auto constraint = equivClass->findAnyConcreteConstraintAsWritten()){ Impl->HadAnyError = true; Diags.diagnose(constraint->source->getLoc(), diag::requires_generic_param_made_equal_to_concrete, rep->getDependentType(genericParams)); } continue; } // Don't allow two generic parameters to be equivalent, because then we // don't actually have two parameters. for (auto other : rep->getEquivalenceClassMembers()) { // If it isn't a generic parameter, skip it. if (other == pa || !other->isGenericParam()) continue; // Try to find an exact constraint that matches 'other'. auto repConstraint = findRepresentativeConstraint( *this, equivClass->sameTypeConstraints, RequirementKind::SameType, [pa, other](const Constraint &constraint) { return (constraint.isSubjectEqualTo(pa) && constraint.value->isEqual(other->getDependentType())) || (constraint.isSubjectEqualTo(other) && constraint.value->isEqual(pa->getDependentType())); }); // Otherwise, just take any old constraint. if (!repConstraint) { repConstraint = findRepresentativeConstraint( *this, equivClass->sameTypeConstraints, RequirementKind::SameType, [](const Constraint &constraint) { return true; }); } if (repConstraint && repConstraint->source->getLoc().isValid()) { Impl->HadAnyError = true; Diags.diagnose(repConstraint->source->getLoc(), diag::requires_generic_params_made_equal, pa->getDependentType(genericParams), other->getDependentType(genericParams)); } break; } } } // Emit a diagnostic if we recorded any constraints where the constraint // type was not constrained to a protocol or class. Provide a fix-it if // allowConcreteGenericParams is true or the subject type is a member type. if (!invalidIsaConstraints.empty()) { for (auto constraint : invalidIsaConstraints) { auto subjectType = constraint.getSubjectDependentType(getGenericParams()); auto constraintType = constraint.value; auto source = constraint.source; auto loc = source->getLoc(); Diags.diagnose(loc, diag::requires_conformance_nonprotocol, subjectType, constraintType); auto getNameWithoutSelf = [&](std::string subjectTypeName) { std::string selfSubstring = "Self."; if (subjectTypeName.rfind(selfSubstring, 0) == 0) { return subjectTypeName.erase(0, selfSubstring.length()); } return subjectTypeName; }; if (allowConcreteGenericParams || (subjectType->is() && !source->isProtocolRequirement())) { auto subjectTypeName = subjectType.getString(); auto subjectTypeNameWithoutSelf = getNameWithoutSelf(subjectTypeName); Diags.diagnose(loc, diag::requires_conformance_nonprotocol_fixit, subjectTypeNameWithoutSelf, constraintType.getString()) .fixItReplace(loc, " == "); } } invalidIsaConstraints.clear(); } } /// Turn a requirement right-hand side into an unresolved type. static GenericSignatureBuilder::UnresolvedType asUnresolvedType( GenericSignatureBuilder::UnresolvedRequirementRHS rhs) { if (auto pa = rhs.dyn_cast()) return GenericSignatureBuilder::UnresolvedType(pa); return GenericSignatureBuilder::UnresolvedType(rhs.get()); } void GenericSignatureBuilder::processDelayedRequirements() { // If we're already up-to-date, do nothing. if (Impl->Generation == Impl->LastProcessedGeneration) { return; } // If there are no delayed requirements, do nothing. if (Impl->DelayedRequirements.empty()) { return; } if (Impl->ProcessingDelayedRequirements) { return; } ++NumProcessDelayedRequirements; llvm::SaveAndRestore processing(Impl->ProcessingDelayedRequirements, true); bool anyChanges = false; SWIFT_DEFER { Impl->LastProcessedGeneration = Impl->Generation; if (!anyChanges) ++NumProcessDelayedRequirementsUnchanged; }; bool anySolved; do { // Steal the delayed requirements so we can reprocess them. anySolved = false; auto delayed = std::move(Impl->DelayedRequirements); Impl->DelayedRequirements.clear(); // Process delayed requirements. for (const auto &req : delayed) { // Reprocess the delayed requirement. ConstraintResult reqResult; switch (req.kind) { case DelayedRequirement::Type: reqResult = addTypeRequirement(req.lhs, asUnresolvedType(req.rhs), req.source, UnresolvedHandlingKind::GenerateUnresolved, /*inferForModule=*/nullptr); break; case DelayedRequirement::Layout: reqResult = addLayoutRequirement( req.lhs, req.rhs.get(), req.source, UnresolvedHandlingKind::GenerateUnresolved); break; case DelayedRequirement::SameType: reqResult = addSameTypeRequirement( req.lhs, asUnresolvedType(req.rhs), req.source, UnresolvedHandlingKind::GenerateUnresolved); break; } // Update our state based on what happened. switch (reqResult) { case ConstraintResult::Concrete: ++NumDelayedRequirementConcrete; anySolved = true; break; case ConstraintResult::Conflicting: anySolved = true; break; case ConstraintResult::Resolved: ++NumDelayedRequirementResolved; anySolved = true; break; case ConstraintResult::Unresolved: // Add the requirement back. ++NumDelayedRequirementUnresolved; break; } } if (anySolved) { anyChanges = true; } } while (anySolved); } namespace { /// Remove self-derived sources from the given vector of constraints. template void removeSelfDerived(GenericSignatureBuilder &builder, std::vector> &constraints, ProtocolDecl *proto, bool allCanBeSelfDerived = false) { auto genericParams = builder.getGenericParams(); SmallVector, 4> minimalSources; constraints.erase( std::remove_if(constraints.begin(), constraints.end(), [&](const Constraint &constraint) { auto minimalSource = constraint.source->getMinimalConformanceSource( builder, constraint.getSubjectDependentType(genericParams), proto); if (minimalSource != constraint.source) { // The minimal source is smaller than the original source, so the // original source is self-derived. ++NumSelfDerived; if (minimalSource) { // Record a constraint with a minimized source. minimalSources.push_back( {constraint.subject, constraint.value, minimalSource}); } return true; } return false; }), constraints.end()); // If we found any minimal sources, add them now, avoiding introducing any // redundant sources. if (!minimalSources.empty()) { // Collect the sources we already know about. SmallPtrSet sources; for (const auto &constraint : constraints) { sources.insert(constraint.source); } // Add any minimal sources we didn't know about. for (const auto &minimalSource : minimalSources) { if (sources.insert(minimalSource.source).second) { constraints.push_back(minimalSource); } } } assert((!constraints.empty() || allCanBeSelfDerived) && "All constraints were self-derived!"); } } // end anonymous namespace template Constraint GenericSignatureBuilder::checkConstraintList( TypeArrayView genericParams, std::vector> &constraints, RequirementKind kind, llvm::function_ref &)> isSuitableRepresentative, llvm::function_ref< ConstraintRelation(const Constraint&)> checkConstraint, Optional> conflictingDiag, Diag redundancyDiag, Diag otherNoteDiag) { assert(!constraints.empty() && "No constraints?"); // Sort the constraints, so we get a deterministic ordering of diagnostics. std::sort(constraints.begin(), constraints.end()); // Find a representative constraint. auto representativeConstraint = findRepresentativeConstraint(*this, constraints, kind, isSuitableRepresentative); // Local function to provide a note describing the representative constraint. auto noteRepresentativeConstraint = [&] { if (representativeConstraint->source->getLoc().isInvalid()) return; Diags.diagnose(representativeConstraint->source->getLoc(), otherNoteDiag, representativeConstraint->source->classifyDiagKind(), representativeConstraint->getSubjectDependentType( genericParams), representativeConstraint->value); }; // Go through the concrete constraints looking for redundancies. bool diagnosedConflictingRepresentative = false; for (const auto &constraint : constraints) { // Leave the representative alone. if (representativeConstraint && constraint == *representativeConstraint) continue; switch (checkConstraint(constraint)) { case ConstraintRelation::Unrelated: continue; case ConstraintRelation::Conflicting: { // Figure out what kind of subject we have; it will affect the // diagnostic. auto getSubjectType = [&](Type subjectType) -> std::pair { unsigned kind; if (auto gp = subjectType->getAs()) { if (gp->getDecl() && isa(gp->getDecl()->getDeclContext())) { kind = 1; subjectType = cast(gp->getDecl()->getDeclContext()) ->getDeclaredInterfaceType(); } else { kind = 0; } } else { kind = 2; } return std::make_pair(kind, subjectType); }; // The requirement conflicts. If this constraint has a location, complain // about it. if (constraint.source->getLoc().isValid()) { Impl->HadAnyError = true; auto subject = getSubjectType(constraint.getSubjectDependentType(genericParams)); Diags.diagnose(constraint.source->getLoc(), *conflictingDiag, subject.first, subject.second, constraint.value, representativeConstraint->value); noteRepresentativeConstraint(); break; } // If the representative itself conflicts and we haven't diagnosed it yet, // do so now. if (!diagnosedConflictingRepresentative && representativeConstraint->source->getLoc().isValid()) { Impl->HadAnyError = true; auto subject = getSubjectType( representativeConstraint->getSubjectDependentType(genericParams)); Diags.diagnose(representativeConstraint->source->getLoc(), *conflictingDiag, subject.first, subject.second, representativeConstraint->value, constraint.value); diagnosedConflictingRepresentative = true; break; } break; } case ConstraintRelation::Redundant: // If this requirement is not derived or inferred (but has a useful // location) complain that it is redundant. if (constraint.source->shouldDiagnoseRedundancy(true) && representativeConstraint && representativeConstraint->source->shouldDiagnoseRedundancy(false)) { Diags.diagnose(constraint.source->getLoc(), redundancyDiag, constraint.getSubjectDependentType(genericParams), constraint.value); noteRepresentativeConstraint(); } break; } } return *representativeConstraint; } /// Determine whether this is a redundantly inheritable Objective-C protocol. /// /// A redundantly-inheritable Objective-C protocol is one where we will /// silently accept a directly-stated redundant conformance to this protocol, /// and emit this protocol in the list of "inherited" protocols. There are /// two cases where we allow this: /// // 1) For a protocol defined in Objective-C, so that we will match Clang's /// behavior, and /// 2) For an @objc protocol defined in Swift that directly inherits from /// JavaScriptCore's JSExport, which depends on this behavior. static bool isRedundantlyInheritableObjCProtocol( ProtocolDecl *proto, const RequirementSource *source) { if (!proto->isObjC()) return false; // Only do this for the requirement signature computation. auto parentSource = source->parent; if (!parentSource || parentSource->kind != RequirementSource::RequirementSignatureSelf) return false; // Check the two conditions in which we will suppress the diagnostic and // emit the redundant inheritance. auto inheritingProto = parentSource->getProtocolDecl(); if (!inheritingProto->hasClangNode() && !proto->getName().is("JSExport")) return false; // If the inheriting protocol already has @_restatedObjCConformance with // this protocol, we're done. for (auto *attr : inheritingProto->getAttrs() .getAttributes()) { if (attr->Proto == proto) return true; } // Otherwise, add @_restatedObjCConformance. auto &ctx = proto->getASTContext(); inheritingProto->getAttrs().add(new (ctx) RestatedObjCConformanceAttr(proto)); return true; } /// Diagnose any conformance requirements on 'Self' that are not derived from /// the protocol's inheritance clause. void GenericSignatureBuilder::diagnoseProtocolRefinement( const ProtocolDecl *requirementSignatureSelfProto) { if (requirementSignatureSelfProto == nullptr) return; auto selfType = requirementSignatureSelfProto->getSelfInterfaceType(); auto *equivClass = resolveEquivalenceClass( selfType, ArchetypeResolutionKind::AlreadyKnown); assert(equivClass != nullptr); for (auto pair : equivClass->conformsTo) { auto *proto = pair.first; bool found = false; SourceLoc loc; for (const auto &constraint : pair.second) { if (!involvesNonSelfSubjectTypes(constraint.source)) { found = true; break; } auto *parent = constraint.source; while (parent->kind != RequirementSource::RequirementSignatureSelf) { loc = parent->getLoc(); if (loc) break; } } if (!found) { requirementSignatureSelfProto->diagnose( diag::missing_protocol_refinement, const_cast(requirementSignatureSelfProto), proto); if (loc.isValid()) { Context.Diags.diagnose(loc, diag::redundant_conformance_here, selfType, proto); } } } } void GenericSignatureBuilder::diagnoseRedundantRequirements( bool onlyDiagnoseExplicitConformancesImpliedByConcrete) const { for (const auto &req : Impl->ExplicitRequirements) { auto *source = req.getSource(); auto loc = source->getLoc(); // Don't diagnose anything without a source location. if (loc.isInvalid()) continue; // Don't diagnose inferred requirements. if (source->isInferredRequirement()) continue; // Check if its actually redundant. auto found = Impl->RedundantRequirements.find(req); if (found == Impl->RedundantRequirements.end()) continue; if (onlyDiagnoseExplicitConformancesImpliedByConcrete && Impl->ExplicitConformancesImpliedByConcrete.count(req) == 0) continue; // Don't diagnose explicit requirements that are implied by // inferred requirements. if (llvm::all_of(found->second, [&](const ExplicitRequirement &otherReq) { return otherReq.getSource()->isInferredRequirement(); })) continue; auto subjectType = getSugaredDependentType(req.getSubjectType(), getGenericParams()); switch (req.getKind()) { case RequirementKind::Conformance: { auto *proto = req.getRHS().get(); // If this conformance requirement recursively makes a protocol // conform to itself, don't complain here, because we diagnose // the circular inheritance elsewhere. { auto rootSource = source->getRoot(); if (proto == rootSource->getProtocolDecl() && rootSource->kind == RequirementSource::RequirementSignatureSelf && rootSource->getRootType()->isEqual(source->getAffectedType())) { break; } } // If this is a redundantly inherited Objective-C protocol, treat it // as "unrelated" to silence the warning about the redundant // conformance. if (isRedundantlyInheritableObjCProtocol(proto, source)) break; Context.Diags.diagnose(loc, diag::redundant_conformance_constraint, subjectType, proto); for (auto otherReq : found->second) { auto *otherSource = otherReq.getSource(); if (otherSource->isInferredRequirement()) continue; auto otherLoc = otherSource->getLoc(); if (otherLoc.isInvalid()) continue; Context.Diags.diagnose(otherLoc, diag::redundant_conformance_here, subjectType, proto); } break; } case RequirementKind::Layout: { auto layout = req.getRHS().get(); auto conflict = Impl->ConflictingRequirements.find(req); if (conflict != Impl->ConflictingRequirements.end()) { Impl->HadAnyError = true; auto otherLayout = conflict->second.get(); Context.Diags.diagnose(loc, diag::conflicting_layout_constraints, subjectType, layout, otherLayout); for (auto otherReq : found->second) { auto *otherSource = otherReq.getSource(); auto otherLoc = otherSource->getLoc(); if (otherLoc.isInvalid()) continue; Context.Diags.diagnose(otherLoc, diag::conflicting_layout_constraint, subjectType, otherLayout); } } else { Context.Diags.diagnose(loc, diag::redundant_layout_constraint, subjectType, layout); for (auto otherReq : found->second) { auto *otherSource = otherReq.getSource(); if (otherSource->isInferredRequirement()) continue; auto otherLoc = otherSource->getLoc(); if (otherLoc.isInvalid()) continue; Context.Diags.diagnose(otherLoc, diag::previous_layout_constraint, subjectType, layout); } } break; } case RequirementKind::Superclass: { auto superclass = req.getRHS().get(); auto conflict = Impl->ConflictingRequirements.find(req); if (conflict != Impl->ConflictingRequirements.end()) { Impl->HadAnyError = true; auto otherSuperclass = conflict->second.get(); Context.Diags.diagnose(loc, diag::conflicting_superclass_constraints, subjectType, superclass, otherSuperclass); for (auto otherReq : found->second) { auto *otherSource = otherReq.getSource(); auto otherLoc = otherSource->getLoc(); if (otherLoc.isInvalid()) continue; Context.Diags.diagnose(otherLoc, diag::conflicting_superclass_constraint, subjectType, otherSuperclass); } } else { Context.Diags.diagnose(loc, diag::redundant_superclass_constraint, subjectType, superclass); for (auto otherReq : found->second) { auto *otherSource = otherReq.getSource(); if (otherSource->isInferredRequirement()) continue; auto otherLoc = otherSource->getLoc(); if (otherLoc.isInvalid()) continue; Context.Diags.diagnose(otherLoc, diag::superclass_redundancy_here, subjectType, superclass); } } break; } case RequirementKind::SameType: // TODO break; } } } void GenericSignatureBuilder::diagnoseConflictingConcreteTypeRequirements( const ProtocolDecl *requirementSignatureSelfProto) { for (auto pair : Impl->ConflictingConcreteTypeRequirements) { auto subjectType = pair.otherRequirement.getSubjectType(); auto *equivClass = resolveEquivalenceClass(subjectType, ArchetypeResolutionKind::AlreadyKnown); assert(equivClass && "Explicit requirement names an unknown equivalence class?"); auto foundConcreteRequirement = llvm::find_if( equivClass->concreteTypeConstraints, [&](const Constraint &constraint) { SmallVector result; getBaseRequirements( [&]() { return std::make_pair(RequirementKind::SameType, constraint.value); }, constraint.source, requirementSignatureSelfProto, result); for (const auto &otherReq : result) { if (isRedundantExplicitRequirement(otherReq)) return false; } return true; }); assert(foundConcreteRequirement != equivClass->concreteTypeConstraints.end()); SourceLoc loc = foundConcreteRequirement->source->getLoc(); SourceLoc otherLoc = pair.otherRequirement.getSource()->getLoc(); if (loc.isInvalid() && otherLoc.isInvalid()) continue; SourceLoc subjectLoc = (loc.isInvalid() ? otherLoc : loc); Impl->HadAnyError = true; switch (pair.otherRequirement.getKind()) { case RequirementKind::Superclass: { Context.Diags.diagnose(subjectLoc, diag::type_does_not_inherit, subjectType, pair.resolvedConcreteType, pair.otherRHS.get()); if (otherLoc.isValid()) { Context.Diags.diagnose(otherLoc, diag::superclass_redundancy_here, subjectType, pair.otherRHS.get()); } break; } case RequirementKind::Layout: { Context.Diags.diagnose(subjectLoc, diag::type_is_not_a_class, subjectType, pair.resolvedConcreteType, Type()); if (otherLoc.isValid()) { Context.Diags.diagnose(otherLoc, diag::previous_layout_constraint, subjectType, pair.otherRHS.get()); } break; } case RequirementKind::Conformance: case RequirementKind::SameType: llvm_unreachable("TODO"); } if (loc.isValid()) { Context.Diags.diagnose(loc, diag::same_type_redundancy_here, 1, subjectType, pair.resolvedConcreteType); } } } namespace swift { bool operator<(const DerivedSameTypeComponent &lhs, const DerivedSameTypeComponent &rhs) { return compareDependentTypes(lhs.type, rhs.type) < 0; } } // namespace swift /// Find the representative in a simple union-find data structure of /// integral values. static unsigned findRepresentative(SmallVectorImpl &parents, unsigned index) { if (parents[index] == index) return index; return parents[index] = findRepresentative(parents, parents[index]); } /// Union the same-type components denoted by \c index1 and \c index2. /// /// \param successThreshold Returns true when two sets have been joined /// and both representatives are below the threshold. The default of 0 /// is equivalent to \c successThreshold == parents.size(). /// /// \returns \c true if the two components were separate and have now /// been joined; \c false if they were already in the same set. static bool unionSets(SmallVectorImpl &parents, unsigned index1, unsigned index2, unsigned successThreshold = 0) { // Find the representatives of each component class. unsigned rep1 = findRepresentative(parents, index1); unsigned rep2 = findRepresentative(parents, index2); if (rep1 == rep2) return false; // Point at the lowest-numbered representative. if (rep1 < rep2) parents[rep2] = rep1; else parents[rep1] = rep2; return (successThreshold == 0) || (rep1 < successThreshold && rep2 < successThreshold); } /// Computes the ordered set of archetype anchors required to form a minimum /// spanning tree among the connected components formed by only the derived /// same-type requirements within the equivalence class \c equivClass. /// /// The equivalence class contains all potential archetypes that are made /// equivalent by the known set of same-type constraints, which includes both /// directly-stated same-type constraints (e.g., \c T.A == T.B) as well as /// same-type constraints that are implied either because the names coincide /// (e.g., \c T[.P1].A == T[.P2].A) or due to a requirement in a protocol. /// /// The equivalence class of the given representative potential archetype /// (\c rep) is formed from a graph whose vertices are the potential archetypes /// and whose edges are the same-type constraints. These edges include both /// directly-stated same-type constraints (e.g., \c T.A == T.B) as well as /// same-type constraints that are implied either because the names coincide /// (e.g., \c T[.P1].A == T[.P2].A) or due to a requirement in a protocol. /// The equivalence class forms a single connected component. /// /// Within that graph is a subgraph that includes only those edges that are /// implied (and, therefore, excluding those edges that were explicitly stated). /// The connected components within that subgraph describe the potential /// archetypes that would be equivalence even with all of the (explicit) /// same-type constraints removed. /// /// The entire equivalence class can be restored by introducing edges between /// the connected components. This function computes a minimal, canonicalized /// set of edges (same-type constraints) needed to describe the equivalence /// class, which is suitable for the generation of the canonical generic /// signature. /// /// The resulting set of "edges" is returned as a set of vertices, one per /// connected component (of the subgraph). Each is the anchor for that /// connected component (as determined by \c compareDependentTypes()), and the /// set itself is ordered by \c compareDependentTypes(). The actual set of /// canonical edges connects vertex i to vertex i+1 for i in 0.. &componentOf){ // Set up the array of "parents" in the union-find data structure. llvm::SmallDenseMap parentIndices; SmallVector parents; for (unsigned i : indices(equivClass->members)) { Type depType = equivClass->members[i]->getDependentType(); parentIndices[depType->getCanonicalType()] = parents.size(); parents.push_back(i); } // Walk all of the same-type constraints, performing a union-find operation. for (const auto &constraint : equivClass->sameTypeConstraints) { // Treat nested-type-name-match constraints specially. if (constraint.source->getRoot()->kind == RequirementSource::NestedTypeNameMatch) continue; // Skip non-derived constraints. if (!constraint.source->isDerivedRequirement()) continue; CanType source = constraint.getSubjectDependentType({ })->getCanonicalType(); CanType target = constraint.value->getCanonicalType(); assert(parentIndices.count(source) == 1 && "Missing source"); assert(parentIndices.count(target) == 1 && "Missing target"); unionSets(parents, parentIndices[source], parentIndices[target]); } // Compute and record the components. auto &components = equivClass->derivedSameTypeComponents; for (unsigned i : indices(equivClass->members)) { auto pa = equivClass->members[i]; auto depType = pa->getDependentType(); // Find the representative of this set. assert(parentIndices.count(depType) == 1 && "Unknown member?"); unsigned index = parentIndices[depType]; unsigned representative = findRepresentative(parents, index); // If this is the representative, add a component for it. if (representative == index) { componentOf[depType] = components.size(); components.push_back(DerivedSameTypeComponent{depType, nullptr}); continue; } // This is not the representative; point at the component of the // representative. CanType representativeDepTy = equivClass->members[representative]->getDependentType(); assert(componentOf.count(representativeDepTy) == 1 && "Missing representative component?"); unsigned componentIndex = componentOf[representativeDepTy]; componentOf[depType] = componentIndex; // If this is a better anchor, record it. if (compareDependentTypes(depType, components[componentIndex].type) < 0) { components[componentIndex].type = depType; } } // If there is a concrete type, figure out the best concrete type anchor // per component. auto genericParams = builder.getGenericParams(); for (const auto &concrete : equivClass->concreteTypeConstraints) { // Dig out the component associated with constraint. Type subjectType = concrete.getSubjectDependentType(genericParams); assert(componentOf.count(subjectType->getCanonicalType()) > 0); auto &component = components[componentOf[subjectType->getCanonicalType()]]; // FIXME: Skip self-derived sources. This means our attempts to "stage" // construction of self-derived sources really don't work, because we // discover more information later, so we need a more on-line or // iterative approach. if (concrete.source->isSelfDerivedSource(builder, subjectType)) continue; // If it has a better source than we'd seen before for this component, // keep it. auto &bestConcreteTypeSource = component.concreteTypeSource; if (!bestConcreteTypeSource || concrete.source->compare(bestConcreteTypeSource) < 0) bestConcreteTypeSource = concrete.source; } } namespace { /// An edge in the same-type constraint graph that spans two different /// components. struct IntercomponentEdge { unsigned source; unsigned target; Constraint constraint; bool isSelfDerived = false; IntercomponentEdge(unsigned source, unsigned target, const Constraint &constraint) : source(source), target(target), constraint(constraint) { assert(source != target && "Not an intercomponent edge"); if (this->source > this->target) std::swap(this->source, this->target); } friend bool operator<(const IntercomponentEdge &lhs, const IntercomponentEdge &rhs) { if (lhs.source != rhs.source) return lhs.source < rhs.source; if (lhs.target != rhs.target) return lhs.target < rhs.target; // Prefer non-inferred requirement sources. bool lhsIsInferred = lhs.constraint.source->isInferredRequirement(); bool rhsIsInferred = rhs.constraint.source->isInferredRequirement(); if (lhsIsInferred != rhsIsInferred) return rhsIsInferred;; return lhs.constraint < rhs.constraint; } SWIFT_DEBUG_DUMP; }; } void IntercomponentEdge::dump() const { llvm::errs() << constraint.getSubjectDependentType({ }).getString() << " -- " << constraint.value << ": "; constraint.source->print(llvm::errs(), nullptr); llvm::errs() << "\n"; } /// Determine whether the removal of the given edge will disconnect the /// nodes \c from and \c to within the given equivalence class. static bool removalDisconnectsEquivalenceClass( EquivalenceClass *equivClass, llvm::SmallDenseMap &componentOf, std::vector &sameTypeEdges, unsigned edgeIndex, CanType fromDepType, CanType toDepType) { // Which component are "from" and "to" in within the intercomponent edges? assert(componentOf.count(fromDepType) > 0); auto fromComponentIndex = componentOf[fromDepType]; assert(componentOf.count(toDepType) > 0); auto toComponentIndex = componentOf[toDepType]; // If they're in the same component, they're always connected (due to // derived edges). if (fromComponentIndex == toComponentIndex) return false; /// Describes the parents in the equivalence classes we're forming. SmallVector parents; for (unsigned i : range(equivClass->derivedSameTypeComponents.size())) { parents.push_back(i); } for (const auto existingEdgeIndex : indices(sameTypeEdges)) { if (existingEdgeIndex == edgeIndex) continue; const auto &edge = sameTypeEdges[existingEdgeIndex]; if (edge.isSelfDerived) continue; if (unionSets(parents, edge.source, edge.target) && findRepresentative(parents, fromComponentIndex) == findRepresentative(parents, toComponentIndex)) return false; } const auto &edge = sameTypeEdges[edgeIndex]; return !unionSets(parents, edge.source, edge.target) || findRepresentative(parents, fromComponentIndex) != findRepresentative(parents, toComponentIndex); } static AssociatedTypeDecl *takeMemberOfDependentMemberType(Type &type) { if (auto depMemTy = type->getAs()) { type = depMemTy->getBase(); return depMemTy->getAssocType(); } return nullptr; } static bool isSelfDerivedNestedTypeNameMatchEdge( GenericSignatureBuilder &builder, EquivalenceClass *equivClass, llvm::SmallDenseMap &componentOf, std::vector &sameTypeEdges, unsigned edgeIndex) { const auto &edge = sameTypeEdges[edgeIndex]; auto genericParams = builder.getGenericParams(); Type sourceType = edge.constraint.getSubjectDependentType(genericParams); Type target = edge.constraint.value; DependentMemberType *sourceDepMemTy; while ((sourceDepMemTy = sourceType->getAs()) && sourceDepMemTy->getAssocType() == takeMemberOfDependentMemberType(target)) { sourceType = sourceDepMemTy->getBase(); auto targetEquivClass = builder.maybeResolveEquivalenceClass(target, ArchetypeResolutionKind::WellFormed, false) .getEquivalenceClassIfPresent(); if (targetEquivClass == equivClass && builder.maybeResolveEquivalenceClass( sourceType, ArchetypeResolutionKind::WellFormed, /*wantExactPotentialArchetype=*/false) .getEquivalenceClass(builder) == equivClass && !removalDisconnectsEquivalenceClass(equivClass, componentOf, sameTypeEdges, edgeIndex, sourceType->getCanonicalType(), target->getCanonicalType())) return true; } return false; } /// Collapse same-type components using the "delayed" requirements of the /// equivalence class. /// /// This operation looks through the delayed requirements within the equivalence /// class to find paths that connect existing potential archetypes. static void collapseSameTypeComponentsThroughDelayedRequirements( EquivalenceClass *equivClass, llvm::SmallDenseMap &componentOf, SmallVectorImpl &collapsedParents, unsigned &remainingComponents) { unsigned numCollapsedParents = collapsedParents.size(); /// "Virtual" components for types that aren't resolve to potential /// archetypes. llvm::SmallDenseMap virtualComponents; /// Retrieve the component for a type representing a virtual component auto getTypeVirtualComponent = [&](CanType canType) { auto knownActual = componentOf.find(canType); if (knownActual != componentOf.end()) return knownActual->second; auto knownVirtual = virtualComponents.find(canType); if (knownVirtual != virtualComponents.end()) return knownVirtual->second; unsigned component = collapsedParents.size(); collapsedParents.push_back(component); virtualComponents[canType] = component; return component; }; /// Retrieve the component for the given potential archetype. auto getPotentialArchetypeVirtualComponent = [&](PotentialArchetype *pa) { if (pa->getEquivalenceClassIfPresent() == equivClass) return getTypeVirtualComponent(pa->getDependentType()); // We found a potential archetype in another equivalence class. Treat it // as a "virtual" component representing that potential archetype's // equivalence class. return getTypeVirtualComponent( pa->getRepresentative()->getDependentType()); }; for (const auto &delayedReq : equivClass->delayedRequirements) { // Only consider same-type requirements. if (delayedReq.kind != DelayedRequirement::SameType) continue; unsigned lhsComponent; if (auto lhsPA = delayedReq.lhs.dyn_cast()) lhsComponent = getPotentialArchetypeVirtualComponent(lhsPA); else lhsComponent = getTypeVirtualComponent(delayedReq.lhs.get() ->getCanonicalType()); unsigned rhsComponent; if (auto rhsPA = delayedReq.rhs.dyn_cast()) rhsComponent = getPotentialArchetypeVirtualComponent(rhsPA); else rhsComponent = getTypeVirtualComponent(delayedReq.rhs.get() ->getCanonicalType()); // Collapse the sets if (unionSets(collapsedParents, lhsComponent, rhsComponent, numCollapsedParents) && lhsComponent < numCollapsedParents && rhsComponent < numCollapsedParents) --remainingComponents; } /// Remove any additional collapsed parents we added. collapsedParents.erase(collapsedParents.begin() + numCollapsedParents, collapsedParents.end()); } /// Collapse same-type components within an equivalence class, minimizing the /// number of requirements required to express the equivalence class. static void collapseSameTypeComponents( GenericSignatureBuilder &builder, EquivalenceClass *equivClass, llvm::SmallDenseMap &componentOf, std::vector &sameTypeEdges) { SmallVector collapsedParents; for (unsigned i : indices(equivClass->derivedSameTypeComponents)) { collapsedParents.push_back(i); } unsigned remainingComponents = equivClass->derivedSameTypeComponents.size(); for (unsigned edgeIndex : indices(sameTypeEdges)) { auto &edge = sameTypeEdges[edgeIndex]; // If this edge is self-derived, remove it. if (isSelfDerivedNestedTypeNameMatchEdge(builder, equivClass, componentOf, sameTypeEdges, edgeIndex)) { // Note that this edge is self-derived, so we don't consider it again. edge.isSelfDerived = true; auto &constraints = equivClass->sameTypeConstraints; auto known = std::find_if(constraints.begin(), constraints.end(), [&](const Constraint &existing) { // Check the requirement source, first. if (existing.source != edge.constraint.source) return false; return (existing.hasSameSubjectAs(edge.constraint) && existing.value->isEqual(edge.constraint.value)) || (existing.isSubjectEqualTo(edge.constraint.value) && edge.constraint.isSubjectEqualTo(existing.value)); }); assert(known != constraints.end()); constraints.erase(known); continue; } // Otherwise, collapse the derived same-type components along this edge, // because it's derived. if (unionSets(collapsedParents, edge.source, edge.target)) --remainingComponents; } if (remainingComponents > 1) { // Collapse same-type components by looking at the delayed requirements. collapseSameTypeComponentsThroughDelayedRequirements( equivClass, componentOf, collapsedParents, remainingComponents); } // If needed, collapse the same-type components merged by a derived // nested-type-name-match edge. unsigned maxComponents = equivClass->derivedSameTypeComponents.size(); if (remainingComponents < maxComponents) { std::vector newComponents; std::vector newIndices(maxComponents, maxComponents); for (unsigned oldIndex : range(0, maxComponents)) { auto &oldComponent = equivClass->derivedSameTypeComponents[oldIndex]; unsigned oldRepresentativeIndex = findRepresentative(collapsedParents, oldIndex); // If this is the representative, it's a new component; record it. if (oldRepresentativeIndex == oldIndex) { assert(newIndices[oldIndex] == maxComponents && "Already saw this component?"); unsigned newIndex = newComponents.size(); newIndices[oldIndex] = newIndex; newComponents.push_back( {oldComponent.type, oldComponent.concreteTypeSource}); continue; } // This is not the representative; merge it into the representative // component. auto newRepresentativeIndex = newIndices[oldRepresentativeIndex]; assert(newRepresentativeIndex != maxComponents && "Representative should have come earlier"); auto &newComponent = newComponents[newRepresentativeIndex]; // If the old component has a better anchor, keep it. if (compareDependentTypes(oldComponent.type, newComponent.type) < 0) { newComponent.type = oldComponent.type; } // If the old component has a better concrete type source, keep it. if (!newComponent.concreteTypeSource || (oldComponent.concreteTypeSource && oldComponent.concreteTypeSource ->compare(newComponent.concreteTypeSource) < 0)) newComponent.concreteTypeSource = oldComponent.concreteTypeSource; } // Move the new results into place. equivClass->derivedSameTypeComponents = std::move(newComponents); } // Sort the components. llvm::array_pod_sort(equivClass->derivedSameTypeComponents.begin(), equivClass->derivedSameTypeComponents.end()); } void GenericSignatureBuilder::checkSameTypeConstraints( TypeArrayView genericParams, EquivalenceClass *equivClass) { if (!equivClass->derivedSameTypeComponents.empty()) return; // Remove self-derived constraints. removeSelfDerived(*this, equivClass->sameTypeConstraints, /*proto=*/nullptr, /*allCanBeSelfDerived=*/true); // Sort the constraints, so we get a deterministic ordering of diagnostics. llvm::array_pod_sort(equivClass->sameTypeConstraints.begin(), equivClass->sameTypeConstraints.end()); // Compute the components in the subgraph of the same-type constraint graph // that includes only derived constraints. llvm::SmallDenseMap componentOf; computeDerivedSameTypeComponents(*this, equivClass, componentOf); // Go through all of the same-type constraints, collecting all of the // non-derived constraints to put them into bins: intra-component and // inter-component. // Intra-component edges are stored per-component, so we can perform // diagnostics within each component. unsigned numComponents = equivClass->derivedSameTypeComponents.size(); std::vector>> intracomponentEdges(numComponents, std::vector>()); // Intercomponent edges are stored as one big list, which tracks the // source/target components. std::vector intercomponentEdges; std::vector nestedTypeNameMatchEdges; for (const auto &constraint : equivClass->sameTypeConstraints) { // If the source/destination are identical, complain. if (constraint.isSubjectEqualTo(constraint.value)) { if (constraint.source->shouldDiagnoseRedundancy(true)) { Diags.diagnose(constraint.source->getLoc(), diag::redundant_same_type_constraint, constraint.getSubjectDependentType(genericParams), constraint.value); } continue; } // Determine which component each of the source/destination fall into. CanType subjectType = constraint.getSubjectDependentType({ })->getCanonicalType(); assert(componentOf.count(subjectType) > 0 && "unknown potential archetype?"); unsigned firstComponentIdx = componentOf[subjectType]; assert(componentOf.count(constraint.value->getCanonicalType()) > 0 && "unknown potential archetype?"); unsigned secondComponentIdx = componentOf[constraint.value->getCanonicalType()]; // Separately track nested-type-name-match constraints. if (constraint.source->getRoot()->kind == RequirementSource::NestedTypeNameMatch) { // If this is an intercomponent edge, record it separately. if (firstComponentIdx != secondComponentIdx) { nestedTypeNameMatchEdges.push_back( IntercomponentEdge(firstComponentIdx, secondComponentIdx, constraint)); } continue; } // If both vertices are within the same component, this is an // intra-component edge. Record it as such. if (firstComponentIdx == secondComponentIdx) { intracomponentEdges[firstComponentIdx].push_back(constraint); continue; } // Otherwise, it's an intercomponent edge, which is never derived. assert(!constraint.source->isDerivedRequirement() && "Must not be derived"); // Ignore inferred requirements; we don't want to diagnose them. intercomponentEdges.push_back( IntercomponentEdge(firstComponentIdx, secondComponentIdx, constraint)); } // Walk through each of the components, checking the intracomponent edges. // This will diagnose any explicitly-specified requirements within a // component, all of which are redundant. for (auto &constraints : intracomponentEdges) { if (constraints.empty()) continue; checkConstraintList( genericParams, constraints, RequirementKind::SameType, [](const Constraint &) { return true; }, [](const Constraint &constraint) { // Ignore nested-type-name-match constraints. if (constraint.source->getRoot()->kind == RequirementSource::NestedTypeNameMatch) return ConstraintRelation::Unrelated; return ConstraintRelation::Redundant; }, None, diag::redundant_same_type_constraint, diag::previous_same_type_constraint); } // Diagnose redundant same-type constraints across components. First, // sort the edges so that edges that between the same component pairs // occur next to each other. llvm::array_pod_sort(intercomponentEdges.begin(), intercomponentEdges.end()); // Diagnose and erase any redundant edges between the same two components. intercomponentEdges.erase( std::unique( intercomponentEdges.begin(), intercomponentEdges.end(), [&](const IntercomponentEdge &lhs, const IntercomponentEdge &rhs) { // If either the source or target is different, we have // different elements. if (lhs.source != rhs.source || lhs.target != rhs.target) return false; // Check whethe we should diagnose redundancy for both constraints. if (!lhs.constraint.source->shouldDiagnoseRedundancy(true) || !rhs.constraint.source->shouldDiagnoseRedundancy(false)) return true; Diags.diagnose(lhs.constraint.source->getLoc(), diag::redundant_same_type_constraint, lhs.constraint.getSubjectDependentType(genericParams), lhs.constraint.value); Diags.diagnose(rhs.constraint.source->getLoc(), diag::previous_same_type_constraint, rhs.constraint.source->classifyDiagKind(), rhs.constraint.getSubjectDependentType(genericParams), rhs.constraint.value); return true; }), intercomponentEdges.end()); // If we have more intercomponent edges than are needed to form a spanning // tree, complain about redundancies. Note that the edges we have must // connect all of the components, or else we wouldn't have an equivalence // class. if (intercomponentEdges.size() > numComponents - 1) { // First let's order all of the intercomponent edges // as written in source, this helps us to diagnose // all of the duplicate constraints in correct order. std::vector sourceOrderedEdges; for (auto &edge : intercomponentEdges) sourceOrderedEdges.push_back(&edge); llvm::array_pod_sort( sourceOrderedEdges.begin(), sourceOrderedEdges.end(), [](IntercomponentEdge *const *a, IntercomponentEdge *const *b) -> int { auto &sourceMgr = (*a)->constraint.value->getASTContext().SourceMgr; auto locA = (*a)->constraint.source->getLoc(); auto locB = (*b)->constraint.source->getLoc(); // Put invalid locations after valid ones. if (locA.isInvalid() || locB.isInvalid()) { if (locA.isInvalid() != locB.isInvalid()) return locA.isValid() ? 1 : -1; return 0; } auto bufferA = sourceMgr.findBufferContainingLoc(locA); auto bufferB = sourceMgr.findBufferContainingLoc(locB); if (bufferA != bufferB) return bufferA < bufferB ? -1 : 1; auto offsetA = sourceMgr.getLocOffsetInBuffer(locA, bufferA); auto offsetB = sourceMgr.getLocOffsetInBuffer(locB, bufferB); return offsetA < offsetB ? -1 : (offsetA == offsetB ? 0 : 1); }); auto isDiagnosable = [](const IntercomponentEdge &edge, bool isPrimary) { return edge.constraint.source->shouldDiagnoseRedundancy(isPrimary); }; using EquivClass = llvm::DenseMap; llvm::DenseMap equivalences; // The idea here is to form an equivalence class per representative // (picked from each edge constraint in type parameter order) and // propagate all new equivalent types up the chain until duplicate // entry is found, that entry is going to point to previous // declaration and is going to mark current edge as a duplicate of // such entry. for (auto edgeIdx : indices(sourceOrderedEdges)) { const auto &edge = *sourceOrderedEdges[edgeIdx]; Type lhs = edge.constraint.getSubjectDependentType(genericParams); Type rhs = edge.constraint.value; // Make sure that representative for equivalence class is picked // in canonical type parameter order. if (compareDependentTypes(rhs, lhs) < 0) std::swap(lhs, rhs); // Index of the previous declaration of the same-type constraint // which current edge might be a duplicate of. Optional previousIndex; bool isDuplicate = false; auto &representative = equivalences[lhs]; if (representative.insert({rhs, edgeIdx}).second) { // Since this is a new equivalence, and right-hand side might // be a representative of some other equivalence class, // its existing members have to be merged up. auto RHSEquivClass = equivalences.find(rhs); if (RHSEquivClass != equivalences.end()) { auto &equivClass = RHSEquivClass->getSecond(); representative.insert(equivClass.begin(), equivClass.end()); } // If left-hand side is involved in any other equivalences // let's propagate new information up the chain. for (auto &e : equivalences) { auto &repr = e.first; auto &equivClass = e.second; if (repr->isEqual(lhs) || !equivClass.count(lhs)) continue; if (!equivClass.insert({rhs, edgeIdx}).second) { // Even if "previous" edge is not diagnosable we // still need to produce diagnostic about main duplicate. isDuplicate = true; auto prevIdx = equivClass[rhs]; if (!isDiagnosable(intercomponentEdges[prevIdx], /*isPrimary=*/false)) continue; // If there is a diagnosable duplicate equivalence, // it means that we've found our previous declaration. previousIndex = prevIdx; break; } } } else { // Looks like this is a situation like T.A == T.B, ..., T.B == T.A previousIndex = representative[rhs]; isDuplicate = true; } if (!isDuplicate || !isDiagnosable(edge, /*isPrimary=*/true)) continue; Diags.diagnose(edge.constraint.source->getLoc(), diag::redundant_same_type_constraint, edge.constraint.getSubjectDependentType(genericParams), edge.constraint.value); if (previousIndex) { auto &prevEquiv = sourceOrderedEdges[*previousIndex]->constraint; Diags.diagnose( prevEquiv.source->getLoc(), diag::previous_same_type_constraint, prevEquiv.source->classifyDiagKind(), prevEquiv.getSubjectDependentType(genericParams), prevEquiv.value); } } } collapseSameTypeComponents(*this, equivClass, componentOf, nestedTypeNameMatchEdges); } void GenericSignatureBuilder::checkConcreteTypeConstraints( TypeArrayView genericParams, EquivalenceClass *equivClass) { // Resolve any thus-far-unresolved dependent types. Type resolvedConcreteType = getCanonicalTypeInContext(equivClass->concreteType, genericParams); removeSelfDerived(*this, equivClass->concreteTypeConstraints, /*proto=*/nullptr, /*allCanBeSelfDerived=*/true); // This can occur if the combination of a superclass requirement and // protocol conformance requirement force a type to become concrete. if (equivClass->concreteTypeConstraints.empty()) return; checkConstraintList( genericParams, equivClass->concreteTypeConstraints, RequirementKind::SameType, [&](const ConcreteConstraint &constraint) { if (constraint.value->isEqual(resolvedConcreteType)) return true; auto resolvedType = getCanonicalTypeInContext(constraint.value, { }); return resolvedType->isEqual(resolvedConcreteType); }, [&](const Constraint &constraint) { Type concreteType = constraint.value; // If the concrete type is equivalent, the constraint is redundant. if (concreteType->isEqual(equivClass->concreteType)) return ConstraintRelation::Redundant; // If either has a type parameter or type variable, call them unrelated. if (concreteType->hasTypeParameter() || equivClass->concreteType->hasTypeParameter() || concreteType->hasTypeVariable() || equivClass->concreteType->hasTypeVariable()) return ConstraintRelation::Unrelated; return ConstraintRelation::Conflicting; }, diag::same_type_conflict, diag::redundant_same_type_to_concrete, diag::same_type_redundancy_here); } bool GenericSignatureBuilder::isRedundantExplicitRequirement( const ExplicitRequirement &req) const { assert(Impl->computedRedundantRequirements && "Must ensure computeRedundantRequirements() is called first"); auto &redundantReqs = Impl->RedundantRequirements; return (redundantReqs.find(req) != redundantReqs.end()); } static Optional createRequirement(RequirementKind kind, Type depTy, RequirementRHS rhs, TypeArrayView genericParams) { depTy = getSugaredDependentType(depTy, genericParams); if (auto type = rhs.dyn_cast()) { if (type->hasError()) return None; // Drop requirements involving concrete types containing // unresolved associated types. if (type->findUnresolvedDependentMemberType()) return None; if (type->isTypeParameter()) type = getSugaredDependentType(type, genericParams); return Requirement(kind, depTy, type); } else if (auto *proto = rhs.dyn_cast()) { auto type = proto->getDeclaredInterfaceType(); return Requirement(kind, depTy, type); } else { auto layoutConstraint = rhs.get(); return Requirement(kind, depTy, layoutConstraint); } } static int compareRequirements(const Requirement *lhsPtr, const Requirement *rhsPtr) { return lhsPtr->compare(*rhsPtr); } void GenericSignatureBuilder::enumerateRequirements( TypeArrayView genericParams, SmallVectorImpl &requirements) { auto recordRequirement = [&](RequirementKind kind, Type depTy, RequirementRHS rhs) { if (auto req = createRequirement(kind, depTy, rhs, genericParams)) requirements.push_back(*req); else Impl->HadAnyError = true; }; // Collect all non-same type requirements. for (auto &req : Impl->ExplicitRequirements) { if (isRedundantExplicitRequirement(req)) continue; auto depTy = getCanonicalTypeInContext( req.getSubjectType(), { }); // FIXME: This should be an assert once we ensure that concrete // same-type requirements always mark other requirements on the // same subject type as redundant or conflicting. if (!depTy->isTypeParameter()) continue; auto rhs = req.getRHS(); if (auto constraintType = rhs.dyn_cast()) { rhs = getCanonicalTypeInContext(constraintType, genericParams); } recordRequirement(req.getKind(), depTy, rhs); } // Collect all same type requirements. if (!Impl->ExplicitSameTypeRequirements.empty()) { for (auto &equivClass : Impl->EquivalenceClasses) { if (equivClass.derivedSameTypeComponents.empty()) { checkSameTypeConstraints(genericParams, &equivClass); } for (unsigned i : indices(equivClass.derivedSameTypeComponents)) { // Dig out the subject type and its corresponding component. auto &component = equivClass.derivedSameTypeComponents[i]; Type subjectType = component.type; assert(!subjectType->hasError()); assert(!subjectType->findUnresolvedDependentMemberType()); // If this equivalence class is bound to a concrete type, equate the // anchor with a concrete type. if (Type concreteType = equivClass.concreteType) { concreteType = getCanonicalTypeInContext(concreteType, genericParams); // If the parent of this anchor is also a concrete type, don't // create a requirement. if (!subjectType->is() && maybeResolveEquivalenceClass( subjectType->castTo()->getBase(), ArchetypeResolutionKind::WellFormed, /*wantExactPotentialArchetype=*/false) .getEquivalenceClass(*this)->concreteType) continue; // Drop recursive and invalid concrete-type constraints. if (equivClass.recursiveConcreteType || equivClass.invalidConcreteType) continue; // Filter out derived requirements... except for concrete-type // requirements on generic parameters. The exception is due to // the canonicalization of generic signatures, which never // eliminates generic parameters even when they have been // mapped to a concrete type. if (subjectType->is() || component.concreteTypeSource == nullptr || !component.concreteTypeSource->isDerivedRequirement()) { recordRequirement(RequirementKind::SameType, subjectType, concreteType); } continue; } // If we're at the last anchor in the component, do nothing; if (i + 1 != equivClass.derivedSameTypeComponents.size()) { // Form a same-type constraint from this anchor within the component // to the next. // FIXME: Distinguish between explicit and inferred here? auto &nextComponent = equivClass.derivedSameTypeComponents[i + 1]; Type otherSubjectType = nextComponent.type; recordRequirement(RequirementKind::SameType, subjectType, otherSubjectType); } } } } // Sort the requirements in canonical order. llvm::array_pod_sort(requirements.begin(), requirements.end(), compareRequirements); } void GenericSignatureBuilder::dump() { dump(llvm::errs()); } void GenericSignatureBuilder::dump(llvm::raw_ostream &out) { out << "Potential archetypes:\n"; for (auto pa : Impl->PotentialArchetypes) { pa->dump(out, &Context.SourceMgr, 2); } out << "\n"; out << "Equivalence classes:\n"; for (auto &equiv : Impl->EquivalenceClasses) { equiv.dump(out, this); } out << "\n"; } void GenericSignatureBuilder::addGenericSignature(GenericSignature sig) { for (auto param : sig.getGenericParams()) addGenericParameter(param); for (auto &reqt : sig.getRequirements()) addRequirement(reqt, FloatingRequirementSource::forAbstract(), nullptr); } static Type stripBoundDependentMemberTypes(Type t) { if (auto *depMemTy = t->getAs()) { return DependentMemberType::get( stripBoundDependentMemberTypes(depMemTy->getBase()), depMemTy->getName()); } return t; } static Requirement stripBoundDependentMemberTypes(Requirement req) { auto subjectType = stripBoundDependentMemberTypes(req.getFirstType()); switch (req.getKind()) { case RequirementKind::Conformance: return Requirement(RequirementKind::Conformance, subjectType, req.getSecondType()); case RequirementKind::Superclass: case RequirementKind::SameType: return Requirement(req.getKind(), subjectType, req.getSecondType().transform([](Type t) { return stripBoundDependentMemberTypes(t); })); case RequirementKind::Layout: return Requirement(RequirementKind::Layout, subjectType, req.getLayoutConstraint()); } llvm_unreachable("Bad requirement kind"); } GenericSignature GenericSignatureBuilder::rebuildSignatureWithoutRedundantRequirements( bool allowConcreteGenericParams, const ProtocolDecl *requirementSignatureSelfProto) && { NumSignaturesRebuiltWithoutRedundantRequirements++; GenericSignatureBuilder newBuilder(Context); newBuilder.Impl->RebuildingWithoutRedundantConformances = true; for (auto param : getGenericParams()) newBuilder.addGenericParameter(param); const RequirementSource *requirementSignatureSource = nullptr; if (auto *proto = const_cast(requirementSignatureSelfProto)) { auto selfType = proto->getSelfInterfaceType(); requirementSignatureSource = RequirementSource::forRequirementSignature(newBuilder, selfType, proto); // Add the conformance requirement 'Self : Proto' directly without going // through addConformanceRequirement(), since the latter calls // expandConformanceRequirement(), which we want to skip since we're // re-adding the requirements directly below. auto resolvedType = ResolvedType(newBuilder.Impl->PotentialArchetypes[0]); auto equivClass = resolvedType.getEquivalenceClass(newBuilder); (void) equivClass->recordConformanceConstraint(newBuilder, resolvedType, proto, requirementSignatureSource); } auto getRebuiltSource = [&](const RequirementSource *source) { assert(!source->isDerivedRequirement()); if (auto *proto = const_cast(requirementSignatureSelfProto)) { return FloatingRequirementSource::viaProtocolRequirement( requirementSignatureSource, proto, source->getLoc(), source->isInferredRequirement()); } if (source->isInferredRequirement()) return FloatingRequirementSource::forInferred(source->getLoc()); return FloatingRequirementSource::forExplicit(source->getLoc()); }; for (const auto &req : Impl->ExplicitRequirements) { if (Impl->DebugRedundantRequirements) { req.dump(llvm::dbgs(), &Context.SourceMgr); llvm::dbgs() << "\n"; } assert(req.getKind() != RequirementKind::SameType && "Should not see same-type requirement here"); if (isRedundantExplicitRequirement(req) && Impl->ExplicitConformancesImpliedByConcrete.count(req)) { if (Impl->DebugRedundantRequirements) { llvm::dbgs() << "... skipping\n"; } continue; } auto subjectType = req.getSubjectType(); auto resolvedSubject = maybeResolveEquivalenceClass(subjectType, ArchetypeResolutionKind::WellFormed, /*wantExactPotentialArchetype=*/false); auto *resolvedEquivClass = resolvedSubject.getEquivalenceClass(*this); Type resolvedSubjectType; if (resolvedEquivClass != nullptr) resolvedSubjectType = resolvedEquivClass->getAnchor(*this, { }); // This can occur if the combination of a superclass requirement and // protocol conformance requirement force a type to become concrete. // // FIXME: Is there a more principled formulation of this? if (req.getKind() == RequirementKind::Superclass) { if (resolvedSubject.getAsConcreteType()) { auto unresolvedSubjectType = stripBoundDependentMemberTypes(subjectType); newBuilder.addRequirement(Requirement(RequirementKind::SameType, unresolvedSubjectType, resolvedSubject.getAsConcreteType()), getRebuiltSource(req.getSource()), nullptr); continue; } if (resolvedEquivClass->concreteType) { auto unresolvedSubjectType = stripBoundDependentMemberTypes( resolvedSubjectType); newBuilder.addRequirement(Requirement(RequirementKind::SameType, unresolvedSubjectType, resolvedEquivClass->concreteType), getRebuiltSource(req.getSource()), nullptr); continue; } } assert(resolvedSubjectType && resolvedSubjectType->isTypeParameter()); if (auto optReq = createRequirement(req.getKind(), resolvedSubjectType, req.getRHS(), getGenericParams())) { auto newReq = stripBoundDependentMemberTypes(*optReq); newBuilder.addRequirement(newReq, getRebuiltSource(req.getSource()), nullptr); } else { Impl->HadAnyError = true; } } for (const auto &req : Impl->ExplicitSameTypeRequirements) { if (Impl->DebugRedundantRequirements) { req.dump(llvm::dbgs(), &Context.SourceMgr); llvm::dbgs() << "\n"; } auto resolveType = [this](Type t) -> Type { t = stripBoundDependentMemberTypes(t); if (t->is()) { return t; } else if (auto *depMemTy = t->getAs()) { auto resolvedBaseTy = resolveDependentMemberTypes(*this, depMemTy->getBase(), ArchetypeResolutionKind::WellFormed); if (resolvedBaseTy->isTypeParameter()) { return DependentMemberType::get(resolvedBaseTy, depMemTy->getName()); } else { return resolveDependentMemberTypes(*this, t, ArchetypeResolutionKind::WellFormed); } } else { return t; } }; // If we have a same-type requirement where the right hand side is concrete, // canonicalize the left hand side, in case dropping some redundant // conformance requirement turns the original left hand side into an // unresolvable type. if (!req.getRHS().get()->isTypeParameter()) { auto resolvedSubject = maybeResolveEquivalenceClass(req.getSubjectType(), ArchetypeResolutionKind::WellFormed, /*wantExactPotentialArchetype=*/false); auto *resolvedEquivClass = resolvedSubject.getEquivalenceClass(*this); auto resolvedSubjectType = resolvedEquivClass->getAnchor(*this, { }); auto constraintType = resolveType(req.getRHS().get()); auto newReq = stripBoundDependentMemberTypes( Requirement(RequirementKind::SameType, resolvedSubjectType, constraintType)); if (Impl->DebugRedundantRequirements) { llvm::dbgs() << "=> "; newReq.dump(llvm::dbgs()); llvm::dbgs() << "\n"; } newBuilder.addRequirement(newReq, getRebuiltSource(req.getSource()), nullptr); continue; } // Otherwise, we can't canonicalize the two sides of the requirement, since // doing so will produce a trivial same-type requirement T == T. Instead, // apply some ad-hoc rules to improve the odds that the requirement will // resolve in the rebuilt GSB. auto subjectType = resolveType(req.getSubjectType()); auto constraintType = resolveType(req.getRHS().get()); auto newReq = stripBoundDependentMemberTypes( Requirement(RequirementKind::SameType, subjectType, constraintType)); if (Impl->DebugRedundantRequirements) { llvm::dbgs() << "=> "; newReq.dump(llvm::dbgs()); llvm::dbgs() << "\n"; } newBuilder.addRequirement(newReq, getRebuiltSource(req.getSource()), nullptr); } // Wipe out the internal state of the old builder, since we don't need it anymore. Impl.reset(); // Build a new signature using the new builder. return std::move(newBuilder).computeGenericSignature( allowConcreteGenericParams, requirementSignatureSelfProto); } bool GenericSignatureBuilder::hadAnyError() const { return Impl->HadAnyError; } GenericSignature GenericSignatureBuilder::computeGenericSignature( bool allowConcreteGenericParams, const ProtocolDecl *requirementSignatureSelfProto) && { // Process any delayed requirements that we can handle now. processDelayedRequirements(); computeRedundantRequirements(requirementSignatureSelfProto); // If any of our explicit conformance requirements were implied by // superclass or concrete same-type requirements, we have to build the // signature again, since dropping the redundant conformance requirements // changes the canonical type computation. // // However, if we already diagnosed an error, don't do this, because // we might end up emitting duplicate diagnostics. // // Also, don't do this when building a requirement signature. if (!Impl->RebuildingWithoutRedundantConformances && !Impl->HadAnyError && !Impl->ExplicitConformancesImpliedByConcrete.empty()) { diagnoseRedundantRequirements( /*onlyDiagnoseExplicitConformancesImpliedByConcrete=*/true); if (Impl->DebugRedundantRequirements) { llvm::dbgs() << "Going to rebuild signature\n"; } return std::move(*this).rebuildSignatureWithoutRedundantRequirements( allowConcreteGenericParams, requirementSignatureSelfProto); } if (Impl->RebuildingWithoutRedundantConformances) { if (Impl->DebugRedundantRequirements) { llvm::dbgs() << "Rebuilding signature\n"; } #ifndef NDEBUG for (const auto &req : Impl->ExplicitConformancesImpliedByConcrete) { if (isRedundantExplicitRequirement(req)) { llvm::errs() << "Rebuilt signature still had redundant conformance requirement\n"; req.dump(llvm::errs(), &Context.SourceMgr); llvm::errs() << "\n"; abort(); } } #endif } // Diagnose redundant requirements, check for recursive concrete types // and compute minimized same-type requirements. finalize(getGenericParams(), allowConcreteGenericParams, requirementSignatureSelfProto); // Collect all non-redundant explicit requirements. SmallVector requirements; enumerateRequirements(getGenericParams(), requirements); // Form the generic signature. auto sig = GenericSignature::get(getGenericParams(), requirements); bool hadAnyError = Impl->HadAnyError; // When we can, move this generic signature builder to make it the canonical // builder, rather than constructing a new generic signature builder that // will produce the same thing. // // We cannot do this when there were errors. // // Also, we cannot do this when building a requirement signature. if (requirementSignatureSelfProto == nullptr && !hadAnyError) { // Register this generic signature builder as the canonical builder for the // given signature. Context.registerGenericSignatureBuilder(sig, std::move(*this)); } // Wipe out the internal state, ensuring that nobody uses this builder for // anything more. Impl.reset(); #ifndef NDEBUG if (requirementSignatureSelfProto == nullptr && !hadAnyError) { sig.verify(); } #endif return sig; } /// Check whether the inputs to the \c AbstractGenericSignatureRequest are /// all canonical. static bool isCanonicalRequest(GenericSignature baseSignature, ArrayRef genericParams, ArrayRef requirements) { if (baseSignature && !baseSignature->isCanonical()) return false; for (auto gp : genericParams) { if (!gp->isCanonical()) return false; } for (const auto &req : requirements) { if (!req.isCanonical()) return false; } return true; } GenericSignatureWithError AbstractGenericSignatureRequest::evaluate( Evaluator &evaluator, const GenericSignatureImpl *baseSignatureImpl, SmallVector addedParameters, SmallVector addedRequirements) const { GenericSignature baseSignature = GenericSignature{baseSignatureImpl}; // If nothing is added to the base signature, just return the base // signature. if (addedParameters.empty() && addedRequirements.empty()) return GenericSignatureWithError(baseSignature, /*hadError=*/false); ASTContext &ctx = addedParameters.empty() ? addedRequirements.front().getFirstType()->getASTContext() : addedParameters.front()->getASTContext(); // If there are no added requirements, we can form the signature directly // with the added parameters. if (addedRequirements.empty()) { addedParameters.insert(addedParameters.begin(), baseSignature.getGenericParams().begin(), baseSignature.getGenericParams().end()); auto result = GenericSignature::get(addedParameters, baseSignature.getRequirements()); return GenericSignatureWithError(result, /*hadError=*/false); } // If the request is non-canonical, we won't need to build our own // generic signature builder. if (!isCanonicalRequest(baseSignature, addedParameters, addedRequirements)) { // Canonicalize the inputs so we can form the canonical request. auto canBaseSignature = baseSignature.getCanonicalSignature(); SmallVector canAddedParameters; canAddedParameters.reserve(addedParameters.size()); for (auto gp : addedParameters) { auto canGP = gp->getCanonicalType()->castTo(); canAddedParameters.push_back(canGP); } SmallVector canAddedRequirements; canAddedRequirements.reserve(addedRequirements.size()); for (const auto &req : addedRequirements) { canAddedRequirements.push_back(req.getCanonical()); } // Build the canonical signature. auto canSignatureResult = evaluateOrDefault( ctx.evaluator, AbstractGenericSignatureRequest{ canBaseSignature.getPointer(), std::move(canAddedParameters), std::move(canAddedRequirements)}, GenericSignatureWithError()); if (!canSignatureResult.getPointer()) return GenericSignatureWithError(); // Substitute in the original generic parameters to form the sugared // result the original request wanted. auto canSignature = canSignatureResult.getPointer(); SmallVector resugaredParameters; resugaredParameters.reserve(canSignature.getGenericParams().size()); if (baseSignature) { resugaredParameters.append(baseSignature.getGenericParams().begin(), baseSignature.getGenericParams().end()); } resugaredParameters.append(addedParameters.begin(), addedParameters.end()); assert(resugaredParameters.size() == canSignature.getGenericParams().size()); SmallVector resugaredRequirements; resugaredRequirements.reserve(canSignature.getRequirements().size()); for (const auto &req : canSignature.getRequirements()) { auto resugaredReq = req.subst( [&](SubstitutableType *type) { if (auto gp = dyn_cast(type)) { unsigned ordinal = canSignature->getGenericParamOrdinal(gp); return Type(resugaredParameters[ordinal]); } return Type(type); }, MakeAbstractConformanceForGenericType(), SubstFlags::AllowLoweredTypes); resugaredRequirements.push_back(*resugaredReq); } return GenericSignatureWithError( GenericSignature::get(resugaredParameters, resugaredRequirements), canSignatureResult.getInt()); } auto buildViaGSB = [&]() { // Create a generic signature that will form the signature. GenericSignatureBuilder builder(ctx); if (baseSignature) builder.addGenericSignature(baseSignature); auto source = GenericSignatureBuilder::FloatingRequirementSource::forAbstract(); for (auto param : addedParameters) builder.addGenericParameter(param); for (const auto &req : addedRequirements) builder.addRequirement(req, source, nullptr); bool hadError = builder.hadAnyError(); auto result = std::move(builder).computeGenericSignature( /*allowConcreteGenericParams=*/true); return GenericSignatureWithError(result, hadError); }; auto buildViaRQM = [&]() { return evaluateOrDefault( ctx.evaluator, AbstractGenericSignatureRequestRQM{ baseSignature.getPointer(), std::move(addedParameters), std::move(addedRequirements)}, GenericSignatureWithError()); }; switch (ctx.LangOpts.RequirementMachineAbstractSignatures) { case RequirementMachineMode::Disabled: return buildViaGSB(); case RequirementMachineMode::Enabled: return buildViaRQM(); case RequirementMachineMode::Verify: { auto rqmResult = buildViaRQM(); auto gsbResult = buildViaGSB(); if (!rqmResult.getPointer() && !gsbResult.getPointer()) return gsbResult; if (!rqmResult.getPointer()->isEqual(gsbResult.getPointer())) { llvm::errs() << "RequirementMachine generic signature minimization is broken:\n"; llvm::errs() << "RequirementMachine says: " << rqmResult.getPointer() << "\n"; llvm::errs() << "GenericSignatureBuilder says: " << gsbResult.getPointer() << "\n"; abort(); } return gsbResult; } } } GenericSignatureWithError InferredGenericSignatureRequest::evaluate( Evaluator &evaluator, ModuleDecl *parentModule, const GenericSignatureImpl *parentSig, GenericParamList *genericParams, WhereClauseOwner whereClause, SmallVector addedRequirements, SmallVector inferenceSources, bool allowConcreteGenericParams) const { auto buildViaGSB = [&]() { GenericSignatureBuilder builder(parentModule->getASTContext()); // If there is a parent context, add the generic parameters and requirements // from that context. builder.addGenericSignature(parentSig); DeclContext *lookupDC = nullptr; const auto visitRequirement = [&](const Requirement &req, RequirementRepr *reqRepr) { const auto source = FloatingRequirementSource::forExplicit( reqRepr->getSeparatorLoc()); // If we're extending a protocol and adding a redundant requirement, // for example, `extension Foo where Self: Foo`, then emit a // diagnostic. if (auto decl = lookupDC->getAsDecl()) { if (auto extDecl = dyn_cast(decl)) { auto extType = extDecl->getDeclaredInterfaceType(); auto extSelfType = extDecl->getSelfInterfaceType(); auto reqLHSType = req.getFirstType(); auto reqRHSType = req.getSecondType(); if (extType->isExistentialType() && reqLHSType->isEqual(extSelfType) && reqRHSType->isEqual(extType)) { auto &ctx = extDecl->getASTContext(); ctx.Diags.diagnose(extDecl->getLoc(), diag::protocol_extension_redundant_requirement, extType->getString(), extSelfType->getString(), reqRHSType->getString()); } } } builder.addRequirement(req, reqRepr, source, nullptr, lookupDC->getParentModule()); return false; }; if (genericParams) { // Extensions never have a parent signature. if (genericParams->getOuterParameters()) assert(parentSig == nullptr); // Type check the generic parameters, treating all generic type // parameters as dependent, unresolved. SmallVector gpLists; for (auto *outerParams = genericParams; outerParams != nullptr; outerParams = outerParams->getOuterParameters()) { gpLists.push_back(outerParams); } // The generic parameter lists MUST appear from innermost to outermost. // We walk them backwards to order outer requirements before // inner requirements. for (auto &genericParams : llvm::reverse(gpLists)) { assert(genericParams->size() > 0 && "Parsed an empty generic parameter list?"); // First, add the generic parameters to the generic signature builder. // Do this before checking the inheritance clause, since it may // itself be dependent on one of these parameters. for (const auto param : *genericParams) builder.addGenericParameter(param); // Add the requirements for each of the generic parameters to the builder. // Now, check the inheritance clauses of each parameter. for (const auto param : *genericParams) builder.addGenericParameterRequirements(param); // Determine where and how to perform name lookup. lookupDC = genericParams->begin()[0]->getDeclContext(); // Add the requirements clause to the builder. WhereClauseOwner(lookupDC, genericParams) .visitRequirements(TypeResolutionStage::Structural, visitRequirement); } } if (whereClause) { lookupDC = whereClause.dc; std::move(whereClause).visitRequirements( TypeResolutionStage::Structural, visitRequirement); } /// Perform any remaining requirement inference. for (auto sourcePair : inferenceSources) { auto *typeRepr = sourcePair.getTypeRepr(); auto source = FloatingRequirementSource::forInferred( typeRepr ? typeRepr->getStartLoc() : SourceLoc()); builder.inferRequirements(*parentModule, sourcePair.getType(), source); } // Finish by adding any remaining requirements. auto source = FloatingRequirementSource::forInferred(SourceLoc()); for (const auto &req : addedRequirements) builder.addRequirement(req, source, parentModule); bool hadError = builder.hadAnyError(); auto result = std::move(builder).computeGenericSignature( allowConcreteGenericParams); return GenericSignatureWithError(result, hadError); }; auto &ctx = parentModule->getASTContext(); auto buildViaRQM = [&]() { return evaluateOrDefault( ctx.evaluator, InferredGenericSignatureRequestRQM{ parentModule, parentSig, genericParams, whereClause, addedRequirements, inferenceSources, allowConcreteGenericParams}, GenericSignatureWithError()); }; switch (ctx.LangOpts.RequirementMachineInferredSignatures) { case RequirementMachineMode::Disabled: return buildViaGSB(); case RequirementMachineMode::Enabled: return buildViaRQM(); case RequirementMachineMode::Verify: { auto rqmResult = buildViaRQM(); auto gsbResult = buildViaGSB(); if (!rqmResult.getPointer() && !gsbResult.getPointer()) return gsbResult; if (!rqmResult.getPointer()->isEqual(gsbResult.getPointer())) { llvm::errs() << "RequirementMachine generic signature minimization is broken:\n"; llvm::errs() << "RequirementMachine says: " << rqmResult.getPointer() << "\n"; llvm::errs() << "GenericSignatureBuilder says: " << gsbResult.getPointer() << "\n"; abort(); } return gsbResult; } } } ArrayRef RequirementSignatureRequest::evaluate(Evaluator &evaluator, ProtocolDecl *proto) const { ASTContext &ctx = proto->getASTContext(); // First check if we have a deserializable requirement signature. if (proto->hasLazyRequirementSignature()) { ++NumLazyRequirementSignaturesLoaded; // FIXME: (transitional) increment the redundant "always-on" counter. if (ctx.Stats) ++ctx.Stats->getFrontendCounters().NumLazyRequirementSignaturesLoaded; auto contextData = static_cast( ctx.getOrCreateLazyContextData(proto, nullptr)); SmallVector requirements; contextData->loader->loadRequirementSignature( proto, contextData->requirementSignatureData, requirements); if (requirements.empty()) return None; return ctx.AllocateCopy(requirements); } auto buildViaGSB = [&]() { GenericSignatureBuilder builder(proto->getASTContext(), /*requirementSignature=*/true); // Add all of the generic parameters. for (auto gp : *proto->getGenericParams()) builder.addGenericParameter(gp); // Add the conformance of 'self' to the protocol. auto selfType = proto->getSelfInterfaceType()->castTo(); auto requirement = Requirement(RequirementKind::Conformance, selfType, proto->getDeclaredInterfaceType()); builder.addRequirement( requirement, GenericSignatureBuilder::RequirementSource::forRequirementSignature( builder, selfType, proto), nullptr); auto reqSignature = std::move(builder).computeGenericSignature( /*allowConcreteGenericParams=*/false, /*requirementSignatureSelfProto=*/proto); return reqSignature.getRequirements(); }; auto buildViaRQM = [&]() { return evaluateOrDefault( ctx.evaluator, RequirementSignatureRequestRQM{const_cast(proto)}, ArrayRef()); }; switch (ctx.LangOpts.RequirementMachineProtocolSignatures) { case RequirementMachineMode::Disabled: return buildViaGSB(); case RequirementMachineMode::Enabled: return buildViaRQM(); case RequirementMachineMode::Verify: { auto rqmResult = buildViaRQM(); auto gsbResult = buildViaGSB(); // For now, only compare conformance requirements, since those are the // important ones from the ABI perspective. SmallVector rqmConformances; for (auto req : rqmResult) { if (req.getKind() == RequirementKind::Conformance) rqmConformances.push_back(req); } SmallVector gsbConformances; for (auto req : gsbResult) { if (req.getKind() == RequirementKind::Conformance) gsbConformances.push_back(req); } if (rqmConformances.size() != gsbConformances.size() || !std::equal(rqmConformances.begin(), rqmConformances.end(), gsbConformances.begin())) { llvm::errs() << "RequirementMachine protocol signature minimization is broken:\n"; llvm::errs() << "Protocol: " << proto->getName() << "\n"; auto rqmSig = GenericSignature::get( proto->getGenericSignature().getGenericParams(), rqmResult); llvm::errs() << "RequirementMachine says: " << rqmSig << "\n"; auto gsbSig = GenericSignature::get( proto->getGenericSignature().getGenericParams(), gsbResult); llvm::errs() << "GenericSignatureBuilder says: " << gsbSig << "\n"; abort(); } return gsbResult; } } }