//===--- 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 "swift/AST/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/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 this to 1 to enable expensive assertions. #define SWIFT_GSB_EXPENSIVE_ASSERTIONS 0 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, Type type) : sourceAndKind(source, kind), rhs(type ? type->getCanonicalType() : Type()) {} ExplicitRequirement(RequirementKind kind, const RequirementSource *source, ProtocolDecl *proto) : sourceAndKind(source, kind), rhs(proto) {} ExplicitRequirement(RequirementKind kind, const RequirementSource *source, LayoutConstraint layout) : sourceAndKind(source, kind), rhs(layout) {} /// For a Constraint with an explicit requirement source, we recover the /// subject type from the requirement source and the right hand side from the /// constraint. /// /// The requirement kind must be passed in since Constraint's kind is /// implicit by virtue of which list it appears under inside its equivalence /// class, and is not stored inside the constraint. template static ExplicitRequirement fromExplicitConstraint(RequirementKind kind, Constraint constraint) { assert(!constraint.source->isDerivedNonRootRequirement()); return ExplicitRequirement(kind, constraint.source, constraint.value); } /// To recover the root explicit requirement from a Constraint, we walk the /// requirement source up the root, and look at both the root and the next /// innermost child. /// Together, these give us the subject type (via the root) and the right hand /// side of the requirement (from the next innermost child). /// /// The requirement kind must be passed in since Constraint's kind is /// implicit by virtue of which list it appears under inside its equivalence /// class, and is not stored inside the constraint. /// /// The constraint's actual value is ignored; that's the right hand /// side of the derived constraint, not the right hand side of the original /// explicit requirement. template static ExplicitRequirement fromDerivedConstraint(RequirementKind kind, Constraint constraint) { assert(constraint.source->isDerivedNonRootRequirement()); const RequirementSource *root = constraint.source; const RequirementSource *child = nullptr; while (root->parent && root->isDerivedRequirement()) { child = root; root = root->parent; } assert(root != nullptr); assert(child != nullptr); switch (child->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 = child->getProtocolDecl(); return ExplicitRequirement(RequirementKind::Conformance, root, 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 = child->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 = child->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. auto &ctx = constraint.getSubjectDependentType({ })->getASTContext(); conformingType = ErrorType::get(ctx); } } auto kind = (child->kind == RequirementSource::Superclass ? RequirementKind::Superclass : RequirementKind::SameType); return ExplicitRequirement(kind, root, 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 = child->getStoredType(); return ExplicitRequirement(RequirementKind::Superclass, root, type); } default: { auto &SM = constraint.getSubjectDependentType({ })->getASTContext().SourceMgr; constraint.source->dump(llvm::errs(), &SM, 0); llvm::errs() << "\n"; llvm_unreachable("Unknown root kind"); } } } RequirementKind getKind() const { return sourceAndKind.getInt(); } 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; } }; } 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; /// A mapping of redundant explicit requirements to the best root requirement /// that implies them. using RedundantRequirementMap = llvm::DenseMap>; RedundantRequirementMap RedundantRequirements; #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].getOpaqueValue(); return nullptr; } const void *RequirementSource::getOpaqueStorage3() const { if (numTrailingObjects(OverloadToken()) == 1 && numTrailingObjects(OverloadToken()) == 1) return getTrailingObjects()[0].getOpaqueValue(); 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, bool &derivedViaConcrete) const { return getMinimalConformanceSource(builder, type, /*proto=*/nullptr, derivedViaConcrete) != 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, 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, bool &derivedViaConcrete) const { derivedViaConcrete = false; // 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); }; bool sawProtocolRequirement = false; ProtocolDecl *requirementSignatureSelfProto = nullptr; Type rootType = nullptr; Optional> redundantSubpath; bool isSelfDerived = visitPotentialArchetypesAlongPath( [&](Type parentType, const RequirementSource *source) { switch (source->kind) { case ProtocolRequirement: case InferredProtocolRequirement: { // Special handling for top-level requirement signature requirements; // pretend the root type is the subject type as written in the // protocol, and not 'Self', so that we can consider this requirement // self-derived if it depends on one of the conformances that make // the root type valid. if (requirementSignatureSelfProto) { if (source->getProtocolDecl() == requirementSignatureSelfProto && source->parent->kind == RequirementSource::RequirementSignatureSelf) { rootType = source->getAffectedType(); return false; } } // Note that we've seen a protocol requirement. sawProtocolRequirement = true; // If the base has been made concrete, note it. auto parentEquivClass = builder.resolveEquivalenceClass(parentType, ArchetypeResolutionKind::WellFormed); assert(parentEquivClass && "Not a well-formed type?"); if (parentEquivClass->concreteType) derivedViaConcrete = true; else if (parentEquivClass->superclass && builder.lookupConformance(parentType->getCanonicalType(), parentEquivClass->superclass, source->getProtocolDecl())) derivedViaConcrete = true; // 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: rootType = parentType; 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, derivedViaConcrete); } // It's self-derived but we don't have a redundant subpath to eliminate. if (isSelfDerived) return nullptr; // If we haven't seen a protocol requirement, we're done. if (!sawProtocolRequirement) return this; // The root might be a nested type, which implies constraints // for each of the protocols of the associated types referenced (if any). for (auto depMemTy = rootType->getAs(); depMemTy; depMemTy = depMemTy->getBase()->getAs()) { auto assocType = depMemTy->getAssocType(); assert(assocType); if (addTypeConstraint(depMemTy->getBase(), assocType->getProtocol(), nullptr)) 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.isNull()? 0 : 1); \ 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, WrittenRequirementLoc()), 0, WrittenRequirementLoc()); } const RequirementSource *RequirementSource::forExplicit( GenericSignatureBuilder &builder, Type rootType, GenericSignatureBuilder::WrittenRequirementLoc writtenLoc) { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, Explicit, nullptr, rootType.getPointer(), writtenLoc.getOpaqueValue(), nullptr), (Explicit, rootType, nullptr, writtenLoc), 0, writtenLoc); } const RequirementSource *RequirementSource::forInferred( GenericSignatureBuilder &builder, Type rootType, const TypeRepr *typeRepr) { WrittenRequirementLoc writtenLoc = typeRepr; REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, Inferred, nullptr, rootType.getPointer(), writtenLoc.getOpaqueValue(), 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, WrittenRequirementLoc()), 1, WrittenRequirementLoc()); } const RequirementSource *RequirementSource::forNestedTypeNameMatch( GenericSignatureBuilder &builder, Type rootType) { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, NestedTypeNameMatch, nullptr, rootType.getPointer(), nullptr, nullptr), (NestedTypeNameMatch, rootType, nullptr, WrittenRequirementLoc()), 0, WrittenRequirementLoc()); } const RequirementSource *RequirementSource::viaProtocolRequirement( GenericSignatureBuilder &builder, Type dependentType, ProtocolDecl *protocol, bool inferred, GenericSignatureBuilder::WrittenRequirementLoc writtenLoc) const { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, inferred ? InferredProtocolRequirement : ProtocolRequirement, this, dependentType.getPointer(), protocol, writtenLoc.getOpaqueValue()), (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, WrittenRequirementLoc()); } const RequirementSource *RequirementSource::viaConcrete( GenericSignatureBuilder &builder, ProtocolConformanceRef conformance) const { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, Concrete, this, conformance.getOpaqueValue(), nullptr, nullptr), (Concrete, this, conformance), 0, WrittenRequirementLoc()); } 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, WrittenRequirementLoc()); } const RequirementSource *RequirementSource::viaParent( GenericSignatureBuilder &builder, AssociatedTypeDecl *assocType) const { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, Parent, this, assocType, nullptr, nullptr), (Parent, this, assocType), 0, WrittenRequirementLoc()); } const RequirementSource *RequirementSource::viaLayout( GenericSignatureBuilder &builder, Type superclass) const { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, Layout, this, superclass.getPointer(), nullptr, nullptr), (Layout, this, superclass), 0, WrittenRequirementLoc()); } const RequirementSource *RequirementSource::viaEquivalentType( GenericSignatureBuilder &builder, Type newType) const { REQUIREMENT_SOURCE_FACTORY_BODY( (nodeID, EquivalentType, this, newType.getPointer(), nullptr, nullptr), (EquivalentType, this, newType), 0, WrittenRequirementLoc()); } #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, getWrittenRequirementLoc()); case InferredProtocolRequirement: return parent->withoutRedundantSubpath(builder, start, end) ->viaProtocolRequirement(builder, getStoredType(), getProtocolDecl(), /*inferred=*/true, getWrittenRequirementLoc()); 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(); if (auto typeRepr = getTypeRepr()) return typeRepr->getStartLoc(); if (auto requirementRepr = getRequirementRepr()) return requirementRepr->getSeparatorLoc(); 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 (getTypeRepr() || getRequirementRepr()) { dumpSourceLoc(getLoc()); } } /// 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 storage.get(); case Explicit: { auto depType = type.getDependentType(builder); if (auto requirementRepr = storage.dyn_cast()) return RequirementSource::forExplicit(builder, depType, requirementRepr); if (auto typeRepr = storage.dyn_cast()) return RequirementSource::forExplicit(builder, depType, typeRepr); return RequirementSource::forAbstract(builder, depType); } case Inferred: { auto depType = type.getDependentType(builder); return RequirementSource::forInferred(builder, depType, storage.get()); } case AbstractProtocol: { 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 baseSource = storage.get(); auto baseSourceType = baseSource->getAffectedType(); auto dependentType = formProtocolRelativeType(protocolReq.protocol, baseSourceType, depType); return storage.get() ->viaProtocolRequirement(builder, dependentType, protocolReq.protocol, protocolReq.inferred, protocolReq.written); } case NestedTypeNameMatch: { auto depType = type.getDependentType(builder); return RequirementSource::forNestedTypeNameMatch(builder, depType); } } llvm_unreachable("Unhandled FloatingPointRequirementSourceKind in switch."); } SourceLoc FloatingRequirementSource::getLoc() const { // For an explicit abstract protocol source, we can get a more accurate source // location from the written protocol requirement. if (kind == Kind::AbstractProtocol && isExplicit()) { auto written = protocolReq.written; if (auto typeRepr = written.dyn_cast()) return typeRepr->getLoc(); if (auto requirementRepr = written.dyn_cast()) return requirementRepr->getSeparatorLoc(); } if (auto source = storage.dyn_cast()) return source->getLoc(); if (auto typeRepr = storage.dyn_cast()) return typeRepr->getLoc(); if (auto requirementRepr = storage.dyn_cast()) return requirementRepr->getSeparatorLoc(); return SourceLoc(); } bool FloatingRequirementSource::isDerived() const { switch (kind) { case Explicit: case Inferred: case NestedTypeNameMatch: return false; case AbstractProtocol: switch (storage.get()->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 storage.get()->isDerivedRequirement(); } llvm_unreachable("unhandled kind"); } bool FloatingRequirementSource::isExplicit() const { switch (kind) { case Explicit: return true; case Inferred: case NestedTypeNameMatch: return false; case AbstractProtocol: // 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 (storage.get()->kind) { case RequirementSource::RequirementSignatureSelf: return !protocolReq.inferred; 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 Resolved: switch (storage.get()->kind) { case RequirementSource::Explicit: return true; case RequirementSource::ProtocolRequirement: return storage.get()->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 { switch (kind) { case Explicit: return forInferred(typeRepr); case Inferred: case Resolved: case NestedTypeNameMatch: return *this; case AbstractProtocol: return viaProtocolRequirement(storage.get(), protocolReq.protocol, typeRepr, /*inferred=*/true); } llvm_unreachable("unhandled kind"); } bool FloatingRequirementSource::isRecursive( GenericSignatureBuilder &builder) const { llvm::SmallSet, 32> visitedAssocReqs; for (auto storedSource = storage.dyn_cast(); 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. if (!builder.resolveConcreteConformance(type, proto)) { // Otherwise, determine whether there is a superclass constraint where the // superclass conforms to this protocol. (void)builder.resolveSuperConformance(type, proto); } } // 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; } /// Compare two associated types. static int compareAssociatedTypes(AssociatedTypeDecl *assocType1, AssociatedTypeDecl *assocType2) { // - by name. if (int result = assocType1->getName().str().compare( assocType2->getName().str())) return result; // Prefer an associated type with no overrides (i.e., an anchor) to one // that has overrides. bool hasOverridden1 = !assocType1->getOverriddenDecls().empty(); bool hasOverridden2 = !assocType2->getOverriddenDecls().empty(); if (hasOverridden1 != hasOverridden2) return hasOverridden1 ? +1 : -1; // - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q) auto proto1 = assocType1->getProtocol(); auto proto2 = assocType2->getProtocol(); if (int compareProtocols = TypeDecl::compare(proto1, proto2)) return compareProtocols; // Error case: if we have two associated types with the same name in the // same protocol, just tie-break based on address. if (assocType1 != assocType2) return assocType1 < assocType2 ? -1 : +1; return 0; } 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 auto 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, SmallVectorImpl *otherConcreteTypes) { // Populates the result structures from the given cache entry. auto populateResult = [&](const CachedNestedType &cache) -> TypeDecl * { if (otherConcreteTypes) otherConcreteTypes->clear(); // If there aren't any types in the cache, we're done. if (cache.types.empty()) return nullptr; // The first type in the cache is always the final result. // Collect the rest in the concrete-declarations list, if needed. if (otherConcreteTypes) { for (auto type : ArrayRef(cache.types).slice(1)) { otherConcreteTypes->push_back(type); } } return cache.types.front(); }; // 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())) { ++NumNestedTypeCacheHits; return populateResult(cached->second); } // 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(); if (bestAssocType) { entry.types.push_back(bestAssocType); entry.types.insert(entry.types.end(), concreteDecls.begin(), concreteDecls.end()); assert(bestAssocType->getOverriddenDecls().empty() && "Lookup should never keep a non-anchor associated type"); } else if (!concreteDecls.empty()) { // Find the best concrete type. auto bestConcreteTypeIter = findBestConcreteNestedType(concreteDecls); // Put the best concrete type first; the rest will follow. entry.types.push_back(*bestConcreteTypeIter); entry.types.insert(entry.types.end(), concreteDecls.begin(), bestConcreteTypeIter); entry.types.insert(entry.types.end(), bestConcreteTypeIter + 1, concreteDecls.end()); } return populateResult((nestedTypeNameCache[name] = std::move(entry))); } 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(); } Type EquivalenceClass::getTypeInContext(GenericSignatureBuilder &builder, GenericEnvironment *genericEnv) { auto genericParams = genericEnv->getGenericParams(); // The anchor descr Type anchor = getAnchor(builder, genericParams); // If this equivalence class is mapped to a concrete type, produce that // type. if (concreteType) { if (recursiveConcreteType) return ErrorType::get(anchor); // Prevent recursive substitution. this->recursiveConcreteType = true; SWIFT_DEFER { this->recursiveConcreteType = false; }; return genericEnv->mapTypeIntoContext(concreteType, builder.getLookupConformanceFn()); } // Local function to check whether we have a generic parameter that has // already been recorded auto getAlreadyRecoveredGenericParam = [&]() -> Type { auto genericParam = anchor->getAs(); if (!genericParam) return Type(); auto type = genericEnv->getMappingIfPresent(genericParam); if (!type) return Type(); // We already have a mapping for this generic parameter in the generic // environment. Return it. return *type; }; AssociatedTypeDecl *assocType = nullptr; ArchetypeType *parentArchetype = nullptr; if (auto depMemTy = anchor->getAs()) { // Resolve the equivalence class of the parent. auto parentEquivClass = builder.resolveEquivalenceClass( depMemTy->getBase(), ArchetypeResolutionKind::CompleteWellFormed); if (!parentEquivClass) return ErrorType::get(anchor); // Map the parent type into this context. parentArchetype = parentEquivClass->getTypeInContext(builder, genericEnv) ->castTo(); // If we already have a nested type with this name, return it. assocType = depMemTy->getAssocType(); if (auto nested = parentArchetype->getNestedTypeIfKnown(assocType->getName())) { return *nested; } // We will build the archetype below. } else if (auto result = getAlreadyRecoveredGenericParam()) { // Return already-contextualized generic type parameter. return result; } // Substitute into the superclass. Type superclass = this->recursiveSuperclassType ? Type() : this->superclass; if (superclass && superclass->hasTypeParameter()) { // Prevent recursive substitution. this->recursiveSuperclassType = true; SWIFT_DEFER { this->recursiveSuperclassType = false; }; superclass = genericEnv->mapTypeIntoContext( superclass, builder.getLookupConformanceFn()); if (superclass->is()) superclass = Type(); // We might have recursively recorded the archetype; if so, return early. // FIXME: This should be detectable before we end up building archetypes. if (auto result = getAlreadyRecoveredGenericParam()) return result; } // Build a new archetype. // Collect the protocol conformances for the archetype. SmallVector protos; for (const auto &conforms : conformsTo) { auto proto = conforms.first; if (!isConformanceSatisfiedBySuperclass(proto)) protos.push_back(proto); } ArchetypeType *archetype; ASTContext &ctx = builder.getASTContext(); if (parentArchetype) { // Create a nested archetype. auto *depMemTy = anchor->castTo(); archetype = NestedArchetypeType::getNew(ctx, parentArchetype, depMemTy, protos, superclass, layout); // Register this archetype with its parent. parentArchetype->registerNestedType(assocType->getName(), archetype); } else { // Create a top-level archetype. auto genericParam = anchor->castTo(); archetype = PrimaryArchetypeType::getNew(ctx, genericEnv, genericParam, protos, superclass, layout); // Register the archetype with the generic environment. genericEnv->addMapping(genericParam, archetype); } return archetype; } void EquivalenceClass::dump(llvm::raw_ostream &out, GenericSignatureBuilder *builder) const { 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) { constraint.source->dump(out, &builder->getASTContext().SourceMgr, 4); if (constraint.source->isDerivedRequirement()) out << " [derived]"; out << "\n"; } } out << "Same-type constraints:\n"; for (auto constraint : sameTypeConstraints) { out << " " << constraint.getSubjectDependentType({}) << " == " << constraint.value << "\n"; constraint.source->dump(out, &builder->getASTContext().SourceMgr, 4); if (constraint.source->isDerivedRequirement()) out << " [derived]"; out << "\n"; } if (concreteType) out << "Concrete type: " << concreteType.getString() << "\n"; if (superclass) out << "Superclass: " << superclass.getString() << "\n"; if (layout) out << "Layout: " << layout.getString() << "\n"; 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"); } bool GenericSignatureBuilder::addConditionalRequirements( ProtocolConformanceRef conformance, ModuleDecl *inferForModule, SourceLoc loc) { // Abstract conformances don't have associated decl-contexts/modules, but also // don't have conditional requirements. if (conformance.isConcrete()) { if (auto condReqs = conformance.getConditionalRequirementsIfAvailable()) { auto source = FloatingRequirementSource::forInferred(nullptr); for (auto requirement : *condReqs) { addRequirement(requirement, source, inferForModule); ++NumConditionalRequirementsAdded; } } else { if (loc.isValid()) Diags.diagnose(loc, diag::unsupported_recursive_requirements); Impl->HadAnyError = true; return true; } } return false; } const RequirementSource * GenericSignatureBuilder::resolveConcreteConformance(ResolvedType type, ProtocolDecl *proto) { 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(type.getDependentType(), 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 hasExplicitSource = llvm::any_of( equivClass->concreteTypeConstraints, [](const ConcreteConstraint &constraint) { return (!constraint.source->isDerivedRequirement() && constraint.source->getLoc().isValid()); }); if (hasExplicitSource) { if (addConditionalRequirements(conformance, /*inferForModule=*/nullptr, concreteSource->getLoc())) return nullptr; } } return concreteSource; } const RequirementSource *GenericSignatureBuilder::resolveSuperConformance( ResolvedType type, ProtocolDecl *proto) { // 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(type.getDependentType(), 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 hasExplicitSource = llvm::any_of( equivClass->superclassConstraints, [](const ConcreteConstraint &constraint) { return (!constraint.source->isDerivedRequirement() && constraint.source->getLoc().isValid()); }); if (hasExplicitSource) { if (addConditionalRequirements(conformance, /*inferForModule=*/nullptr, superclassSource->getLoc())) return 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; } /// Canonical ordering for dependent types. int swift::compareDependentTypes(Type type1, Type type2) { // Fast-path check for equality. if (type1->isEqual(type2)) return 0; // Ordering is as follows: // - Generic params auto gp1 = type1->getAs(); auto gp2 = type2->getAs(); if (gp1 && gp2) return GenericParamKey(gp1) < GenericParamKey(gp2) ? -1 : +1; // A generic parameter is always ordered before a nested type. if (static_cast(gp1) != static_cast(gp2)) return gp1 ? -1 : +1; // - Dependent members auto depMemTy1 = type1->castTo(); auto depMemTy2 = type2->castTo(); // - by base, so t_0_n.`P.T` < t_1_m.`P.T` if (int compareBases = compareDependentTypes(depMemTy1->getBase(), depMemTy2->getBase())) return compareBases; // - by name, so t_n_m.`P.T` < t_n_m.`P.U` if (int compareNames = depMemTy1->getName().str().compare( depMemTy2->getName().str())) return compareNames; auto *assocType1 = depMemTy1->getAssocType(); auto *assocType2 = depMemTy2->getAssocType(); if (int result = compareAssociatedTypes(assocType1, assocType2)) return result; return 0; } /// 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; } void ArchetypeType::resolveNestedType( std::pair &nested) const { auto genericEnv = getGenericEnvironment(); auto &builder = *genericEnv->getGenericSignatureBuilder(); Type interfaceType = getInterfaceType(); Type memberInterfaceType = DependentMemberType::get(interfaceType, nested.first); auto resolved = builder.maybeResolveEquivalenceClass( memberInterfaceType, ArchetypeResolutionKind::CompleteWellFormed, /*wantExactPotentialArchetype=*/false); if (!resolved) { nested.second = ErrorType::get(interfaceType); return; } Type result; if (auto concrete = resolved.getAsConcreteType()) { result = concrete; } else { auto *equivClass = resolved.getEquivalenceClass(builder); result = equivClass->getTypeInContext(builder, genericEnv); } assert(!nested.second || nested.second->isEqual(result) || (nested.second->hasError() && result->hasError())); nested.second = result; } 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.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()->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()->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->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) : Context(ctx), Diags(Context.Diags), Impl(new Implementation) { if (auto *Stats = Context.Stats) ++Stats->getFrontendCounters().NumGenericSignatureBuilders; } 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(dependentType, conformingReplacementType, conformedProtocol); } ProtocolConformanceRef GenericSignatureBuilder::lookupConformance(CanType dependentType, 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 = ArchetypeResolutionKind::WellFormed) { 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.getEquivalenceClass(builder); if (!equivClass) return ErrorType::get(Type(type)); // If there is a concrete type in this equivalence class, use that. if (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 equivClass->getAnchor(builder, builder.getGenericParams()); }); } 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); 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); auto bestConcreteTypeIter = findBestConcreteNestedType(concreteDecls); concreteDecl = *bestConcreteTypeIter; } } 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(type->getCanonicalType(), baseEquivClass->concreteType, proto)) { // Fall through } else if (baseEquivClass->superclass && lookupConformance(type->getCanonicalType(), 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(type->getCanonicalType(), baseEquivClass->concreteType, proto)) { parentType = baseEquivClass->concreteType; } else if (baseEquivClass->superclass && lookupConformance(type->getCanonicalType(), 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.isExplicit() && 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); } 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; assert(params.empty() || ((GenericParam->getDepth() == params.back()->getDepth() && GenericParam->getIndex() == params.back()->getIndex() + 1) || (GenericParam->getDepth() > params.back()->getDepth() && GenericParam->getIndex() == 0))); // 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)); // 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)) return reqResult; } return ConstraintResult::Resolved; } if (!onlySameTypeConstraints) { // Add all of the inherited protocol requirements, recursively. auto inheritedReqResult = addInheritedRequirements(proto, selfType.getUnresolvedType(), source, proto->getModuleContext()); if (isErrorResult(inheritedReqResult)) return 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, /*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 ConstraintResult::Resolved; } // 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, WrittenRequirementLoc(), /*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) { auto assocResult = addInheritedRequirements(assocTypeDecl, assocType, source, /*inferForModule=*/nullptr); if (isErrorResult(assocResult)) return 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, /*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 ConstraintResult::Resolved; } ConstraintResult GenericSignatureBuilder::addConformanceRequirement( ResolvedType type, ProtocolDecl *proto, FloatingRequirementSource source) { auto resolvedSource = source.getSource(*this, type); // 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 equivClass = type.getEquivalenceClass(*this); // Update the layout in the equivalence class, if we didn't have one already. bool anyChanges = false; if (!equivClass->layout) { equivClass->layout = layout; anyChanges = true; } else { // Try to merge layout constraints. auto mergedLayout = equivClass->layout.merge(layout); if (mergedLayout->isKnownLayout() && mergedLayout != equivClass->layout) { equivClass->layout = mergedLayout; anyChanges = true; } } // Record this layout constraint. equivClass->layoutConstraints.push_back({type.getUnresolvedType(), layout, source.getSource(*this, type)}); 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) { (void)resolveSuperConformance(type, conforms.first); } // 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()->isObjC() ? LayoutConstraintKind::Class : LayoutConstraintKind::NativeClass, 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; } ConstraintResult GenericSignatureBuilder::addSuperclassRequirementDirect( ResolvedType type, Type superclass, FloatingRequirementSource source) { auto resolvedSource = source.getSource(*this, type); // 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()) { if (addConditionalRequirements(conformance, inferForModule, source.getLoc())) return ConstraintResult::Conflicting; } } } } // 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); // 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()); } // 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 { const RequirementSource *source2 = equivClass2->layoutConstraints.front().source; addLayoutRequirementDirect(T1, equivClass2->layout, source2); equivClass->layoutConstraints.insert( equivClass->layoutConstraints.end(), equivClass2->layoutConstraints.begin() + 1, 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) { 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) { if (!resolveConcreteConformance(type, conforms.first)) 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()) { 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) { if (parentSource) { if (auto assocType = dyn_cast(decl)) { auto proto = assocType->getProtocol(); return FloatingRequirementSource::viaProtocolRequirement( parentSource, proto, typeRepr, forInferred); } auto proto = cast(decl); return FloatingRequirementSource::viaProtocolRequirement( parentSource, proto, typeRepr, forInferred); } // We are inferring requirements. if (forInferred) { return FloatingRequirementSource::forInferred(typeRepr); } // Explicit requirement. if (typeRepr) return FloatingRequirementSource::forExplicit(typeRepr); // An abstract explicit requirement. return FloatingRequirementSource::forAbstract(); }; 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()) { 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 genericSig = decl->getGenericSignature(); if (!genericSig) return Action::Continue; auto subMap = TypeAlias->getSubstitutionMap(); for (const auto &rawReq : genericSig->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(CanType(), 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())); } } 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::fromExplicitConstraint( kind, constraint))); bool representativeIsNonRedundantExplicit = (!representativeConstraint->source->isDerivedNonRootRequirement() && !builder.isRedundantExplicitRequirement( ExplicitRequirement::fromExplicitConstraint( kind, *representativeConstraint))); 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) { if (constraint.source->getAffectedType()->isEqual(dependentType)) { alreadyFound = true; break; } // Capture the source for later use, skipping if (!conformsSource && constraint.source->kind != RequirementSource::RequirementSignatureSelf) conformsSource = constraint.source; } 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); } } } /// A directed graph where the vertices are explicit requirement sources and /// an edge (v, w) records that the explicit source v implies the explicit /// source w. /// /// The roots of the strongly connected component graph are the basic set of /// explicit requirements which imply everything else. We pick the best /// representative from each root strongly connected component to form the /// final set of non-redundant explicit requirements. class RedundantRequirementGraph { /// 2**16 explicit requirements ought to be enough for everybody. using VertexID = uint16_t; using ComponentID = uint16_t; struct Vertex { ExplicitRequirement req; explicit Vertex(ExplicitRequirement req) : req(req) {} /// The SCC that this vertex belongs to. ComponentID component = UndefinedComponent; /// State for the SCC algorithm. VertexID index = UndefinedIndex; VertexID lowLink = -1; bool onStack = false; /// Outgoing edges. SmallVector successors; #ifndef NDEBUG bool sawVertex = false; #endif static const ComponentID UndefinedComponent = -1; static const VertexID UndefinedIndex = -1; }; /// Maps each requirement source to a unique 16-bit ID. llvm::SmallDenseMap reqs; SmallVector vertices; ComponentID componentCount = 0; VertexID vertexCount = 0; SmallVector stack; public: template void addConstraintsFromEquivClass( GenericSignatureBuilder &builder, const std::vector> &constraints, RequirementKind kind, Fn filter) { // The set of 'redundant explicit requirements', which are known to be less // specific than some other explicit requirements. An example is a type // parameter with multiple superclass constraints: // // class A {} // class B : A {} // class C : B {} // // func f(_: T) where T : A, T : B, T : C {} // // 'T : C' supercedes 'T : A' and 'T : B', because C is a subclass of // 'A' and 'B'. SmallVector redundantExplicitReqs; // The set of all other explicit requirements, which are known to be the most // specific. These imply the less specific 'redundant explicit sources' // above. // // Also, if there is more than one most specific explicit requirements, they // all imply each other. SmallVector explicitReqs; // The set of root explicit requirements for each derived requirements. // // These 'root requirements' imply the 'explicit requirements'. SmallVector rootReqs; for (auto constraint : constraints) { auto *source = constraint.source; if (source->isDerivedNonRootRequirement()) { // If the derived requirement was filtered by our predicate, it doesn't // make our explicit requirements redundant. if (filter(constraint)) continue; auto req = ExplicitRequirement::fromDerivedConstraint(kind, constraint); rootReqs.push_back(req); } else { auto req = ExplicitRequirement::fromExplicitConstraint(kind, constraint); VertexID v = addVertex(req); #ifndef NDEBUG // Record that we saw an actual explicit requirement rooted at this vertex, // for verification purposes. vertices[v].sawVertex = true; #endif (void) v; // If the explicit requirement was filtered by our predicate, it doesn't // make the other explicit requirements redundant. if (filter(constraint)) { redundantExplicitReqs.push_back(req); } else { explicitReqs.push_back(req); } } } // If all requirements are derived, there is nothing to do. if (explicitReqs.empty()) { if (!redundantExplicitReqs.empty()) { assert(!rootReqs.empty()); for (auto rootReq : rootReqs) { for (auto redundantReq : redundantExplicitReqs) { addEdge(rootReq, redundantReq); } } } return; } // If there are multiple most specific explicit requirements, they will form a cycle. if (explicitReqs.size() > 1) { for (unsigned index : indices(explicitReqs)) { auto firstReq = explicitReqs[index]; auto secondReq = explicitReqs[(index + 1) % explicitReqs.size()]; addEdge(firstReq, secondReq); } } // The cycle of most specific explicit requirements implies all less specific // explicit requirements. for (auto redundantReq : redundantExplicitReqs) { addEdge(explicitReqs[0], redundantReq); } // The root explicit requirement of each derived requirement implies the cycle of // most specific explicit requirements. for (auto rootReq : rootReqs) { addEdge(rootReq, explicitReqs[0]); } } private: /// If we haven't seen this requirement yet, add it and /// return a new ID. Otherwise, return an existing ID. VertexID addVertex(ExplicitRequirement req) { assert(!req.getSource()->isDerivedNonRootRequirement()); VertexID id = vertices.size(); // Check for wrap-around. if (id != vertices.size()) { llvm::errs() << "Too many explicit requirements"; abort(); } assert(reqs.size() == vertices.size()); auto inserted = reqs.insert(std::make_pair(req, id)); // Check if we've already seen this vertex. if (!inserted.second) return inserted.first->second; vertices.emplace_back(req); return id; } /// Add a directed edge from one requirement to another. /// If we haven't seen either requirement yet, we add a /// new vertex; this allows visiting equivalence classes in /// a single pass, without having to build the set of vertices /// first. void addEdge(ExplicitRequirement fromReq, ExplicitRequirement toReq) { assert(!fromReq.getSource()->isDerivedNonRootRequirement()); assert(!toReq.getSource()->isDerivedNonRootRequirement()); VertexID from = addVertex(fromReq); VertexID to = addVertex(toReq); vertices[from].successors.push_back(to); } /// Tarjan's algorithm. void computeSCCs() { for (VertexID v : indices(vertices)) { if (vertices[v].index == Vertex::UndefinedIndex) strongConnect(v); } } void strongConnect(VertexID v) { // Set the depth index for v to the smallest unused index. assert(vertices[v].index == Vertex::UndefinedIndex); vertices[v].index = vertexCount; assert(vertices[v].lowLink == Vertex::UndefinedIndex); vertices[v].lowLink = vertexCount; vertexCount++; stack.push_back(v); assert(!vertices[v].onStack); vertices[v].onStack = true; // Consider successors of v. for (VertexID w : vertices[v].successors) { if (vertices[w].index == Vertex::UndefinedIndex) { // Successor w has not yet been visited; recurse on it. strongConnect(w); assert(vertices[w].lowLink != Vertex::UndefinedIndex); vertices[v].lowLink = std::min(vertices[v].lowLink, vertices[w].lowLink); } else if (vertices[w].onStack) { // Successor w is in stack S and hence in the current SCC. // // If w is not on stack, then (v, w) is an edge pointing // to an SCC already found and must be ignored. assert(vertices[w].lowLink != Vertex::UndefinedIndex); vertices[v].lowLink = std::min(vertices[v].lowLink, vertices[w].index); } } // If v is a root node, pop the stack and generate an SCC. if (vertices[v].lowLink == vertices[v].index) { VertexID w = Vertex::UndefinedIndex; do { w = stack.back(); assert(vertices[w].onStack); stack.pop_back(); vertices[w].onStack = false; assert(vertices[w].component == Vertex::UndefinedComponent); vertices[w].component = componentCount; } while (v != w); componentCount++; } } public: using RedundantRequirementMap = llvm::DenseMap>; void computeRedundantRequirements(SourceManager &SM, RedundantRequirementMap &redundant) { // First, compute SCCs. computeSCCs(); // The set of edges pointing to each connected component. SmallVector, 2> inboundComponentEdges; inboundComponentEdges.resize(componentCount); // The set of edges originating from this connected component. SmallVector, 2> outboundComponentEdges; outboundComponentEdges.resize(componentCount); // Visit all vertices and build the adjacency sets for the connected // component graph. for (const auto &vertex : vertices) { assert(vertex.component != Vertex::UndefinedComponent); for (auto successor : vertex.successors) { ComponentID otherComponent = vertices[successor].component; if (vertex.component != otherComponent) { inboundComponentEdges[otherComponent].push_back(vertex.component); outboundComponentEdges[vertex.component].push_back(otherComponent); } } } auto isRootComponent = [&](ComponentID component) -> bool { return inboundComponentEdges[component].empty(); }; // The set of root components. llvm::SmallDenseSet rootComponents; // The best explicit requirement for each root component. SmallVector, 2> bestExplicitReq; bestExplicitReq.resize(componentCount); // Visit all vertices and find the best requirement for each root component. for (const auto &vertex : vertices) { if (isRootComponent(vertex.component)) { rootComponents.insert(vertex.component); // If this vertex is part of a root SCC, see if the requirement is // better than the one we have so far. auto &best = bestExplicitReq[vertex.component]; if (isBetterExplicitRequirement(SM, best, vertex.req)) best = vertex.req; } } // The set of root components that each component is reachable from. SmallVector, 2> reachableFromRoot; reachableFromRoot.resize(componentCount); // Traverse the graph of connected components starting from the roots. for (auto rootComponent : rootComponents) { SmallVector worklist; auto addToWorklist = [&](ComponentID nextComponent) { if (!reachableFromRoot[nextComponent].count(rootComponent)) worklist.push_back(nextComponent); }; addToWorklist(rootComponent); while (!worklist.empty()) { auto component = worklist.back(); worklist.pop_back(); reachableFromRoot[component].insert(rootComponent); for (auto nextComponent : outboundComponentEdges[component]) addToWorklist(nextComponent); } } // Compute the mapping of redundant requirements to the best root // requirement that implies them. for (const auto &vertex : vertices) { if (isRootComponent(vertex.component)) { // A root component is reachable from itself, and itself only. assert(reachableFromRoot[vertex.component].size() == 1); assert(reachableFromRoot[vertex.component].count(vertex.component) == 1); } else { assert(!bestExplicitReq[vertex.component].hasValue() && "Recorded best requirement for non-root SCC?"); } // We have a non-root component. This requirement is always // redundant. auto reachableFromRootSet = reachableFromRoot[vertex.component]; assert(reachableFromRootSet.size() > 0); for (auto rootComponent : reachableFromRootSet) { assert(isRootComponent(rootComponent)); auto best = bestExplicitReq[rootComponent]; assert(best.hasValue() && "Did not record best requirement for root SCC?"); assert(vertex.req != *best || vertex.component == rootComponent); if (vertex.req != *best) { redundant[vertex.req].insert(*best); } } } } private: bool isBetterExplicitRequirement(SourceManager &SM, Optional optExisting, ExplicitRequirement current) { if (!optExisting.hasValue()) return true; auto existing = *optExisting; auto *existingSource = existing.getSource(); auto *currentSource = current.getSource(); // Prefer explicit sources over inferred ones, so that you can // write either of the following without a warning: // // func foo(_: Set) {} // func foo(_: Set) {} bool existingInferred = existingSource->isInferredRequirement(); bool currentInferred = currentSource->isInferredRequirement(); if (existingInferred != currentInferred) return currentInferred; // Prefer a RequirementSignatureSelf over anything else. if ((currentSource->kind == RequirementSource::RequirementSignatureSelf) || (existingSource->kind == RequirementSource::RequirementSignatureSelf)) return (currentSource->kind == RequirementSource::RequirementSignatureSelf); // Prefer sources with a shorter type. auto existingType = existingSource->getStoredType(); auto currentType = currentSource->getStoredType(); int cmpTypes = compareDependentTypes(currentType, existingType); if (cmpTypes != 0) return cmpTypes < 0; // Prefer source-location-based over abstract. auto existingLoc = existingSource->getLoc(); auto currentLoc = currentSource->getLoc(); if (existingLoc.isValid() != currentLoc.isValid()) return currentLoc.isValid(); if (existingLoc.isValid() && currentLoc.isValid()) { unsigned existingBuffer = SM.findBufferContainingLoc(existingLoc); unsigned currentBuffer = SM.findBufferContainingLoc(currentLoc); // If the buffers are the same, use source location ordering. if (existingBuffer == currentBuffer) { if (SM.isBeforeInBuffer(currentLoc, existingLoc)) return true; } else { // Otherwise, order by buffer identifier. if (SM.getIdentifierForBuffer(currentBuffer) .compare(SM.getIdentifierForBuffer(existingBuffer))) return true; } } return true; } public: void dump(llvm::raw_ostream &out, SourceManager *SM) const { out << "* Vertices:\n"; for (const auto &vertex : vertices) { out << "Component " << vertex.component << ", "; vertex.req.dump(out, SM); out << "\n"; } out << "* Edges:\n"; for (const auto &from : vertices) { for (VertexID w : from.successors) { const auto &to = vertices[w]; from.req.dump(out, SM); out << " -> "; to.req.dump(out, SM); out << "\n"; } } } #ifndef NDEBUG void verifyAllVerticesWereSeen(SourceManager *SM) const { for (const auto &vertex : vertices) { if (!vertex.sawVertex) { // We found a vertex that was referenced by an edge, but was // never added explicitly. This means we have a derived // requirement rooted at the source, but we never saw the // corresponding explicit requirement. This should not happen. llvm::errs() << "Found an orphaned vertex:\n"; vertex.req.dump(llvm::errs(), SM); llvm::errs() << "\nRedundant requirement graph:\n"; dump(llvm::errs(), SM); abort(); } } } #endif }; 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; } getSource()->dump(out, SM, 0); out << " : "; if (auto type = rhs.dyn_cast()) out << type; else if (auto *proto = rhs.dyn_cast()) out << proto->getName(); else out << rhs.get(); } void GenericSignatureBuilder::computeRedundantRequirements() { assert(!Impl->computedRedundantRequirements && "Already computed redundant requirements"); #ifndef NDEBUG Impl->computedRedundantRequirements = true; #endif RedundantRequirementGraph graph; // Visit each equivalence class, recording all explicit requirement sources, // and the root of each derived requirement source that implies an explicit // source. for (auto &equivClass : Impl->EquivalenceClasses) { for (auto &entry : equivClass.conformsTo) { graph.addConstraintsFromEquivClass( *this, entry.second, RequirementKind::Conformance, [&](Constraint constraint) -> bool { auto *source = constraint.source; bool derivedViaConcrete = false; if (source->getMinimalConformanceSource( *this, constraint.getSubjectDependentType({ }), entry.first, derivedViaConcrete) != source) return true; if (derivedViaConcrete) return true; return false; }); } if (equivClass.concreteType) { Type resolvedConcreteType = resolveDependentMemberTypes(*this, equivClass.concreteType); graph.addConstraintsFromEquivClass( *this, equivClass.concreteTypeConstraints, RequirementKind::SameType, [&](Constraint constraint) -> bool { auto *source = constraint.source; Type t = constraint.value; bool derivedViaConcrete = false; if (source->getMinimalConformanceSource( *this, constraint.getSubjectDependentType({ }), nullptr, derivedViaConcrete) != source) return true; if (derivedViaConcrete) return true; if (t->isEqual(resolvedConcreteType)) return false; auto resolvedType = resolveDependentMemberTypes(*this, t); if (resolvedType->isEqual(resolvedConcreteType)) return false; // We have a less-specific constraint. return true; }); } if (equivClass.superclass) { // Resolve any thus-far-unresolved dependent types. Type resolvedSuperclass = resolveDependentMemberTypes(*this, equivClass.superclass); graph.addConstraintsFromEquivClass( *this, equivClass.superclassConstraints, RequirementKind::Superclass, [&](Constraint constraint) -> bool { auto *source = constraint.source; Type t = constraint.value; bool derivedViaConcrete = false; if (source->getMinimalConformanceSource( *this, constraint.getSubjectDependentType({ }), nullptr, derivedViaConcrete) != source) return true; if (derivedViaConcrete) return true; if (t->isEqual(resolvedSuperclass)) return false; Type resolvedType = resolveDependentMemberTypes(*this, t); if (resolvedType->isEqual(resolvedSuperclass)) return false; // We have a less-specific constraint. return true; }); } if (equivClass.layout) { graph.addConstraintsFromEquivClass( *this, equivClass.layoutConstraints, RequirementKind::Layout, [&](Constraint constraint) -> bool { auto *source = constraint.source; auto layout = constraint.value; bool derivedViaConcrete = false; if (source->getMinimalConformanceSource( *this, constraint.getSubjectDependentType({ }), nullptr, derivedViaConcrete) != source) return true; if (derivedViaConcrete) return true; return layout != equivClass.layout; }); } } auto &SM = getASTContext().SourceMgr; #ifndef NDEBUG graph.verifyAllVerticesWereSeen(&SM); #endif // Determine which explicit requirement sources are actually redundant. assert(Impl->RedundantRequirements.empty()); graph.computeRedundantRequirements(SM, Impl->RedundantRequirements); } void GenericSignatureBuilder::finalize(TypeArrayView genericParams, bool allowConcreteGenericParams) { // Process any delayed requirements that we can handle now. processDelayedRequirements(); computeRedundantRequirements(); 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; } else { checkSuperclassConstraints(genericParams, &equivClass); } } checkConformanceConstraints(genericParams, &equivClass); checkLayoutConstraints(genericParams, &equivClass); }; // 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); } 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) { return checkConstraintList(genericParams, constraints, kind, isSuitableRepresentative, checkConstraint, conflictingDiag, redundancyDiag, otherNoteDiag, [](const T& value) { return value; }, /*removeSelfDerived=*/true); } namespace { /// Remove self-derived sources from the given vector of constraints. /// /// \returns true if any derived-via-concrete constraints were found. template bool removeSelfDerived(GenericSignatureBuilder &builder, std::vector> &constraints, ProtocolDecl *proto, bool dropDerivedViaConcrete = true, bool allCanBeSelfDerived = false) { auto genericParams = builder.getGenericParams(); bool anyDerivedViaConcrete = false; Optional> remainingConcrete; SmallVector, 4> minimalSources; constraints.erase( std::remove_if(constraints.begin(), constraints.end(), [&](const Constraint &constraint) { bool derivedViaConcrete; auto minimalSource = constraint.source->getMinimalConformanceSource( builder, constraint.getSubjectDependentType(genericParams), proto, derivedViaConcrete); 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; } if (!derivedViaConcrete) return false; anyDerivedViaConcrete = true; if (!dropDerivedViaConcrete) return false; // Drop derived-via-concrete requirements. if (!remainingConcrete) remainingConcrete = constraint; ++NumSelfDerived; return true; }), 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); } } } // If we only had concrete conformances, put one back. if (constraints.empty() && remainingConcrete) constraints.push_back(*remainingConcrete); assert((!constraints.empty() || allCanBeSelfDerived) && "All constraints were self-derived!"); return anyDerivedViaConcrete; } } // 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, llvm::function_ref diagValue, bool removeSelfDerived) { assert(!constraints.empty() && "No constraints?"); if (removeSelfDerived) { ::removeSelfDerived(*this, constraints, /*proto=*/nullptr); } // 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), diagValue(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, diagValue(constraint.value), diagValue(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, diagValue(representativeConstraint->value), diagValue(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), diagValue(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; } void GenericSignatureBuilder::checkConformanceConstraints( TypeArrayView genericParams, EquivalenceClass *equivClass) { for (auto &entry : equivClass->conformsTo) { // Remove self-derived constraints. assert(!entry.second.empty() && "No constraints to work with?"); // Remove any self-derived constraints. removeSelfDerived(*this, entry.second, entry.first); checkConstraintList( genericParams, entry.second, RequirementKind::Conformance, [](const Constraint &constraint) { return true; }, [&](const Constraint &constraint) { auto proto = constraint.value; assert(proto == entry.first && "Mixed up protocol constraints"); // If this conformance requirement recursively makes a protocol // conform to itself, don't complain here. auto source = constraint.source; auto rootSource = source->getRoot(); if (rootSource->kind == RequirementSource::RequirementSignatureSelf && source != rootSource && proto == rootSource->getProtocolDecl() && areInSameEquivalenceClass(rootSource->getRootType(), source->getAffectedType())) { return ConstraintRelation::Unrelated; } // If this is a redundantly inherited Objective-C protocol, treat it // as "unrelated" to silence the warning about the redundant // conformance. if (isRedundantlyInheritableObjCProtocol(proto, constraint.source)) return ConstraintRelation::Unrelated; return ConstraintRelation::Redundant; }, None, diag::redundant_conformance_constraint, diag::redundant_conformance_here, [](ProtocolDecl *proto) { return proto; }, /*removeSelfDerived=*/false); } } 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. bool derivedViaConcrete; if (concrete.source->isSelfDerivedSource(builder, subjectType, derivedViaConcrete)) 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; bool anyDerivedViaConcrete = false; // Remove self-derived constraints. if (removeSelfDerived(*this, equivClass->sameTypeConstraints, /*proto=*/nullptr, /*dropDerivedViaConcrete=*/false, /*allCanBeSelfDerived=*/true)) anyDerivedViaConcrete = 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)); } // If there were any derived-via-concrete constraints, drop them now before // we emit other diagnostics. if (anyDerivedViaConcrete) { // Remove derived-via-concrete constraints. (void)removeSelfDerived(*this, equivClass->sameTypeConstraints, /*proto=*/nullptr, /*dropDerivedViaConcrete=*/true, /*allCanBeSelfDerived=*/true); } // 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, [&](Type type) { return type; }, /*removeSelfDerived=*/false); } // 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 = resolveDependentMemberTypes(*this, equivClass->concreteType); checkConstraintList( genericParams, equivClass->concreteTypeConstraints, RequirementKind::SameType, [&](const ConcreteConstraint &constraint) { if (constraint.value->isEqual(resolvedConcreteType)) return true; auto resolvedType = resolveDependentMemberTypes(*this, 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); equivClass->concreteType = resolvedConcreteType; } void GenericSignatureBuilder::checkSuperclassConstraints( TypeArrayView genericParams, EquivalenceClass *equivClass) { assert(equivClass->superclass && "No superclass constraint?"); // Resolve any thus-far-unresolved dependent types. Type resolvedSuperclass = resolveDependentMemberTypes(*this, equivClass->superclass); auto representativeConstraint = checkConstraintList( genericParams, equivClass->superclassConstraints, RequirementKind::Superclass, [&](const ConcreteConstraint &constraint) { if (constraint.value->isEqual(resolvedSuperclass)) return true; Type resolvedType = resolveDependentMemberTypes(*this, constraint.value); return resolvedType->isEqual(resolvedSuperclass); }, [&](const Constraint &constraint) { Type superclass = constraint.value; // If this class is a superclass of the "best" if (superclass->isExactSuperclassOf(resolvedSuperclass)) return ConstraintRelation::Redundant; // Otherwise, it conflicts. return ConstraintRelation::Conflicting; }, diag::requires_superclass_conflict, diag::redundant_superclass_constraint, diag::superclass_redundancy_here); // Record the resolved superclass type. equivClass->superclass = resolvedSuperclass; // If we have a concrete type, check it. // FIXME: Substitute into the concrete type. if (equivClass->concreteType) { Type resolvedConcreteType = resolveDependentMemberTypes(*this, equivClass->concreteType); auto existing = equivClass->findAnyConcreteConstraintAsWritten(); // Make sure the concrete type fulfills the superclass requirement. if (!equivClass->superclass->isExactSuperclassOf(resolvedConcreteType)){ Impl->HadAnyError = true; if (existing) { Diags.diagnose(existing->source->getLoc(), diag::type_does_not_inherit, existing->getSubjectDependentType(getGenericParams()), existing->value, equivClass->superclass); if (representativeConstraint.source->getLoc().isValid()) { Diags.diagnose(representativeConstraint.source->getLoc(), diag::superclass_redundancy_here, representativeConstraint.source->classifyDiagKind(), representativeConstraint.getSubjectDependentType( genericParams), equivClass->superclass); } } else if (representativeConstraint.source->getLoc().isValid()) { Diags.diagnose(representativeConstraint.source->getLoc(), diag::type_does_not_inherit, representativeConstraint.getSubjectDependentType( genericParams), resolvedConcreteType, equivClass->superclass); } } else if (representativeConstraint.source->shouldDiagnoseRedundancy(true) && existing && existing->source->shouldDiagnoseRedundancy(false)) { // It does fulfill the requirement; diagnose the redundancy. Diags.diagnose(representativeConstraint.source->getLoc(), diag::redundant_superclass_constraint, representativeConstraint.getSubjectDependentType( genericParams), representativeConstraint.value); Diags.diagnose(existing->source->getLoc(), diag::same_type_redundancy_here, existing->source->classifyDiagKind(), existing->getSubjectDependentType(genericParams), existing->value); } } } void GenericSignatureBuilder::checkLayoutConstraints( TypeArrayView genericParams, EquivalenceClass *equivClass) { if (!equivClass->layout) return; checkConstraintList( genericParams, equivClass->layoutConstraints, RequirementKind::Layout, [&](const Constraint &constraint) { return constraint.value == equivClass->layout; }, [&](const Constraint &constraint) { auto layout = constraint.value; // If the layout constraints are mergable, i.e. compatible, // it is a redundancy. if (layout.merge(equivClass->layout)->isKnownLayout()) return ConstraintRelation::Redundant; return ConstraintRelation::Conflicting; }, diag::conflicting_layout_constraints, diag::redundant_layout_constraint, diag::previous_layout_constraint); } bool GenericSignatureBuilder::isRedundantExplicitRequirement( ExplicitRequirement req) const { assert(Impl->computedRedundantRequirements && "Must ensure computeRedundantRequirements() is called first"); auto &redundantReqs = Impl->RedundantRequirements; return (redundantReqs.find(req) != redundantReqs.end()); } namespace { template bool hasNonRedundantRequirementSource(ArrayRef> constraints, RequirementKind kind, GenericSignatureBuilder &builder) { for (auto constraint : constraints) { if (constraint.source->isDerivedRequirement()) continue; auto req = ExplicitRequirement::fromExplicitConstraint(kind, constraint); if (builder.isRedundantExplicitRequirement(req)) continue; return true; } return false; } using SameTypeComponentRef = std::pair; } // end anonymous namespace void GenericSignatureBuilder::enumerateRequirements( TypeArrayView genericParams, SmallVectorImpl &requirements) { auto recordRequirement = [&](RequirementKind kind, Type depTy, RequirementRHS rhs) { depTy = getSugaredDependentType(depTy, genericParams); if (auto type = rhs.dyn_cast()) { if (type->hasError()) return; // Drop requirements involving concrete types containing // unresolved associated types. if (type->findUnresolvedDependentMemberType()) { assert(Impl->HadAnyError); return; } if (type->isTypeParameter()) type = getSugaredDependentType(type, genericParams); requirements.push_back(Requirement(kind, depTy, type)); } else if (auto *proto = rhs.dyn_cast()) { auto type = proto->getDeclaredInterfaceType(); requirements.push_back(Requirement(kind, depTy, type)); } else { auto layoutConstraint = rhs.get(); requirements.push_back(Requirement(kind, depTy, layoutConstraint)); return; } }; // Collect all of the subject types that will be involved in constraints. SmallVector subjects; for (auto &equivClass : Impl->EquivalenceClasses) { if (equivClass.derivedSameTypeComponents.empty()) { checkSameTypeConstraints(getGenericParams(), &equivClass); } for (unsigned i : indices(equivClass.derivedSameTypeComponents)) subjects.push_back({&equivClass, i}); } for (const auto &subject : subjects) { // Dig out the subject type and its corresponding component. auto equivClass = subject.first; auto &component = equivClass->derivedSameTypeComponents[subject.second]; 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) { // 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; } std::function deferredSameTypeRequirement; // If we're at the last anchor in the component, do nothing; if (subject.second + 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[subject.second + 1]; Type otherSubjectType = nextComponent.type; deferredSameTypeRequirement = [&recordRequirement, subjectType, otherSubjectType] { recordRequirement(RequirementKind::SameType, subjectType, otherSubjectType); }; } SWIFT_DEFER { if (deferredSameTypeRequirement) deferredSameTypeRequirement(); }; // If this is not the first component anchor in its equivalence class, // we're done. if (subject.second > 0) continue; // If we have a superclass, produce a superclass requirement if (equivClass->superclass && !equivClass->recursiveSuperclassType && !equivClass->superclass->hasError()) { if (hasNonRedundantRequirementSource( equivClass->superclassConstraints, RequirementKind::Superclass, *this)) { recordRequirement(RequirementKind::Superclass, subjectType, equivClass->superclass); } } // If we have a layout constraint, produce a layout requirement. if (equivClass->layout) { if (hasNonRedundantRequirementSource( equivClass->layoutConstraints, RequirementKind::Layout, *this)) { recordRequirement(RequirementKind::Layout, subjectType, equivClass->layout); } } // Enumerate conformance requirements. SmallVector protocols; for (const auto &conforms : equivClass->conformsTo) { if (hasNonRedundantRequirementSource( conforms.second, RequirementKind::Conformance, *this)) { protocols.push_back(conforms.first); } } // Sort the protocols in canonical order. llvm::array_pod_sort(protocols.begin(), protocols.end(), TypeDecl::compare); // Enumerate the conformance requirements. for (auto proto : protocols) { recordRequirement(RequirementKind::Conformance, subjectType, proto); } } // Sort the subject types in canonical order. This needs to be a stable sort // so that the relative order of requirements that have the same subject type // is preserved. std::stable_sort(requirements.begin(), requirements.end(), [](const Requirement &lhs, const Requirement &rhs) { return compareDependentTypes(lhs.getFirstType(), rhs.getFirstType()) < 0; }); } 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) { if (!sig) return; for (auto param : sig->getGenericParams()) addGenericParameter(param); for (auto &reqt : sig->getRequirements()) addRequirement(reqt, FloatingRequirementSource::forAbstract(), nullptr); } #ifndef NDEBUG /// Determine the canonical ordering of requirements. static unsigned getRequirementKindOrder(RequirementKind kind) { switch (kind) { case RequirementKind::Conformance: return 2; case RequirementKind::Superclass: return 0; case RequirementKind::SameType: return 3; case RequirementKind::Layout: return 1; } llvm_unreachable("unhandled kind"); } static void checkGenericSignature(CanGenericSignature canSig, GenericSignatureBuilder &builder) { PrettyStackTraceGenericSignature debugStack("checking", canSig); auto canonicalRequirements = canSig->getRequirements(); // Check that the signature is canonical. for (unsigned idx : indices(canonicalRequirements)) { debugStack.setRequirement(idx); const auto &reqt = canonicalRequirements[idx]; // Left-hand side must be canonical in its context. // Check canonicalization of requirement itself. switch (reqt.getKind()) { case RequirementKind::Superclass: assert(canSig->isCanonicalTypeInContext(reqt.getFirstType(), builder) && "Left-hand side is not canonical"); assert(canSig->isCanonicalTypeInContext(reqt.getSecondType(), builder) && "Superclass type isn't canonical in its own context"); break; case RequirementKind::Layout: assert(canSig->isCanonicalTypeInContext(reqt.getFirstType(), builder) && "Left-hand side is not canonical"); break; case RequirementKind::SameType: { auto isCanonicalAnchor = [&](Type type) { if (auto *dmt = type->getAs()) return canSig->isCanonicalTypeInContext(dmt->getBase(), builder); return type->is(); }; auto firstType = reqt.getFirstType(); auto secondType = reqt.getSecondType(); assert(isCanonicalAnchor(firstType)); if (reqt.getSecondType()->isTypeParameter()) { assert(isCanonicalAnchor(secondType)); assert(compareDependentTypes(firstType, secondType) < 0 && "Out-of-order type parameters in same-type constraint"); } else { assert(canSig->isCanonicalTypeInContext(secondType) && "Concrete same-type isn't canonical in its own context"); } break; } case RequirementKind::Conformance: assert(canSig->isCanonicalTypeInContext(reqt.getFirstType(), builder) && "Left-hand side is not canonical"); assert(reqt.getFirstType()->isTypeParameter() && "Left-hand side must be a type parameter"); assert(isa(reqt.getSecondType().getPointer()) && "Right-hand side of conformance isn't a protocol type"); break; } // From here on, we're only interested in requirements beyond the first. if (idx == 0) continue; // Make sure that the left-hand sides are in nondecreasing order. const auto &prevReqt = canonicalRequirements[idx-1]; int compareLHS = compareDependentTypes(prevReqt.getFirstType(), reqt.getFirstType()); assert(compareLHS <= 0 && "Out-of-order left-hand sides"); // If we have two same-type requirements where the left-hand sides differ // but fall into the same equivalence class, we can check the form. if (compareLHS < 0 && reqt.getKind() == RequirementKind::SameType && prevReqt.getKind() == RequirementKind::SameType && canSig->areSameTypeParameterInContext(prevReqt.getFirstType(), reqt.getFirstType(), builder)) { // If it's a it's a type parameter, make sure the equivalence class is // wired together sanely. if (prevReqt.getSecondType()->isTypeParameter()) { assert(prevReqt.getSecondType()->isEqual(reqt.getFirstType()) && "same-type constraints within an equiv. class are out-of-order"); } else { // Otherwise, the concrete types must match up. assert(prevReqt.getSecondType()->isEqual(reqt.getSecondType()) && "inconsistent concrete same-type constraints in equiv. class"); } } // From here on, we only care about cases where the previous and current // requirements have the same left-hand side. if (compareLHS != 0) continue; // Check ordering of requirement kinds. assert((getRequirementKindOrder(prevReqt.getKind()) <= getRequirementKindOrder(reqt.getKind())) && "Requirements for a given kind are out-of-order"); // From here on, we only care about the same requirement kind. if (prevReqt.getKind() != reqt.getKind()) continue; assert(reqt.getKind() == RequirementKind::Conformance && "Only conformance requirements can have multiples"); auto prevProto = prevReqt.getProtocolDecl(); auto proto = reqt.getProtocolDecl(); assert(TypeDecl::compare(prevProto, proto) < 0 && "Out-of-order conformance requirements"); } } #endif bool GenericSignatureBuilder::hasExplicitConformancesImpliedByConcrete() const { for (auto pair : Impl->RedundantRequirements) { if (pair.first.getKind() != RequirementKind::Conformance) continue; for (auto impliedByReq : pair.second) { if (impliedByReq.getKind() == RequirementKind::Superclass) return true; if (impliedByReq.getKind() == RequirementKind::SameType) return true; } } return false; } 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::Conformance, subjectType, req.getLayoutConstraint()); } llvm_unreachable("Bad requirement kind"); } GenericSignature GenericSignatureBuilder::computeGenericSignature( bool allowConcreteGenericParams, bool buildingRequirementSignature, bool rebuildingWithoutRedundantConformances) && { // Finalize the builder, producing any necessary diagnostics. finalize(getGenericParams(), allowConcreteGenericParams); // Collect the requirements placed on the generic parameter types. SmallVector requirements; enumerateRequirements(getGenericParams(), requirements); // Form the generic signature. auto sig = GenericSignature::get(getGenericParams(), requirements); // 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 (!buildingRequirementSignature && !Impl->HadAnyError && hasExplicitConformancesImpliedByConcrete()) { NumSignaturesRebuiltWithoutRedundantRequirements++; if (rebuildingWithoutRedundantConformances) { llvm::errs() << "Rebuilt signature still has " << "redundant conformance requirements: "; llvm::errs() << sig << "\n"; abort(); } GenericSignatureBuilder newBuilder(Context); for (auto param : sig->getGenericParams()) newBuilder.addGenericParameter(param); for (auto &req : sig->getRequirements()) { newBuilder.addRequirement(stripBoundDependentMemberTypes(req), FloatingRequirementSource::forAbstract(), nullptr); } return std::move(newBuilder).computeGenericSignature( allowConcreteGenericParams, buildingRequirementSignature, /*rebuildingWithoutRedundantConformances=*/true); } #ifndef NDEBUG if (!Impl->HadAnyError) { checkGenericSignature(sig.getCanonicalSignature(), *this); } #endif // 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 (!buildingRequirementSignature && !Impl->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(); return sig; } #pragma mark Generic signature verification void GenericSignatureBuilder::verifyGenericSignature(ASTContext &context, GenericSignature sig) { llvm::errs() << "Validating generic signature: "; sig->print(llvm::errs()); llvm::errs() << "\n"; // Try building a new signature having the same requirements. auto genericParams = sig->getGenericParams(); auto requirements = sig->getRequirements(); { PrettyStackTraceGenericSignature debugStack("verifying", sig); // Form a new generic signature builder. GenericSignatureBuilder builder(context); // Add the generic parameters. for (auto gp : genericParams) builder.addGenericParameter(gp); // Add the requirements. auto source = FloatingRequirementSource::forAbstract(); for (auto req : requirements) builder.addRequirement(req, source, nullptr); // If there were any errors, the signature was invalid. if (builder.Impl->HadAnyError) { context.Diags.diagnose(SourceLoc(), diag::generic_signature_not_valid, sig->getAsString()); } // Form a generic signature from the result. auto newSig = std::move(builder).computeGenericSignature( /*allowConcreteGenericParams=*/true); // The new signature should be equal. if (!newSig->isEqual(sig)) { context.Diags.diagnose(SourceLoc(), diag::generic_signature_not_equal, sig->getAsString(), newSig->getAsString()); } } // Try removing each requirement in turn. for (unsigned victimIndex : indices(requirements)) { PrettyStackTraceGenericSignature debugStack("verifying", sig, victimIndex); // Form a new generic signature builder. GenericSignatureBuilder builder(context); // Add the generic parameters. for (auto gp : genericParams) builder.addGenericParameter(gp); // Add the requirements *except* the victim. auto source = FloatingRequirementSource::forAbstract(); for (unsigned i : indices(requirements)) { if (i != victimIndex) builder.addRequirement(requirements[i], source, nullptr); } // If there were any errors, we formed an invalid signature, so // just continue. if (builder.Impl->HadAnyError) continue; // Form a generic signature from the result. auto newSig = std::move(builder).computeGenericSignature( /*allowConcreteGenericParams=*/true); // If the removed requirement is satisfied by the new generic signature, // it is redundant. Complain. if (newSig->isRequirementSatisfied(requirements[victimIndex])) { SmallString<32> reqString; { llvm::raw_svector_ostream out(reqString); requirements[victimIndex].print(out, PrintOptions()); } context.Diags.diagnose(SourceLoc(), diag::generic_signature_not_minimal, reqString, sig->getAsString()); } // Canonicalize the signature to check that it is canonical. (void)newSig.getCanonicalSignature(); } } void GenericSignatureBuilder::verifyGenericSignaturesInModule( ModuleDecl *module) { LoadedFile *loadedFile = nullptr; for (auto fileUnit : module->getFiles()) { loadedFile = dyn_cast(fileUnit); if (loadedFile) break; } if (!loadedFile) return; // Check all of the (canonical) generic signatures. SmallVector allGenericSignatures; SmallPtrSet knownGenericSignatures; (void)loadedFile->getAllGenericSignatures(allGenericSignatures); ASTContext &context = module->getASTContext(); for (auto genericSig : allGenericSignatures) { // Check whether this is the first time we've checked this (canonical) // signature. auto canGenericSig = genericSig.getCanonicalSignature(); if (!knownGenericSignatures.insert(canGenericSig).second) continue; verifyGenericSignature(context, canGenericSig); } } bool AbstractGenericSignatureRequest::isCached() const { return true; } bool InferredGenericSignatureRequest::isCached() const { return true; } /// 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; } GenericSignature AbstractGenericSignatureRequest::evaluate( Evaluator &evaluator, const GenericSignatureImpl *baseSignature, SmallVector addedParameters, SmallVector addedRequirements) const { // If nothing is added to the base signature, just return the base // signature. if (addedParameters.empty() && addedRequirements.empty()) return baseSignature; 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()) { ArrayRef requirements; if (baseSignature) { addedParameters.insert(addedParameters.begin(), baseSignature->getGenericParams().begin(), baseSignature->getGenericParams().end()); requirements = baseSignature->getRequirements(); } return GenericSignature::get(addedParameters, requirements); } // 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. GenericSignature canBaseSignature; if (baseSignature) 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 = evaluator( AbstractGenericSignatureRequest{ canBaseSignature.getPointer(), std::move(canAddedParameters), std::move(canAddedRequirements)}); if (!canSignatureResult || !*canSignatureResult) return GenericSignature(); // Substitute in the original generic parameters to form the sugared // result the original request wanted. auto canSignature = *canSignatureResult; 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 GenericSignature::get(resugaredParameters, resugaredRequirements); } // 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); return std::move(builder).computeGenericSignature( /*allowConcreteGenericParams=*/true); } GenericSignature InferredGenericSignatureRequest::evaluate( Evaluator &evaluator, ModuleDecl *parentModule, const GenericSignatureImpl *parentSig, GenericParamSource paramSource, SmallVector addedRequirements, SmallVector inferenceSources, bool allowConcreteGenericParams) const { 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); // 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; }; GenericParamList *genericParams = nullptr; if (auto params = paramSource.dyn_cast()) genericParams = params; else genericParams = paramSource.get()->getGenericParams(); 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 (auto *ctx = paramSource.dyn_cast()) { // The declaration might have a trailing where clause. if (auto *where = ctx->getTrailingWhereClause()) { // Determine where and how to perform name lookup. lookupDC = ctx; WhereClauseOwner(lookupDC, where).visitRequirements( TypeResolutionStage::Structural, visitRequirement); } } /// Perform any remaining requirement inference. for (auto sourcePair : inferenceSources) { auto source = FloatingRequirementSource::forInferred(sourcePair.getTypeRepr()); builder.inferRequirements(*parentModule, sourcePair.getType(), source); } // Finish by adding any remaining requirements. auto source = FloatingRequirementSource::forInferred(nullptr); for (const auto &req : addedRequirements) builder.addRequirement(req, source, parentModule); return std::move(builder).computeGenericSignature( allowConcreteGenericParams); }