//===--- ProtocolConformance.h - AST Protocol Conformance -------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines the protocol conformance data structures. // //===----------------------------------------------------------------------===// #ifndef SWIFT_AST_PROTOCOLCONFORMANCE_H #define SWIFT_AST_PROTOCOLCONFORMANCE_H #include "swift/AST/ConcreteDeclRef.h" #include "swift/AST/Decl.h" #include "swift/AST/ProtocolConformanceRef.h" #include "swift/AST/Substitution.h" #include "swift/AST/Type.h" #include "swift/AST/Types.h" #include "swift/AST/TypeAlignments.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallPtrSet.h" #include namespace swift { class ASTContext; class DiagnosticEngine; class GenericParamList; class NormalProtocolConformance; class ProtocolConformance; class ModuleDecl; class SubstitutionIterator; enum class AllocationArena; /// \brief Type substitution mapping from substitutable types to their /// replacements. typedef llvm::DenseMap TypeSubstitutionMap; /// Map from non-type requirements to the corresponding conformance witnesses. typedef llvm::DenseMap WitnessMap; /// Map from associated type requirements to the corresponding substitution, /// which captures the replacement type along with any conformances it requires. typedef llvm::DenseMap> TypeWitnessMap; /// Map from a directly-inherited protocol to its corresponding protocol /// conformance. typedef llvm::DenseMap InheritedConformanceMap; /// Describes the kind of protocol conformance structure used to encode /// conformance. enum class ProtocolConformanceKind { /// "Normal" conformance of a (possibly generic) nominal type, which /// contains complete mappings. Normal, /// Conformance for a specialization of a generic type, which projects the /// underlying generic conformance. Specialized, /// Conformance of a generic class type projected through one of its /// superclass's conformances. Inherited }; /// Describes the state of a protocol conformance, which may be complete, /// incomplete, or currently being checked. enum class ProtocolConformanceState { /// The conformance has been fully checked. Complete, /// The conformance is known but is not yet complete. Incomplete, /// The conformance's type witnesses are currently being resolved. CheckingTypeWitnesses, /// The conformance is being checked. Checking, }; /// \brief Describes how a particular type conforms to a given protocol, /// providing the mapping from the protocol members to the type (or extension) /// members that provide the functionality for the concrete type. /// /// ProtocolConformance is an abstract base class, implemented by subclasses /// for the various kinds of conformance (normal, specialized, inherited). class alignas(1 << DeclAlignInBits) ProtocolConformance { /// The kind of protocol conformance. ProtocolConformanceKind Kind; /// \brief The type that conforms to the protocol, in the context of the /// conformance definition. Type ConformingType; /// \brief The interface type that conforms to the protocol. Type ConformingInterfaceType; protected: ProtocolConformance(ProtocolConformanceKind kind, Type conformingType, Type conformingInterfaceType) : Kind(kind), ConformingType(conformingType), ConformingInterfaceType(conformingInterfaceType) { } public: /// Determine the kind of protocol conformance. ProtocolConformanceKind getKind() const { return Kind; } /// Get the conforming type. Type getType() const { return ConformingType; } /// Get the conforming interface type. Type getInterfaceType() const { return ConformingInterfaceType; } /// Get the protocol being conformed to. ProtocolDecl *getProtocol() const; /// Get the declaration context that contains the conforming extension or /// nominal type declaration. DeclContext *getDeclContext() const; /// Retrieve the state of this conformance. ProtocolConformanceState getState() const; /// Determine whether this conformance is complete. bool isComplete() const { return getState() == ProtocolConformanceState::Complete; } /// Determine whether this conformance is invalid. bool isInvalid() const; /// Determine whether this conformance is incomplete. bool isIncomplete() const { return getState() == ProtocolConformanceState::Incomplete || getState() == ProtocolConformanceState::CheckingTypeWitnesses || getState() == ProtocolConformanceState::Checking; } /// Return true if the conformance has a witness for the given associated /// type. bool hasTypeWitness(AssociatedTypeDecl *assocType, LazyResolver *resolver = nullptr) const; /// Retrieve the type witness substitution for the given associated type. const Substitution &getTypeWitness(AssociatedTypeDecl *assocType, LazyResolver *resolver) const; /// Retrieve the type witness substitution and type decl (if one exists) /// for the given associated type. std::pair getTypeWitnessSubstAndDecl(AssociatedTypeDecl *assocType, LazyResolver *resolver) const; static Type getTypeWitnessByName(Type type, ProtocolConformance *conformance, Identifier name, LazyResolver *resolver); /// Apply the given function object to each type witness within this /// protocol conformance. /// /// The function object should accept an \c AssociatedTypeDecl* for the /// requirement followed by the \c Substitution for the witness and a /// (possibly null) \c TypeDecl* that explicitly declared the type. /// It should return true to indicate an early exit. /// /// \returns true if the function ever returned true template bool forEachTypeWitness(LazyResolver *resolver, F f) const { const ProtocolDecl *protocol = getProtocol(); for (auto req : protocol->getMembers()) { auto assocTypeReq = dyn_cast(req); if (!assocTypeReq || req->isInvalid()) continue; const auto &TWInfo = getTypeWitnessSubstAndDecl(assocTypeReq, resolver); if (f(assocTypeReq, TWInfo.first, TWInfo.second)) return true; } return false; } /// Retrieve the non-type witness for the given requirement. ConcreteDeclRef getWitness(ValueDecl *requirement, LazyResolver *resolver) const; private: /// Determine whether we have a witness for the given requirement. bool hasWitness(ValueDecl *requirement) const; public: /// Apply the given function object to each value witness within this /// protocol conformance. /// /// The function object should accept a \c ValueDecl* for the requirement /// followed by the \c ConcreteDeclRef for the witness. Note that a generic /// witness will only be specialized if the conformance came from the current /// file. template void forEachValueWitness(LazyResolver *resolver, F f) const { const ProtocolDecl *protocol = getProtocol(); for (auto req : protocol->getMembers()) { auto valueReq = dyn_cast(req); if (!valueReq || isa(valueReq) || valueReq->isInvalid()) continue; // Ignore accessors. if (auto *FD = dyn_cast(valueReq)) if (FD->isAccessor()) continue; // If we don't have and cannot resolve witnesses, skip it. if (!resolver && !hasWitness(valueReq)) continue; f(valueReq, getWitness(valueReq, resolver)); } } /// Retrieve the protocol conformance for the inherited protocol. ProtocolConformance *getInheritedConformance(ProtocolDecl *protocol) const; /// Retrieve the complete set of protocol conformances for directly inherited /// protocols. const InheritedConformanceMap &getInheritedConformances() const; /// Get the generic parameters open on the conforming type. /// FIXME: Retire in favor of getGenericSignature(). GenericParamList *getGenericParams() const; /// Get the generic signature containing the parameters open on the conforming /// interface type. GenericSignature *getGenericSignature() const; /// Get the underlying normal conformance. const NormalProtocolConformance *getRootNormalConformance() const; /// Get the underlying normal conformance. NormalProtocolConformance *getRootNormalConformance() { return const_cast( const_cast(this) ->getRootNormalConformance()); } /// Determine whether the witness for the given requirement /// is either the default definition or was otherwise deduced. /// /// FIXME: This is a crummy API. This information should be recorded in the /// witnesses themselves. bool usesDefaultDefinition(ValueDecl *requirement) const; // Make vanilla new/delete illegal for protocol conformances. void *operator new(size_t bytes) = delete; void operator delete(void *data) = delete; // Only allow allocation of protocol conformances using the allocator in // ASTContext or by doing a placement new. void *operator new(size_t bytes, ASTContext &context, AllocationArena arena, unsigned alignment = alignof(ProtocolConformance)); void *operator new(size_t bytes, void *mem) { assert(mem); return mem; } /// Print a parseable and human-readable description of the identifying /// information of the protocol conformance. void printName(raw_ostream &os, const PrintOptions &PO = PrintOptions()) const; /// True if the conformance is for a property behavior instantiation. bool isBehaviorConformance() const; /// Get the property declaration for a behavior conformance, if this is one. AbstractStorageDecl *getBehaviorDecl() const; void dump() const; private: friend class Substitution; /// Substitute the conforming type and produce a ProtocolConformance that /// applies to the substituted type. ProtocolConformance *subst(ModuleDecl *module, Type substType, ArrayRef subs, TypeSubstitutionMap &subMap, ArchetypeConformanceMap &conformanceMap); }; /// Normal protocol conformance, which involves mapping each of the protocol /// requirements to a witness. /// /// Normal protocol conformance is used for the explicit conformances placed on /// nominal types and extensions. For example: /// /// \code /// protocol P { func foo() } /// struct A : P { func foo() { } } /// class B : P { func foo() { } } /// \endcode /// /// Here, there is a normal protocol conformance for both \c A and \c B, /// providing the witnesses \c A.foo and \c B.foo, respectively, for the /// requirement \c foo. class NormalProtocolConformance : public ProtocolConformance, public llvm::FoldingSetNode { /// \brief The protocol being conformed to and its current state. llvm::PointerIntPair ProtocolAndState; /// The location of this protocol conformance in the source. SourceLoc Loc; using Context = llvm::PointerUnion; /// The declaration context containing the ExtensionDecl or /// NominalTypeDecl that declared the conformance, or the VarDecl whose /// behavior this conformance represents. /// /// Also stores the "invalid" bit. llvm::PointerIntPair ContextAndInvalid; /// \brief The mapping of individual requirements in the protocol over to /// the declarations that satisfy those requirements. mutable WitnessMap Mapping; /// The mapping from associated type requirements to their substitutions. mutable TypeWitnessMap TypeWitnesses; /// \brief The mapping from any directly-inherited protocols over to the /// protocol conformance structures that indicate how the given type meets /// the requirements of those protocols. InheritedConformanceMap InheritedMapping; /// The set of requirements for which we have used default definitions or /// otherwise deduced the result. llvm::SmallPtrSet DefaultedDefinitions; LazyMemberLoader *Resolver = nullptr; uint64_t ResolverContextData; friend class ASTContext; NormalProtocolConformance(Type conformingType, ProtocolDecl *protocol, SourceLoc loc, DeclContext *dc, ProtocolConformanceState state) : ProtocolConformance(ProtocolConformanceKind::Normal, conformingType, // FIXME: interface type should be passed in dc->getDeclaredInterfaceType()), ProtocolAndState(protocol, state), Loc(loc), ContextAndInvalid(dc, false) { } NormalProtocolConformance(Type conformingType, Type conformingInterfaceType, ProtocolDecl *protocol, SourceLoc loc, AbstractStorageDecl *behaviorStorage, ProtocolConformanceState state) : ProtocolConformance(ProtocolConformanceKind::Normal, conformingType, // FIXME: interface type should be passed in conformingInterfaceType), ProtocolAndState(protocol, state), Loc(loc), ContextAndInvalid(behaviorStorage, false) { } void resolveLazyInfo() const; public: /// Get the protocol being conformed to. ProtocolDecl *getProtocol() const { return ProtocolAndState.getPointer(); } /// Retrieve the location of this SourceLoc getLoc() const { return Loc; } /// Get the declaration context that contains the conforming extension or /// nominal type declaration. DeclContext *getDeclContext() const { auto context = ContextAndInvalid.getPointer(); if (auto DC = context.dyn_cast()) { return DC; } else { return context.get()->getDeclContext(); } } /// Retrieve the state of this conformance. ProtocolConformanceState getState() const { return ProtocolAndState.getInt(); } /// Set the state of this conformance. void setState(ProtocolConformanceState state) { ProtocolAndState.setInt(state); } /// Determine whether this conformance is invalid. bool isInvalid() const { return ContextAndInvalid.getInt(); } /// Mark this conformance as invalid. void setInvalid() { ContextAndInvalid.setInt(true); } /// Determine whether this conformance is lazily resolved. /// /// This only matters to the AST verifier. bool isLazilyResolved() const { return Resolver != nullptr; } /// True if the conformance describes a property behavior. bool isBehaviorConformance() const { return ContextAndInvalid.getPointer().is(); } /// Return the declaration using the behavior for this conformance, or null /// if this isn't a behavior conformance. AbstractStorageDecl *getBehaviorDecl() const { return ContextAndInvalid.getPointer().dyn_cast(); } /// Retrieve the type witness substitution and type decl (if one exists) /// for the given associated type. std::pair getTypeWitnessSubstAndDecl(AssociatedTypeDecl *assocType, LazyResolver *resolver) const; /// Determine whether the protocol conformance has a type witness for the /// given associated type. bool hasTypeWitness(AssociatedTypeDecl *assocType, LazyResolver *resolver = nullptr) const; /// Set the type witness for the given associated type. /// \param typeDecl the type decl the witness type came from, if one exists. void setTypeWitness(AssociatedTypeDecl *assocType, const Substitution &substitution, TypeDecl *typeDecl) const; /// Retrieve the value witness corresponding to the given requirement. /// /// Note that a generic witness will only be specialized if the conformance /// came from the current file. ConcreteDeclRef getWitness(ValueDecl *requirement, LazyResolver *resolver) const; /// Determine whether the protocol conformance has a witness for the given /// requirement. bool hasWitness(ValueDecl *requirement) const { if (Resolver) resolveLazyInfo(); return Mapping.count(requirement) > 0; } /// Set the witness for the given requirement. void setWitness(ValueDecl *requirement, ConcreteDeclRef witness) const; /// Retrieve the protocol conformances directly-inherited protocols. const InheritedConformanceMap &getInheritedConformances() const { return InheritedMapping; } /// Determine whether the protocol conformance has a particular inherited /// conformance. /// /// Only usable on incomplete or invalid protocol conformances. bool hasInheritedConformance(ProtocolDecl *proto) const { return InheritedMapping.count(proto) > 0; } /// Set the given inherited conformance. void setInheritedConformance(ProtocolDecl *proto, ProtocolConformance *conformance) { assert(InheritedMapping.count(proto) == 0 && "Already recorded inherited conformance"); assert(!isComplete() && "Conformance already complete?"); InheritedMapping[proto] = conformance; } /// Determine whether the witness for the given requirement /// is either the default definition or was otherwise deduced. bool usesDefaultDefinition(ValueDecl *requirement) const { if (Resolver) resolveLazyInfo(); return DefaultedDefinitions.count(requirement) > 0; } /// Retrieve the complete set of defaulted definitions. const llvm::SmallPtrSet &getDefaultedDefinitions() const { if (Resolver) resolveLazyInfo(); return DefaultedDefinitions; } /// Note that the given requirement was a default definition. void addDefaultDefinition(ValueDecl *requirement) { DefaultedDefinitions.insert(requirement); } void setLazyLoader(LazyMemberLoader *resolver, uint64_t contextData); void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getProtocol(), getDeclContext()); } static void Profile(llvm::FoldingSetNodeID &ID, ProtocolDecl *protocol, DeclContext *dc) { ID.AddPointer(protocol); ID.AddPointer(dc); } static bool classof(const ProtocolConformance *conformance) { return conformance->getKind() == ProtocolConformanceKind::Normal; } }; /// Specialized protocol conformance, which projects a generic protocol /// conformance to one of the specializations of the generic type. /// /// For example: /// \code /// protocol P { func foo() } /// class A : P { func foo() { } } /// \endcode /// /// \c A conforms to \c P via normal protocol conformance. Any specialization /// of \c A conforms to \c P via a specialized protocol conformance. For /// example, \c A conforms to \c P via a specialized protocol conformance /// that refers to the normal protocol conformance \c A to \c P with the /// substitution \c T -> \c Int. class SpecializedProtocolConformance : public ProtocolConformance, public llvm::FoldingSetNode { /// The generic conformance from which this conformance was derived. ProtocolConformance *GenericConformance; /// The substitutions applied to the generic conformance to produce this /// conformance. ArrayRef GenericSubstitutions; /// The mapping from associated type requirements to their substitutions. /// /// This mapping is lazily produced by specializing the underlying, /// generic conformance. mutable TypeWitnessMap TypeWitnesses; friend class ASTContext; SpecializedProtocolConformance(Type conformingType, ProtocolConformance *genericConformance, ArrayRef substitutions); public: /// Get the generic conformance from which this conformance was derived, /// if there is one. ProtocolConformance *getGenericConformance() const { return GenericConformance; } /// Get the substitutions used to produce this specialized conformance from /// the generic conformance. ArrayRef getGenericSubstitutions() const { return GenericSubstitutions; } SubstitutionIterator getGenericSubstitutionIterator() const; /// Get the protocol being conformed to. ProtocolDecl *getProtocol() const { return GenericConformance->getProtocol(); } /// Get the declaration context that contains the conforming extension or /// nominal type declaration. DeclContext *getDeclContext() const { return GenericConformance->getDeclContext(); } /// Retrieve the state of this conformance. ProtocolConformanceState getState() const { return GenericConformance->getState(); } bool hasTypeWitness(AssociatedTypeDecl *assocType, LazyResolver *resolver = nullptr) const; /// Retrieve the type witness substitution and type decl (if one exists) /// for the given associated type. std::pair getTypeWitnessSubstAndDecl(AssociatedTypeDecl *assocType, LazyResolver *resolver) const; /// Retrieve the value witness corresponding to the given requirement. ConcreteDeclRef getWitness(ValueDecl *requirement, LazyResolver *resolver) const; /// Retrieve the protocol conformances directly-inherited protocols. const InheritedConformanceMap &getInheritedConformances() const { return GenericConformance->getInheritedConformances(); } /// Determine whether the witness for the given requirement /// is either the default definition or was otherwise deduced. bool usesDefaultDefinition(ValueDecl *requirement) const { return GenericConformance->usesDefaultDefinition(requirement); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getType(), getGenericConformance()); } static void Profile(llvm::FoldingSetNodeID &ID, Type type, ProtocolConformance *genericConformance) { // FIXME: Consider profiling substitutions here. They could differ in // some crazy cases that also require major diagnostic work, where the // substitutions involve conformances of the same type to the same // protocol drawn from different imported modules. ID.AddPointer(type->getCanonicalType().getPointer()); ID.AddPointer(genericConformance); } static bool classof(const ProtocolConformance *conformance) { return conformance->getKind() == ProtocolConformanceKind::Specialized; } }; /// Inherited protocol conformance, which projects the conformance of a /// superclass to its subclasses. /// /// An example: /// \code /// protocol P { func foo() } /// class A : P { func foo() { } } /// class B : A { } /// \endcode /// /// \c A conforms to \c P via normal protocol conformance. The subclass \c B /// of \c A conforms to \c P via an inherited protocol conformance. class InheritedProtocolConformance : public ProtocolConformance, public llvm::FoldingSetNode { /// The conformance inherited from the superclass. ProtocolConformance *InheritedConformance; friend class ASTContext; InheritedProtocolConformance(Type conformingType, ProtocolConformance *inheritedConformance) : ProtocolConformance(ProtocolConformanceKind::Inherited, conformingType, // FIXME: interface type should be passed in inheritedConformance->getDeclContext()->getDeclaredInterfaceType()), InheritedConformance(inheritedConformance) { } public: /// Retrieve the conformance for the inherited type. ProtocolConformance *getInheritedConformance() const { return InheritedConformance; } /// Get the protocol being conformed to. ProtocolDecl *getProtocol() const { return InheritedConformance->getProtocol(); } /// Get the declaration context that contains the conforming extension or /// nominal type declaration. DeclContext *getDeclContext() const { return InheritedConformance->getDeclContext(); } /// Retrieve the state of this conformance. ProtocolConformanceState getState() const { return InheritedConformance->getState(); } bool hasTypeWitness(AssociatedTypeDecl *assocType, LazyResolver *resolver = nullptr) const { return InheritedConformance->hasTypeWitness(assocType, resolver); } /// Retrieve the type witness substitution and type decl (if one exists) /// for the given associated type. std::pair getTypeWitnessSubstAndDecl(AssociatedTypeDecl *assocType, LazyResolver *resolver) const { return InheritedConformance->getTypeWitnessSubstAndDecl(assocType,resolver); } /// Retrieve the value witness corresponding to the given requirement. ConcreteDeclRef getWitness(ValueDecl *requirement, LazyResolver *resolver) const { return InheritedConformance->getWitness(requirement, resolver); } /// Retrieve the protocol conformances directly-inherited protocols. const InheritedConformanceMap &getInheritedConformances() const { return InheritedConformance->getInheritedConformances(); } /// Determine whether the witness for the given requirement /// is either the default definition or was otherwise deduced. bool usesDefaultDefinition(ValueDecl *requirement) const { return InheritedConformance->usesDefaultDefinition(requirement); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getType(), getInheritedConformance()); } static void Profile(llvm::FoldingSetNodeID &ID, Type type, ProtocolConformance *inheritedConformance) { ID.AddPointer(type->getCanonicalType().getPointer()); ID.AddPointer(inheritedConformance); } static bool classof(const ProtocolConformance *conformance) { return conformance->getKind() == ProtocolConformanceKind::Inherited; } }; inline bool ProtocolConformance::isInvalid() const { return getRootNormalConformance()->isInvalid(); } inline bool ProtocolConformance::hasWitness(ValueDecl *requirement) const { return getRootNormalConformance()->hasWitness(requirement); } } // end namespace swift #endif // LLVM_SWIFT_AST_PROTOCOLCONFORMANCE_H