//===--- GenericEnvironment.h - Generic Environment AST ---------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines the GenericEnvironment class. // //===----------------------------------------------------------------------===// #ifndef SWIFT_AST_GENERIC_ENVIRONMENT_H #define SWIFT_AST_GENERIC_ENVIRONMENT_H #include "swift/AST/SubstitutionMap.h" #include "swift/AST/GenericParamKey.h" #include "swift/AST/GenericParamList.h" #include "swift/AST/GenericSignature.h" #include "swift/Basic/Compiler.h" #include "swift/Basic/Debug.h" #include "swift/Basic/UUID.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TrailingObjects.h" #include namespace swift { class ArchetypeType; class ASTContext; class GenericTypeParamType; class OpaqueTypeDecl; class ElementArchetypeType; class ExistentialArchetypeType; class PackArchetypeType; class PackExpansionType; class SILModule; class SILType; template class CanTypeWrapper; /// Query function suitable for use as a \c TypeSubstitutionFn that queries /// the mapping of interface types to archetypes. class QueryInterfaceTypeSubstitutions { const GenericEnvironment *self; public: QueryInterfaceTypeSubstitutions(const GenericEnvironment *self) : self(self) { } Type operator()(SubstitutableType *type) const; }; /// Extra data in a generic environment for an opaque type. struct OpaqueEnvironmentData { OpaqueTypeDecl *decl; }; /// Extra data in a generic environment for an opened existential. struct OpenedExistentialEnvironmentData { Type existential; UUID uuid; }; /// Extra data in a generic environment for an opened pack element. struct OpenedElementEnvironmentData { UUID uuid; CanGenericTypeParamType shapeClass; }; /// Describes the mapping between archetypes and interface types for the /// generic parameters of a DeclContext. /// /// The most frequently used method here is mapTypeIntoContext(), which /// maps an interface type to a type written in terms of the generic /// environment's archetypes; to go in the other direction, use /// TypeBase::mapTypeOutOfContext(). /// class alignas(1 << DeclAlignInBits) GenericEnvironment final : private llvm::TrailingObjects< GenericEnvironment, SubstitutionMap, OpaqueEnvironmentData, OpenedExistentialEnvironmentData, OpenedElementEnvironmentData, Type> { public: enum class Kind { /// A normal generic environment, determined only by its generic /// signature. Primary, /// A generic environment describing an opaque type archetype. Opaque, /// A generic environment describing an opened existential archetype. OpenedExistential, /// A generic environment describing an opened element type of a /// pack archetype inside a pack expansion expression. OpenedElement, }; class NestedTypeStorage; private: mutable llvm::PointerIntPair SignatureAndKind{ GenericSignature(), Kind::Primary}; NestedTypeStorage *nestedTypeStorage = nullptr; friend TrailingObjects; friend OpaqueTypeArchetypeType; size_t numTrailingObjects(OverloadToken) const; size_t numTrailingObjects(OverloadToken) const; size_t numTrailingObjects(OverloadToken) const; size_t numTrailingObjects(OverloadToken) const; size_t numTrailingObjects(OverloadToken) const; /// Retrieve the array containing the context types associated with the /// generic parameters, stored in parallel with the generic parameters of the /// generic signature. MutableArrayRef getContextTypes(); /// Retrieve the array containing the context types associated with the /// generic parameters, stored in parallel with the generic parameters of the /// generic signature. ArrayRef getContextTypes() const; /// Retrieve the array of opened pack parameters for this opened-element /// environment. This is parallel to the array of element parameters, /// i.e. the innermost generic context. MutableArrayRef getOpenedPackParams(); ArrayRef getOpenedPackParams() const; /// Get the nested type storage, allocating it if required. NestedTypeStorage &getOrCreateNestedTypeStorage(); /// Private constructor for primary environments. explicit GenericEnvironment(GenericSignature signature); /// Private constructor for opaque type environments. explicit GenericEnvironment( GenericSignature signature, OpaqueTypeDecl *opaque, SubstitutionMap subs); /// Private constructor for opened existential environments. explicit GenericEnvironment( GenericSignature signature, Type existential, SubstitutionMap subs, UUID uuid); /// Private constructor for opened element environments. explicit GenericEnvironment(GenericSignature signature, UUID uuid, CanGenericTypeParamType shapeClass, SubstitutionMap outerSubs); friend ArchetypeType; friend QueryInterfaceTypeSubstitutions; /// Add a mapping of a type parameter to a contextual type, usually /// an archetype. void addMapping(CanType depType, Type contextType); /// Retrieve the mapping for the given type parameter, if present. /// /// This is only useful when lazily populating a generic environment. Type getMappingIfPresent(CanType depType) const; public: GenericSignature getGenericSignature() const { return SignatureAndKind.getPointer(); } Kind getKind() const { return SignatureAndKind.getInt(); } ArrayRef getGenericParams() const; /// Retrieve the existential type for an opened existential environment. Type getOpenedExistentialType() const; /// Retrieve the UUID for an opened existential environment. UUID getOpenedExistentialUUID() const; /// Retrieve the opaque type declaration for a generic environment describing /// opaque types. OpaqueTypeDecl *getOpaqueTypeDecl() const; /// Retrieve the outer substitutions for an opaque or local environment. /// /// Applying a substitution map to a local or opaque archetype outputs /// an archetype with the same interface type, and composed outer /// substitutions. SubstitutionMap getOuterSubstitutions() const; /// Retrieve the shape equivalence class for an opened element environment. /// This is always a pack parameter. CanGenericTypeParamType getOpenedElementShapeClass() const; /// Retrieve the UUID for an opened element environment. UUID getOpenedElementUUID() const; /// Return the number of opened pack parameters. unsigned getNumOpenedPackParams() const; void forEachPackElementArchetype( llvm::function_ref function) const; void forEachPackElementGenericTypeParam( llvm::function_ref function) const; using PackElementBindingCallback = llvm::function_ref; /// Given that this is an opened element environment, iterate the /// opened pack element bindings: the pack archetype that's been opened /// (which may not be meaningful in the surrounding context), the element /// archetype that it has been opened as, and the pack type whose elements /// are opened. void forEachPackElementBinding(PackElementBindingCallback function) const; /// Create a new, primary generic environment. static GenericEnvironment *forPrimary(GenericSignature signature); /// Create a new generic environment for an opaque type with the given set of /// outer substitutions. static GenericEnvironment *forOpaqueType( OpaqueTypeDecl *opaque, SubstitutionMap subs); /// Create a new generic environment for an opened existential. /// /// \param existential The subject existential type /// \param uuid The unique identifier for this opened existential static GenericEnvironment * forOpenedExistential(Type existential, UUID uuid); /// Create a new generic environment for an opened existential. /// /// \param signature The opened existential signature /// \param existential The generalized existential type /// \param outerSubs The substitution map containing archetypes from the /// outer generic context /// \param uuid The unique identifier for this opened existential static GenericEnvironment * forOpenedExistential(GenericSignature signature, Type existential, SubstitutionMap outerSubs, UUID uuid); /// Create a new generic environment for an opened element. /// /// \param signature The opened element signature, which is the same as the /// signature of the context whose element type is being opened, but with /// the pack parameter bit erased from one or more generic parameters /// \param uuid The unique identifier for this opened element /// \param shapeClass The shape equivalence class for the originating packs /// \param outerSubs The substitution map containing archetypes from the /// outer generic context static GenericEnvironment * forOpenedElement(GenericSignature signature, UUID uuid, CanGenericTypeParamType shapeClass, SubstitutionMap outerSubs); /// Make vanilla new/delete illegal. void *operator new(size_t Bytes) = delete; void operator delete(void *Data) = delete; /// Only allow placement new. void *operator new(size_t Bytes, void *Mem) { assert(Mem); return Mem; } /// For an opaque or pack element archetype environment, apply the /// substitutions. Type maybeApplyOuterContextSubstitutions(Type type) const; /// Map an interface type to a contextual type. static Type mapTypeIntoContext(GenericEnvironment *genericEnv, Type type); /// Map an interface type to a contextual type. Type mapTypeIntoContext(Type type) const; /// Map a generic parameter type to a contextual type. Type mapTypeIntoContext(GenericTypeParamType *type) const; /// Map a type parameter type to a contextual type. Type getOrCreateArchetypeFromInterfaceType(Type depType); /// Map an interface type containing parameter packs to a contextual /// type in the opened element generic context. Type mapPackTypeIntoElementContext(Type type) const; /// Map a contextual type containing parameter packs to a contextual /// type in the opened element generic context. /// /// This operation only makes sense if the generic environment that the /// pack archetypes are contextual in matches the generic signature /// of this environment. That will be true for opened element /// environments coming straight out of the type checker, such as /// the one in a PackExpansionExpr, or opened element environments /// created directly from the current environment. It is not /// reliable for opened element environments in arbitrary SIL functions. Type mapContextualPackTypeIntoElementContext(Type type) const; /// Map a contextual type containing parameter packs to a contextual /// type in the opened element generic context. /// /// This operation only makes sense if the generic environment that the /// pack archetypes are contextual in matches the generic signature /// of this environment. That will be true for opened element /// environments coming straight out of the type checker, such as /// the one in a PackExpansionExpr, or opened element environments /// created directly from the current environment. It is not /// reliable for opened element environments in arbitrary SIL functions. CanType mapContextualPackTypeIntoElementContext(CanType type) const; /// Map a type containing pack element type parameters to a contextual /// type in the pack generic context. Type mapElementTypeIntoPackContext(Type type) const; /// Map the given SIL interface type to a contextual type. /// /// This operation will also reabstract dependent types according to the /// abstraction level of their associated type requirements. SILType mapTypeIntoContext(SILModule &M, SILType type) const; /// Map an interface type's protocol conformance into the corresponding /// conformance for the contextual type. static std::pair mapConformanceRefIntoContext(GenericEnvironment *genericEnv, Type conformingType, ProtocolConformanceRef conformance); /// Map an interface type's protocol conformance into the corresponding /// conformance for the contextual type. std::pair mapConformanceRefIntoContext(Type conformingType, ProtocolConformanceRef conformance) const; /// Returns a substitution map that sends every generic parameter to its /// corresponding archetype in this generic environment. SubstitutionMap getForwardingSubstitutionMap() const; void dump(raw_ostream &os) const; SWIFT_DEBUG_DUMP; }; /// A pair of an opened-element generic signature and an opened-element /// generic environment. struct OpenedElementContext { /// The opened-element environment for this expansion. GenericEnvironment *environment; /// The opened-element signature for this expansion. CanGenericSignature signature; /// Create a fresh opened element context from a contextual pack /// expansion type. This is useful when writing code that needs to /// break down the components of a pack expansion. static OpenedElementContext createForContextualExpansion(ASTContext &ctx, CanTypeWrapper expansionType); }; } // end namespace swift #endif // SWIFT_AST_GENERIC_ENVIRONMENT_H