text: //===--- SILType.h - Defines the SILType type -------------------*- C++ -*-===//
  //
  // This source file is part of the Swift.org open source project
  //
  // Copyright (c) 2014 - 2015 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 SILType class, which is used to refer to SIL
  // representation types.
  //
  //===----------------------------------------------------------------------===//
  
  #ifndef SWIFT_SIL_SILTYPE_H
  #define SWIFT_SIL_SILTYPE_H
  
  #include "swift/AST/CanTypeVisitor.h"
  #include "swift/AST/Types.h"
  #include "llvm/ADT/PointerIntPair.h"
  #include "llvm/Support/ErrorHandling.h"
  #include "swift/SIL/SILAllocated.h"
  #include "llvm/ADT/Hashing.h"
  #include "swift/SIL/SILDeclRef.h"
  
  namespace swift {
    class ASTContext;
    class VarDecl;
  
  namespace Lowering {
    class AbstractionPattern;
    class TypeConverter;
  }
  
  } // end namespace swift
    
  namespace swift {
  
  /// How an existential type container is represented.
  enum class ExistentialRepresentation {
    /// The type is not existential.
    None,
    /// The container uses an opaque existential container, with a fixed-sized
    /// buffer. The type is address-only and is manipulated using the
    /// {init,open,deinit}_existential_addr family of instructions.
    Opaque,
    /// The container uses a class existential container, which holds a reference
    /// to the class instance that conforms to the protocol. The type is
    /// reference-counted and is manipulated using the
    /// {init,open}_existential_ref family of instructions.
    Class,
    /// The container uses a metatype existential container, which holds a
    /// reference to the type metadata for a type that
    /// conforms to the protocol. The type is trivial, and is manipulated using
    /// the {init,open}_existential_metatype family of instructions.
    Metatype,
    /// The container uses a boxed existential container, which is a
    /// reference-counted buffer that indirectly contains the
    /// conforming value. The type is manipulated
    /// using the {alloc,open,dealloc}_existential_box family of instructions.
    /// The container may be able to directly adopt a class reference using
    /// init_existential_ref for some class types.
    Boxed,
  };
  
  /// The value category.
  enum class SILValueCategory {
    /// An object is a value of the type.
    Object,
  
    /// An address is a pointer to an allocated variable of the type
    /// (possibly uninitialized).
    Address,
  
    /// Local storage is the container for a local allocation.  For
    /// statically-sized types, this is just the allocation itself.
    /// However, for dynamically-sized types (like archetypes or
    /// resilient structs), it may be some sort of fixed-size buffer,
    /// stack depth, or the like.
    LocalStorage
  };
  
  /// SILType - A Swift type that has been lowered to a SIL representation type.
  /// In addition to the Swift type system, SIL adds "address" types that can
  /// reference any Swift type (but cannot take the address of an address). *T
  /// is the type of an address pointing at T.
  ///
  class SILType {
  public:
    /// The unsigned is a SILValueCategory.
    using ValueType = llvm::PointerIntPair<TypeBase *, 2, unsigned>;
  private:
    ValueType value;
  
    /// Private constructor. SILTypes are normally vended by
    /// TypeConverter::getLoweredType().
    SILType(CanType ty, SILValueCategory category)
        : value(ty.getPointer(), unsigned(category)) {
      if (!ty) return;
      assert(ty->isLegalSILType() &&
             "constructing SILType with type that should have been "
             "eliminated by SIL lowering");
    }
    
    SILType(ValueType value) : value(value) {
    }
  
    friend class Lowering::TypeConverter;
    friend struct llvm::DenseMapInfo<SILType>;
  public:
    SILType() = default;
  
    /// getPrimitiveType - Form a SILType for a primitive type that does not
    /// require any special handling (i.e., not a function or aggregate type).
    static SILType getPrimitiveType(CanType T, SILValueCategory category) {
      return SILType(T, category);
    }
  
    /// Form the type of an r-value, given a Swift type that either does
    /// not require any special handling or has already been
    /// appropriately lowered.
    static SILType getPrimitiveObjectType(CanType T) {
      return SILType(T, SILValueCategory::Object);
    }
  
    /// Form the type for the address of an object, given a Swift type
    /// that either does not require any special handling or has already
    /// been appropriately lowered.
    static SILType getPrimitiveAddressType(CanType T) {
      return SILType(T, SILValueCategory::Address);
    }
  
    /// Form the type for the backing storage of a locally-allocated
    /// object, given a Swift type that either does not require any
    /// special handling or has already been appropriately lowered.
    static SILType getPrimitiveLocalStorageType(CanType T) {
      return SILType(T, SILValueCategory::LocalStorage);
    }
  
    ///  Apply a substitution to the type to produce another lowered SIL type.
    static SILType substType(SILModule &silModule, ModuleDecl *astModule,
                             TypeSubstitutionMap &subs, SILType SrcTy);
  
    ///  Apply a substitution to the function type.
    static CanSILFunctionType substFuncType(SILModule &silModule,
                                            ModuleDecl *astModule,
                                            TypeSubstitutionMap &subs,
                                            CanSILFunctionType SrcTy,
                                            bool dropGenerics);
  
    bool isNull() const { return value.getPointer() == nullptr; }
    explicit operator bool() const { return bool(value.getPointer()); }
  
    SILValueCategory getCategory() const {
      return SILValueCategory(value.getInt());
    }
    
    /// Returns the address variant of this type.  Instructions which
    /// manipulate memory will generally work with object addresses.
    SILType getAddressType() const {
      return SILType(getSwiftRValueType(), SILValueCategory::Address);
    }
  
    /// Returns the object variant of this type.  Note that address-only
    /// types are not legal to manipulate directly as objects in SIL.
    SILType getObjectType() const {
      return SILType(getSwiftRValueType(), SILValueCategory::Object);
    }
  
    /// Returns the local storage variant of this type.  Local
    /// allocations of dynamically-sized types generally require some
    /// sort of buffer.
    SILType getLocalStorageType() const {
      return SILType(getSwiftRValueType(), SILValueCategory::LocalStorage);
    }
  
    /// Returns the Swift type referenced by this SIL type.
    CanType getSwiftRValueType() const {
      return CanType(value.getPointer());
    }
  
    /// Returns the Swift type equivalent to this SIL type. If the SIL type is
    /// an address type, returns an InOutType.
    CanType getSwiftType() const {
      CanType rvalueTy = getSwiftRValueType();
      if (isAddress())
        return CanInOutType::get(rvalueTy);
      return rvalueTy;
    }
    
    /// Returns the Swift return type of a function type.
    /// The SILType must refer to a function type.
    SILType getFunctionInterfaceResultType() const {
      return castTo<SILFunctionType>()->getSemanticResultSILType();
    }
  
    /// Returns true if this function type has an indirect argument.
    ///
    /// The SILType must refer to a function type.
    bool isFunctionTypeWithIndirectResult() const {
      return castTo<SILFunctionType>()->hasIndirectResult();
    }
    
    /// Returns the AbstractCC of a function type.
    /// The SILType must refer to a function type.
    SILFunctionTypeRepresentation getFunctionRepresentation() const {
      return castTo<SILFunctionType>()->getRepresentation();
    }
  
    /// Cast the Swift type referenced by this SIL type, or return null if the
    /// cast fails.
    template<typename TYPE>
    typename CanTypeWrapperTraits<TYPE>::type
    getAs() const { return dyn_cast<TYPE>(getSwiftRValueType()); }
  
    /// Cast the Swift type referenced by this SIL type, which must be of the
    /// specified subtype.
    template<typename TYPE>
    typename CanTypeWrapperTraits<TYPE>::type
    castTo() const { return cast<TYPE>(getSwiftRValueType()); }
  
    /// Returns true if the Swift type referenced by this SIL type is of the
    /// specified subtype.
    template<typename TYPE>
    bool is() const { return isa<TYPE>(getSwiftRValueType()); }
  
    bool isVoid() const {
      return value.getPointer()->isVoid();
    }
  
    /// Retrieve the ClassDecl for a type that maps to a Swift class or
    /// bound generic class type.
    ClassDecl *getClassOrBoundGenericClass() const {
      return getSwiftRValueType().getClassOrBoundGenericClass();
    }
    /// Retrieve the StructDecl for a type that maps to a Swift struct or
    /// bound generic struct type.
    StructDecl *getStructOrBoundGenericStruct() const {
      return getSwiftRValueType().getStructOrBoundGenericStruct();
    }
    /// Retrieve the EnumDecl for a type that maps to a Swift enum or
    /// bound generic enum type.
    EnumDecl *getEnumOrBoundGenericEnum() const {
      return getSwiftRValueType().getEnumOrBoundGenericEnum();
    }
    /// Retrieve the NominalTypeDecl for a type that maps to a Swift
    /// nominal or bound generic nominal type.
    NominalTypeDecl *getNominalOrBoundGenericNominal() const {
      return getSwiftRValueType().getNominalOrBoundGenericNominal();
    }
    
    /// True if the type is an address type.
    bool isAddress() const { return getCategory() == SILValueCategory::Address; }
  
    /// True if the type is an object type.
    bool isObject() const { return getCategory() == SILValueCategory::Object; }
  
    /// True if the type is a local-storage type.
    bool isLocalStorage() const {
      return getCategory() == SILValueCategory::LocalStorage;
    }
  
    /// isAddressOnly - True if the type, or the referenced type of an address
    /// type, is address-only.  For example, it could be a resilient struct or
    /// something of unknown size.
    ///
    /// This is equivalent to, but possibly faster than, calling
    /// M.Types.getTypeLowering(type).isAddressOnly().
    static bool isAddressOnly(CanType T, SILModule &M);
  
    /// Return true if this type must be returned indirectly.
    ///
    /// This is equivalent to, but possibly faster than, calling
    /// M.Types.getTypeLowering(type).isReturnedIndirectly().
    static bool isReturnedIndirectly(CanType type, SILModule &M) {
      return isAddressOnly(type, M);
    }
  
    /// Return true if this type must be passed indirectly.
    ///
    /// This is equivalent to, but possibly faster than, calling
    /// M.Types.getTypeLowering(type).isPassedIndirectly().
    static bool isPassedIndirectly(CanType type, SILModule &M) {
      return isAddressOnly(type, M);
    }
  
    /// Returns true if this type exposes a fixed layout to the given module's
    /// resilience domain.
    ///
    /// This is currently only implemented for nominal types.
    bool hasFixedLayout(SILModule &M) const;
    
    /// True if the type, or the referenced type of an address type, is loadable.
    /// This is the opposite of isAddressOnly.
    bool isLoadable(SILModule &M) const {
      return !isAddressOnly(M);
    }
    /// True if the type, or the referenced type of an address type, is
    /// address-only. This is the opposite of isLoadable.
    bool isAddressOnly(SILModule &M) const;
  
    /// True if the type, or the referenced type of an address type, is trivial.
    bool isTrivial(SILModule &M) const;
  
    /// True if the type, or the referenced type of an address type, is a
    /// scalar reference-counted type.
    bool isReferenceCounted(SILModule &M) const;
    
    /// Returns true if the referenced type has reference semantics.
    bool hasReferenceSemantics() const {
      return getSwiftRValueType().hasReferenceSemantics();
    }
    
    /// Returns true if the referenced type is guaranteed to have a
    /// single-retainable-pointer representation.
    bool hasRetainablePointerRepresentation() const {
      return getSwiftRValueType()->hasRetainablePointerRepresentation();
    }
    /// Returns true if the referenced type is an existential type.
    bool isExistentialType() const {
      return getSwiftRValueType().isExistentialType();
    }
    /// Returns true if the referenced type is any kind of existential type.
    bool isAnyExistentialType() const {
      return getSwiftRValueType().isAnyExistentialType();
    }
    /// Returns true if the referenced type is a class existential type.
    bool isClassExistentialType() const {
      return getSwiftRValueType()->isClassExistentialType();
    }
    
    /// Returns the representation used by an existential type. If the concrete
    /// type is provided, this may return a specialized representation kind that
    /// can be used for that type. Otherwise, returns the most general
    /// representation kind for the type. Returns None if the type is not an
    /// existential type.
    ExistentialRepresentation
    getPreferredExistentialRepresentation(SILModule &M,
                                          Type containedType = Type()) const;
    
    /// Returns true if the existential type can use operations for the given
    /// existential representation when working with values of the given type,
    /// or when working with an unknown type if containedType is null.
    bool
    canUseExistentialRepresentation(SILModule &M,
                                    ExistentialRepresentation repr,
                                    Type containedType = Type()) const;
    
    /// True if the type contains a type parameter.
    bool hasTypeParameter() const {
      return getSwiftRValueType()->hasTypeParameter();
    }
    
    /// True if the type is bridgeable to an ObjC object pointer type.
    bool isBridgeableObjectType() const {
      return getSwiftRValueType()->isBridgeableObjectType();
    }
  
    static bool isClassOrClassMetatype(Type t) {
      if (auto *meta = t->getAs<AnyMetatypeType>()) {
        return bool(meta->getInstanceType()->getClassOrBoundGenericClass());
      } else {
        return bool(t->getClassOrBoundGenericClass());
      }
    }
  
    /// True if the type is a class type or class metatype type.
    bool isClassOrClassMetatype() {
      return isObject() && isClassOrClassMetatype(getSwiftRValueType());
    }
  
    /// True if the type involves any archetypes.
    bool hasArchetype() const {
      return getSwiftRValueType()->hasArchetype();
    }
    
    /// Returns the ASTContext for the referenced Swift type.
    const ASTContext &getASTContext() const {
      return getSwiftRValueType()->getASTContext();
    }
  
    /// True if the given type has at least the size and alignment of a native
    /// pointer.
    bool isPointerSizeAndAligned();
  
    /// True if the layout of `fromType` is known to cover the layout of
    /// `totype`. This is conservatively imprecise and is not
    /// reflexive. `fromType` may be larger than the given type and still be
    /// castable. It is the caller's responsibility to ensure that the overlapping
    /// fields are layout compatible.
    static bool canUnsafeCastValue(SILType fromType, SILType toType,
                                   SILModule &M);
  
    /// True if `operTy` can be cast by single-reference value into `resultTy`.
    static bool canRefCast(SILType operTy, SILType resultTy, SILModule &M);
  
    /// True if the type is block-pointer-compatible, meaning it either is a block
    /// or is an Optional or ImplicitlyUnwrappedOptional with a block payload.
    bool isBlockPointerCompatible() const {
      CanType ty = getSwiftRValueType();
      if (auto optPayload = ty->getAnyOptionalObjectType()) {
        // The object type of Optional<T> is an unlowered AST type.
        auto fTy = optPayload->getAs<FunctionType>();
        if (!fTy)
          return false;
        return fTy->getRepresentation() == FunctionType::Representation::Block;
      }
        
      auto fTy = dyn_cast<SILFunctionType>(ty);
      if (!fTy)
        return false;
      return fTy->getRepresentation() == SILFunctionType::Representation::Block;
    }
  
    /// Given that this is a nominal type, return the lowered type of
    /// the given field.  Applies substitutions as necessary.  The
    /// result will be an address type if the base type is an address
    /// type or a class.
    SILType getFieldType(VarDecl *field, SILModule &M) const;
  
    /// Given that this is an enum type, return the lowered type of the
    /// data for the given element.  Applies substitutions as necessary.
    /// The result will have the same value category as the base type.
    SILType getEnumElementType(EnumElementDecl *elt, SILModule &M) const;
  
    /// Given that this is a tuple type, return the lowered type of the
    /// given tuple element.  The result will have the same value
    /// category as the base type.
    SILType getTupleElementType(unsigned index) const {
      return SILType(castTo<TupleType>().getElementType(index), getCategory());
    }
  
    /// Return the immediate superclass type of this type, or null if
    /// it's the most-derived type.
    SILType getSuperclass(LazyResolver *resolver) const {
      auto superclass = getSwiftRValueType()->getSuperclass(resolver);
      if (!superclass) return SILType();
      return SILType::getPrimitiveObjectType(superclass->getCanonicalType());
    }
  
    /// Return true if Ty is a subtype of this SILType, or null otherwise.
    bool isSuperclassOf(SILType Ty) const {
      return getSwiftRValueType()->isSuperclassOf(Ty.getSwiftRValueType(),
                                                  nullptr);
    }
  
    /// Transform the function type SILType by replacing all of its interface
    /// generic args with the appropriate item from the substitution.
    ///
    /// Only call this with function types!
    SILType substGenericArgs(SILModule &M,
                             ArrayRef<Substitution> Subs) const;
  
    SILType subst(SILModule &silModule, ModuleDecl *astModule,
                  TypeSubstitutionMap &subs) const;
  
    /// If this is a specialized generic type, return all substitutions used to
    /// generate it.
    ArrayRef<Substitution> gatherAllSubstitutions(SILModule &M);
  
    /// Return true if this type references a "ref" type that has a single pointer
    /// representation. Class existentials do not always qualify.
    bool isHeapObjectReferenceType() const;
  
    /// Return the SILType corresponding to the underlying type of the given
    /// metatype type.
    ///
    /// *NOTE* Only call on SILTypes for metatype types.
    SILType getMetatypeInstanceType(SILModule& M) const;
  
    /// Returns true if this SILType is an aggregate that contains \p Ty
    bool aggregateContainsRecord(SILType Ty, SILModule &SILMod) const;
    
    /// Returns true if this SILType is an aggregate with unreferenceable storage,
    /// meaning it cannot be fully destructured in SIL.
    bool aggregateHasUnreferenceableStorage() const;
  
    /// Returns the lowered type for T if this type is Optional<T> or
    /// ImplicitlyUnwrappedOptional<T>; otherwise, return the null type.
    SILType getAnyOptionalObjectType(SILModule &SILMod,
                                     OptionalTypeKind &OTK) const;
  
    /// Unwraps one level of optional type.
    /// Returns the lowered T if the given type is Optional<T> or IUO<T>.
    /// Otherwise directly returns the given type.
    static SILType unwrapAnyOptionalType(SILType Ty, SILModule &SILMod,
                                         OptionalTypeKind &OTK) {
      if (auto unwrappedTy = Ty.getAnyOptionalObjectType(SILMod, OTK))
        return unwrappedTy;
  
      return Ty;
    };
  
    /// Classify this type as an optional type.
    OptionalTypeKind getOptionalTypeKind() const;
  
    /// Returns true if this is the AnyObject SILType;
    bool isAnyObject() const { return getSwiftRValueType()->isAnyObject(); }
  
    /// Returns the hash code for the SILType.
    llvm::hash_code getHashCode() const {
      return llvm::hash_combine(*this);
    }
  
    //
    // Accessors for types used in SIL instructions:
    //
    
    /// Get the NativeObject type as a SILType.
    static SILType getNativeObjectType(const ASTContext &C);
    /// Get the UnknownObject type as a SILType.
    static SILType getUnknownObjectType(const ASTContext &C);
    /// Get the BridgeObject type as a SILType.
    static SILType getBridgeObjectType(const ASTContext &C);
    /// Get the RawPointer type as a SILType.
    static SILType getRawPointerType(const ASTContext &C);
    /// Get a builtin integer type as a SILType.
    static SILType getBuiltinIntegerType(unsigned bitWidth, const ASTContext &C);
    /// Get a builtin floating-point type as a SILType.
    static SILType getBuiltinFloatType(BuiltinFloatType::FPKind Kind,
                                       const ASTContext &C);
    /// Get the builtin word type as a SILType;
    static SILType getBuiltinWordType(const ASTContext &C);
  
    /// Get the standard exception type.
    static SILType getExceptionType(const ASTContext &C);
  
    //
    // Utilities for treating SILType as a pointer-like type.
    //
    static SILType getFromOpaqueValue(void *P) {
      return SILType(ValueType::getFromOpaqueValue(P));
    }
    void *getOpaqueValue() const {
      return value.getOpaqueValue();
    }
    
    bool operator==(SILType rhs) const {
      return value.getOpaqueValue() == rhs.value.getOpaqueValue();
    }
    bool operator!=(SILType rhs) const {
      return value.getOpaqueValue() != rhs.value.getOpaqueValue();
    }
    
    std::string getAsString() const;
    void dump() const;
    void print(raw_ostream &OS) const;
  };
  
  // Statically prevent SILTypes from being directly cast to a type
  // that's not legal as a SIL value.
  #define NON_SIL_TYPE(ID)                                             \
  template<> Can##ID##Type SILType::getAs<ID##Type>() const = delete;  \
  template<> Can##ID##Type SILType::castTo<ID##Type>() const = delete; \
  template<> bool SILType::is<ID##Type>() const = delete;
  NON_SIL_TYPE(Function)
  NON_SIL_TYPE(PolymorphicFunction)
  NON_SIL_TYPE(AnyFunction)
  NON_SIL_TYPE(LValue)
  #undef NON_SIL_TYPE
  
  CanSILFunctionType getNativeSILFunctionType(SILModule &M,
                          Lowering::AbstractionPattern orig,
                          CanAnyFunctionType subst,
                          CanAnyFunctionType substInterface,
                          SILDeclRef::Kind kind = SILDeclRef::Kind::Func);
  
  inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SILType T) {
    T.print(OS);
    return OS;
  }
  
  inline SILType SILParameterInfo::getSILType() const {
    if (isIndirect()) {
      return SILType::getPrimitiveAddressType(getType());
    } else {
      return SILType::getPrimitiveObjectType(getType());
    }
  }
  
  inline SILType
  SILFunctionType::getParameterSILType(const SILParameterInfo &param) {
    return param.getSILType();
  }
  
  inline SILType SILFunctionType::getSILResult() const {
    return getResult().getSILType();
  }
  
  inline SILType SILResultInfo::getSILType() const {
    return SILType::getPrimitiveObjectType(getType());
  }
  
  inline SILType SILFunctionType::getSemanticResultSILType() const {
    return (hasIndirectResult() ? getIndirectResult().getSILType()
                                : getResult().getSILType());
  }  
    
  inline SILType SILBlockStorageType::getCaptureAddressType() const {
    return SILType::getPrimitiveAddressType(getCaptureType());
  }
  
  inline SILType SILBoxType::getBoxedAddressType() const {
    return SILType::getPrimitiveAddressType(getBoxedType());
  }
  
  /// The hash of a SILType is the hash of its opaque value.
  static inline llvm::hash_code hash_value(SILType V) {
    return llvm::hash_value(V.getOpaqueValue());
  }
    
  } // end swift namespace
  
  namespace llvm {
  
  // Allow the low bit of SILType to be used for nefarious purposes, e.g. putting
  // a SILType into a PointerUnion.
  template<>
  class PointerLikeTypeTraits<swift::SILType> {
  public:
    static inline void *getAsVoidPointer(swift::SILType T) {
      return T.getOpaqueValue();
    }
    static inline swift::SILType getFromVoidPointer(void *P) {
      return swift::SILType::getFromOpaqueValue(P);
    }
    // SILType is just a wrapper around its ValueType, so it has a bit available.
    enum { NumLowBitsAvailable =
      PointerLikeTypeTraits<swift::SILType::ValueType>::NumLowBitsAvailable };
  };
  
  
  // Allow SILType to be used as a DenseMap key.
  template<>
  struct DenseMapInfo<swift::SILType> {
    using SILType = swift::SILType;
    using PointerMapInfo = DenseMapInfo<void*>;
  public:
    static SILType getEmptyKey() {
      return SILType::getFromOpaqueValue(PointerMapInfo::getEmptyKey());
    }
    static SILType getTombstoneKey() {
      return SILType::getFromOpaqueValue(PointerMapInfo::getTombstoneKey());
    }
    static unsigned getHashValue(SILType t) {
      return PointerMapInfo::getHashValue(t.getOpaqueValue());
    }
    static bool isEqual(SILType LHS, SILType RHS) {
      return LHS == RHS;
    }
  };
  
  } // end llvm namespace
  
  
  #endif
  