From da39d9b17b4845611f79ae7c4b1124e60d7c6672 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Thu, 16 Feb 2017 16:56:53 -0800 Subject: [PATCH] [GenericSig Builder] Rework RequirementSource to describe requirement path. Reimplement the RequirementSource class, which captures how a particular requirement is satisfied by a generic signature. The primary goal of this rework is to keep the complete path one follows in a generic signature to get from some explicit requirement in the generic signature to some derived requirement or type, e.g., 1) Start at an explicit requirement "C: Collection" 2) Go to the inherited protocol Sequence, 3) Get the "Iterator" associated type 4) Get its conformance to "IteratorProtocol" 5) Get the "Element" associated type We don't currently capture all of the information we want in the path, but the basic structure is there, and should also allow us to capture more source-location information, find the "optimal" path, etc. There are are a number of potential uses: * IRGen could eventually use this to dig out the witness tables and type metadata it needs, instead of using its own fulfillment strategy * SubstitutionMap could use this to lookup conformances, rather than it's egregious hacks * The canonical generic signature builder could use this to lookup conformances as needed, e.g., for the recursive-conformances case. ... and probably more simplifications, once we get this right. --- include/swift/AST/GenericSignatureBuilder.h | 408 ++++++++-- lib/AST/Decl.cpp | 10 +- lib/AST/GenericSignatureBuilder.cpp | 828 +++++++++++++------- lib/SILGen/SILGenPoly.cpp | 2 +- lib/SILOptimizer/Utils/Generics.cpp | 2 +- lib/Sema/TypeCheckAttr.cpp | 10 +- lib/Sema/TypeCheckGeneric.cpp | 2 +- lib/Sema/TypeCheckProtocol.cpp | 2 +- test/Generics/associated_type_typo.swift | 6 +- test/Generics/requirement_inference.swift | 27 +- test/Generics/superclass_constraint.swift | 12 +- 11 files changed, 937 insertions(+), 372 deletions(-) diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h index 4f5718e25cf86..d7c457292d478 100644 --- a/include/swift/AST/GenericSignatureBuilder.h +++ b/include/swift/AST/GenericSignatureBuilder.h @@ -26,6 +26,7 @@ #include "swift/AST/TypeLoc.h" #include "swift/Basic/LLVM.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/MapVector.h" @@ -39,6 +40,7 @@ class DeclContext; class DependentMemberType; class GenericParamList; class GenericSignature; +class GenericSignatureBuilder; class GenericTypeParamType; class LazyResolver; class ModuleDecl; @@ -53,60 +55,306 @@ class TypeRepr; class ASTContext; class DiagnosticEngine; -/// Describes how a requirement was determined. -class RequirementSource { +/// Describes how a generic signature determines a requirement, from its origin +/// in some requirement written in the source, inferred through a path of +/// other implications (e.g., introduced by a particular protocol). +/// +/// Requirement sources are uniqued within a generic signature builder. +class RequirementSource : public llvm::FoldingSetNode { public: - enum Kind : unsigned char { - /// The requirement was explicitly stated in the generic parameter - /// clause. + enum Kind : uint8_t { + /// A requirement stated explicitly, e.g., in a where clause or type + /// parameter declaration. + /// + /// Explicitly-stated requirement can be tied to a specific requirement + /// in a 'where' clause (which stores a \c RequirementRepr), a type in an + /// 'inheritance' clause (which stores a \c TypeRepr), or can be 'abstract', + /// , e.g., due to canonicalization, deserialization, or other + /// source-independent formulation. + /// + /// This is a root requirement source. Explicit, - /// The requirement was inferred from the function's parameter or - /// result types. + + /// A requirement inferred from part of the signature of a declaration, + /// e.g., the type of a generic function. For example: + /// + /// func f(_: Set) { } // infers T: Hashable + /// + /// This is a root requirement source, which can be described by a + /// \c TypeRepr. Inferred, - /// The requirement was part of a protocol requirement on an - /// associated type. + /// A requirement for the creation of the requirement signature of a + /// protocol. + /// + /// This is a root requirement source, which is described by the protocol + /// whose requirement signature is being computed. + RequirementSignatureSelf, + + /// The requirement came from two nested types of the equivalent types whose + /// names match. /// - /// These are dropped when building the GenericSignature. - Protocol, + /// This is a root requirement source. + NestedTypeNameMatch, - /// The requirement is redundant with some other requirement. + /// The requirement is a protocol requirement. /// - /// These are dropped when building the GenericSignature. - Redundant, + /// This stores the protocol that introduced the requirement. + ProtocolRequirement, - /// The requirement is redundant due to the superclass conforming to one - /// of the protocols. + /// A requirement that was resolved via a superclass requirement. /// - /// These are dropped when building the GenericSignature. - Inherited, + /// This stores the \c ProtocolConformance* used to resolve the + /// requirement. + Superclass, - /// The requirement is the Self: Protocol requirement, when computing a - /// protocol's requirement signature. - ProtocolRequirementSignatureSelf, + /// A requirement that was resolved for a nested type via its parent + /// type. + Parent, + + /// A requirement that was resolved for a nested type via a same-type-to- + /// concrete constraint. + /// + /// This stores the \c ProtocolConformance* used to resolve the + /// requirement. + Concrete, }; - RequirementSource(Kind kind, SourceLoc loc) : StoredKind(kind), Loc(loc) { } + /// The kind of requirement source. + const Kind kind; + +private: + /// The kind of storage we have. + enum class StorageKind : uint8_t { + None, + TypeRepr, + RequirementRepr, + ProtocolDecl, + ProtocolConformance, + }; + + /// The kind of storage we have. + const StorageKind storageKind; + + /// The actual storage, described by \c storageKind. + union { + /// The type representation descibing where the requirement came from. + TypeRepr *typeRepr; + + /// Where a requirement came from. + const RequirementRepr *requirementRepr; + + /// The protocol being described. + ProtocolDecl *protocol; + + /// A protocol conformance used to satisfy the requirement. + ProtocolConformance *conformance; + } storage; + + /// Determines whether we have been provided with an acceptable storage kind + /// for the given requirement source kind. + static bool isAcceptableStorageKind(Kind kind, StorageKind storageKind); + + /// Retrieve the opaque storage as a single pointer, for use in uniquing. + const void *getOpaqueStorage() const; + + /// Whether this kind of requirement source is a root. + static bool isRootKind(Kind kind) { + switch (kind) { + case Explicit: + case Inferred: + case RequirementSignatureSelf: + case NestedTypeNameMatch: + return true; + + case ProtocolRequirement: + case Superclass: + case Parent: + case Concrete: + return false; + } + } + +public: + /// The "parent" of this requirement source. + /// + /// The chain of parent requirement sources will eventually terminate in a + /// requirement source with one of the "root" kinds. + const RequirementSource * const parent; + + RequirementSource(Kind kind, const RequirementSource *parent) + : kind(kind), storageKind(StorageKind::None), parent(parent) { + assert((static_cast(parent) != isRootKind(kind)) && + "Root RequirementSource should not have parent (or vice versa)"); + assert(isAcceptableStorageKind(kind, storageKind) && + "RequirementSource kind/storageKind mismatch"); + + // Prevent uninitialized memory. + storage.typeRepr = nullptr; + } + + RequirementSource(Kind kind, const RequirementSource *parent, + TypeRepr *typeRepr) + : kind(kind), storageKind(StorageKind::TypeRepr), parent(parent) { + assert((static_cast(parent) != isRootKind(kind)) && + "Root RequirementSource should not have parent (or vice versa)"); + assert(isAcceptableStorageKind(kind, storageKind) && + "RequirementSource kind/storageKind mismatch"); + + storage.typeRepr = typeRepr; + } + + RequirementSource(Kind kind, const RequirementSource *parent, + const RequirementRepr *requirementRepr) + : kind(kind), storageKind(StorageKind::RequirementRepr), parent(parent) { + assert((static_cast(parent) != isRootKind(kind)) && + "Root RequirementSource should not have parent (or vice versa)"); + assert(isAcceptableStorageKind(kind, storageKind) && + "RequirementSource kind/storageKind mismatch"); + + storage.requirementRepr = requirementRepr; + } + + RequirementSource(Kind kind, const RequirementSource *parent, + ProtocolDecl *protocol) + : kind(kind), storageKind(StorageKind::ProtocolDecl), parent(parent) { + assert((static_cast(parent) != isRootKind(kind)) && + "Root RequirementSource should not have parent (or vice versa)"); + assert(isAcceptableStorageKind(kind, storageKind) && + "RequirementSource kind/storageKind mismatch"); + + storage.protocol = protocol; + } + + RequirementSource(Kind kind, const RequirementSource *parent, + ProtocolConformance *conformance) + : kind(kind), storageKind(StorageKind::ProtocolConformance), + parent(parent) { + assert((static_cast(parent) != isRootKind(kind)) && + "Root RequirementSource should not have parent (or vice versa)"); + assert(isAcceptableStorageKind(kind, storageKind) && + "RequirementSource kind/storageKind mismatch"); - /// Retrieve the kind of requirement source. - Kind getKind() const { return StoredKind; } + storage.conformance = conformance; + } + +public: + /// Retrieve an abstract requirement source. + static const RequirementSource *forAbstract(GenericSignatureBuilder &builder); + + /// Retrieve a requirement source representing an explicit requirement + /// stated in an 'inheritance' clause. + static const RequirementSource *forExplicit(GenericSignatureBuilder &builder, + TypeRepr *typeRepr); + + /// Retrieve a requirement source representing an explicit requirement + /// stated in an 'where' clause. + static const RequirementSource *forExplicit(GenericSignatureBuilder &builder, + const RequirementRepr *requirementRepr); + + /// Retrieve a requirement source representing a requirement that is + /// inferred from some part of a generic declaration's signature, e.g., the + /// parameter or result type of a generic function. + static const RequirementSource *forInferred(GenericSignatureBuilder &builder, + TypeRepr *typeRepr); + + /// Retrieve a requirement source representing the requirement signature + /// computation for a protocol. + static const RequirementSource *forRequirementSignature( + GenericSignatureBuilder &builder, + ProtocolDecl *protocol); + + /// Retrieve an requirement source for nested type name matches. + static const RequirementSource *forNestedTypeNameMatch( + GenericSignatureBuilder &builder); + + /// A requirement source that describes that a requirement comes from a + /// requirement of the given protocol described by the parent. + const RequirementSource *viaAbstractProtocolRequirement( + GenericSignatureBuilder &builder, + ProtocolDecl *protocol) const; + + /// A requirement source that describes that a requirement that is resolved + /// via a superclass requirement. + const RequirementSource *viaSuperclass( + GenericSignatureBuilder &builder, + ProtocolConformance *conformance) const; + + /// A requirement source that describes that a requirement that is resolved + /// via a same-type-to-concrete requirement. + const RequirementSource *viaConcrete(GenericSignatureBuilder &builder, + ProtocolConformance *conformance) const; + + /// A constraint source that describes that a constraint that is resolved + /// for a nested type via a constraint on its parent. + const RequirementSource *viaParent(GenericSignatureBuilder &builder) const; + + /// Whether the requirement can be derived from something in its path. + /// + /// Derived requirements will not be recorded in a minimized generic + /// signature, because the information can be re-derived by following the + /// path. + bool isDerivedRequirement() const; + + /// Retrieve a source location that corresponds to the requirement. + SourceLoc getLoc() const; + + /// Compare two requirement sources to determine which has the more + /// optimal path. + /// + /// \returns -1 if the \c this is better, 1 if the \c other is better, and 0 + /// if they are equivalent in length. + int compare(const RequirementSource *other) const; + + /// Retrieve the type representation for this requirement, if there is one. + TypeRepr *getTypeRepr() const { + if (storageKind != StorageKind::TypeRepr) return nullptr; + return storage.typeRepr; + } + + /// Retrieve the requirement representation for this requirement, if there is + /// one. + const RequirementRepr *getRequirementRepr() const { + if (storageKind != StorageKind::RequirementRepr) return nullptr; + return storage.requirementRepr; + } + + /// Retrieve the protocol for this requirement, if there is one. + ProtocolDecl *getProtocolDecl() const; - /// Set the kind of the requirement source. - void setKind(Kind kind) { StoredKind = kind; } + /// Retrieve the protocol conformance for this requirement, if there is one. + ProtocolConformance *getProtocolConformance() const { + if (storageKind != StorageKind::ProtocolConformance) return nullptr; + return storage.conformance; + } + + /// Profiling support for \c FoldingSet. + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, kind, parent, getOpaqueStorage()); + } - /// Retrieve the source location at which the requirement originated. - SourceLoc getLoc() const { return Loc; } + /// Profiling support for \c FoldingSet. + static void Profile(llvm::FoldingSetNodeID &ID, Kind kind, + const RequirementSource *parent, const void *storage) { + ID.AddInteger(kind); + ID.AddPointer(parent); + ID.AddPointer(storage); + } LLVM_ATTRIBUTE_DEPRECATED( - void dump(SourceManager *srcMgr) const, + void dump() const, "only for use within the debugger"); /// Dump the requirement source. - void dump(llvm::raw_ostream &out, SourceManager *srcMgr) const; + void dump(llvm::raw_ostream &out, SourceManager *SrcMgr, + unsigned indent) const; -private: - Kind StoredKind; - SourceLoc Loc; + LLVM_ATTRIBUTE_DEPRECATED( + void print() const, + "only for use within the debugger"); + + /// Print the requirement source (shorter form) + void print(llvm::raw_ostream &out, SourceManager *SrcMgr) const; }; /// \brief Collects a set of requirements of generic parameters, both explicitly @@ -121,6 +369,8 @@ class GenericSignatureBuilder { using RequirementRHS = llvm::PointerUnion3; + friend class RequirementSource; + private: class InferRequirementsWalker; friend class InferRequirementsWalker; @@ -134,15 +384,38 @@ class GenericSignatureBuilder { GenericSignatureBuilder(const GenericSignatureBuilder &) = delete; GenericSignatureBuilder &operator=(const GenericSignatureBuilder &) = delete; + /// Update an existing constraint source reference when another constraint + /// source was found to produce the same constraint. Only the better + /// constraint source will be kept. + /// + /// \returns true if the new constraint source was better, false otherwise. + bool updateRequirementSource(const RequirementSource *&existingSource, + const RequirementSource *newSource); + + /// Retrieve the constraint source conformance for the superclass constraint + /// of the given potential archetype (if present) to the given protocol. + /// + /// \param pa The potential archetype whose superclass constraint is being + /// queried. + /// + /// \param proto The protocol to which we are establishing conformance. + /// + /// \param protoSource The requirement source for the conformance to the + /// given protocol. + const RequirementSource *resolveSuperConformance( + GenericSignatureBuilder::PotentialArchetype *pa, + ProtocolDecl *proto, + const RequirementSource *&protoSource); + /// \brief Add a new conformance requirement specifying that the given /// potential archetype conforms to the given protocol. bool addConformanceRequirement(PotentialArchetype *T, ProtocolDecl *Proto, - RequirementSource Source); + const RequirementSource *Source); bool addConformanceRequirement(PotentialArchetype *T, ProtocolDecl *Proto, - RequirementSource Source, + const RequirementSource *Source, llvm::SmallPtrSetImpl &Visited); public: @@ -150,20 +423,20 @@ class GenericSignatureBuilder { /// potential archetypes are equivalent. bool addSameTypeRequirementBetweenArchetypes(PotentialArchetype *T1, PotentialArchetype *T2, - RequirementSource Source); + const RequirementSource *Source); /// \brief Add a new conformance requirement specifying that the given /// potential archetype is bound to a concrete type. bool addSameTypeRequirementToConcrete(PotentialArchetype *T, Type Concrete, - RequirementSource Source); + const RequirementSource *Source); private: /// \brief Add a new superclass requirement specifying that the given /// potential archetype has the given type as an ancestor. bool addSuperclassRequirement(PotentialArchetype *T, Type Superclass, - RequirementSource Source); + const RequirementSource *Source); /// \brief Add a new same-type requirement specifying that the given two /// types should be the same. @@ -171,7 +444,7 @@ class GenericSignatureBuilder { /// \param diagnoseMismatch Callback invoked when the types in the same-type /// requirement mismatch. bool addSameTypeRequirement( - Type T1, Type T2, RequirementSource Source, + Type T1, Type T2, const RequirementSource *Source, llvm::function_ref diagnoseMismatch); /// Add the requirements placed on the given abstract type parameter @@ -179,7 +452,7 @@ class GenericSignatureBuilder { bool addAbstractTypeParamRequirements( AbstractTypeParamDecl *decl, PotentialArchetype *pa, - RequirementSource::Kind kind, + const RequirementSource *source, llvm::SmallPtrSetImpl &visited); /// Visit all of the types that show up in the list of inherited @@ -195,7 +468,7 @@ class GenericSignatureBuilder { void markPotentialArchetypeRecursive(PotentialArchetype *pa, ProtocolDecl *proto, - RequirementSource source); + const RequirementSource *source); public: /// Construct a new generic signature builder. @@ -226,7 +499,7 @@ class GenericSignatureBuilder { void (RequirementKind kind, PotentialArchetype *archetype, RequirementRHS constraint, - RequirementSource source)> f); + const RequirementSource *source)> f); public: /// \brief Add a new generic parameter for which there may be requirements. @@ -245,7 +518,7 @@ class GenericSignatureBuilder { /// /// \returns true if this requirement makes the set of requirements /// inconsistent, in which case a diagnostic will have been issued. - bool addRequirement(const RequirementRepr &Req); + bool addRequirement(const RequirementRepr *Req); /// \brief Add an already-checked requirement. /// @@ -254,14 +527,14 @@ class GenericSignatureBuilder { /// /// \returns true if this requirement makes the set of requirements /// inconsistent, in which case a diagnostic will have been issued. - bool addRequirement(const Requirement &req, RequirementSource source); + bool addRequirement(const Requirement &req, const RequirementSource *source); - bool addRequirement(const Requirement &req, RequirementSource source, + bool addRequirement(const Requirement &req, const RequirementSource *source, llvm::SmallPtrSetImpl &Visited); bool addLayoutRequirement(PotentialArchetype *PAT, LayoutConstraint Layout, - RequirementSource Source); + const RequirementSource *Source); /// \brief Add all of a generic signature's parameters and requirements. void addGenericSignature(GenericSignature *sig); @@ -365,26 +638,27 @@ class GenericSignatureBuilder::PotentialArchetype { /// \brief The representative of the equivalence class of potential archetypes /// to which this potential archetype belongs. - PotentialArchetype *Representative; + mutable PotentialArchetype *Representative; /// Same-type constraints between this potential archetype and any other /// archetype in its equivalence class. - llvm::MapVector SameTypeConstraints; + llvm::MapVector + SameTypeConstraints; /// \brief The superclass of this archetype, if specified. Type Superclass; /// The source of the superclass requirement. - Optional SuperclassSource; + const RequirementSource *SuperclassSource = nullptr; /// \brief The list of protocols to which this archetype will conform. - llvm::MapVector ConformsTo; + llvm::MapVector ConformsTo; /// \brief The layout constraint of this archetype, if specified. LayoutConstraint Layout; /// The source of the layout constraint requirement. - Optional LayoutSource; + const RequirementSource *LayoutSource = nullptr; /// \brief The set of nested types of this archetype. /// @@ -399,7 +673,7 @@ class GenericSignatureBuilder::PotentialArchetype { Type ConcreteType; /// The source of the concrete type requirement. - Optional ConcreteTypeSource; + const RequirementSource *ConcreteTypeSource = nullptr; /// Whether this is an unresolved nested type. unsigned isUnresolvedNestedType : 1; @@ -480,7 +754,7 @@ class GenericSignatureBuilder::PotentialArchetype { /// \brief Retrieve the representative for this archetype, performing /// path compression on the way. - PotentialArchetype *getRepresentative(); + PotentialArchetype *getRepresentative() const; /// Retrieve the generic signature builder with which this archetype is associated. GenericSignatureBuilder *getBuilder() const { @@ -561,8 +835,8 @@ class GenericSignatureBuilder::PotentialArchetype { } /// Retrieve the set of protocols to which this type conforms. - const llvm::MapVector & - getConformsTo() const { + llvm::MapVector & + getConformsTo() { return ConformsTo; } @@ -570,23 +844,23 @@ class GenericSignatureBuilder::PotentialArchetype { /// /// \returns true if the conformance was new, false if it already existed. bool addConformance(ProtocolDecl *proto, bool updateExistingSource, - const RequirementSource &source, + const RequirementSource *source, GenericSignatureBuilder &builder); /// Retrieve the superclass of this archetype. Type getSuperclass() const { return Superclass; } /// Retrieve the requirement source for the superclass requirement. - const RequirementSource &getSuperclassSource() const { - return *SuperclassSource; + const RequirementSource *getSuperclassSource() const { + return SuperclassSource; } /// Retrieve the layout constraint of this archetype. LayoutConstraint getLayout() const { return Layout; } /// Retrieve the requirement source for the layout constraint requirement. - const RequirementSource &getLayoutSource() const { - return *LayoutSource; + const RequirementSource *getLayoutSource() const { + return LayoutSource; } /// Retrieve the set of nested types. @@ -611,11 +885,11 @@ class GenericSignatureBuilder::PotentialArchetype { /// Add a same-type constraint between this archetype and the given /// other archetype. void addSameTypeConstraint(PotentialArchetype *otherPA, - const RequirementSource& source); + const RequirementSource *source); /// Retrieve the same-type constraints. llvm::iterator_range< - std::vector> + std::vector> ::const_iterator> getSameTypeConstraints() const { return llvm::make_range(SameTypeConstraints.begin(), @@ -624,11 +898,11 @@ class GenericSignatureBuilder::PotentialArchetype { /// Retrieve the source of the same-type constraint that maps this potential /// archetype to a concrete type. - const RequirementSource &getConcreteTypeSource() const { + const RequirementSource *getConcreteTypeSource() const { if (Representative != this) return Representative->getConcreteTypeSource(); - return *ConcreteTypeSource; + return ConcreteTypeSource; } /// \brief Retrieve (or create) a nested type with the given name. @@ -701,8 +975,12 @@ class GenericSignatureBuilder::PotentialArchetype { /// Note that we already diagnosed this rename. void setAlreadyDiagnosedRename() { DiagnosedRename = true; } + LLVM_ATTRIBUTE_DEPRECATED( + void dump() const, + "only for use within the debugger"); + void dump(llvm::raw_ostream &Out, SourceManager *SrcMgr, - unsigned Indent); + unsigned Indent) const; friend class GenericSignatureBuilder; }; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 581dd6725d25e..18dcf8d023a19 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -3020,12 +3020,12 @@ void ProtocolDecl::computeRequirementSignature() { auto selfType = genericSig->getGenericParams()[0]; auto requirement = genericSig->getRequirements()[0]; - RequirementSource source(RequirementSource::ProtocolRequirementSignatureSelf, - getLoc()); - - GenericSignatureBuilder builder(getASTContext(), LookUpConformanceInModule(module)); + GenericSignatureBuilder builder(getASTContext(), + LookUpConformanceInModule(module)); builder.addGenericParameter(selfType); - builder.addRequirement(requirement, source); + builder.addRequirement(requirement, + RequirementSource::forRequirementSignature(builder, + this)); builder.finalize(SourceLoc(), { selfType }); RequirementSignature = builder.getGenericSignature(); diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index dc12467e70f5f..d47ff3ae260d9 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -38,80 +38,374 @@ using namespace swift; using llvm::DenseMap; -void RequirementSource::dump(SourceManager *srcMgr) const { - dump(llvm::errs(), srcMgr); +struct GenericSignatureBuilder::Implementation { + /// Function used to look up conformances. + std::function LookupConformance; + + /// 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 number of nested types that haven't yet been resolved to archetypes. + /// Once all requirements have been added, this will be zero in well-formed + /// code. + unsigned NumUnresolvedNestedTypes = 0; + + /// The nested types that have been renamed. + SmallVector RenamedNestedTypes; + + /// The requirement sources used in this generic signature builder. + llvm::FoldingSet RequirementSources; + +#ifndef NDEBUG + /// Whether we've already finalized the builder. + bool finalized = false; +#endif +}; + +#pragma mark Requirement sources +bool RequirementSource::isAcceptableStorageKind(Kind kind, + StorageKind storageKind) { + switch (kind) { + case Explicit: + switch (storageKind) { + case StorageKind::None: + case StorageKind::TypeRepr: + case StorageKind::RequirementRepr: + return true; + + case StorageKind::ProtocolDecl: + case StorageKind::ProtocolConformance: + return false; + } + + case Inferred: + switch (storageKind) { + case StorageKind::None: + case StorageKind::TypeRepr: + return true; + + case StorageKind::ProtocolDecl: + case StorageKind::ProtocolConformance: + case StorageKind::RequirementRepr: + return false; + } + + case NestedTypeNameMatch: + case Parent: + switch (storageKind) { + case StorageKind::None: + return true; + + case StorageKind::TypeRepr: + case StorageKind::ProtocolDecl: + case StorageKind::ProtocolConformance: + case StorageKind::RequirementRepr: + return false; + } + + case RequirementSignatureSelf: + case ProtocolRequirement: + switch (storageKind) { + case StorageKind::ProtocolDecl: + return true; + + case StorageKind::None: + case StorageKind::TypeRepr: + case StorageKind::ProtocolConformance: + case StorageKind::RequirementRepr: + return false; + } + + case Superclass: + case Concrete: + switch (storageKind) { + case StorageKind::ProtocolConformance: + return true; + + case StorageKind::None: + case StorageKind::ProtocolDecl: + case StorageKind::TypeRepr: + case StorageKind::RequirementRepr: + return false; + } + } +} + +const void *RequirementSource::getOpaqueStorage() const { + switch (storageKind) { + case StorageKind::None: + // Note: always null. + return storage.typeRepr; + + case StorageKind::TypeRepr: + return storage.typeRepr; + + case StorageKind::RequirementRepr: + return storage.requirementRepr; + + case StorageKind::ProtocolConformance: + return storage.conformance; + + case StorageKind::ProtocolDecl: + return storage.protocol; + } } -void RequirementSource::dump(llvm::raw_ostream &out, - SourceManager *srcMgr) const { - switch (getKind()) { +bool RequirementSource::isDerivedRequirement() const { + switch (kind) { case Explicit: - out << "explicit"; - break; + case Inferred: + return false; + + case NestedTypeNameMatch: + case Parent: + case Superclass: + case Concrete: + case RequirementSignatureSelf: + return true; + + case ProtocolRequirement: + // 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; + } +} + +#define REQUIREMENT_SOURCE_FACTORY_BODY(SourceKind, Parent, Storage) \ + llvm::FoldingSetNodeID nodeID; \ + Profile(nodeID, Kind::SourceKind, Parent, Storage); \ + \ + void *insertPos = nullptr; \ + if (auto known = \ + builder.Impl->RequirementSources.FindNodeOrInsertPos(nodeID, \ + insertPos)) \ + return known; \ + \ + auto result = new RequirementSource(Kind::SourceKind, Parent, Storage); \ + builder.Impl->RequirementSources.InsertNode(result, insertPos); \ + return result + +#define REQUIREMENT_SOURCE_FACTORY_BODY_NOSTORAGE(SourceKind, Parent) \ + llvm::FoldingSetNodeID nodeID; \ + Profile(nodeID, Kind::SourceKind, Parent, nullptr); \ + \ + void *insertPos = nullptr; \ + if (auto known = \ + builder.Impl->RequirementSources.FindNodeOrInsertPos(nodeID, \ + insertPos)) \ + return known; \ + \ + auto result = new RequirementSource(Kind::SourceKind, Parent); \ + builder.Impl->RequirementSources.InsertNode(result, insertPos); \ + return result + +const RequirementSource *RequirementSource::forAbstract( + GenericSignatureBuilder &builder) { + REQUIREMENT_SOURCE_FACTORY_BODY_NOSTORAGE(Explicit, nullptr); +} - case Redundant: - out << "redundant"; +const RequirementSource *RequirementSource::forExplicit( + GenericSignatureBuilder &builder, + TypeRepr *typeRepr) { + REQUIREMENT_SOURCE_FACTORY_BODY(Explicit, nullptr, typeRepr); +} + +const RequirementSource *RequirementSource::forExplicit( + GenericSignatureBuilder &builder, + const RequirementRepr *requirementRepr) { + REQUIREMENT_SOURCE_FACTORY_BODY(Explicit, nullptr, requirementRepr); +} + +const RequirementSource *RequirementSource::forInferred( + GenericSignatureBuilder &builder, + TypeRepr *typeRepr) { + REQUIREMENT_SOURCE_FACTORY_BODY(Inferred, nullptr, typeRepr); +} + +const RequirementSource *RequirementSource::forRequirementSignature( + GenericSignatureBuilder &builder, + ProtocolDecl *protocol) { + REQUIREMENT_SOURCE_FACTORY_BODY(RequirementSignatureSelf, nullptr, protocol); +} + +const RequirementSource *RequirementSource::forNestedTypeNameMatch( + GenericSignatureBuilder &builder) { + REQUIREMENT_SOURCE_FACTORY_BODY_NOSTORAGE(NestedTypeNameMatch, nullptr); +} + +const RequirementSource *RequirementSource::viaAbstractProtocolRequirement( + GenericSignatureBuilder &builder, + ProtocolDecl *protocol) const { + REQUIREMENT_SOURCE_FACTORY_BODY(ProtocolRequirement, this, protocol); +} + +const RequirementSource *RequirementSource::viaSuperclass( + GenericSignatureBuilder &builder, + ProtocolConformance *conformance) const { + REQUIREMENT_SOURCE_FACTORY_BODY(Superclass, this, conformance); +} + +const RequirementSource *RequirementSource::viaConcrete( + GenericSignatureBuilder &builder, + ProtocolConformance *conformance) const { + REQUIREMENT_SOURCE_FACTORY_BODY(Concrete, this, conformance); +} + +const RequirementSource *RequirementSource::viaParent( + GenericSignatureBuilder &builder) const { + REQUIREMENT_SOURCE_FACTORY_BODY_NOSTORAGE(Parent, this); +} + +#undef REQUIREMENT_SOURCE_FACTORY_BODY_NOSTORAGE +#undef REQUIREMENT_SOURCE_FACTORY_BODY + +ProtocolDecl *RequirementSource::getProtocolDecl() const { + switch (storageKind) { + case StorageKind::None: + case StorageKind::TypeRepr: + case StorageKind::RequirementRepr: + return nullptr; + + case StorageKind::ProtocolDecl: + return storage.protocol; + + case StorageKind::ProtocolConformance: + if (storage.conformance) + return storage.conformance->getProtocol(); + + return nullptr; + } +} + +SourceLoc RequirementSource::getLoc() const { + if (auto typeRepr = getTypeRepr()) + return typeRepr->getStartLoc(); + if (auto requirementRepr = getRequirementRepr()) { + switch (requirementRepr->getKind()) { + case RequirementReprKind::LayoutConstraint: + case RequirementReprKind::TypeConstraint: + return requirementRepr->getColonLoc(); + + case RequirementReprKind::SameType: + return requirementRepr->getEqualLoc(); + } + } + if (parent) + return parent->getLoc(); + if (kind == RequirementSignatureSelf) + return getProtocolDecl()->getLoc(); + + return SourceLoc(); +} + +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; + + // FIXME: Arbitrary hack to allow later requirement sources to stop on + // earlier ones. We need a proper ordering here. + return +1; +} + +void RequirementSource::dump() const { + dump(llvm::errs(), nullptr, 0); +} + +/// 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); + out.flush(); +} + +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 << " -> "; + } + + switch (kind) { + case Concrete: + out << "Concrete"; break; - case Protocol: - out << "protocol"; + case Explicit: + out << "Explicit"; break; case Inferred: - out << "inferred"; + out << "Inferred"; break; - case Inherited: - out << "inherited"; + case NestedTypeNameMatch: + out << "Nested type match"; break; - case ProtocolRequirementSignatureSelf: - out << "protocol_requirement_signature_self"; + case Parent: + out << "Parent"; + break; + + case ProtocolRequirement: + out << "Protocol requirement"; + break; + + case RequirementSignatureSelf: + out << "Requirement signature self"; break; - } - if (srcMgr && getLoc().isValid()) { - out << " @ "; - getLoc().dump(*srcMgr); + case Superclass: + out << "Superclass"; + break; } -} -/// Update the recorded requirement source when a new requirement -/// source provides the same requirement. -static void updateRequirementSource(RequirementSource &source, - RequirementSource newSource) { - // If the new source is less explicit than the existing source, - // or if they have the same kind but we don't have source location - // information yet, replace the existing source. - if (source.getKind() < newSource.getKind() || - (source.getKind() == newSource.getKind() && - !source.getLoc().isValid())) - source = newSource; -} + // Local function to dump a source location, if we can. + auto dumpSourceLoc = [&](SourceLoc loc) { + if (!srcMgr) return; + if (loc.isInvalid()) return; -struct GenericSignatureBuilder::Implementation { - /// Function used to look up conformances. - std::function LookupConformance; + unsigned bufferID = srcMgr->findBufferContainingLoc(loc); - /// The generic parameters that this generic signature builder is working with. - SmallVector GenericParams; + auto lineAndCol = srcMgr->getLineAndColumn(loc, bufferID); + out << " @ " << lineAndCol.first << ':' << lineAndCol.second; + }; - /// The potential archetypes for the generic parameters in \c GenericParams. - SmallVector PotentialArchetypes; + switch (storageKind) { + case StorageKind::None: + break; - /// The number of nested types that haven't yet been resolved to archetypes. - /// Once all requirements have been added, this will be zero in well-formed - /// code. - unsigned NumUnresolvedNestedTypes = 0; + case StorageKind::TypeRepr: + case StorageKind::RequirementRepr: + dumpSourceLoc(getLoc()); + break; - /// The nested types that have been renamed. - SmallVector RenamedNestedTypes; + case StorageKind::ProtocolDecl: + if (storage.protocol) + out << " (" << storage.protocol->getName() << ")"; + break; -#ifndef NDEBUG - /// Whether we've already finalized the builder. - bool finalized = false; -#endif -}; + case StorageKind::ProtocolConformance: + if (storage.conformance) { + out << " (" << storage.conformance->getType()->getString() << ": " + << storage.conformance->getProtocol()->getName() << ")"; + } + break; + } +} GenericSignatureBuilder::PotentialArchetype::~PotentialArchetype() { for (const auto &nested : NestedTypes) { @@ -177,75 +471,76 @@ void GenericSignatureBuilder::PotentialArchetype::resolveAssociatedType( --builder.Impl->NumUnresolvedNestedTypes; } -/// Retrieve the conformance for the superclass constraint of the given -/// potential archetype (if present) to the given protocol. -/// -/// \param pa The potential archetype whose superclass constraint is being -/// queried. -/// -/// \param proto The protocol to which we are establishing conformance. -/// -/// \param conformsSource The requirement source for the conformance to the -/// given protocol. -/// -/// \param builder The generic signature builder in which the potential archetype -/// resides. -static ProtocolConformance *getSuperConformance( - GenericSignatureBuilder::PotentialArchetype *pa, - ProtocolDecl *proto, - RequirementSource &conformsSource, - GenericSignatureBuilder &builder) { +bool GenericSignatureBuilder::updateRequirementSource( + const RequirementSource *&existingSource, + const RequirementSource *newSource) { + if (int result = newSource->compare(existingSource)) { + if (result < 0) { + existingSource = newSource; + return true; + } + + return false; + } + + assert(existingSource == newSource && "incomparable requirement sources"); + return false; +} + +const RequirementSource *GenericSignatureBuilder::resolveSuperConformance( + GenericSignatureBuilder::PotentialArchetype *pa, + ProtocolDecl *proto, + const RequirementSource *&protoSource) { // Get the superclass constraint. Type superclass = pa->getSuperclass(); if (!superclass) return nullptr; // Lookup the conformance of the superclass to this protocol. auto conformance = - builder.getLookupConformanceFn()(pa->getDependentType( - { }, /*allowUnresolved=*/true) - ->getCanonicalType(), - superclass, - proto->getDeclaredInterfaceType() - ->castTo()); + getLookupConformanceFn()(pa->getDependentType({ }, /*allowUnresolved=*/true) + ->getCanonicalType(), + superclass, + proto->getDeclaredInterfaceType() + ->castTo()); if (!conformance) return nullptr; // Conformance to this protocol is redundant; update the requirement source // appropriately. - updateRequirementSource( - conformsSource, - RequirementSource(RequirementSource::Inherited, - pa->getSuperclassSource().getLoc())); - return conformance->getConcrete(); + auto superclassSource = + pa->getSuperclassSource()->viaSuperclass(*this, conformance->getConcrete()); + updateRequirementSource(protoSource, superclassSource); + return superclassSource; } /// If there is a same-type requirement to be added for the given nested type /// due to a superclass constraint on the parent type, add it now. static void maybeAddSameTypeRequirementForNestedType( GenericSignatureBuilder::PotentialArchetype *nestedPA, - RequirementSource fromSource, - ProtocolConformance *superConformance, + const RequirementSource *superSource, GenericSignatureBuilder &builder) { // If there's no super conformance, we're done. - if (!superConformance) return; + if (!superSource) return; auto assocType = nestedPA->getResolvedAssociatedType(); assert(assocType && "Not resolved to an associated type?"); // Dig out the type witness. + auto superConformance = superSource->getProtocolConformance(); auto concreteType = superConformance->getTypeWitness(assocType, builder.getLazyResolver()) .getReplacement(); if (!concreteType) return; // Add the same-type constraint. + auto nestedSource = superSource->viaParent(builder); concreteType = superConformance->getDeclContext() ->mapTypeOutOfContext(concreteType); if (auto otherPA = builder.resolveArchetype(concreteType)) builder.addSameTypeRequirementBetweenArchetypes( - nestedPA, otherPA, fromSource); + nestedPA, otherPA, nestedSource); else builder.addSameTypeRequirementToConcrete( - nestedPA, concreteType, fromSource); + nestedPA, concreteType, nestedSource); } /// Walk the members of a protocol. @@ -264,7 +559,7 @@ static DeclRange getProtocolMembers(ProtocolDecl *proto) { bool GenericSignatureBuilder::PotentialArchetype::addConformance( ProtocolDecl *proto, bool updateExistingSource, - const RequirementSource &source, + const RequirementSource *source, GenericSignatureBuilder &builder) { auto rep = getRepresentative(); if (rep != this) @@ -276,7 +571,7 @@ bool GenericSignatureBuilder::PotentialArchetype::addConformance( // We already have this requirement. Update the requirement source // appropriately. if (updateExistingSource) - updateRequirementSource(known->second, source); + builder.updateRequirementSource(known->second, source); return false; } @@ -285,12 +580,8 @@ bool GenericSignatureBuilder::PotentialArchetype::addConformance( // Determine whether there is a superclass constraint where the // superclass conforms to this protocol. - ProtocolConformance *superConformance = getSuperConformance(this, proto, - inserted->second, - builder); - - RequirementSource redundantSource(RequirementSource::Redundant, - source.getLoc()); + auto superSource = getBuilder()->resolveSuperConformance(this, proto, + inserted->second); // Check whether any associated types in this protocol resolve // nested types of this potential archetype. @@ -310,8 +601,7 @@ bool GenericSignatureBuilder::PotentialArchetype::addConformance( // If there's a superclass constraint that conforms to the protocol, // add the appropriate same-type relationship. maybeAddSameTypeRequirementForNestedType(known->second.front(), - redundantSource, - superConformance, + superSource, builder); continue; } @@ -320,19 +610,19 @@ bool GenericSignatureBuilder::PotentialArchetype::addConformance( // and make it equivalent to the first potential archetype we encountered. auto otherPA = new PotentialArchetype(this, assocType); known->second.push_back(otherPA); + auto sameNamedSource = RequirementSource::forNestedTypeNameMatch(builder); builder.addSameTypeRequirementBetweenArchetypes(known->second.front(), - otherPA, redundantSource); + otherPA, sameNamedSource); // If there's a superclass constraint that conforms to the protocol, // add the appropriate same-type relationship. - maybeAddSameTypeRequirementForNestedType(otherPA, redundantSource, - superConformance, builder); + maybeAddSameTypeRequirementForNestedType(otherPA, superSource, builder); } return true; } -auto GenericSignatureBuilder::PotentialArchetype::getRepresentative() +auto GenericSignatureBuilder::PotentialArchetype::getRepresentative() const -> PotentialArchetype *{ // Find the representative. PotentialArchetype *Result = Representative; @@ -340,9 +630,9 @@ auto GenericSignatureBuilder::PotentialArchetype::getRepresentative() Result = Result->Representative; // Perform (full) path compression. - PotentialArchetype *FixUp = this; + const PotentialArchetype *FixUp = this; while (FixUp != FixUp->Representative) { - PotentialArchetype *Next = FixUp->Representative; + const PotentialArchetype *Next = FixUp->Representative; FixUp->Representative = Result; FixUp = Next; } @@ -491,25 +781,27 @@ auto GenericSignatureBuilder::PotentialArchetype::getArchetypeAnchor( // parent PA that has a concrete type. static void concretizeNestedTypeFromConcreteParent( GenericSignatureBuilder::PotentialArchetype *parent, - GenericSignatureBuilder::PotentialArchetype *nestedPA, GenericSignatureBuilder &builder, + GenericSignatureBuilder::PotentialArchetype *nestedPA, + GenericSignatureBuilder &builder, llvm::function_ref lookupConformance) { auto concreteParent = parent->getConcreteType(); assert(concreteParent && "attempting to resolve concrete nested type of non-concrete PA"); - // These requirements are all redundant: they're implied by the concrete - // parent. - auto Source = RequirementSource(RequirementSource::Redundant, - parent->getConcreteTypeSource().getLoc()); - + // These requirements are all implied based on the parent's concrete + // conformance. + auto source = parent->getConcreteTypeSource()->viaConcrete(builder, nullptr) + ->viaParent(builder); auto assocType = nestedPA->getResolvedAssociatedType(); if (auto *concreteArchetype = concreteParent->getAs()) { + // FIXME: I think this code is dead... Type witnessType = concreteArchetype->getNestedType(nestedPA->getNestedName()); - builder.addSameTypeRequirementToConcrete(nestedPA, witnessType, Source); + builder.addSameTypeRequirementToConcrete(nestedPA, witnessType, source); } else if (assocType) { + // FIXME: Get the conformance from the parent. auto conformance = lookupConformance(assocType->getProtocol()); Type witnessType; @@ -523,9 +815,9 @@ static void concretizeNestedTypeFromConcreteParent( if (auto witnessPA = builder.resolveArchetype(witnessType)) { builder.addSameTypeRequirementBetweenArchetypes(nestedPA, witnessPA, - Source); + source); } else { - builder.addSameTypeRequirementToConcrete(nestedPA, witnessType, Source); + builder.addSameTypeRequirementToConcrete(nestedPA, witnessType, source); } } } @@ -545,13 +837,12 @@ auto GenericSignatureBuilder::PotentialArchetype::getNestedType( if (rep != this) repNested = rep->getNestedType(nestedName, builder); - RequirementSource redundantSource(RequirementSource::Redundant, - SourceLoc()); + auto sameNestedTypeSource = RequirementSource::forNestedTypeNameMatch(builder); // Attempt to resolve this nested type to an associated type // of one of the protocols to which the parent potential // archetype conforms. - SmallVector, 4> + SmallVector, 4> conformsTo(rep->ConformsTo.begin(), rep->ConformsTo.end()); for (auto &conforms : conformsTo) { for (auto member : conforms.first->lookupDirect(nestedName)) { @@ -572,9 +863,10 @@ auto GenericSignatureBuilder::PotentialArchetype::getNestedType( auto type = alias->getDeclaredInterfaceType(); if (auto existingPA = builder.resolveArchetype(type)) { builder.addSameTypeRequirementBetweenArchetypes(pa, existingPA, - redundantSource); + sameNestedTypeSource); } else { - builder.addSameTypeRequirementToConcrete(pa, type, redundantSource); + builder.addSameTypeRequirementToConcrete(pa, type, + sameNestedTypeSource); } } else continue; @@ -589,22 +881,21 @@ auto GenericSignatureBuilder::PotentialArchetype::getNestedType( // Produce a same-type constraint between the two same-named // potential archetypes. builder.addSameTypeRequirementBetweenArchetypes(pa, nested.front(), - redundantSource); + sameNestedTypeSource); } else { nested.push_back(pa); if (repNested) { builder.addSameTypeRequirementBetweenArchetypes(pa, repNested, - redundantSource); + sameNestedTypeSource); } } // If there's a superclass constraint that conforms to the protocol, // add the appropriate same-type relationship. - ProtocolConformance *superConformance = - getSuperConformance(this, conforms.first, conforms.second, builder); - maybeAddSameTypeRequirementForNestedType(pa, redundantSource, - superConformance, builder); + auto superSource = builder.resolveSuperConformance(this, conforms.first, + conforms.second); + maybeAddSameTypeRequirementForNestedType(pa, superSource, builder); } } @@ -648,7 +939,7 @@ auto GenericSignatureBuilder::PotentialArchetype::getNestedType( // somewhere else. bool failed = builder.addConformanceRequirement( this, assocType->getProtocol(), - RequirementSource(RequirementSource::Inferred, SourceLoc())); + RequirementSource::forInferred(builder, nullptr)); (void)failed; // Trigger the construction of nested types with this name. @@ -782,20 +1073,8 @@ Type GenericSignatureBuilder::PotentialArchetype::getTypeInContext( // Collect the protocol conformances for the archetype. SmallVector Protos; for (const auto &conforms : representative->getConformsTo()) { - switch (conforms.second.getKind()) { - case RequirementSource::Explicit: - case RequirementSource::Inferred: - case RequirementSource::Protocol: - case RequirementSource::ProtocolRequirementSignatureSelf: - case RequirementSource::Redundant: + if (conforms.second->kind != RequirementSource::Superclass) Protos.push_back(conforms.first); - break; - - case RequirementSource::Inherited: - // Inherited conformances are recoverable from the superclass - // constraint. - break; - } } // Create the archetype. @@ -879,9 +1158,13 @@ Type GenericSignatureBuilder::PotentialArchetype::getDependentType( return genericParams[index]; } +void GenericSignatureBuilder::PotentialArchetype::dump() const { + dump(llvm::errs(), nullptr, 0); +} + void GenericSignatureBuilder::PotentialArchetype::dump(llvm::raw_ostream &Out, - SourceManager *SrcMgr, - unsigned Indent) { + SourceManager *SrcMgr, + unsigned Indent) const { // Print name. if (Indent == 0 || isGenericParam()) Out << getDebugName(); @@ -892,8 +1175,23 @@ void GenericSignatureBuilder::PotentialArchetype::dump(llvm::raw_ostream &Out, if (Superclass) { Out << " : "; Superclass.print(Out); - Out << " ["; - SuperclassSource->dump(Out, SrcMgr); + Out << " "; + if (!SuperclassSource->isDerivedRequirement()) + Out << "*"; + Out << "["; + SuperclassSource->print(Out, SrcMgr); + Out << "]"; + } + + // Print concrete type. + if (ConcreteType) { + Out << " == "; + ConcreteType.print(Out); + Out << " "; + if (!ConcreteTypeSource->isDerivedRequirement()) + Out << "*"; + Out << "["; + ConcreteTypeSource->print(Out, SrcMgr); Out << "]"; } @@ -908,8 +1206,11 @@ void GenericSignatureBuilder::PotentialArchetype::dump(llvm::raw_ostream &Out, else Out << " & "; - Out << ProtoAndSource.first->getName().str() << " ["; - ProtoAndSource.second.dump(Out, SrcMgr); + Out << ProtoAndSource.first->getName().str() << " "; + if (!ProtoAndSource.second->isDerivedRequirement()) + Out << "*"; + Out << "["; + ProtoAndSource.second->print(Out, SrcMgr); Out << "]"; } } @@ -997,15 +1298,25 @@ void GenericSignatureBuilder::addGenericParameter(GenericTypeParamDecl *GenericP GenericParam->getDeclaredInterfaceType()->castTo()); } -bool GenericSignatureBuilder::addGenericParameterRequirements(GenericTypeParamDecl *GenericParam) { +bool GenericSignatureBuilder::addGenericParameterRequirements( + GenericTypeParamDecl *GenericParam) { GenericParamKey Key(GenericParam); auto PA = Impl->PotentialArchetypes[Key.findIndexIn(Impl->GenericParams)]; // Add the requirements from the declaration. + // FIXME: addAbstractTypeParamRequirements() should supply the source itself + // based on a parent source. + const RequirementSource *source; + if (GenericParam->getInherited().size() > 0 && + GenericParam->getInherited()[0].getTypeRepr()) { + source = RequirementSource::forExplicit( + *this, + GenericParam->getInherited()[0].getTypeRepr()); + } else { + source = RequirementSource::forAbstract(*this); + } llvm::SmallPtrSet visited; - return addAbstractTypeParamRequirements(GenericParam, PA, - RequirementSource::Explicit, - visited); + return addAbstractTypeParamRequirements(GenericParam, PA, source, visited); } void GenericSignatureBuilder::addGenericParameter(GenericTypeParamType *GenericParam) { @@ -1024,14 +1335,14 @@ void GenericSignatureBuilder::addGenericParameter(GenericTypeParamType *GenericP bool GenericSignatureBuilder::addConformanceRequirement(PotentialArchetype *PAT, ProtocolDecl *Proto, - RequirementSource Source) { + const RequirementSource *Source) { llvm::SmallPtrSet Visited; return addConformanceRequirement(PAT, Proto, Source, Visited); } bool GenericSignatureBuilder::addConformanceRequirement(PotentialArchetype *PAT, ProtocolDecl *Proto, - RequirementSource Source, + const RequirementSource *Source, llvm::SmallPtrSetImpl &Visited) { // Add the requirement to the representative. auto T = PAT->getRepresentative(); @@ -1044,12 +1355,7 @@ bool GenericSignatureBuilder::addConformanceRequirement(PotentialArchetype *PAT, assert(inserted); (void) inserted; - // Requirements introduced by the main protocol are explicit in a protocol - // requirement signature, but inferred from this conformance otherwise. - auto Kind = - Source.getKind() == RequirementSource::ProtocolRequirementSignatureSelf - ? RequirementSource::Explicit - : RequirementSource::Protocol; + auto InnerSource = Source->viaAbstractProtocolRequirement(*this, Proto); // Use the requirement signature to avoid rewalking the entire protocol. This // cannot compute the requirement signature directly, because that may be @@ -1064,17 +1370,9 @@ bool GenericSignatureBuilder::addConformanceRequirement(PotentialArchetype *PAT, for (auto rawReq : reqSig->getRequirements()) { auto req = rawReq.subst(subMap); assert(req && "substituting Self in requirement shouldn't fail"); - RequirementSource InnerSource(Kind, Source.getLoc()); addRequirement(*req, InnerSource, Visited); } } else { - // Conformances to inherit protocols are explicit in a protocol requirement - // signature, but inferred from this conformance otherwise. - auto InnerKind = - Source.getKind() == RequirementSource::ProtocolRequirementSignatureSelf - ? RequirementSource::Explicit - : RequirementSource::Redundant; - RequirementSource InnerSource(InnerKind, Source.getLoc()); // Add all of the inherited protocol requirements, recursively. if (auto resolver = getLazyResolver()) resolver->resolveInheritedProtocols(Proto); @@ -1096,7 +1394,7 @@ bool GenericSignatureBuilder::addConformanceRequirement(PotentialArchetype *PAT, auto AssocPA = T->getNestedType(AssocType, *this); if (AssocPA != T) { - if (addAbstractTypeParamRequirements(AssocType, AssocPA, Kind, + if (addAbstractTypeParamRequirements(AssocType, AssocPA, InnerSource, Visited)) return true; } @@ -1114,7 +1412,7 @@ bool GenericSignatureBuilder::addConformanceRequirement(PotentialArchetype *PAT, bool GenericSignatureBuilder::addLayoutRequirement(PotentialArchetype *PAT, LayoutConstraint Layout, - RequirementSource Source) { + const RequirementSource *Source) { // Add the requirement to the representative. auto T = PAT->getRepresentative(); @@ -1125,7 +1423,7 @@ bool GenericSignatureBuilder::addLayoutRequirement(PotentialArchetype *PAT, return false; } // There is an existing layout constraint for this archetype. - Diags.diagnose(Source.getLoc(), diag::mutiple_layout_constraints, + Diags.diagnose(Source->getLoc(), diag::mutiple_layout_constraints, Layout, T->Layout); Diags.diagnose(T->LayoutSource->getLoc(), diag::previous_layout_constraint, T->Layout); @@ -1142,7 +1440,7 @@ bool GenericSignatureBuilder::addLayoutRequirement(PotentialArchetype *PAT, bool GenericSignatureBuilder::addSuperclassRequirement(PotentialArchetype *T, Type Superclass, - RequirementSource Source) { + const RequirementSource *Source) { T = T->getRepresentative(); // Make sure the concrete type fulfills the superclass requirement @@ -1150,12 +1448,12 @@ bool GenericSignatureBuilder::addSuperclassRequirement(PotentialArchetype *T, if (T->isConcreteType()) { Type concrete = T->getConcreteType(); if (!Superclass->isExactSuperclassOf(concrete, getLazyResolver())) { - Diags.diagnose(T->getConcreteTypeSource().getLoc(), + Diags.diagnose(T->getConcreteTypeSource()->getLoc(), diag::type_does_not_inherit, T->getDependentType(/*FIXME:*/{ }, /*allowUnresolved=*/true), concrete, Superclass) - .highlight(Source.getLoc()); + .highlight(Source->getLoc()); return true; } @@ -1166,8 +1464,8 @@ bool GenericSignatureBuilder::addSuperclassRequirement(PotentialArchetype *T, // when the superclass constraint changes. auto updateSuperclassConformances = [&] { for (auto &conforms : T->ConformsTo) { - if (auto superConformance = getSuperConformance(T, conforms.first, - conforms.second, *this)) { + if (auto superSource = resolveSuperConformance(T, conforms.first, + conforms.second)) { for (auto req : getProtocolMembers(conforms.first)) { auto assocType = dyn_cast(req); if (!assocType) continue; @@ -1176,14 +1474,10 @@ bool GenericSignatureBuilder::addSuperclassRequirement(PotentialArchetype *T, auto nested = nestedTypes.find(assocType->getName()); if (nested == nestedTypes.end()) continue; - RequirementSource redundantSource(RequirementSource::Inherited, - Source.getLoc()); - for (auto nestedPA : nested->second) { if (nestedPA->getResolvedAssociatedType() == assocType) - maybeAddSameTypeRequirementForNestedType(nestedPA, - redundantSource, - superConformance, *this); + maybeAddSameTypeRequirementForNestedType(nestedPA, superSource, + *this); } } } @@ -1219,7 +1513,7 @@ bool GenericSignatureBuilder::addSuperclassRequirement(PotentialArchetype *T, // then the second `U: Foo` constraint introduces a `T == Int` // constraint. } else if (!Superclass->isExactSuperclassOf(T->Superclass, nullptr)) { - Diags.diagnose(Source.getLoc(), + Diags.diagnose(Source->getLoc(), diag::requires_superclass_conflict, T->getDependentType(/*FIXME: */{ }, true), T->Superclass, Superclass) @@ -1227,7 +1521,7 @@ bool GenericSignatureBuilder::addSuperclassRequirement(PotentialArchetype *T, return true; } - updateRequirementSource(*T->SuperclassSource, Source); + updateRequirementSource(T->SuperclassSource, Source); return false; } @@ -1242,25 +1536,29 @@ bool GenericSignatureBuilder::addSuperclassRequirement(PotentialArchetype *T, void GenericSignatureBuilder::PotentialArchetype::addSameTypeConstraint( PotentialArchetype *otherPA, - const RequirementSource &source) { + const RequirementSource *source) { // If the types are the same, there's nothing to do. if (this == otherPA) return; // Update the same-type constraints of this PA to reference the other PA. auto insertedIntoThis = SameTypeConstraints.insert({otherPA, source}); - if (!insertedIntoThis.second) - updateRequirementSource(insertedIntoThis.first->second, source); + if (!insertedIntoThis.second) { + getBuilder()->updateRequirementSource(insertedIntoThis.first->second, + source); + } // Update the same-type constraints of the other PA to reference this PA. auto insertedIntoOther = otherPA->SameTypeConstraints.insert({this, source}); - if (!insertedIntoOther.second) - updateRequirementSource(insertedIntoOther.first->second, source); + if (!insertedIntoOther.second) { + getBuilder()->updateRequirementSource(insertedIntoOther.first->second, + source); + } } bool GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes( PotentialArchetype *OrigT1, PotentialArchetype *OrigT2, - RequirementSource Source) + const RequirementSource *Source) { // Record the same-type constraint. OrigT1->addSameTypeConstraint(OrigT2, Source); @@ -1280,7 +1578,7 @@ bool GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes( if (concrete1 && concrete2) { bool mismatch = addSameTypeRequirement( concrete1, concrete2, Source, [&](Type type1, Type type2) { - Diags.diagnose(Source.getLoc(), + Diags.diagnose(Source->getLoc(), diag::requires_same_type_conflict, T1->getDependentType(/*FIXME: */{ }, true), type1, type2); @@ -1342,13 +1640,13 @@ bool GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes( } // Recursively merge the associated types of T2 into T1. - RequirementSource redundantSource(RequirementSource::Redundant, SourceLoc()); + auto sameNestedTypeSource = RequirementSource::forNestedTypeNameMatch(*this); for (auto equivT2 : T2->EquivalenceClass) { for (auto T2Nested : equivT2->NestedTypes) { auto T1Nested = T1->getNestedType(T2Nested.first, *this); if (addSameTypeRequirementBetweenArchetypes(T1Nested, T2Nested.second.front(), - redundantSource)) + sameNestedTypeSource)) return true; } } @@ -1359,7 +1657,7 @@ bool GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes( bool GenericSignatureBuilder::addSameTypeRequirementToConcrete( PotentialArchetype *T, Type Concrete, - RequirementSource Source) { + const RequirementSource *Source) { // Operate on the representative. T = T->getRepresentative(); @@ -1368,7 +1666,7 @@ bool GenericSignatureBuilder::addSameTypeRequirementToConcrete( if (auto oldConcrete = T->getConcreteType()) { bool mismatch = addSameTypeRequirement( oldConcrete, Concrete, Source, [&](Type type1, Type type2) { - Diags.diagnose(Source.getLoc(), + Diags.diagnose(Source->getLoc(), diag::requires_same_type_conflict, T->getDependentType(/*FIXME: */{ }, true), type1, type2); @@ -1384,20 +1682,25 @@ bool GenericSignatureBuilder::addSameTypeRequirementToConcrete( if (!Concrete->is()) { CanType depTy = T->getDependentType({ }, /*allowUnresolved=*/true) ->getCanonicalType(); - for (auto conforms : T->getConformsTo()) { + for (auto &conforms : T->getConformsTo()) { auto protocol = conforms.first; auto conformance = getLookupConformanceFn()(depTy, Concrete, protocol->getDeclaredInterfaceType() ->castTo()); if (!conformance) { - Diags.diagnose(Source.getLoc(), + Diags.diagnose(Source->getLoc(), diag::requires_generic_param_same_type_does_not_conform, Concrete, protocol->getName()); return true; } conformances.insert({protocol, *conformance}); + + // Update the requirement source now that we know it's concrete. + auto concreteSource = Source->viaConcrete(*this, + conformance->getConcrete()); + updateRequirementSource(conforms.second, concreteSource); } } @@ -1407,11 +1710,9 @@ bool GenericSignatureBuilder::addSameTypeRequirementToConcrete( // Make sure the concrete type fulfills the superclass requirement // of the archetype. - RequirementSource redundantSource(RequirementSource::Redundant, - Source.getLoc()); if (T->Superclass) { if (!T->Superclass->isExactSuperclassOf(Concrete, getLazyResolver())) { - Diags.diagnose(Source.getLoc(), diag::type_does_not_inherit, + Diags.diagnose(Source->getLoc(), diag::type_does_not_inherit, T->getDependentType(/*FIXME: */{ }, /*allowUnresolved=*/true), Concrete, T->Superclass) @@ -1421,7 +1722,8 @@ bool GenericSignatureBuilder::addSameTypeRequirementToConcrete( // The superclass requirement is made redundant by the concrete type // assignment. - updateRequirementSource(*T->SuperclassSource, redundantSource); + auto concreteSource = Source->viaConcrete(*this, nullptr); + updateRequirementSource(T->SuperclassSource, concreteSource); } // Eagerly resolve any existing nested types to their concrete forms (others @@ -1440,16 +1742,16 @@ bool GenericSignatureBuilder::addSameTypeRequirementToConcrete( } bool GenericSignatureBuilder::addSameTypeRequirement( - Type type1, Type type2, RequirementSource source, + Type type1, Type type2, const RequirementSource *source, llvm::function_ref diagnoseMismatch) { // Local class to handle matching the two sides of the same-type constraint. class ReqTypeMatcher : public TypeMatcher { GenericSignatureBuilder &builder; - RequirementSource source; + const RequirementSource *source; llvm::function_ref diagnoseMismatch; public: - ReqTypeMatcher(GenericSignatureBuilder &builder, RequirementSource source, + ReqTypeMatcher(GenericSignatureBuilder &builder, const RequirementSource *source, llvm::function_ref diagnoseMismatch) : builder(builder), source(source), diagnoseMismatch(diagnoseMismatch) { } @@ -1484,7 +1786,7 @@ bool GenericSignatureBuilder::addSameTypeRequirement( // Local function to mark the given associated type as recursive, // diagnosing it if this is the first such occurrence. void GenericSignatureBuilder::markPotentialArchetypeRecursive( - PotentialArchetype *pa, ProtocolDecl *proto, RequirementSource source) { + PotentialArchetype *pa, ProtocolDecl *proto, const RequirementSource *source) { if (pa->isRecursive()) return; pa->setIsRecursive(); @@ -1507,7 +1809,7 @@ void GenericSignatureBuilder::markPotentialArchetypeRecursive( bool GenericSignatureBuilder::addAbstractTypeParamRequirements( AbstractTypeParamDecl *decl, PotentialArchetype *pa, - RequirementSource::Kind kind, + const RequirementSource *source, llvm::SmallPtrSetImpl &visited) { if (isa(decl) && decl->hasInterfaceType() && @@ -1519,7 +1821,6 @@ bool GenericSignatureBuilder::addAbstractTypeParamRequirements( resolver->resolveInheritanceClause(decl); return visitInherited(decl->getInherited(), [&](Type inheritedType, SourceLoc loc) -> bool { - RequirementSource source(kind, loc); // Protocol requirement. if (auto protocolType = inheritedType->getAs()) { if (visited.count(protocolType->getDecl())) { @@ -1568,48 +1869,44 @@ bool GenericSignatureBuilder::visitInherited( return isInvalid; } -bool GenericSignatureBuilder::addRequirement(const RequirementRepr &Req) { - switch (Req.getKind()) { +bool GenericSignatureBuilder::addRequirement(const RequirementRepr *Req) { + auto source = RequirementSource::forExplicit(*this, Req); + + switch (Req->getKind()) { case RequirementReprKind::LayoutConstraint: { // FIXME: Need to do something here. - PotentialArchetype *PA = resolveArchetype(Req.getSubject()); + PotentialArchetype *PA = resolveArchetype(Req->getSubject()); if (!PA) { // FIXME: Poor location information. // FIXME: Delay diagnostic until after type validation? - Diags.diagnose(Req.getColonLoc(), diag::requires_not_suitable_archetype, - 0, Req.getSubjectLoc(), 0); + Diags.diagnose(Req->getColonLoc(), diag::requires_not_suitable_archetype, + 0, Req->getSubjectLoc(), 0); return true; } - RequirementSource source( - RequirementSource::Explicit, - Req.getLayoutConstraintLoc().getSourceRange().Start); - - if (addLayoutRequirement(PA, Req.getLayoutConstraint(), source)) + if (addLayoutRequirement(PA, Req->getLayoutConstraint(), source)) return true; return false; } case RequirementReprKind::TypeConstraint: { - PotentialArchetype *PA = resolveArchetype(Req.getSubject()); + PotentialArchetype *PA = resolveArchetype(Req->getSubject()); if (!PA) { // FIXME: Poor location information. // FIXME: Delay diagnostic until after type validation? - Diags.diagnose(Req.getColonLoc(), diag::requires_not_suitable_archetype, - 0, Req.getSubjectLoc(), 0); + Diags.diagnose(Req->getColonLoc(), diag::requires_not_suitable_archetype, + 0, Req->getSubjectLoc(), 0); return true; } // Check whether this is a supertype requirement. - RequirementSource source(RequirementSource::Explicit, - Req.getConstraintLoc().getSourceRange().Start); - if (Req.getConstraint()->getClassOrBoundGenericClass()) { - return addSuperclassRequirement(PA, Req.getConstraint(), source); + if (Req->getConstraint()->getClassOrBoundGenericClass()) { + return addSuperclassRequirement(PA, Req->getConstraint(), source); } SmallVector ConformsTo; - if (!Req.getConstraint()->isExistentialType(ConformsTo)) { + if (!Req->getConstraint()->isExistentialType(ConformsTo)) { // FIXME: Diagnose this failure here, rather than over in type-checking. return true; } @@ -1625,32 +1922,31 @@ bool GenericSignatureBuilder::addRequirement(const RequirementRepr &Req) { case RequirementReprKind::SameType: // Require that at least one side of the requirement contain a type // parameter. - if (!Req.getFirstType()->hasTypeParameter() && - !Req.getSecondType()->hasTypeParameter()) { - Diags.diagnose(Req.getEqualLoc(), diag::requires_no_same_type_archetype) - .highlight(Req.getFirstTypeLoc().getSourceRange()) - .highlight(Req.getSecondTypeLoc().getSourceRange()); + if (!Req->getFirstType()->hasTypeParameter() && + !Req->getSecondType()->hasTypeParameter()) { + Diags.diagnose(Req->getEqualLoc(), diag::requires_no_same_type_archetype) + .highlight(Req->getFirstTypeLoc().getSourceRange()) + .highlight(Req->getSecondTypeLoc().getSourceRange()); return true; } return addRequirement(Requirement(RequirementKind::SameType, - Req.getFirstType(), - Req.getSecondType()), - RequirementSource(RequirementSource::Explicit, - Req.getEqualLoc())); + Req->getFirstType(), + Req->getSecondType()), + source); } llvm_unreachable("Unhandled requirement?"); } bool GenericSignatureBuilder::addRequirement(const Requirement &req, - RequirementSource source) { + const RequirementSource *source) { llvm::SmallPtrSet Visited; return addRequirement(req, source, Visited); } bool GenericSignatureBuilder::addRequirement( - const Requirement &req, RequirementSource source, + const Requirement &req, const RequirementSource *source, llvm::SmallPtrSetImpl &Visited) { switch (req.getKind()) { case RequirementKind::Superclass: { @@ -1694,8 +1990,8 @@ bool GenericSignatureBuilder::addRequirement( return addSameTypeRequirement( req.getFirstType(), req.getSecondType(), source, [&](Type type1, Type type2) { - if (source.getLoc().isValid()) - Diags.diagnose(source.getLoc(), + if (source->getLoc().isValid()) + Diags.diagnose(source->getLoc(), diag::requires_same_concrete_type, type1, type2); }); @@ -1707,7 +2003,7 @@ bool GenericSignatureBuilder::addRequirement( /// AST walker that infers requirements from type representations. class GenericSignatureBuilder::InferRequirementsWalker : public TypeWalker { GenericSignatureBuilder &Builder; - SourceLoc Loc; + TypeRepr *typeRepr; unsigned MinDepth; unsigned MaxDepth; @@ -1722,10 +2018,11 @@ class GenericSignatureBuilder::InferRequirementsWalker : public TypeWalker { public: InferRequirementsWalker(GenericSignatureBuilder &builder, - SourceLoc loc, + TypeRepr *typeRepr, unsigned MinDepth, unsigned MaxDepth) - : Builder(builder), Loc(loc), MinDepth(MinDepth), MaxDepth(MaxDepth) { } + : Builder(builder), typeRepr(typeRepr), MinDepth(MinDepth), + MaxDepth(MaxDepth) { } Action walkToTypePost(Type ty) override { auto boundGeneric = ty->getAs(); @@ -1752,13 +2049,15 @@ class GenericSignatureBuilder::InferRequirementsWalker : public TypeWalker { }; // Handle the requirements. - RequirementSource source(RequirementSource::Inferred, Loc); + // FIXME: Inaccurate TypeReprs. + auto source = RequirementSource::forInferred(Builder, typeRepr); for (const auto &rawReq : genericSig->getRequirements()) { auto req = rawReq.subst(getTypeSubstitution, Builder.getLookupConformanceFn()); if (!req) continue; + // FIXME: Use Requirement substitution here. switch (req->getKind()) { case RequirementKind::SameType: { auto firstType = req->getFirstType(); @@ -1836,7 +2135,7 @@ void GenericSignatureBuilder::inferRequirements(TypeLoc type, if (!type.getType()) return; // FIXME: Crummy source-location information. - InferRequirementsWalker walker(*this, type.getSourceRange().Start, + InferRequirementsWalker walker(*this, type.getTypeRepr(), minDepth, maxDepth); type.getType().walk(walker); } @@ -2081,7 +2380,7 @@ GenericSignatureBuilder::finalize(SourceLoc loc, SourceLoc constraintLoc; for (const auto &sameType : pa->getSameTypeConstraints()) { - SourceLoc sameTypeLoc = sameType.second.getLoc(); + SourceLoc sameTypeLoc = sameType.second->getLoc(); if (sameTypeLoc.isInvalid()) continue; if (sameType.first == other) { @@ -2130,8 +2429,8 @@ GenericSignatureBuilder::finalize(SourceLoc loc, pa->resolveAssociatedType(replacement->getResolvedAssociatedType(), *this); addSameTypeRequirementBetweenArchetypes( - pa, replacement, - RequirementSource(RequirementSource::Redundant, SourceLoc())); + pa, replacement, + RequirementSource::forNestedTypeNameMatch(*this)); }); } } @@ -2205,16 +2504,18 @@ static void sameTypeDFS(PotentialArchetype *pa, // Visit its adjacent potential archetypes. for (const auto &sameType : pa->getSameTypeConstraints()) { - switch (sameType.second.getKind()) { + switch (sameType.second->kind) { case RequirementSource::Explicit: case RequirementSource::Inferred: - case RequirementSource::ProtocolRequirementSignatureSelf: + case RequirementSource::RequirementSignatureSelf: // Skip explicit constraints. continue; - case RequirementSource::Inherited: - case RequirementSource::Protocol: - case RequirementSource::Redundant: + case RequirementSource::Concrete: + case RequirementSource::NestedTypeNameMatch: + case RequirementSource::Parent: + case RequirementSource::ProtocolRequirement: + case RequirementSource::Superclass: break; } @@ -2292,7 +2593,7 @@ void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref< void (RequirementKind kind, PotentialArchetype *archetype, GenericSignatureBuilder::RequirementRHS constraint, - RequirementSource source)> f) { + const RequirementSource *source)> f) { // Collect all archetypes. SmallVector archetypes; visitPotentialArchetypes([&](PotentialArchetype *archetype) { @@ -2353,7 +2654,7 @@ void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref< f(RequirementKind::SameType, archetype, concreteType, knownAnchor == componentAnchors.begin() ? rep->getConcreteTypeSource() - : RequirementSource(RequirementSource::Explicit, SourceLoc())); + : RequirementSource::forAbstract(*this)); continue; } @@ -2365,9 +2666,9 @@ void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref< // to the next. // FIXME: Distinguish between explicit and inferred here? auto otherPA = *nextAnchor; - deferredSameTypeRequirement = [&f, archetype, otherPA] { + deferredSameTypeRequirement = [&f, archetype, otherPA, this] { f(RequirementKind::SameType, archetype, otherPA, - RequirementSource(RequirementSource::Explicit, SourceLoc())); + RequirementSource::forAbstract(*this)); }; } } @@ -2393,7 +2694,7 @@ void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref< // Enumerate conformance requirements. SmallVector protocols; - DenseMap protocolSources; + DenseMap protocolSources; for (const auto &conforms : rep->getConformsTo()) { protocols.push_back(conforms.first); assert(protocolSources.count(conforms.first) == 0 && @@ -2424,21 +2725,21 @@ void GenericSignatureBuilder::dump(llvm::raw_ostream &out) { enumerateRequirements([&](RequirementKind kind, PotentialArchetype *archetype, GenericSignatureBuilder::RequirementRHS constraint, - RequirementSource source) { + const RequirementSource *source) { switch (kind) { case RequirementKind::Conformance: case RequirementKind::Superclass: out << "\n "; out << archetype->getDebugName() << " : " << constraint.get().getString() << " ["; - source.dump(out, &Context.SourceMgr); + source->print(out, &Context.SourceMgr); out << "]"; break; case RequirementKind::Layout: out << "\n "; out << archetype->getDebugName() << " : " << constraint.get().getString() << " ["; - source.dump(out, &Context.SourceMgr); + source->print(out, &Context.SourceMgr); out << "]"; break; case RequirementKind::SameType: @@ -2450,7 +2751,7 @@ void GenericSignatureBuilder::dump(llvm::raw_ostream &out) { out << constraint.get()->getDebugName(); } out << " ["; - source.dump(out, &Context.SourceMgr); + source->print(out, &Context.SourceMgr); out << "]"; break; } @@ -2467,11 +2768,10 @@ void GenericSignatureBuilder::dump(llvm::raw_ostream &out) { void GenericSignatureBuilder::addGenericSignature(GenericSignature *sig) { if (!sig) return; - RequirementSource::Kind sourceKind = RequirementSource::Explicit; for (auto param : sig->getGenericParams()) addGenericParameter(param); - RequirementSource source(sourceKind, SourceLoc()); + auto source = RequirementSource::forAbstract(*this); for (auto &reqt : sig->getRequirements()) { addRequirement(reqt, source); } @@ -2485,21 +2785,9 @@ static void collectRequirements(GenericSignatureBuilder &builder, builder.enumerateRequirements([&](RequirementKind kind, GenericSignatureBuilder::PotentialArchetype *archetype, GenericSignatureBuilder::RequirementRHS type, - RequirementSource source) { - // Filter out redundant requirements. - switch (source.getKind()) { - case RequirementSource::Explicit: - case RequirementSource::Inferred: - // The requirement was explicit and required, keep it. - break; - - case RequirementSource::Protocol: - case RequirementSource::Redundant: - case RequirementSource::Inherited: - case RequirementSource::ProtocolRequirementSignatureSelf: - // The requirement was redundant, drop it. - return; - } + const RequirementSource *source) { + // Filter out derived requirements. + if (source->isDerivedRequirement()) return; auto depTy = archetype->getDependentType(params, /*allowUnresolved=*/false); diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index 414566fc3e991..77b74906823e5 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -2509,7 +2509,7 @@ buildThunkSignature(SILGenFunction &gen, builder.addGenericParameter(newGenericParam); Requirement newRequirement(RequirementKind::Conformance, newGenericParam, openedExistential->getOpenedExistentialType()); - RequirementSource source(RequirementSource::Explicit, SourceLoc()); + auto source = RequirementSource::forAbstract(builder); builder.addRequirement(newRequirement, source); builder.finalize(SourceLoc(), {newGenericParam}, diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp index 80081dfa520a8..710049640a149 100644 --- a/lib/SILOptimizer/Utils/Generics.cpp +++ b/lib/SILOptimizer/Utils/Generics.cpp @@ -294,7 +294,7 @@ getSignatureWithRequirements(GenericSignature *OrigGenSig, // First, add the old generic signature. Builder.addGenericSignature(OrigGenSig); - RequirementSource Source(RequirementSource::Explicit, SourceLoc()); + auto Source = RequirementSource::forAbstract(Builder); // For each substitution with a concrete type as a replacement, // add a new concrete type equality requirement. for (auto &Req : Requirements) { diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 897d0bc0e6301..a9195abaaae8c 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -1650,9 +1650,6 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) { secondType->is()) continue; - RequirementSource source(RequirementSource::Kind::Explicit, - req.getEqualLoc()); - Type genericType; Type concreteType; if (interfaceFirstType->hasTypeParameter()) { @@ -1672,7 +1669,6 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) { TypeLoc(req.getFirstTypeRepr(), concreteType), req.getEqualLoc(), TypeLoc(req.getSecondTypeRepr(), genericType))); } - Builder.addRequirement(resolvedRequirements.back()); // Convert the requirement into a form which uses canonical interface // types. @@ -1707,7 +1703,6 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) { req.getLayoutConstraintLoc()); // Add a resolved requirement. - Builder.addRequirement(resolvedReq); resolvedRequirements.push_back(resolvedReq); // Convert the requirement into a form which uses canonical interface @@ -1750,7 +1745,6 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) { TypeLoc(req.getConstraintRepr(), interfaceLayoutConstraint)); // Add a resolved requirement. - Builder.addRequirement(resolvedReq); resolvedRequirements.push_back(resolvedReq); // Convert the requirement into a form which uses canonical interface @@ -1771,6 +1765,10 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) { // Store converted requirements in the attribute so that they are // serialized later. attr->setRequirements(DC->getASTContext(), convertedRequirements); + + // Add the requirements to the builder. + for (auto &req : resolvedRequirements) + Builder.addRequirement(&req); } static Accessibility getAccessForDiagnostics(const ValueDecl *D) { diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index c3409b0b15c25..48de78454e54b 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -350,7 +350,7 @@ void TypeChecker::checkGenericParamList(GenericSignatureBuilder *builder, break; } - if (builder && builder->addRequirement(req)) + if (builder && builder->addRequirement(&req)) req.setInvalid(); } } diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index b5fc841481cd4..0e47a4a74257d 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -1073,7 +1073,7 @@ RequirementEnvironment::RequirementEnvironment( // Next, add each of the requirements (mapped from the requirement's // interface types into the abstract type parameters). - RequirementSource source(RequirementSource::Explicit, SourceLoc()); + auto source = RequirementSource::forAbstract(builder); for (auto &reqReq : reqSig->getRequirements()) { switch (reqReq.getKind()) { case RequirementKind::Conformance: { diff --git a/test/Generics/associated_type_typo.swift b/test/Generics/associated_type_typo.swift index 683fa8e9ca658..e287affb862f8 100644 --- a/test/Generics/associated_type_typo.swift +++ b/test/Generics/associated_type_typo.swift @@ -37,9 +37,9 @@ func typoAssoc4(_: T) where T.Assocp2.assoc : P3 {} // CHECK-GENERIC-LABEL: .typoAssoc4@ // CHECK-GENERIC-NEXT: Requirements: -// CHECK-GENERIC-NEXT: τ_0_0 : P2 [inferred] -// CHECK-GENERIC-NEXT: τ_0_0[.P2].AssocP2 : P1 [protocol -// CHECK-GENERIC-NEXT: τ_0_0[.P2].AssocP2[.P1].Assoc : P3 [explicit +// CHECK-GENERIC-NEXT: τ_0_0 : P2 [Explicit @ {{.*}}:21] +// CHECK-GENERIC-NEXT: τ_0_0[.P2].AssocP2 : P1 [Explicit @ {{.*}}:21 -> Protocol requirement (P2)] +// CHECK-GENERIC-NEXT: τ_0_0[.P2].AssocP2[.P1].Assoc : P3 [Explicit @ {{.*}}:53] // CHECK-GENERIC-NEXT: Potential archetypes // diff --git a/test/Generics/requirement_inference.swift b/test/Generics/requirement_inference.swift index 32d740c78f29d..2d480752f7cc2 100644 --- a/test/Generics/requirement_inference.swift +++ b/test/Generics/requirement_inference.swift @@ -57,7 +57,7 @@ class Fox : P1 { class Box { // CHECK-LABEL: .unpack@ // CHECK-NEXT: Requirements: -// CHECK-NEXT: τ_0_0 : Fox [explicit] +// CHECK-NEXT: τ_0_0 : Fox [Explicit] func unpack(_ x: X1) {} } @@ -111,26 +111,27 @@ struct Model_P3_P4_Eq where T.P3Assoc == U.P4Assoc {} // CHECK-LABEL: .inferSameType1@ // CHECK-NEXT: Requirements: -// CHECK-NEXT: τ_0_0 : P3 [inferred @ {{.*}}:32] -// CHECK-NEXT: τ_0_1 : P4 [inferred @ {{.*}}:32] -// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P1 [protocol @ {{.*}}:32] -// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [protocol @ {{.*}}:32] +// CHECK-NEXT: τ_0_0 : P3 [Inferred @ {{.*}}:32] +// CHECK-NEXT: τ_0_1 : P4 [Inferred @ {{.*}}:32] +// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P1 [Inferred @ {{.*}}:32 -> Protocol requirement (P3) -> Protocol requirement (P2)] +// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [Inferred @ {{.*}}:32 -> Protocol requirement (P3)] +// FIXME: τ_0_0[.P3].P3Assoc == τ_0_1[.P4].P4Assoc [Inferred] func inferSameType1(_ x: Model_P3_P4_Eq) { } // CHECK-LABEL: .inferSameType2@ // CHECK-NEXT: Requirements: -// CHECK-NEXT: τ_0_0 : P3 [inferred] -// CHECK-NEXT: τ_0_1 : P4 [inferred] -// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P1 [protocol @ {{.*}}requirement_inference.swift:{{.*}}:25] -// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [protocol @ {{.*}}requirement_inference.swift:{{.*}}:25] -// CHECK-NEXT: τ_0_0[.P3].P3Assoc == τ_0_1[.P4].P4Assoc [explicit] +// CHECK-NEXT: τ_0_0 : P3 [Explicit @ {{.*}}:25] +// CHECK-NEXT: τ_0_1 : P4 [Explicit @ {{.*}}:33] +// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P1 [Explicit @ {{.*}}:25 -> Protocol requirement (P3) -> Protocol requirement (P2)] +// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [Explicit @ {{.*}}:25 -> Protocol requirement (P3)] +// CHECK-NEXT: τ_0_0[.P3].P3Assoc == τ_0_1[.P4].P4Assoc [Explicit] func inferSameType2(_: T, _: U) where U.P4Assoc : P2, T.P3Assoc == U.P4Assoc {} // CHECK-LABEL: .inferSameType3@ // CHECK-NEXT: Requirements: -// CHECK-NEXT: τ_0_0 : PCommonAssoc1 [inferred] -// CHECK-NEXT: τ_0_0 : PCommonAssoc2 [explicit @ {{.*}}requirement_inference.swift:{{.*}}:76] -// CHECK-NEXT: τ_0_0[.PCommonAssoc1].CommonAssoc : P1 [explicit @ {{.*}}requirement_inference.swift:{{.*}}:68] +// CHECK-NEXT: τ_0_0 : PCommonAssoc1 [Explicit @ {{.*}}:25] +// CHECK-NEXT: τ_0_0 : PCommonAssoc2 [Explicit @ {{.*}}:74] +// CHECK-NEXT: τ_0_0[.PCommonAssoc1].CommonAssoc : P1 [Explicit @ {{.*}}:66] // CHECK-NEXT: Potential archetypes func inferSameType3(_: T) where T.CommonAssoc : P1, T : PCommonAssoc2 {} diff --git a/test/Generics/superclass_constraint.swift b/test/Generics/superclass_constraint.swift index ce82a3073a0cb..784c0d68a0a1f 100644 --- a/test/Generics/superclass_constraint.swift +++ b/test/Generics/superclass_constraint.swift @@ -65,15 +65,15 @@ extension P2 where Self.T : C { // CHECK: superclassConformance1 // CHECK: Requirements: -// CHECK-NEXT: τ_0_0 : C [explicit @ -// CHECK-NEXT: τ_0_0 : P3 [inherited @ +// CHECK-NEXT: τ_0_0 : C [Explicit @ {{.*}}:46] +// CHECK-NEXT: τ_0_0 : P3 [Explicit @ {{.*}}:46 -> Superclass (C: P3)] // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C> func superclassConformance1(t: T) where T : C, T : P3 {} // CHECK: superclassConformance2 // CHECK: Requirements: -// CHECK-NEXT: τ_0_0 : C [explicit @ -// CHECK-NEXT: τ_0_0 : P3 [inherited @ +// CHECK-NEXT: τ_0_0 : C [Explicit @ {{.*}}:46] +// CHECK-NEXT: τ_0_0 : P3 [Explicit @ {{.*}}:46 -> Superclass (C: P3)] // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C> func superclassConformance2(t: T) where T : C, T : P3 {} @@ -83,7 +83,7 @@ class C2 : C, P4 { } // CHECK: superclassConformance3 // CHECK: Requirements: -// CHECK-NEXT: τ_0_0 : C2 [explicit @ -// CHECK-NEXT: τ_0_0 : P4 [inherited @ +// CHECK-NEXT: τ_0_0 : C2 [Explicit @ {{.*}}:46] +// CHECK-NEXT: τ_0_0 : P4 [Explicit @ {{.*}}:46 -> Superclass (C2: P4)] // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C2> func superclassConformance3(t: T) where T : C, T : P4, T : C2 {}