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 {}