text: //===--- TypeLowering.cpp - Type information for SILGen ---------*- 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
  //
  //===----------------------------------------------------------------------===//
  
  #define DEBUG_TYPE "libsil"
  #include "swift/AST/AnyFunctionRef.h"
  #include "swift/AST/ArchetypeBuilder.h"
  #include "swift/AST/ASTContext.h"
  #include "swift/AST/CanTypeVisitor.h"
  #include "swift/AST/Decl.h"
  #include "swift/AST/DiagnosticEngine.h"
  #include "swift/AST/DiagnosticsSIL.h"
  #include "swift/AST/Expr.h"
  #include "swift/AST/Module.h"
  #include "swift/AST/NameLookup.h"
  #include "swift/AST/Pattern.h"
  #include "swift/AST/Types.h"
  #include "swift/Basic/Fallthrough.h"
  #include "swift/SIL/SILArgument.h"
  #include "swift/SIL/SILBuilder.h"
  #include "swift/SIL/SILModule.h"
  #include "swift/SIL/TypeLowering.h"
  #include "clang/AST/Type.h"
  #include "llvm/Support/Debug.h"
  
  using namespace swift;
  using namespace Lowering;
  
  namespace {
    /// A CRTP type visitor for deciding whether the metatype for a type
    /// is a singleton type, i.e. whether there can only ever be one
    /// such value.
    struct HasSingletonMetatype : CanTypeVisitor<HasSingletonMetatype, bool> {
      /// Class metatypes have non-trivial representation due to the
      /// possibility of subclassing.
      bool visitClassType(CanClassType type) {
        return false;
      }
      bool visitBoundGenericClassType(CanBoundGenericClassType type) {
        return false;
      }
      bool visitDynamicSelfType(CanDynamicSelfType type) {
        return false;
      }
  
      /// Dependent types have non-trivial representation in case they
      /// instantiate to a class metatype.
      bool visitGenericTypeParamType(CanGenericTypeParamType type) {
        return false;
      }
      bool visitDependentMemberType(CanDependentMemberType type) {
        return false;
      }
      
      /// Archetype metatypes have non-trivial representation in case
      /// they instantiate to a class metatype.
      bool visitArchetypeType(CanArchetypeType type) {
        return false;
      }
      
      /// All levels of class metatypes support subtyping.
      bool visitMetatypeType(CanMetatypeType type) {
        return visit(type.getInstanceType());
      }
  
      /// Everything else is trivial.  Note that ordinary metatypes of
      /// existential types are still singleton.
      bool visitType(CanType type) {
        return true;
      }
    };
  }
  
  /// Does the metatype for the given type have a known-singleton
  /// representation?
  static bool hasSingletonMetatype(CanType instanceType) {
    return HasSingletonMetatype().visit(instanceType);
  }
  
  CaptureKind TypeConverter::getDeclCaptureKind(CapturedValue capture) {
    auto decl = capture.getDecl();
    if (VarDecl *var = dyn_cast<VarDecl>(decl)) {
      switch (var->getStorageKind()) {
      case VarDecl::StoredWithTrivialAccessors:
        llvm_unreachable("stored local variable with trivial accessors?");
  
      case VarDecl::InheritedWithObservers:
        llvm_unreachable("inherited local variable?");
  
      case VarDecl::Computed:
        llvm_unreachable("computed captured property should have been lowered "
                         "away");
  
      case VarDecl::StoredWithObservers:
      case VarDecl::Addressed:
      case VarDecl::AddressedWithTrivialAccessors:
      case VarDecl::AddressedWithObservers:
      case VarDecl::ComputedWithMutableAddress:
        // Computed captures should have been lowered away.
        assert(capture.isDirect()
               && "computed captured property should have been lowered away");
  
        // If captured directly, the variable is captured by box or pointer.
        assert(var->hasStorage());
        return capture.isNoEscape() ?
          CaptureKind::StorageAddress : CaptureKind::Box;
  
      case VarDecl::Stored:
        // If this is a non-address-only stored 'let' constant, we can capture it
        // by value.  If it is address-only, then we can't load it, so capture it
        // by its address (like a var) instead.
        if (var->isLet() && !getTypeLowering(var->getType()).isAddressOnly())
          return CaptureKind::Constant;
  
        // If we're capturing into a non-escaping closure, we can generally just
        // capture the address of the value as no-escape.
        return capture.isNoEscape() ?
          CaptureKind::StorageAddress : CaptureKind::Box;
      }
      llvm_unreachable("bad storage kind");
    }
    
    // "Captured" local types require no context.
    if (isa<TypeAliasDecl>(decl) || isa<GenericTypeParamDecl>(decl) ||
        isa<AssociatedTypeDecl>(decl))
      return CaptureKind::None;
    
    llvm_unreachable("function-like captures should have been lowered away");
  }
  
  enum class LoweredTypeKind {
    /// Trivial and loadable.
    Trivial,
  
    /// A reference type.
    Reference,
  
    /// An aggregate type that contains references (potentially recursively).
    AggWithReference,
  
    /// Non-trivial and not loadable.
    AddressOnly
  };
  
  static LoweredTypeKind classifyType(CanType type, SILModule &M);
  
  namespace {
    /// A CRTP helper class for doing things that depends on type
    /// classification.
    template <class Impl, class RetTy>
    class TypeClassifierBase : public CanTypeVisitor<Impl, RetTy> {
      SILModule &M;
      Impl &asImpl() { return *static_cast<Impl*>(this); }
    protected:
      TypeClassifierBase(SILModule &M) : M(M) {}
  
    public:
      // The subclass should implement:
      //   RetTy handleAddressOnly(CanType);
      //   RetTy handleReference(CanType);
      //   RetTy handleTrivial(CanType);
      // In addition, if it does not override visitTupleType
      // and visitAnyStructType, it should also implement:
      //   RetTy handleAggWithReference(CanType);
  
  #define IMPL(TYPE, LOWERING)                            \
      RetTy visit##TYPE##Type(Can##TYPE##Type type) {     \
        return asImpl().handle##LOWERING(type);        \
      }
  
      IMPL(BuiltinInteger, Trivial)
      IMPL(BuiltinFloat, Trivial)
      IMPL(BuiltinRawPointer, Trivial)
      IMPL(BuiltinNativeObject, Reference)
      IMPL(BuiltinBridgeObject, Reference)
      IMPL(BuiltinUnknownObject, Reference)
      IMPL(BuiltinUnsafeValueBuffer, AddressOnly)
      IMPL(BuiltinVector, Trivial)
      IMPL(Class, Reference)
      IMPL(BoundGenericClass, Reference)
      IMPL(AnyMetatype, Trivial)
      IMPL(Module, Trivial)
      
      RetTy visitAnyFunctionType(CanAnyFunctionType type) {
        switch (type->getRepresentation()) {
        case AnyFunctionType::Representation::Swift:
        case AnyFunctionType::Representation::Block:
          return asImpl().handleReference(type);
        case AnyFunctionType::Representation::CFunctionPointer:
        case AnyFunctionType::Representation::Thin:
          return asImpl().handleTrivial(type);
        }
        llvm_unreachable("bad function representation");
      }
      
      RetTy visitSILFunctionType(CanSILFunctionType type) {
        if (type->getExtInfo().hasContext())
          return asImpl().handleReference(type);
        return asImpl().handleTrivial(type);
      }
  
  #undef IMPL
  
      RetTy visitLValueType(CanLValueType type) {
        llvm_unreachable("shouldn't get an l-value type here");
      }
      RetTy visitInOutType(CanInOutType type) {
        llvm_unreachable("shouldn't get an inout type here");
      }
  
      // Dependent types should be contextualized before visiting.
  
      RetTy visitGenericTypeParamType(CanGenericTypeParamType type) {
        llvm_unreachable("should have substituted dependent type into context");
      }
      RetTy visitDependentMemberType(CanDependentMemberType type) {
        llvm_unreachable("should have substituted dependent type into context");
      }
  
      RetTy visitUnmanagedStorageType(CanUnmanagedStorageType type) {
        return asImpl().handleTrivial(type);
      }
  
      RetTy visitUnownedStorageType(CanUnownedStorageType type) {
        // FIXME: resilience
        if (type->isLoadable(ResilienceExpansion::Maximal)) {
          return asImpl().visitLoadableUnownedStorageType(type);
        } else {
          return asImpl().visitAddressOnlyUnownedStorageType(type);
        }
      }
  
      RetTy visitLoadableUnownedStorageType(CanUnownedStorageType type) {
        return asImpl().handleReference(type);
      }
  
      RetTy visitAddressOnlyUnownedStorageType(CanUnownedStorageType type) {
        return asImpl().handleAddressOnly(type);
      }
  
      RetTy visitWeakStorageType(CanWeakStorageType type) {
        return asImpl().handleAddressOnly(type);
      }
  
      RetTy visitArchetypeType(CanArchetypeType type) {
        if (type->requiresClass()) {
          return asImpl().handleReference(type);
        } else {
          return asImpl().handleAddressOnly(type);
        }
      }
  
      RetTy visitExistentialType(CanType type) {
        switch (SILType::getPrimitiveObjectType(type)
                  .getPreferredExistentialRepresentation(M)) {
        case ExistentialRepresentation::None:
          llvm_unreachable("not an existential type?!");
        // Opaque existentials are address-only.
        case ExistentialRepresentation::Opaque:
          return asImpl().handleAddressOnly(type);
        // Class-constrained and boxed existentials are refcounted.
        case ExistentialRepresentation::Class:
        case ExistentialRepresentation::Boxed:
          return asImpl().handleReference(type);
        // Existential metatypes are trivial.
        case ExistentialRepresentation::Metatype:
          return asImpl().handleTrivial(type);
        }
      }
      RetTy visitProtocolType(CanProtocolType type) {
        return visitExistentialType(type);
      }
      RetTy visitProtocolCompositionType(CanProtocolCompositionType type) {
        return visitExistentialType(type);
      }
  
      // Enums depend on their enumerators.
      RetTy visitEnumType(CanEnumType type) {
        return asImpl().visitAnyEnumType(type, type->getDecl());
      }
      RetTy visitBoundGenericEnumType(CanBoundGenericEnumType type) {
        return asImpl().visitAnyEnumType(type, type->getDecl());
      }
      RetTy visitAnyEnumType(CanType type, EnumDecl *D) {
        // Consult the type lowering.
        auto &lowering = M.Types.getTypeLowering(type);
        return handleClassificationFromLowering(type, lowering);
      }
      
      RetTy handleClassificationFromLowering(CanType type,
                                             const TypeLowering &lowering) {
        if (lowering.isAddressOnly())
          return asImpl().handleAddressOnly(type);
        if (lowering.isTrivial())
          return asImpl().handleTrivial(type);
        return asImpl().handleAggWithReference(type);
      }
  
      // Structs depend on their physical fields.
      RetTy visitStructType(CanStructType type) {
        return asImpl().visitAnyStructType(type, type->getDecl());
      }
      RetTy visitBoundGenericStructType(CanBoundGenericStructType type) {
        return asImpl().visitAnyStructType(type, type->getDecl());
      }
  
      RetTy visitAnyStructType(CanType type, StructDecl *D) {
        // Consult the type lowering.  This means we implicitly get
        // caching, but that type lowering needs to override this case.
        auto &lowering = M.Types.getTypeLowering(type);
        return handleClassificationFromLowering(type, lowering);
      }
      
      // Tuples depend on their elements.
      RetTy visitTupleType(CanTupleType type) {
        bool hasReference = false;
        // TODO: We ought to be able to early-exit as soon as we've established
        // that a type is address-only. However, we also currently rely on
        // SIL lowering to catch unsupported recursive value types.
        bool isAddressOnly = false;
        for (auto eltType : type.getElementTypes()) {
          switch (classifyType(eltType, M)) {
          case LoweredTypeKind::Trivial:
            continue;
          case LoweredTypeKind::AddressOnly:
            isAddressOnly = true;
            continue;
          case LoweredTypeKind::Reference:
          case LoweredTypeKind::AggWithReference:
            hasReference = true;
            continue;
          }
          llvm_unreachable("bad type classification");
        }
  
        if (isAddressOnly)
          return asImpl().handleAddressOnly(type);
        if (hasReference)
          return asImpl().handleAggWithReference(type);
        return asImpl().handleTrivial(type);
      }
  
      RetTy visitDynamicSelfType(CanDynamicSelfType type) {
        return this->visit(type.getSelfType());
      }
      
      RetTy visitSILBlockStorageType(CanSILBlockStorageType type) {
        // Should not be loaded.
        return asImpl().handleAddressOnly(type);
      }
  
      RetTy visitSILBoxType(CanSILBoxType type) {
        // Should not be loaded.
        return asImpl().handleReference(type);
      }
    };
  
    class TypeClassifier :
        public TypeClassifierBase<TypeClassifier, LoweredTypeKind> {
    public:
      TypeClassifier(SILModule &M) : TypeClassifierBase(M) {}
  
      LoweredTypeKind handleReference(CanType type) {
        return LoweredTypeKind::Reference;
      }
      LoweredTypeKind handleAggWithReference(CanType type) {
        return LoweredTypeKind::AggWithReference;
      }
      LoweredTypeKind handleTrivial(CanType type) {
        return LoweredTypeKind::Trivial;
      }
      LoweredTypeKind handleAddressOnly(CanType type) {
        return LoweredTypeKind::AddressOnly;
      }
    };
  }
  
  static LoweredTypeKind classifyType(CanType type, SILModule &M) {
    if (type->hasTypeParameter())
      type = M.Types.getArchetypes().substDependentType(type)->getCanonicalType();
    return TypeClassifier(M).visit(type);
  }
  
  /// 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.
  bool SILType::isAddressOnly(CanType type, SILModule &M) {
    return classifyType(type, M) == LoweredTypeKind::AddressOnly;
  }
  
  namespace {
    /// A class for loadable types.
    class LoadableTypeLowering : public TypeLowering {
    protected:
      LoadableTypeLowering(SILType type, IsTrivial_t isTrivial,
                           IsReferenceCounted_t isRefCounted)
        : TypeLowering(type, isTrivial, IsNotAddressOnly, isRefCounted) {}
  
    public:
      void emitDestroyAddress(SILBuilder &B, SILLocation loc,
                              SILValue addr) const override {
        SILValue value = B.createLoad(loc, addr);
        emitReleaseValue(B, loc, value);
      }
  
      void emitDestroyRValue(SILBuilder &B, SILLocation loc,
                             SILValue value) const override {
        emitReleaseValue(B, loc, value);
      }
  
      void emitCopyInto(SILBuilder &B, SILLocation loc,
                        SILValue src, SILValue dest, IsTake_t isTake,
                        IsInitialization_t isInit) const override {
        SILValue value = emitLoadOfCopy(B, loc, src, isTake);
        emitStoreOfCopy(B, loc, value, dest, isInit);
      }
    };
  
    /// A class for trivial, loadable types.
    class TrivialTypeLowering final : public LoadableTypeLowering {
    public:
      TrivialTypeLowering(SILType type)
        : LoadableTypeLowering(type, IsTrivial, IsNotReferenceCounted) {}
  
      SILValue emitLoadOfCopy(SILBuilder &B, SILLocation loc, SILValue addr,
                              IsTake_t isTake) const override {
        return B.createLoad(loc, addr);
      }
  
      void emitStoreOfCopy(SILBuilder &B, SILLocation loc,
                           SILValue value, SILValue addr,
                           IsInitialization_t isInit) const override {
        B.createStore(loc, value, addr);
      }
  
      void emitDestroyAddress(SILBuilder &B, SILLocation loc,
                              SILValue addr) const override {
        // Trivial
      }
  
      void emitLoweredReleaseValue(SILBuilder &B, SILLocation loc,
                                   SILValue value,
                                   LoweringStyle loweringStyle) const override {
        // Trivial
      }
  
      void emitLoweredRetainValue(SILBuilder &B, SILLocation loc,
                                SILValue value,
                                LoweringStyle style) const override {
        // Trivial
      }
  
      void emitRetainValue(SILBuilder &B, SILLocation loc,
                         SILValue value) const override {
        // Trivial
      }
  
      void emitReleaseValue(SILBuilder &B, SILLocation loc,
                            SILValue value) const override {
        // Trivial
      }
    };
  
    class NonTrivialLoadableTypeLowering : public LoadableTypeLowering {
    public:
      NonTrivialLoadableTypeLowering(SILType type,
                                     IsReferenceCounted_t isRefCounted)
        : LoadableTypeLowering(type, IsNotTrivial, isRefCounted) {}
  
      SILValue emitLoadOfCopy(SILBuilder &B, SILLocation loc,
                              SILValue addr, IsTake_t isTake) const override {
        SILValue value = B.createLoad(loc, addr);
        if (!isTake) emitRetainValue(B, loc, value);
        return value;
      }
  
      void emitStoreOfCopy(SILBuilder &B, SILLocation loc,
                           SILValue newValue, SILValue addr,
                           IsInitialization_t isInit) const override {
        SILValue oldValue;
        if (!isInit) oldValue = B.createLoad(loc, addr);
        B.createStore(loc, newValue, addr);
        if (!isInit) emitReleaseValue(B, loc, oldValue);
      }
    };
  
    /// A CRTP helper class for loadable but non-trivial aggregate types.
    template <class Impl, class IndexType>
    class LoadableAggTypeLowering : public NonTrivialLoadableTypeLowering {
    public:
      /// A child of this aggregate type.
      class Child {
        /// The index of this child, used to project it out.
        IndexType Index;
  
        /// The aggregate's type lowering.
        const TypeLowering *Lowering;
      public:
        Child(IndexType index, const TypeLowering &lowering)
          : Index(index), Lowering(&lowering) {}
        const TypeLowering &getLowering() const { return *Lowering; }
        IndexType getIndex() const { return Index; }
        bool isTrivial() const { return Lowering->isTrivial(); }
      };
  
    private:
      const Impl &asImpl() const { return static_cast<const Impl&>(*this); }
      Impl &asImpl() { return static_cast<Impl&>(*this); }
  
      // A reference to the lazily-allocated children vector.
      mutable ArrayRef<Child> Children = {};
      
    protected:
      virtual void lowerChildren(SILModule &M, SmallVectorImpl<Child> &children)
        const = 0;
      
    public:
      LoadableAggTypeLowering(CanType type)
        : NonTrivialLoadableTypeLowering(SILType::getPrimitiveObjectType(type),
                                         IsNotReferenceCounted) {
      }
  
      ArrayRef<Child> getChildren(SILModule &M) const {
        if (Children.data() == nullptr) {
          SmallVector<Child, 4> children;
          lowerChildren(M, children);
          auto isDependent = IsDependent_t(getLoweredType().hasTypeParameter());
          auto buf = operator new(sizeof(Child) * children.size(), M.Types,
                                  isDependent);
          memcpy(buf, children.data(), sizeof(Child) * children.size());
          Children = {reinterpret_cast<Child*>(buf), children.size()};
        }
        return Children;
      }
  
      template <class T>
      void forEachNonTrivialChild(SILBuilder &B, SILLocation loc,
                                  SILValue aggValue,
                                  const T &operation) const {
        for (auto &child : getChildren(B.getModule())) {
          auto &childLowering = child.getLowering();
          // Skip trivial children.
          if (childLowering.isTrivial())
            continue;
          auto childIndex = child.getIndex();
          auto childValue = asImpl().emitRValueProject(B, loc, aggValue,
                                                     childIndex, childLowering);
          operation(B, loc, childIndex, childValue, childLowering);
        }
      }
  
      using SimpleOperationTy = void (TypeLowering::*)(SILBuilder &B,
                                                       SILLocation loc,
                                                       SILValue value) const;
      void forEachNonTrivialChild(SILBuilder &B, SILLocation loc,
                                  SILValue aggValue,
                                  SimpleOperationTy operation) const {
        forEachNonTrivialChild(B, loc, aggValue,
          [operation](SILBuilder &B, SILLocation loc, IndexType index,
                       SILValue childValue, const TypeLowering &childLowering) {
            (childLowering.*operation)(B, loc, childValue);
          });
      }
  
      void emitRetainValue(SILBuilder &B, SILLocation loc,
                         SILValue aggValue) const override {
        B.createRetainValue(loc, aggValue);
      }
  
      void emitLoweredRetainValue(SILBuilder &B, SILLocation loc,
                                SILValue aggValue,
                                LoweringStyle style) const override {
        for (auto &child : getChildren(B.getModule())) {
          auto &childLowering = child.getLowering();
          SILValue childValue = asImpl().emitRValueProject(B, loc, aggValue,
                                                           child.getIndex(),
                                                           childLowering);
          if (!childLowering.isTrivial()) {
            childLowering.emitLoweredCopyChildValue(B, loc, childValue, style);
          }
        }
      }
  
      void emitReleaseValue(SILBuilder &B, SILLocation loc,
                            SILValue aggValue) const override {
        B.emitReleaseValueAndFold(loc, aggValue);
      }
  
      void emitLoweredReleaseValue(SILBuilder &B, SILLocation loc,
                                   SILValue aggValue,
                                   LoweringStyle loweringStyle) const override {
        SimpleOperationTy Fn;
  
        switch(loweringStyle) {
        case LoweringStyle::Shallow:
          Fn = &TypeLowering::emitReleaseValue;
          break;
        case LoweringStyle::Deep:
          Fn = &TypeLowering::emitLoweredReleaseValueDeep;
          break;
        case LoweringStyle::DeepNoEnum:
          Fn = &TypeLowering::emitLoweredReleaseValueDeepNoEnum;
          break;
        }
  
        forEachNonTrivialChild(B, loc, aggValue, Fn);
      }
    };
  
    /// A lowering for loadable but non-trivial tuple types.
    class LoadableTupleTypeLowering final
        : public LoadableAggTypeLowering<LoadableTupleTypeLowering, unsigned> {
    public:
      LoadableTupleTypeLowering(CanType type)
        : LoadableAggTypeLowering(type) {}
  
      SILValue emitRValueProject(SILBuilder &B, SILLocation loc,
                                 SILValue tupleValue, unsigned index,
                                 const TypeLowering &eltLowering) const {
        return B.createTupleExtract(loc, tupleValue, index,
                                    eltLowering.getLoweredType());
      }
  
      SILValue rebuildAggregate(SILBuilder &B, SILLocation loc,
                                ArrayRef<SILValue> values) const {
        return B.createTuple(loc, getLoweredType(), values);
      }
    
    private:
      void lowerChildren(SILModule &M, SmallVectorImpl<Child> &children)
      const override {
        // The children are just the elements of the lowered tuple.
        auto silTy = getLoweredType();
        auto tupleTy = silTy.castTo<TupleType>();
        children.reserve(tupleTy->getNumElements());
        unsigned index = 0;
        for (auto elt : tupleTy.getElementTypes()) {
          auto silElt = SILType::getPrimitiveType(elt, silTy.getCategory());
          children.push_back(Child{index, M.Types.getTypeLowering(silElt)});
          ++index;
        }
      }
    };
  
    /// A lowering for loadable but non-trivial struct types.
    class LoadableStructTypeLowering final
        : public LoadableAggTypeLowering<LoadableStructTypeLowering, VarDecl*> {
    public:
      LoadableStructTypeLowering(CanType type)
        : LoadableAggTypeLowering(type) {}
  
      SILValue emitRValueProject(SILBuilder &B, SILLocation loc,
                                 SILValue structValue, VarDecl *field,
                                 const TypeLowering &fieldLowering) const {
        return B.createStructExtract(loc, structValue, field,
                                     fieldLowering.getLoweredType());
      }
  
      SILValue rebuildAggregate(SILBuilder &B, SILLocation loc,
                                ArrayRef<SILValue> values) const {
        return B.createStruct(loc, getLoweredType(), values);
      }
          
    private:
      void lowerChildren(SILModule &M, SmallVectorImpl<Child> &children)
      const override {
        auto silTy = getLoweredType();
        auto structDecl = silTy.getStructOrBoundGenericStruct();
        assert(structDecl);
        
        for (auto prop : structDecl->getStoredProperties()) {
          SILType propTy = silTy.getFieldType(prop, M);        
          children.push_back(Child{prop, M.Types.getTypeLowering(propTy)});
        }
      }
    };
    
    /// A lowering for loadable but non-trivial enum types.
    class LoadableEnumTypeLowering final : public NonTrivialLoadableTypeLowering {
    public:
      /// A non-trivial case of the enum.
      class NonTrivialElement {
        /// The non-trivial element.
        EnumElementDecl *element;
        
        /// Its type lowering.
        const TypeLowering *lowering;
        
      public:
        NonTrivialElement(EnumElementDecl *element, const TypeLowering &lowering)
          : element(element), lowering(&lowering) {}
        
        const TypeLowering &getLowering() const { return *lowering; }
        EnumElementDecl *getElement() const { return element; }
      };
      
    private:
  
      using SimpleOperationTy = void (*)(SILBuilder &B, SILLocation loc, SILValue value,
                                         const TypeLowering &valueLowering,
                                         SILBasicBlock *dest);
  
      /// Emit a value semantics operation for each nontrivial case of the enum.
      template <typename T>
      void ifNonTrivialElement(SILBuilder &B, SILLocation loc, SILValue value,
                               const T &operation) const {
        SmallVector<std::pair<EnumElementDecl*,SILBasicBlock*>, 4> nonTrivialBBs;
        
        auto &M = B.getFunction().getModule();
  
        // Create all the blocks up front, so we can set up our switch_enum.
        auto nonTrivialElts = getNonTrivialElements(M);
        for (auto &elt : nonTrivialElts) {
          auto bb = new (M) SILBasicBlock(&B.getFunction());
          auto argTy = elt.getLowering().getLoweredType();
          new (M) SILArgument(bb, argTy);
          nonTrivialBBs.push_back({elt.getElement(), bb});
        }
  
        // If we are appending to the end of a block being constructed, then we
        // create a new basic block to continue cons'ing up code.  If we're
        // emitting this operation into the middle of existing code, we split the
        // block.
        SILBasicBlock *doneBB = B.splitBlockForFallthrough();
        B.createSwitchEnum(loc, value, doneBB, nonTrivialBBs);
        
        for (size_t i = 0; i < nonTrivialBBs.size(); ++i) {
          SILBasicBlock *bb = nonTrivialBBs[i].second;
          const TypeLowering &lowering = nonTrivialElts[i].getLowering();
          B.emitBlock(bb);
          operation(B, loc, bb->getBBArgs()[0], lowering, doneBB);
        }
        
        B.emitBlock(doneBB);
      }
      
      /// A reference to the lazily-allocated array of non-trivial enum cases.
      mutable ArrayRef<NonTrivialElement> NonTrivialElements = {};
      
    public:
      LoadableEnumTypeLowering(CanType type)
        : NonTrivialLoadableTypeLowering(SILType::getPrimitiveObjectType(type),
                                         IsNotReferenceCounted)
      {
      }
      
      ArrayRef<NonTrivialElement> getNonTrivialElements(SILModule &M) const {
        SILType silTy = getLoweredType();
        EnumDecl *enumDecl = silTy.getEnumOrBoundGenericEnum();
        assert(enumDecl);
        
        if (NonTrivialElements.data() == nullptr) {
          SmallVector<NonTrivialElement, 4> elts;
          
          for (auto elt : enumDecl->getAllElements()) {
            if (!elt->hasArgumentType()) continue;
            SILType substTy = silTy.getEnumElementType(elt, M);
            elts.push_back(NonTrivialElement{elt,
                                       M.Types.getTypeLowering(substTy)});
          }
          
          auto isDependent = IsDependent_t(silTy.hasTypeParameter());
          
          auto buf = operator new(sizeof(NonTrivialElement) * elts.size(),
                                  M.Types, isDependent);
          memcpy(buf, elts.data(), sizeof(NonTrivialElement) * elts.size());
          NonTrivialElements = {reinterpret_cast<NonTrivialElement*>(buf),
                                elts.size()};
        }
        return NonTrivialElements;
      }
  
      void emitRetainValue(SILBuilder &B, SILLocation loc,
                         SILValue value) const override {
        B.createRetainValue(loc, value);
      }
  
      void emitLoweredRetainValue(SILBuilder &B, SILLocation loc,
                                SILValue value,
                                LoweringStyle style) const override {
        if (style == LoweringStyle::Shallow ||
            style == LoweringStyle::DeepNoEnum) {
          B.createRetainValue(loc, value);
        } else {
          ifNonTrivialElement(B, loc, value,
            [&](SILBuilder &B, SILLocation loc, SILValue child,
                const TypeLowering &childLowering, SILBasicBlock *dest) {
              childLowering.emitLoweredCopyChildValue(B, loc, child, style);
              B.createBranch(loc, dest);
            });
        }
      }
      
      void emitReleaseValue(SILBuilder &B, SILLocation loc,
                            SILValue value) const override {
        B.emitReleaseValueAndFold(loc, value);
      }
  
      void emitLoweredReleaseValue(SILBuilder &B, SILLocation loc,
                                   SILValue value,
                                   LoweringStyle style) const override {
        assert(style != LoweringStyle::Shallow &&
               "This method should never be called when performing a shallow "
               "destroy value.");
        if (style == LoweringStyle::DeepNoEnum)
          B.emitReleaseValueAndFold(loc, value);
        else
          ifNonTrivialElement(B, loc, value,
            [&](SILBuilder &B, SILLocation loc, SILValue child,
               const TypeLowering &childLowering, SILBasicBlock *dest) {
               childLowering.emitLoweredDestroyChildValue(B, loc, child, style);
               B.createBranch(loc, dest);
            });
      }
    };
  
    class LeafLoadableTypeLowering : public NonTrivialLoadableTypeLowering {
    public:
      LeafLoadableTypeLowering(SILType type, IsReferenceCounted_t isRefCounted)
        : NonTrivialLoadableTypeLowering(type, isRefCounted) {}
  
      void emitLoweredRetainValue(SILBuilder &B, SILLocation loc,
                                SILValue value,
                                LoweringStyle style) const override {
        emitRetainValue(B, loc, value);
      }
  
      void emitLoweredReleaseValue(SILBuilder &B, SILLocation loc,
                                   SILValue value,
                                   LoweringStyle style) const override {
        emitReleaseValue(B, loc, value);
      }
    };
  
    /// A class for reference types, which are all non-trivial but still
    /// loadable.
    class ReferenceTypeLowering : public LeafLoadableTypeLowering {
    public:
      ReferenceTypeLowering(SILType type)
        : LeafLoadableTypeLowering(type, IsReferenceCounted) {}
  
      void emitRetainValue(SILBuilder &B, SILLocation loc,
                         SILValue value) const override {
        if (!isa<FunctionRefInst>(value))
          B.createStrongRetain(loc, value);
      }
  
      void emitReleaseValue(SILBuilder &B, SILLocation loc,
                            SILValue value) const override {
        B.emitStrongReleaseAndFold(loc, value);
      }
    };
  
    /// A type lowering for loadable @unowned types.
    class LoadableUnownedTypeLowering final : public LeafLoadableTypeLowering {
    public:
      LoadableUnownedTypeLowering(SILType type)
        : LeafLoadableTypeLowering(type, IsReferenceCounted) {}
  
      void emitRetainValue(SILBuilder &B, SILLocation loc,
                         SILValue value) const override {
        B.createUnownedRetain(loc, value);
      }
  
      void emitReleaseValue(SILBuilder &B, SILLocation loc,
                            SILValue value) const override {
        B.createUnownedRelease(loc, value);
      }
    };
  
    /// A class for non-trivial, address-only types.
    class AddressOnlyTypeLowering : public TypeLowering {
    public:
      AddressOnlyTypeLowering(SILType type)
        : TypeLowering(type, IsNotTrivial, IsAddressOnly, IsNotReferenceCounted)
      {}
  
      void emitCopyInto(SILBuilder &B, SILLocation loc,
                        SILValue src, SILValue dest, IsTake_t isTake,
                        IsInitialization_t isInit) const override {
        B.createCopyAddr(loc, src, dest, isTake, isInit);
      }
  
      SILValue emitLoadOfCopy(SILBuilder &B, SILLocation loc,
                              SILValue addr, IsTake_t isTake) const override {
        llvm_unreachable("calling emitLoadOfCopy on non-loadable type");
      }
  
      void emitStoreOfCopy(SILBuilder &B, SILLocation loc,
                           SILValue newValue, SILValue addr,
                           IsInitialization_t isInit) const override {
        llvm_unreachable("calling emitStoreOfCopy on non-loadable type");
      }
  
      void emitDestroyAddress(SILBuilder &B, SILLocation loc,
                              SILValue addr) const override {
        B.emitDestroyAddrAndFold(loc, addr);
      }
  
      void emitDestroyRValue(SILBuilder &B, SILLocation loc,
                             SILValue value) const override {
        B.emitDestroyAddrAndFold(loc, value);
      }
  
      void emitRetainValue(SILBuilder &B, SILLocation loc,
                         SILValue value) const override {
        llvm_unreachable("type is not loadable!");
      }
  
      void emitLoweredRetainValue(SILBuilder &B, SILLocation loc,
                                SILValue value,
                                LoweringStyle style) const override {
        llvm_unreachable("type is not loadable!");
      }
  
      void emitReleaseValue(SILBuilder &B, SILLocation loc,
                            SILValue value) const override {
        llvm_unreachable("type is not loadable!");
      }
  
      void emitLoweredReleaseValue(SILBuilder &B, SILLocation loc,
                                   SILValue value,
                                   LoweringStyle style) const override {
        llvm_unreachable("type is not loadable!");
      }
    };
  
    /// A class for Builtin.UnsafeValueBuffer.  The only purpose here is
    /// to catch obviously broken attempts to copy or destroy the buffer.
    class UnsafeValueBufferTypeLowering : public AddressOnlyTypeLowering {
    public:
      UnsafeValueBufferTypeLowering(SILType type)
        : AddressOnlyTypeLowering(type) {}
  
      void emitCopyInto(SILBuilder &B, SILLocation loc,
                        SILValue src, SILValue dest, IsTake_t isTake,
                        IsInitialization_t isInit) const override {
        llvm_unreachable("cannot copy an UnsafeValueBuffer!");
      }
  
      void emitDestroyAddress(SILBuilder &B, SILLocation loc,
                              SILValue addr) const override {
        llvm_unreachable("cannot destroy an UnsafeValueBuffer!");
      }
  
      void emitDestroyRValue(SILBuilder &B, SILLocation loc,
                             SILValue value) const override {
        llvm_unreachable("cannot destroy an UnsafeValueBuffer!");
      }
    };
    
    /// A class that acts as a stand-in for improperly recursive types.
    class RecursiveErrorTypeLowering : public AddressOnlyTypeLowering {
    public:
      RecursiveErrorTypeLowering(SILType type)
        : AddressOnlyTypeLowering(type) {}
      
      bool isValid() const override {
        return false;
      }
    };
  
    /// Build the appropriate TypeLowering subclass for the given type.
    class LowerType
      : public TypeClassifierBase<LowerType, const TypeLowering *>
    {
      TypeConverter &TC;
      CanType OrigType;
      IsDependent_t Dependent;
    public:
      LowerType(TypeConverter &TC, CanType OrigType, IsDependent_t Dependent)
        : TypeClassifierBase(TC.M), TC(TC), OrigType(OrigType),
          Dependent(Dependent) {}
          
      const TypeLowering *handleTrivial(CanType type) {
        auto silType = SILType::getPrimitiveObjectType(OrigType);
        return new (TC, Dependent) TrivialTypeLowering(silType);
      }
    
      const TypeLowering *handleReference(CanType type) {
        auto silType = SILType::getPrimitiveObjectType(OrigType);
        return new (TC, Dependent) ReferenceTypeLowering(silType);
      }
  
      const TypeLowering *handleAddressOnly(CanType type) {
        auto silType = SILType::getPrimitiveAddressType(OrigType);
        return new (TC, Dependent) AddressOnlyTypeLowering(silType);
      }
  
      /// @unowned is basically like a reference type lowering except
      /// it manipulates unowned reference counts instead of strong.
      const TypeLowering *visitUnownedStorageType(CanUnownedStorageType type) {
        // Lower 'Self' as if it were the base type.
        if (auto dynamicSelfType
              = dyn_cast<DynamicSelfType>(type.getReferentType())) {
          auto unownedBaseType = CanUnownedStorageType::get(
                                                  dynamicSelfType.getSelfType());
  
          return LowerType(TC, unownedBaseType, Dependent)
            .visit(unownedBaseType);
        }
  
        return this->TypeClassifierBase::visitUnownedStorageType(type);
      }
  
      const TypeLowering *
      visitLoadableUnownedStorageType(CanUnownedStorageType type) {
        return new (TC, Dependent) LoadableUnownedTypeLowering(
                                       SILType::getPrimitiveObjectType(OrigType));      
      }
  
      const TypeLowering *visitUnmanagedStorageType(
                                            CanUnmanagedStorageType type) {
        if (auto dynamicSelfType
              = dyn_cast<DynamicSelfType>(type.getReferentType())) {
          auto unmanagedBaseType = CanUnmanagedStorageType::get(
                                                  dynamicSelfType.getSelfType());
  
          return LowerType(TC, unmanagedBaseType, Dependent)
            .visit(unmanagedBaseType);
        }
  
        return this->TypeClassifierBase::visitUnmanagedStorageType(type);
      }
  
      const TypeLowering *visitWeakStorageType(CanWeakStorageType type) {
        OptionalTypeKind OTK;
        auto objectType = type.getReferentType().getAnyOptionalObjectType(OTK);
        if (auto dynamicSelfType = dyn_cast<DynamicSelfType>(objectType)) {
          auto optBaseType = OptionalType::get(OTK, dynamicSelfType.getSelfType())
            ->getCanonicalType();
          auto weakBaseType = CanWeakStorageType::get(optBaseType);
  
          return LowerType(TC, weakBaseType, Dependent)
            .visit(weakBaseType);
        }
  
        return this->TypeClassifierBase::visitWeakStorageType(type);
      }
  
      const TypeLowering *
      visitBuiltinUnsafeValueBufferType(CanBuiltinUnsafeValueBufferType type) {
        auto silType = SILType::getPrimitiveAddressType(OrigType);
        return new (TC, Dependent) UnsafeValueBufferTypeLowering(silType);
      }
  
      const TypeLowering *visitTupleType(CanTupleType tupleType) {
        typedef LoadableTupleTypeLowering::Child Child;
        SmallVector<Child, 8> childElts;
        // TODO: We ought to be able to early-exit as soon as we've established
        // that a type is address-only. However, we also currently rely on
        // SIL lowering to catch unsupported recursive value types.
        bool isAddressOnly = false;
        bool hasOnlyTrivialChildren = true;
  
        unsigned i = 0;
        for (auto eltType : tupleType.getElementTypes()) {
          auto &lowering = TC.getTypeLowering(eltType);
          if (lowering.isAddressOnly())
            isAddressOnly = true;
          hasOnlyTrivialChildren &= lowering.isTrivial();
          childElts.push_back(Child(i, lowering));
          ++i;
        }
  
        if (isAddressOnly)
          return handleAddressOnly(tupleType);
        if (hasOnlyTrivialChildren)
          return handleTrivial(tupleType);
        return new (TC, Dependent) LoadableTupleTypeLowering(OrigType);
      }
  
      const TypeLowering *visitAnyStructType(CanType structType, StructDecl *D) {
        // TODO: We ought to be able to early-exit as soon as we've established
        // that a type is address-only. However, we also currently rely on
        // SIL lowering to catch unsupported recursive value types.
        bool isAddressOnly = false;
        
        // For now, if the type does not have a fixed layout in all resilience
        // domains, we will treat it as address-only in SIL.
        if (!D->hasFixedLayout())
          isAddressOnly = true;
  
        // Classify the type according to its stored properties.
        bool trivial = true;
        for (auto field : D->getStoredProperties()) {
          auto substFieldType =
            structType->getTypeOfMember(D->getModuleContext(), field, nullptr);
          switch (classifyType(substFieldType->getCanonicalType(), TC.M)) {
          case LoweredTypeKind::AddressOnly:
            isAddressOnly = true;
            break;
          case LoweredTypeKind::AggWithReference:
          case LoweredTypeKind::Reference:
            trivial = false;
            break;
          case LoweredTypeKind::Trivial:
            break;
          }
        }
  
        if (isAddressOnly)
          return handleAddressOnly(structType);
        if (trivial)
          return handleTrivial(structType);
        return new (TC, Dependent) LoadableStructTypeLowering(OrigType);
      }
          
      const TypeLowering *visitAnyEnumType(CanType enumType, EnumDecl *D) {
        // TODO: We ought to be able to early-exit as soon as we've established
        // that a type is address-only. However, we also currently rely on
        // SIL lowering to catch unsupported recursive value types.
        bool isAddressOnly = false;
  
        // For now, if the type does not have a fixed layout in all resilience
        // domains, we will treat it as address-only in SIL.
        if (!D->hasFixedLayout())
          isAddressOnly = true;
        
        // Lower Self? as if it were Whatever? and Self! as if it were Whatever!.
        if (auto genericEnum = dyn_cast<BoundGenericEnumType>(enumType)) {
          if (auto dynamicSelfType =
                dyn_cast<DynamicSelfType>(genericEnum.getGenericArgs()[0])) {
            if (auto optKind = D->classifyAsOptionalType()) {
              CanType selfType = dynamicSelfType.getSelfType();
              selfType = OptionalType::get(optKind, selfType)->getCanonicalType();
  
              // Remove the DynamicSelfType from OrigType, too.
              if (OrigType == enumType) {
                OrigType = selfType;
              } else {
                CanType origDynamicSelfType =
                  cast<BoundGenericEnumType>(OrigType).getGenericArgs()[0];
                CanType origSelfType =
                  cast<DynamicSelfType>(origDynamicSelfType).getSelfType();
                OrigType =
                  OptionalType::get(optKind, origSelfType)->getCanonicalType();
              }
  
              return visitAnyEnumType(selfType, D);
            }
          }
        }
  
        // If the whole enum is indirect, we lower it as if all payload
        // cases were indirect. This means a fixed-layout indirect enum
        // is always loadable and nontrivial. A resilient indirect enum
        // is still address only, because we don't know how many bits
        // are used for the discriminator.
        if (D->isIndirect()) {
          if (isAddressOnly)
            return handleAddressOnly(OrigType);
          return new (TC, Dependent) LoadableEnumTypeLowering(OrigType);
        }
  
        // If any of the enum elements have address-only data, the enum is
        // address-only.
        bool trivial = true;
        for (auto elt : D->getAllElements()) {
          // No-payload elements do not affect address-only-ness.
          if (!elt->hasArgumentType())
            continue;
  
          // Indirect elements make the type nontrivial, but don't affect
          // address-only-ness.
          if (elt->isIndirect()) {
            trivial = false;
            continue;
          }
          
          auto substEltType = enumType->getTypeOfMember(
                                D->getModuleContext(),
                                elt, nullptr,
                                elt->getArgumentInterfaceType())
            ->getCanonicalType();
          
          switch (classifyType(substEltType->getCanonicalType(), TC.M)) {
          case LoweredTypeKind::AddressOnly:
            isAddressOnly = true;
            break;
          case LoweredTypeKind::AggWithReference:
          case LoweredTypeKind::Reference:
            trivial = false;
            break;
          case LoweredTypeKind::Trivial:
            break;
          }
          
        }
        if (isAddressOnly)
          return handleAddressOnly(enumType);
        if (trivial)
          return handleTrivial(enumType);
        return new (TC, Dependent) LoadableEnumTypeLowering(OrigType);
      }
  
      const TypeLowering *visitDynamicSelfType(CanDynamicSelfType type) {
        return LowerType(TC, cast<DynamicSelfType>(OrigType).getSelfType(), 
                         Dependent)
                 .visit(type.getSelfType());
      }
  
    };
  }
  
  TypeConverter::TypeConverter(SILModule &m)
    : M(m), Context(m.getASTContext()) {
  }
  
  TypeConverter::~TypeConverter() {
    assert(!GenericArchetypes.hasValue() && "generic context was never popped?!");
  
    // The bump pointer allocator destructor will deallocate but not destroy all
    // our independent TypeLowerings.
    for (auto &ti : IndependentTypes) {
      // Destroy only the unique entries.
      CanType srcType = ti.first.OrigType;
      if (!srcType) continue;
      CanType mappedType = ti.second->getLoweredType().getSwiftRValueType();
      if (srcType == mappedType || isa<InOutType>(srcType))
        ti.second->~TypeLowering();
    }
  }
  
  void *TypeLowering::operator new(size_t size, TypeConverter &tc,
                                   IsDependent_t dependent) {
    return dependent
      ? tc.DependentBPA.Allocate(size, alignof(TypeLowering))
      : tc.IndependentBPA.Allocate(size, alignof(TypeLowering));
  }
  
  const TypeLowering *TypeConverter::find(TypeKey k) {
    if (!k.isCacheable()) return nullptr;
  
    auto &Types = k.isDependent() ? DependentTypes : IndependentTypes;
    auto ck = k.getCachingKey();
    auto found = Types.find(ck);
    if (found == Types.end())
      return nullptr;
    // We place a null placeholder in the hashtable to catch
    // reentrancy, which arises as a result of improper recursion.
    // TODO: We should diagnose nonterminating recursion in Sema, and implement
    // terminating recursive enums, instead of diagnosing here.
    // When that Sema check is in place, we should reinstate the early-exit
    // behavior for address-only types (marked by other TODO: items throughout
    // this file).
    if (auto elt = found->second)
      return elt;
      
    // Try to complain about a nominal type.
    auto nomTy = k.SubstType.getAnyNominal();
    assert(nomTy && "non-nominal types should not be recursive");
    
    if (RecursiveNominalTypes.insert(nomTy).second) {
      auto &diags = M.getASTContext().Diags;
      if (auto *ED = dyn_cast<EnumDecl>(nomTy)) {
        diags.diagnose(ED->getStartLoc(),
                       diag::recursive_enum_not_indirect,
                       nomTy->getDeclaredTypeInContext())
        .fixItInsert(ED->getStartLoc(), "indirect ");
      } else {
        diags.diagnose(nomTy->getLoc(),
                       diag::unsupported_recursive_type,
                       nomTy->getDeclaredTypeInContext());
      }
    }
    auto result = new (*this, k.isDependent()) RecursiveErrorTypeLowering(
                              SILType::getPrimitiveAddressType(k.SubstType));
    found->second = result;
    return result;
  }
  
  void TypeConverter::insert(TypeKey k, const TypeLowering *tl) {
    if (!k.isCacheable()) return;
  
    auto &Types = k.isDependent() ? DependentTypes : IndependentTypes;
    // TODO: Types[k] should always be null at this point, except that we
    // rely on type lowering to discover recursive value types right now.
    auto ck = k.getCachingKey();
    if (!Types[ck])
      Types[ck] = tl;
  }
  
  #ifndef NDEBUG
  /// Is this type a lowered type?
  static bool isLoweredType(CanType type) {
    if (isa<LValueType>(type) || isa<InOutType>(type))
      return false;
    if (isa<AnyFunctionType>(type))
      return false;
    if (auto tuple = dyn_cast<TupleType>(type)) {
      for (auto elt : tuple.getElementTypes())
        if (!isLoweredType(elt))
          return false;
      return true;
    }
    if (auto meta = dyn_cast<AnyMetatypeType>(type)) {
      return meta->hasRepresentation();
    }
    return true;
  }
  #endif
  
  /// Lower each of the elements of the substituted type according to
  /// the abstraction pattern of the given original type.
  static CanTupleType getLoweredTupleType(TypeConverter &tc,
                                          AbstractionPattern origType,
                                          CanTupleType substType) {
    assert(origType.matchesTuple(substType));
  
    // Does the lowered tuple type differ from the substituted type in
    // any interesting way?
    bool changed = false;
    SmallVector<TupleTypeElt, 4> loweredElts;
    loweredElts.reserve(substType->getNumElements());
  
    for (auto i : indices(substType->getElementTypes())) {
      auto origEltType = origType.getTupleElementType(i);
      auto substEltType = substType.getElementType(i);
  
      assert(!isa<LValueType>(substEltType) &&
             "lvalue types cannot exist in function signatures");
  
      CanType loweredSubstEltType;
      if (auto substLV = dyn_cast<InOutType>(substEltType)) {
        SILType silType = tc.getLoweredType(origType.getLValueObjectType(),
                                            substLV.getObjectType());
        loweredSubstEltType = CanInOutType::get(silType.getSwiftRValueType());
  
      } else {
        // If the original type was an archetype, use that archetype as
        // the original type of the element --- the actual archetype
        // doesn't matter, just the abstraction pattern.
        SILType silType = tc.getLoweredType(origEltType, substEltType);
        loweredSubstEltType = silType.getSwiftRValueType();
      }
  
      changed = (changed || substEltType != loweredSubstEltType);
  
      auto &substElt = substType->getElement(i);
      loweredElts.push_back(substElt.getWithType(loweredSubstEltType));
    }
    
    if (!changed) return substType;
  
    // Because we're transforming an existing tuple, the weird corner
    // case where TupleType::get does not return a TupleType can't happen.
    return cast<TupleType>(CanType(TupleType::get(loweredElts, tc.Context)));
  }
  
  CanSILFunctionType
  TypeConverter::getSILFunctionType(AbstractionPattern origType,
                                    CanAnyFunctionType substType,
                                    unsigned uncurryLevel) {
    return getLoweredType(origType, substType, uncurryLevel)
             .castTo<SILFunctionType>();
  }
  
  const TypeLowering &
  TypeConverter::getTypeLowering(AbstractionPattern origType,
                                 Type origSubstType,
                                 unsigned uncurryLevel) {
    CanType substType = origSubstType->getCanonicalType();
    auto key = getTypeKey(origType, substType, uncurryLevel);
    
    assert(!key.isDependent() || GenericArchetypes.hasValue()
           && "dependent type outside of generic context?!");
    
    if (auto existing = find(key))
      return *existing;
    
    // Static metatypes are unitary and can optimized to a "thin" empty
    // representation if the type also appears as a static metatype in the
    // original abstraction pattern.
    if (auto substMeta = dyn_cast<MetatypeType>(substType)) {
      SILType loweredTy;
      
      // If the metatype has already been lowered, it will already carry its
      // representation.
      if (substMeta->hasRepresentation()) {
        loweredTy = SILType::getPrimitiveObjectType(substMeta);
      } else {
        MetatypeRepresentation repr;
        
        auto origMeta = origType.getAs<MetatypeType>();
        if (!origMeta) {
          // If the metatype matches a dependent type, it must be thick.
          assert(origType.isOpaque());
          repr = MetatypeRepresentation::Thick;
        } else {
          // Otherwise, we're thin if the metatype is thinnable both
          // substituted and in the abstraction pattern.
          if (hasSingletonMetatype(substMeta.getInstanceType())
              && hasSingletonMetatype(origMeta.getInstanceType()))
            repr = MetatypeRepresentation::Thin;
          else
            repr = MetatypeRepresentation::Thick;
        }
        
        CanType instanceType = substMeta.getInstanceType();
        // If this is a DynamicSelf metatype, turn it into a metatype of the
        // underlying self type.
        if (auto dynamicSelf = dyn_cast<DynamicSelfType>(instanceType)) {
          instanceType = dynamicSelf.getSelfType();
        }
        
        // Regardless of thinness, metatypes are always trivial.
        auto thinnedTy = CanMetatypeType::get(instanceType, repr);
        loweredTy = SILType::getPrimitiveObjectType(thinnedTy);
      }
      
      auto *theInfo
        = new (*this, key.isDependent()) TrivialTypeLowering(loweredTy);
      insert(key, theInfo);
      return *theInfo;
    }
  
    // Give existential metatypes @thick representation by default.
    if (auto existMetatype = dyn_cast<ExistentialMetatypeType>(substType)) {
      CanType loweredType;
      if (existMetatype->hasRepresentation()) {
        loweredType = existMetatype;
      } else {
        loweredType =
          CanExistentialMetatypeType::get(existMetatype.getInstanceType(),
                                          MetatypeRepresentation::Thick);
      }
  
      auto loweredTy = SILType::getPrimitiveObjectType(loweredType);
      auto theInfo
        = new (*this, key.isDependent()) TrivialTypeLowering(loweredTy);
      insert(key, theInfo);
      return *theInfo;
    }
  
    // AST function types are turned into SIL function types:
    //   - the type is uncurried as desired
    //   - types are turned into their unbridged equivalents, depending
    //     on the abstract CC
    //   - ownership conventions are deduced
    if (auto substFnType = dyn_cast<AnyFunctionType>(substType)) {
      // First, lower at the AST level by uncurrying and substituting
      // bridged types.
      auto substLoweredType =
        getLoweredASTFunctionType(substFnType, uncurryLevel, None);
  
      AbstractionPattern origLoweredType = [&] {
        if (origType.isExactType(substType)) {
          return AbstractionPattern(substLoweredType);
        } else if (origType.isOpaque()) {
          return origType;
        } else {
          auto origFnType = cast<AnyFunctionType>(origType.getType());
          return AbstractionPattern(getLoweredASTFunctionType(origFnType,
                                                              uncurryLevel,
                                                              None));
        }
      }();
      TypeKey loweredKey = getTypeKey(origLoweredType, substLoweredType, 0);
  
      // If the uncurrying/unbridging process changed the type, re-check
      // the cache and add a cache entry for the curried type.
      if (substLoweredType != substType) {
        auto &typeInfo = getTypeLoweringForLoweredFunctionType(loweredKey);
        insert(key, &typeInfo);
        return typeInfo;
      }
  
      // If it didn't, use the standard logic.
      return getTypeLoweringForUncachedLoweredFunctionType(loweredKey);
    }
  
    assert(uncurryLevel == 0);
  
    // inout and lvalue types are a special case for lowering, because they get
    // completely removed and represented as 'address' SILTypes.
    if (isa<InOutType>(substType) || isa<LValueType>(substType)) {
      // Derive SILType for InOutType from the object type.
      CanType substObjectType = substType.getLValueOrInOutObjectType();
      AbstractionPattern origObjectType = origType.getLValueObjectType();
  
      SILType loweredType = getLoweredType(origObjectType, substObjectType,
                                           uncurryLevel).getAddressType();
  
      auto *theInfo = new (*this, key.isDependent())
        TrivialTypeLowering(loweredType);
      insert(key, theInfo);
      return *theInfo;
    }
  
    // Lower the object type of boxes.
    if (auto substBoxType = dyn_cast<SILBoxType>(substType)) {
      AbstractionPattern origBoxed(origType.getAs<SILBoxType>()->getBoxedType());
      SILType loweredBoxedType = getLoweredType(origBoxed,
                                                substBoxType->getBoxedType());
      auto loweredBoxType
        = SILBoxType::get(loweredBoxedType.getSwiftRValueType());
      auto loweredBoxSILType
        = SILType::getPrimitiveObjectType(loweredBoxType);
  
      auto *theInfo = new (*this, key.isDependent())
        ReferenceTypeLowering(loweredBoxSILType);
      insert(key, theInfo);
      return *theInfo;
    }
  
    // We need to lower function and metatype types within tuples.
    if (auto substTupleType = dyn_cast<TupleType>(substType)) {
      auto loweredType = getLoweredTupleType(*this, origType, substTupleType);
  
      // If that changed anything, check for a lowering at the lowered
      // type.
      if (loweredType != substType) {
        TypeKey loweredKey = getTypeKey(origType, loweredType, 0);
        auto &lowering = getTypeLoweringForLoweredType(loweredKey);
        insert(key, &lowering);
        return lowering;
      }
  
      // Okay, the lowered type didn't change anything from the subst type.
      // Fall out into the normal path.
    }
  
    // The Swift type directly corresponds to the lowered type; don't
    // re-check the cache.
    return getTypeLoweringForUncachedLoweredType(key);
  }
  
  const TypeLowering &TypeConverter::getTypeLowering(SILType type) {
    auto loweredType = type.getSwiftRValueType();
    auto key = getTypeKey(AbstractionPattern(loweredType), loweredType, 0);
  
    return getTypeLoweringForLoweredType(key);
  }
  
  const TypeLowering &
  TypeConverter::getTypeLoweringForLoweredType(TypeKey key) {
    auto type = key.SubstType;
    assert(isLoweredType(type) && "type is not lowered!");
    (void)type;
  
    // Re-using uncurry level 0 is reasonable because our uncurrying
    // transforms are idempotent at this level.  This means we don't
    // need a ton of redundant entries in the map.
    if (auto existing = find(key))
      return *existing;
  
    return getTypeLoweringForUncachedLoweredType(key);
  }
  
  const TypeLowering &
  TypeConverter::getTypeLoweringForLoweredFunctionType(TypeKey key) {
    assert(isa<AnyFunctionType>(key.SubstType));
    assert(key.UncurryLevel == 0);
  
    // Check for an existing mapping for the key.
    if (auto existing = find(key))
      return *existing;
  
    // Okay, we didn't find one; go ahead and produce a SILFunctionType.
    return getTypeLoweringForUncachedLoweredFunctionType(key);
  }
  
  const TypeLowering &TypeConverter::
  getTypeLoweringForUncachedLoweredFunctionType(TypeKey key) {
    assert(isa<AnyFunctionType>(key.SubstType));
    assert(key.UncurryLevel == 0);
  
    // Catch recursions.
    // FIXME: These should be bugs, so we shouldn't need to do this in release
    // builds.
    insert(key, nullptr);
    
    // Generic functions aren't first-class values and shouldn't end up lowered
    // through this interface.
    assert(!isa<PolymorphicFunctionType>(key.SubstType)
           && !isa<GenericFunctionType>(key.SubstType));
  
    // Construct the SILFunctionType.
    CanType silFnType = getNativeSILFunctionType(M, key.OrigType,
                                         cast<AnyFunctionType>(key.SubstType),
                                         cast<AnyFunctionType>(key.SubstType));
  
    // Do a cached lookup under yet another key, just so later lookups
    // using the SILType will find the same TypeLowering object.
    auto loweredKey = getTypeKey(AbstractionPattern(key.OrigType), silFnType, 0);
    auto &lowering = getTypeLoweringForLoweredType(loweredKey);
    insert(key, &lowering);
    return lowering;
  }
  
  /// Do type-lowering for a lowered type which is not already in the cache.
  const TypeLowering &
  TypeConverter::getTypeLoweringForUncachedLoweredType(TypeKey key) {
    assert(!find(key) && "re-entrant or already cached");
    assert(isLoweredType(key.SubstType) && "didn't lower out l-value type?");
  
    // Catch reentrancy bugs.
    // FIXME: These should be bugs, so we shouldn't need to do this in release
    // builds.
    insert(key, nullptr);
  
    CanType contextType = key.SubstType;
    if (contextType->hasTypeParameter())
      contextType = getArchetypes().substDependentType(contextType)
        ->getCanonicalType();
    auto *theInfo = LowerType(*this, key.SubstType,
                              key.isDependent()).visit(contextType);
    insert(key, theInfo);
    return *theInfo;
  }
  
  namespace {
    using PrimaryArchetypeMap
      = llvm::DenseMap<ArchetypeType *, std::pair<unsigned, unsigned>>;
  }
  
  static CanType
  mapArchetypeToInterfaceType(const PrimaryArchetypeMap &primaryArchetypes,
                              ArchetypeType *arch) {
    auto &C = arch->getASTContext();
  
    // If the archetype is primary, try to map it to a generic type parameter.
    if (arch->isPrimary()) {
      auto foundArchetype = primaryArchetypes.find(arch);
      if (foundArchetype == primaryArchetypes.end()) return CanType(arch);
  
      return CanGenericTypeParamType::get(foundArchetype->second.first,
                                          foundArchetype->second.second, C);
    }
    
    // Otherwise, map it to a dependent member type of the parent archetype.
    assert(arch->getAssocType());
    auto base = mapArchetypeToInterfaceType(primaryArchetypes, arch->getParent());
    if (base->isTypeParameter())
      return CanDependentMemberType::get(base, arch->getAssocType(), C);
    assert(base == CanType(arch->getParent())
           && "substituted to non-dependent type?!");
    return CanType(arch);
  }
  
  /// Map a contextual type out of its context into a dependent generic type.
  CanType
  TypeConverter::getInterfaceTypeOutOfContext(CanType contextTy,
                                           DeclContext *context) const {
    GenericParamList *genericParams;
    do {
      genericParams = context->getGenericParamsOfContext();
      context = context->getParent();
    } while (!genericParams && context);
      
    return getInterfaceTypeOutOfContext(contextTy, genericParams);
  }
  
  CanType
  TypeConverter::getInterfaceTypeOutOfContext(CanType contextTy,
                                          GenericParamList *contextParams) const {
    // If the context is non-generic, we're done.
    if (!contextParams)
      return contextTy;
  
    // Collect the depths and indices of the primary archetypes of our generic
    // context.
    llvm::DenseMap<ArchetypeType *, std::pair<unsigned, unsigned>>
      primaryArchetypes;
    unsigned depth = contextParams->getDepth();
    do {
      for (unsigned index : indices(contextParams->getParams())) {
        ArchetypeType *archetype  = contextParams->getPrimaryArchetypes()[index];
        primaryArchetypes[archetype] = {depth, index};
      }
      contextParams = contextParams->getOuterParameters();
    } while (depth-- > 0);
  
    // Substitute archetypes from the context with dependent types.
    return contextTy.transform([&](Type t) -> Type {
      CanType ct(t);
      ArchetypeType *arch = dyn_cast<ArchetypeType>(ct);
      if (!arch) return t;
      return mapArchetypeToInterfaceType(primaryArchetypes, arch);
    })->getCanonicalType();
  }
  
  /// Get the type of a global variable accessor function, () -> RawPointer.
  static CanAnyFunctionType getGlobalAccessorType(CanType varType) {
    ASTContext &C = varType->getASTContext();
    return CanFunctionType::get(TupleType::getEmpty(C), C.TheRawPointerType);
  }
  
  /// Get the type of a global variable getter function.
  static CanAnyFunctionType getGlobalGetterType(CanType varType) {
    ASTContext &C = varType->getASTContext();
    return CanFunctionType::get(TupleType::getEmpty(C), varType);
  }
  
  /// Get the type of a default argument generator, () -> T.
  static CanAnyFunctionType getDefaultArgGeneratorType(TypeConverter &TC,
                                                       AbstractFunctionDecl *AFD,
                                                       unsigned DefaultArgIndex,
                                                       ASTContext &context) {
    auto resultTy = AFD->getDefaultArg(DefaultArgIndex).second->getCanonicalType();
    assert(resultTy && "Didn't find default argument?");
    
    // Get the generic parameters from the surrounding context.
    auto genericParams
      = TC.getConstantInfo(SILDeclRef(AFD))
          .ContextGenericParams;
    
    if (genericParams)
      return CanPolymorphicFunctionType::get(TupleType::getEmpty(context),
                                             resultTy,
                                             genericParams,
                                             AnyFunctionType::ExtInfo());
  
    return CanFunctionType::get(TupleType::getEmpty(context), resultTy);
  }
  
  /// Get the type of a default argument generator, () -> T.
  static CanAnyFunctionType getDefaultArgGeneratorInterfaceType(
                                                       TypeConverter &TC,
                                                       AbstractFunctionDecl *AFD,
                                                       unsigned DefaultArgIndex,
                                                       ASTContext &context) {
    auto resultTy = AFD->getDefaultArg(DefaultArgIndex).second->getCanonicalType();
    assert(resultTy && "Didn't find default argument?");
    
    // Get the generic signature from the surrounding context.
    auto funcInfo = TC.getConstantInfo(SILDeclRef(AFD));
    CanGenericSignature sig;
    if (auto genTy = funcInfo.FormalInterfaceType->getAs<GenericFunctionType>()) {
      sig = genTy->getGenericSignature()->getCanonicalSignature();
      resultTy = TC.getInterfaceTypeOutOfContext(resultTy,
                                              funcInfo.ContextGenericParams);
    }
    
    if (sig)
      return CanGenericFunctionType::get(sig,
                                         TupleType::getEmpty(context),
                                         resultTy,
                                         AnyFunctionType::ExtInfo());
    
    return CanFunctionType::get(TupleType::getEmpty(context), resultTy);
  }
  
  /// Get the type of a destructor function.
  static CanAnyFunctionType getDestructorType(DestructorDecl *dd,
                                              bool isDeallocating,
                                              ASTContext &C,
                                              bool isForeign) {
    auto classType = dd->getDeclContext()->getDeclaredTypeInContext()
                       ->getCanonicalType();
    
  
    assert((!isForeign || isDeallocating)
           && "There are no foreign destroying destructors");
    AnyFunctionType::ExtInfo extInfo =
              AnyFunctionType::ExtInfo(FunctionTypeRepresentation::Thin,
                                       /*noreturn*/ false,
                                       /*throws*/ false);
    if (isForeign)
      extInfo = extInfo
        .withSILRepresentation(SILFunctionTypeRepresentation::ObjCMethod);
    else
      extInfo = extInfo
        .withSILRepresentation(SILFunctionTypeRepresentation::Method);
    
    CanType resultTy = isDeallocating? TupleType::getEmpty(C)->getCanonicalType()
                                     : C.TheNativeObjectType;
  
    if (auto params = dd->getDeclContext()->getGenericParamsOfContext())
      return CanPolymorphicFunctionType::get(classType, resultTy, params, extInfo);
  
    return CanFunctionType::get(classType, resultTy, extInfo);
  }
  
  /// Get the type of a destructor function.
  static CanAnyFunctionType getDestructorInterfaceType(DestructorDecl *dd,
                                              bool isDeallocating,
                                              ASTContext &C,
                                              bool isForeign) {
    auto classType = dd->getDeclContext()->getDeclaredInterfaceType()
                       ->getCanonicalType();
  
    assert((!isForeign || isDeallocating)
           && "There are no foreign destroying destructors");
    AnyFunctionType::ExtInfo extInfo =
              AnyFunctionType::ExtInfo(FunctionType::Representation::Thin,
                                       /*noreturn*/ false,
                                       /*throws*/ false);
    if (isForeign)
      extInfo = extInfo
        .withSILRepresentation(SILFunctionTypeRepresentation::ObjCMethod);
    else
      extInfo = extInfo
        .withSILRepresentation(SILFunctionTypeRepresentation::Method);
  
    CanType resultTy = isDeallocating? TupleType::getEmpty(C)->getCanonicalType()
                                     : C.TheNativeObjectType;
  
    auto sig = dd->getDeclContext()->getGenericSignatureOfContext();
    if (sig)
      return cast<GenericFunctionType>(
        GenericFunctionType::get(sig, classType, resultTy, extInfo)
        ->getCanonicalType());
    return CanFunctionType::get(classType, resultTy, extInfo);
  }
  
  /// Retrieve the type of the ivar initializer or destroyer method for
  /// a class.
  static CanAnyFunctionType getIVarInitDestroyerType(ClassDecl *cd, 
                                                     bool isObjC,
                                                     ASTContext &ctx,
                                                     bool isDestroyer) {
    auto classType = cd->getDeclaredTypeInContext()->getCanonicalType();
  
    auto emptyTupleTy = TupleType::getEmpty(ctx)->getCanonicalType();
    CanType resultType = isDestroyer? emptyTupleTy : classType;
    auto extInfo = AnyFunctionType::ExtInfo(FunctionType::Representation::Thin,
                                            /*noreturn*/ false,
                                            /*throws*/ false);
    extInfo = extInfo
      .withSILRepresentation(isObjC? SILFunctionTypeRepresentation::ObjCMethod
                                   : SILFunctionTypeRepresentation::Method);
    
    resultType = CanFunctionType::get(emptyTupleTy, resultType, extInfo);
    if (auto params = cd->getGenericParams())
      return CanPolymorphicFunctionType::get(classType, resultType, params, 
                                             extInfo);
    return CanFunctionType::get(classType, resultType, extInfo);
  }
  
  /// Retrieve the type of the ivar initializer or destroyer method for
  /// a class.
  static CanAnyFunctionType getIVarInitDestroyerInterfaceType(ClassDecl *cd,
                                                     bool isObjC,
                                                     ASTContext &ctx,
                                                     bool isDestroyer) {
    auto classType = cd->getDeclaredInterfaceType()->getCanonicalType();
  
    auto emptyTupleTy = TupleType::getEmpty(ctx)->getCanonicalType();
    CanType resultType = isDestroyer? emptyTupleTy : classType;
    auto extInfo = AnyFunctionType::ExtInfo(FunctionType::Representation::Thin,
                                            /*noreturn*/ false,
                                            /*throws*/ false);
    extInfo = extInfo
      .withSILRepresentation(isObjC? SILFunctionTypeRepresentation::ObjCMethod
                             : SILFunctionTypeRepresentation::Method);
  
    resultType = CanFunctionType::get(emptyTupleTy, resultType, extInfo);
    auto sig = cd->getGenericSignatureOfContext();
    if (sig)
      return CanGenericFunctionType::get(sig->getCanonicalSignature(),
                                         classType, resultType,
                                         extInfo);
    return CanFunctionType::get(classType, resultType, extInfo);
  }
  
  GenericParamList *
  TypeConverter::getEffectiveGenericParamsForContext(DeclContext *dc) {
  
    // FIXME: This is a clunky way of uncurrying nested type parameters from
    // a function context.
    if (auto func = dyn_cast<AbstractFunctionDecl>(dc)) {
      return getConstantInfo(SILDeclRef(func)).ContextGenericParams;
    }
  
    if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
      return getConstantInfo(SILDeclRef(closure)).ContextGenericParams;
    }
  
    return dc->getGenericParamsOfContext();
  }
  
  GenericParamList *
  TypeConverter::getEffectiveGenericParams(AnyFunctionRef fn,
                                           CaptureInfo captureInfo) {
    auto dc = fn.getAsDeclContext()->getParent();
  
    if (dc->isLocalContext() &&
        !captureInfo.hasGenericParamCaptures()) {
      return nullptr;
    }
  
    return getEffectiveGenericParamsForContext(dc);
  }
  
  CanGenericSignature
  TypeConverter::getEffectiveGenericSignature(AnyFunctionRef fn,
                                              CaptureInfo captureInfo) {
    auto dc = fn.getAsDeclContext();
  
    if (auto sig = dc->getGenericSignatureOfContext())
      return sig->getCanonicalSignature();
  
    dc = dc->getParent();
  
    if (dc->isLocalContext() &&
        !captureInfo.hasGenericParamCaptures()) {
      return nullptr;
    }
  
    // Find the innermost context that has a generic parameter list.
    // FIXME: This is wrong for generic local functions in generic contexts.
    // Their GenericParamList is not semantically a child of the context
    // GenericParamList because they "capture" their context's already-bound
    // archetypes.
    while (!dc->getGenericSignatureOfContext()) {
      dc = dc->getParent();
      if (!dc) return nullptr;
    }
    
    auto sig = dc->getGenericSignatureOfContext();
    if (!sig)
      return nullptr;
    return sig->getCanonicalSignature();
  }
  
  CanAnyFunctionType
  TypeConverter::getFunctionTypeWithCaptures(CanAnyFunctionType funcType,
                                             AnyFunctionRef theClosure) {
    // Get transitive closure of value captured by this function, and any
    // captured functions.
    auto captureInfo = getLoweredLocalCaptures(theClosure);
  
    // Capture generic parameters from the enclosing context if necessary.
    GenericParamList *genericParams =
        getEffectiveGenericParams(theClosure, captureInfo);
  
    // If we don't have any local captures (including function captures),
    // there's no context to apply.
    if (!theClosure.getCaptureInfo().hasLocalCaptures()) {
      if (!genericParams)
        return adjustFunctionType(funcType,
                                  FunctionType::Representation::Thin);
  
      auto extInfo = AnyFunctionType::ExtInfo(FunctionType::Representation::Thin,
                                              /*noreturn*/ false,
                                              funcType->throws());
      if (funcType->isNoEscape())
        extInfo = extInfo.withNoEscape();
  
      return CanPolymorphicFunctionType::get(funcType.getInput(),
                                             funcType.getResult(),
                                             genericParams, extInfo);
  
    }
  
    SmallVector<TupleTypeElt, 8> inputFields;
  
    for (auto capture : captureInfo.getCaptures()) {
      auto VD = capture.getDecl();
      // A capture of a 'var' or 'inout' variable is done with the underlying
      // object type.
      auto captureType =
        VD->getType()->getLValueOrInOutObjectType()->getCanonicalType();
  
      switch (getDeclCaptureKind(capture)) {
      case CaptureKind::None:
        break;
          
      case CaptureKind::StorageAddress:
        // No-escape stored decls are captured by their raw address.
        inputFields.push_back(TupleTypeElt(CanLValueType::get(captureType)));
        break;
  
      case CaptureKind::Constant:
        // Capture the value directly.
        inputFields.push_back(TupleTypeElt(captureType));
        break;
      case CaptureKind::Box: {
        // Capture the owning box.
        CanType boxTy = SILBoxType::get(captureType);
        inputFields.push_back(boxTy);
        break;
      }
      }
    }
    
    CanType capturedInputs =
      TupleType::get(inputFields, Context)->getCanonicalType();
  
    auto extInfo = AnyFunctionType::ExtInfo(FunctionType::Representation::Thin,
                                            /*noreturn*/ false,
                                            funcType->throws());
    if (funcType->isNoEscape())
      extInfo = extInfo.withNoEscape();
  
    if (genericParams)
      return CanPolymorphicFunctionType::get(capturedInputs, funcType,
                                             genericParams, extInfo);
    
    return CanFunctionType::get(capturedInputs, funcType, extInfo);
  }
  
  CanAnyFunctionType
  TypeConverter::getFunctionInterfaceTypeWithCaptures(CanAnyFunctionType funcType,
                                                      AnyFunctionRef theClosure) {
    // Get transitive closure of value captured by this function, and any
    // captured functions.
    auto captureInfo = getLoweredLocalCaptures(theClosure);
  
    // Capture generic parameters from the enclosing context if necessary.
    CanGenericSignature genericSig = getEffectiveGenericSignature(theClosure,
                                                                  captureInfo);
  
    // If we don't have any local captures (including function captures),
    // there's no context to apply.
    if (!theClosure.getCaptureInfo().hasLocalCaptures()) {
      if (!genericSig)
        return adjustFunctionType(funcType,
                                  FunctionType::Representation::Thin);
      
      auto extInfo = AnyFunctionType::ExtInfo(FunctionType::Representation::Thin,
                                              /*noreturn*/ false,
                                              funcType->throws());
  
      return CanGenericFunctionType::get(genericSig,
                                         funcType.getInput(),
                                         funcType.getResult(),
                                         extInfo);
    }
  
    SmallVector<TupleTypeElt, 8> inputFields;
  
    for (auto capture : captureInfo.getCaptures()) {
      // A capture of a 'var' or 'inout' variable is done with the underlying
      // object type.
      auto vd = capture.getDecl();
      auto captureType =
        vd->getType()->getLValueOrInOutObjectType()->getCanonicalType();
  
      switch (getDeclCaptureKind(capture)) {
      case CaptureKind::None:
        break;
          
      case CaptureKind::StorageAddress:
        // No-escape stored decls are captured by their raw address.
        // Unlike 'inout', captures are allowed to have well-typed, synchronized
        // aliasing references, so capture the raw lvalue type instead.
        inputFields.push_back(TupleTypeElt(CanLValueType::get(captureType)));
        break;
  
      case CaptureKind::Constant:
        // Capture the value directly.
        inputFields.push_back(TupleTypeElt(captureType));
        break;
      case CaptureKind::Box: {
        // Capture the owning box.
        CanType boxTy = SILBoxType::get(captureType);
        inputFields.push_back(boxTy);
        break;
      }
      }
    }
    
    CanType capturedInputs =
      TupleType::get(inputFields, Context)->getCanonicalType();
    
    // Map context archetypes out of the captures.
    capturedInputs =
        getInterfaceTypeOutOfContext(capturedInputs,
                                     theClosure.getAsDeclContext());
  
    auto extInfo = AnyFunctionType::ExtInfo(FunctionType::Representation::Thin,
                                            /*noreturn*/ false,
                                            funcType->throws());
  
    if (genericSig)
      return CanGenericFunctionType::get(genericSig,
                                         capturedInputs, funcType,
                                         extInfo);
    
    return CanFunctionType::get(capturedInputs, funcType, extInfo);
  }
  
  /// Replace any DynamicSelf types with their underlying Self type.
  static Type replaceDynamicSelfWithSelf(Type t) {
    return t.transform([](Type type) -> Type {
      if (auto dynamicSelf = type->getAs<DynamicSelfType>())
        return dynamicSelf->getSelfType();
      return type;
    });
  }
  
  /// Replace any DynamicSelf types with their underlying Self type.
  static CanType replaceDynamicSelfWithSelf(CanType t) {
    return replaceDynamicSelfWithSelf(Type(t))->getCanonicalType();
  }
  
  CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) {
    ValueDecl *vd = c.loc.dyn_cast<ValueDecl *>();
  
    switch (c.kind) {
    case SILDeclRef::Kind::Func: {
      if (auto *ACE = c.loc.dyn_cast<AbstractClosureExpr *>()) {
        // TODO: Substitute out archetypes from the enclosing context with generic
        // parameters.
        auto funcTy = cast<AnyFunctionType>(ACE->getType()->getCanonicalType());
        funcTy = cast<AnyFunctionType>(
                             getInterfaceTypeOutOfContext(funcTy, ACE->getParent()));
        return getFunctionInterfaceTypeWithCaptures(funcTy, ACE);
      }
  
      FuncDecl *func = cast<FuncDecl>(vd);
      auto funcTy = cast<AnyFunctionType>(
                                    func->getInterfaceType()->getCanonicalType());
      if (func->getParent() && func->getParent()->isLocalContext())
        funcTy = cast<AnyFunctionType>(
                           getInterfaceTypeOutOfContext(funcTy, func->getParent()));
      funcTy = cast<AnyFunctionType>(replaceDynamicSelfWithSelf(funcTy));
      return getFunctionInterfaceTypeWithCaptures(funcTy, func);
    }
  
    case SILDeclRef::Kind::Allocator:
    case SILDeclRef::Kind::EnumElement:
      return cast<AnyFunctionType>(vd->getInterfaceType()->getCanonicalType());
    
    case SILDeclRef::Kind::Initializer:
      return cast<AnyFunctionType>(cast<ConstructorDecl>(vd)
                             ->getInitializerInterfaceType()->getCanonicalType());
    
    case SILDeclRef::Kind::Destroyer:
    case SILDeclRef::Kind::Deallocator:
      return getDestructorInterfaceType(cast<DestructorDecl>(vd),
                               c.kind == SILDeclRef::Kind::Deallocator,
                               Context,
                               c.isForeign);
    
    case SILDeclRef::Kind::GlobalAccessor: {
      VarDecl *var = cast<VarDecl>(vd);
      assert(var->hasStorage() &&
             "constant ref to computed global var");
      return getGlobalAccessorType(var->getInterfaceType()->getCanonicalType());
    }
    case SILDeclRef::Kind::GlobalGetter: {
      VarDecl *var = cast<VarDecl>(vd);
      assert(var->hasStorage() &&
             "constant ref to computed global var");
      return getGlobalGetterType(var->getInterfaceType()->getCanonicalType());
    }
    case SILDeclRef::Kind::DefaultArgGenerator:
      return getDefaultArgGeneratorInterfaceType(*this,
                                        cast<AbstractFunctionDecl>(vd),
                                        c.defaultArgIndex, Context);
    case SILDeclRef::Kind::IVarInitializer:
      return getIVarInitDestroyerInterfaceType(cast<ClassDecl>(vd),
                                               c.isForeign, Context, false);
    case SILDeclRef::Kind::IVarDestroyer:
      return getIVarInitDestroyerInterfaceType(cast<ClassDecl>(vd),
                                               c.isForeign, Context, true);
    }
  }
  
  /// Get the context generic parameters for an entity.
  std::pair<GenericParamList *, GenericParamList *>
  TypeConverter::getConstantContextGenericParams(SILDeclRef c) {
    ValueDecl *vd = c.loc.dyn_cast<ValueDecl *>();
    
    /// Get the function generic params, including outer params.
    switch (c.kind) {
    case SILDeclRef::Kind::Func: {
      if (auto *ACE = c.getAbstractClosureExpr()) {
        auto captureInfo = getLoweredLocalCaptures(ACE);
  
        // Closures are currently never natively generic.
        return {getEffectiveGenericParams(ACE, captureInfo), nullptr};
      }
      FuncDecl *func = cast<FuncDecl>(vd);
      // FIXME: For local generic functions we need to chain the local generic
      // context to the outer context.
      if (auto GP = func->getGenericParamsOfContext())
        return {GP, func->getGenericParams()};
      auto captureInfo = getLoweredLocalCaptures(func);
      return {getEffectiveGenericParams(func, captureInfo),
              func->getGenericParams()};
    }
    case SILDeclRef::Kind::EnumElement: {
      auto eltDecl = cast<EnumElementDecl>(vd);
      return {
        eltDecl->getDeclContext()->getGenericParamsOfContext(),
        nullptr
      };
    }
    case SILDeclRef::Kind::Allocator:
    case SILDeclRef::Kind::Initializer:
    case SILDeclRef::Kind::Destroyer:
    case SILDeclRef::Kind::Deallocator: {
      auto *afd = cast<AbstractFunctionDecl>(vd);
      return {afd->getGenericParamsOfContext(), afd->getGenericParams()};
    }
    case SILDeclRef::Kind::GlobalAccessor:
    case SILDeclRef::Kind::GlobalGetter: {
      return {
        cast<VarDecl>(vd)->getDeclContext()->getGenericParamsOfContext(),
        nullptr,
      };
    }
    case SILDeclRef::Kind::IVarInitializer:
    case SILDeclRef::Kind::IVarDestroyer:
      return {cast<ClassDecl>(vd)->getGenericParamsOfContext(), nullptr};
    case SILDeclRef::Kind::DefaultArgGenerator:
      // Use the context generic parameters of the original declaration.
      return getConstantContextGenericParams(SILDeclRef(c.getDecl()));
    }
  }
  
  CanAnyFunctionType TypeConverter::makeConstantType(SILDeclRef c) {
    ValueDecl *vd = c.loc.dyn_cast<ValueDecl *>();
  
    switch (c.kind) {
    case SILDeclRef::Kind::Func: {
      if (auto *ACE = c.loc.dyn_cast<AbstractClosureExpr *>()) {
        auto funcTy = cast<AnyFunctionType>(ACE->getType()->getCanonicalType());
        return getFunctionTypeWithCaptures(funcTy, ACE);
      }
  
      FuncDecl *func = cast<FuncDecl>(vd);
      auto funcTy = cast<AnyFunctionType>(func->getType()->getCanonicalType());
      funcTy = cast<AnyFunctionType>(replaceDynamicSelfWithSelf(funcTy));
      return getFunctionTypeWithCaptures(funcTy, func);
    }
  
    case SILDeclRef::Kind::Allocator:
    case SILDeclRef::Kind::EnumElement:
      return cast<AnyFunctionType>(vd->getType()->getCanonicalType());
    
    case SILDeclRef::Kind::Initializer:
      return cast<AnyFunctionType>(cast<ConstructorDecl>(vd)
                                     ->getInitializerType()->getCanonicalType());
    
    case SILDeclRef::Kind::Destroyer:
    case SILDeclRef::Kind::Deallocator:
      return getDestructorType(cast<DestructorDecl>(vd), 
                               c.kind == SILDeclRef::Kind::Deallocator,
                               Context,
                               c.isForeign);
    
    case SILDeclRef::Kind::GlobalAccessor: {
      VarDecl *var = cast<VarDecl>(vd);
      assert(var->hasStorage() && "constant ref to computed global var");
      return getGlobalAccessorType(var->getType()->getCanonicalType());
    }
    case SILDeclRef::Kind::GlobalGetter: {
      VarDecl *var = cast<VarDecl>(vd);
      assert(var->hasStorage() && "constant ref to computed global var");
      return getGlobalGetterType(var->getType()->getCanonicalType());
    }
    case SILDeclRef::Kind::DefaultArgGenerator:
      return getDefaultArgGeneratorType(*this,
                                        cast<AbstractFunctionDecl>(vd),
                                        c.defaultArgIndex, Context);
    case SILDeclRef::Kind::IVarInitializer:
        return getIVarInitDestroyerType(cast<ClassDecl>(vd), c.isForeign,
                                        Context, false);
    case SILDeclRef::Kind::IVarDestroyer:
      return getIVarInitDestroyerType(cast<ClassDecl>(vd), c.isForeign,
                                      Context, true);
    }
  }
  
  SILType TypeConverter::getSubstitutedStorageType(AbstractStorageDecl *value,
                                                   Type lvalueType) {
    // The l-value type is the result of applying substitutions to
    // the type-of-reference.  Essentially, we want to apply those
    // same substitutions to value->getType().
  
    // Canonicalize and lower the l-value's object type.
    AbstractionPattern origType = getAbstractionPattern(value);
    CanType substType = lvalueType->getCanonicalType();
  
    // Remove a layer of l-value type if present.
    if (auto substLVType = dyn_cast<LValueType>(substType))
      substType = substLVType.getObjectType();
  
    SILType silSubstType = getLoweredType(origType, substType).getAddressType();
    substType = silSubstType.getSwiftRValueType();
  
    // Fast path: if the unsubstituted type from the variable equals the
    // substituted type from the l-value, there's nothing to do.
    if (origType.isExactType(substType))
      return silSubstType;
  
    // Type substitution preserves structural type structure, and the
    // type-of-reference is only different in the outermost structural
    // types.  So, basically, we just need to undo the changes made by
    // getTypeOfReference and then reapply them on the substituted type.
  
    // The only really significant manipulation there is with @weak and
    // @unowned.
    if (auto refType = origType.getAs<ReferenceStorageType>()) {
      substType = CanType(ReferenceStorageType::get(substType,
                                                    refType->getOwnership(),
                                                    Context));
      return SILType::getPrimitiveType(substType, SILValueCategory::Address);
    }
  
    return silSubstType;
  }
  
  void TypeConverter::pushGenericContext(CanGenericSignature sig) {
    // If the generic signature is empty, this is a no-op.
    if (!sig)
      return;
    
    // GenericFunctionTypes shouldn't nest.
    assert(!GenericArchetypes.hasValue() && "already in generic context?!");
    assert(DependentTypes.empty() && "already in generic context?!");
    assert(!CurGenericContext && "already in generic context!");
  
    CurGenericContext = sig;
    
    // Prepare the ArchetypeBuilder with the generic signature.
    GenericArchetypes.emplace(*M.getSwiftModule(), M.getASTContext().Diags);
    if (GenericArchetypes->addGenericSignature(sig, false))
      llvm_unreachable("error adding generic signature to archetype builder?!");
  }
  
  void TypeConverter::popGenericContext(CanGenericSignature sig) {
    // If the generic signature is empty, this is a no-op.
    if (!sig)
      return;
  
    assert(GenericArchetypes.hasValue() && "not in generic context?!");
    assert(CurGenericContext == sig && "unpaired push/pop");
    
    // Erase our cached TypeLowering objects and associated mappings for dependent
    // types.
    // Resetting the DependentBPA will deallocate but not run the destructor of
    // the dependent TypeLowerings.
    for (auto &ti : DependentTypes) {
      // Destroy only the unique entries.
      CanType srcType = ti.first.OrigType;
      if (!srcType) continue;
      CanType mappedType = ti.second->getLoweredType().getSwiftRValueType();
      if (srcType == mappedType || isa<LValueType>(srcType))
        ti.second->~TypeLowering();
    }
    DependentTypes.clear();
    DependentBPA.Reset();
    GenericArchetypes.reset();
    CurGenericContext = nullptr;
  }
  
  ProtocolDispatchStrategy
  TypeConverter::getProtocolDispatchStrategy(ProtocolDecl *P) {
    // AnyObject has no requirements (other than the object being a class), so
    // needs no method dispatch.
    if (auto known = P->getKnownProtocolKind()) {
      if (*known == KnownProtocolKind::AnyObject)
        return ProtocolDispatchStrategy::Empty;
    }
    
    // Otherwise, ObjC protocols use ObjC method dispatch, and Swift protocols
    // use witness tables.
    
    if (P->isObjC())
      return ProtocolDispatchStrategy::ObjC;
    
    return ProtocolDispatchStrategy::Swift;
  }
  
  /// If a capture references a local function, return a reference to that
  /// function.
  static Optional<AnyFunctionRef>
  getAnyFunctionRefFromCapture(CapturedValue capture) {
    if (auto *afd = dyn_cast<AbstractFunctionDecl>(capture.getDecl()))
      return AnyFunctionRef(afd);
    return None;
  }
  
  CaptureInfo
  TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) {
    // First, bail out if there are no local captures at all.
    if (!fn.getCaptureInfo().hasLocalCaptures()) {
      CaptureInfo info;
      info.setGenericParamCaptures(
          fn.getCaptureInfo().hasGenericParamCaptures());
      return info;
    };
    
    // See if we've cached the lowered capture list for this function.
    auto found = LoweredCaptures.find(fn);
    if (found != LoweredCaptures.end())
      return found->second;
    
    // Recursively collect transitive captures from captured local functions.
    llvm::DenseSet<AnyFunctionRef> visitedFunctions;
    llvm::SetVector<CapturedValue> captures;
    bool capturesGenericParams = false;
    
    std::function<void (AnyFunctionRef)> collectFunctionCaptures
    = [&](AnyFunctionRef curFn) {
      if (!visitedFunctions.insert(curFn).second)
        return;
    
      if (curFn.getCaptureInfo().hasGenericParamCaptures())
        capturesGenericParams = true;
  
      SmallVector<CapturedValue, 4> localCaptures;
      curFn.getCaptureInfo().getLocalCaptures(localCaptures);
      for (auto capture : localCaptures) {
        // If the capture is of another local function, grab its transitive
        // captures instead.
        if (auto capturedFn = getAnyFunctionRefFromCapture(capture)) {
          collectFunctionCaptures(*capturedFn);
          continue;
        }
        
        // If the capture is of a computed property, grab the transitive captures
        // of its accessors.
        if (auto capturedVar = dyn_cast<VarDecl>(capture.getDecl())) {
          switch (capturedVar->getStorageKind()) {
          case VarDecl::StoredWithTrivialAccessors:
            llvm_unreachable("stored local variable with trivial accessors?");
  
          case VarDecl::InheritedWithObservers:
            llvm_unreachable("inherited local variable?");
  
          case VarDecl::StoredWithObservers:
          case VarDecl::Addressed:
          case VarDecl::AddressedWithTrivialAccessors:
          case VarDecl::AddressedWithObservers:
          case VarDecl::ComputedWithMutableAddress:
            // Directly capture storage if we're supposed to.
            if (capture.isDirect())
              goto capture_value;
              
            // Otherwise, transitively capture the accessors.
            SWIFT_FALLTHROUGH;
            
          case VarDecl::Computed: {
            collectFunctionCaptures(capturedVar->getGetter());
            if (auto setter = capturedVar->getSetter())
              collectFunctionCaptures(setter);
            continue;
          }
  
          case VarDecl::Stored:
            // We can always capture the storage in these cases.
            goto capture_value;
          }
        }
        
      capture_value:
        // Collect non-function captures.
        captures.insert(capture);
      }
    };
    collectFunctionCaptures(fn);
    
    // Cache the uniqued set of transitive captures.
    auto inserted = LoweredCaptures.insert({fn, CaptureInfo()});
    assert(inserted.second && "already in map?!");
    auto &cachedCaptures = inserted.first->second;
    cachedCaptures.setGenericParamCaptures(capturesGenericParams);
    cachedCaptures.setCaptures(Context.AllocateCopy(captures));
    
    return cachedCaptures;
  }
  
  /// Given that type1 is known to be a subtype of type2, check if the two
  /// types have the same calling convention representation.
  TypeConverter::ABIDifference
  TypeConverter::checkForABIDifferences(CanType type1, CanType type2) {
    assert(!isa<AnyFunctionType>(type1) && !isa<AnyFunctionType>(type2) &&
           "cannot compare unlowered types for ABI compatibility");
  
    // Unwrap optionals, but remember that we did.
    OptionalTypeKind OTK1, OTK2;
  
    {
      // Get the lowered optional payload types.
      AbstractionPattern opaque = AbstractionPattern::getOpaque();
  
      CanType object1 = type1.getAnyOptionalObjectType(OTK1);
      if (OTK1 != OTK_None)
        type1 = getLoweredType(opaque, object1).getSwiftRValueType();
  
      CanType object2 = type2.getAnyOptionalObjectType(OTK2);
      if (OTK2 != OTK_None)
        type2 = getLoweredType(opaque, object2).getSwiftRValueType();
    }
    
    // Forcing IUOs always requires a thunk.
    if (OTK1 == OTK_ImplicitlyUnwrappedOptional && OTK2 == OTK_None)
      return ABIDifference::NeedsThunk;
    
    // Except for the above case, we should not be making a value less optional.
    assert(OTK1 == OTK_None || OTK2 != OTK_None);
    
    // If we're introducing a level of optionality, only certain types are
    // ABI-compatible -- check below.
    bool optionalityChange = (OTK1 == OTK_None && OTK2 != OTK_None);
  
    // If the types are identical and there was no optionality change,
    // we're done.
    if (type1 == type2 && !optionalityChange)
      return ABIDifference::Trivial;
    
    // Classes, class-constrained archetypes, and pure-ObjC existential types
    // all have single retainable pointer representation; optionality change
    // is allowed.
    if ((type1->mayHaveSuperclass() || type1->isObjCExistentialType()) &&
        (type2->mayHaveSuperclass() || type2->isObjCExistentialType()))
      return ABIDifference::Trivial;
  
    // Function parameters are ABI compatible if their differences are
    // trivial.
    if (auto fnTy1 = dyn_cast<SILFunctionType>(type1)) {
      if (auto fnTy2 = dyn_cast<SILFunctionType>(type2)) {
        // @convention(block) is a single retainable pointer so optionality
        // change is allowed.
        if (optionalityChange)
          if (fnTy1->getRepresentation() != fnTy2->getRepresentation() ||
              fnTy1->getRepresentation() != SILFunctionTypeRepresentation::Block)
            return ABIDifference::NeedsThunk;
  
        return checkFunctionForABIDifferences(fnTy1, fnTy2);
      }
    }
    
    // Metatypes are ABI-compatible if they have the same representation.
    if (auto meta1 = dyn_cast<MetatypeType>(type1)) {
      if (auto meta2 = dyn_cast<MetatypeType>(type2)) {
        if (meta1->getRepresentation() == meta2->getRepresentation() &&
            (!optionalityChange ||
             meta1->getRepresentation() == MetatypeRepresentation::Thick))
          return ABIDifference::Trivial;
      }
    }
    
    // Existential metatypes which are not identical are only ABI-compatible
    // in @objc representation.
    //
    // Optionality change is allowed since @objc existential metatypes have a
    // single retainable pointer representation.
    if (auto meta1 = dyn_cast<ExistentialMetatypeType>(type1)) {
      if (auto meta2 = dyn_cast<ExistentialMetatypeType>(type2)) {
        if (meta1->getRepresentation() == meta2->getRepresentation() &&
            meta1->getRepresentation() == MetatypeRepresentation::ObjC)
          return ABIDifference::Trivial;
      }
    }
  
    // Tuple types are ABI-compatible if their elements are.
    if (!optionalityChange) {
      if (auto tuple1 = dyn_cast<TupleType>(type1)) {
        if (auto tuple2 = dyn_cast<TupleType>(type2)) {
          if (tuple1->getNumElements() != tuple2->getNumElements())
            return ABIDifference::NeedsThunk;
          
          for (unsigned i = 0, e = tuple1->getNumElements(); i < e; i++) {
            if (checkForABIDifferences(tuple1.getElementType(i),
                                       tuple2.getElementType(i))
                  != ABIDifference::Trivial)
              return ABIDifference::NeedsThunk;
          }
  
          // Tuple lengths and elements match
          return ABIDifference::Trivial;
        }
      }
    }
  
    // The types are different, or there was an optionality change resulting
    // in a change in representation.
    return ABIDifference::NeedsThunk;
  }
  
  TypeConverter::ABIDifference
  TypeConverter::checkFunctionForABIDifferences(SILFunctionType *fnTy1,
                                                SILFunctionType *fnTy2) {
    // Fast path -- if both functions were unwrapped from a CanSILFunctionType,
    // we might have pointer equality here.
    if (fnTy1 == fnTy2)
      return ABIDifference::Trivial;
  
    if (fnTy1->getParameters().size() != fnTy2->getParameters().size())
      return ABIDifference::NeedsThunk;
  
    if (fnTy1->hasIndirectResult() != fnTy2->hasIndirectResult())
      return ABIDifference::NeedsThunk;
  
    // If we don't have a context but the other type does, we'll return
    // ABIDifference::ThinToThick below.
    if (fnTy1->getExtInfo().hasContext() &&
        fnTy1->getCalleeConvention() != fnTy2->getCalleeConvention())
      return ABIDifference::NeedsThunk;
  
    auto result1 = fnTy1->getResult(), result2 = fnTy2->getResult();
    
    if (result1.getConvention() != result2.getConvention())
      return ABIDifference::NeedsThunk;
  
    if (checkForABIDifferences(result1.getType(), result2.getType())
          != ABIDifference::Trivial)
      return ABIDifference::NeedsThunk;
  
    // If one type does not have an error result, we can still trivially cast
    // (casting away an error result is only safe if the function never throws,
    // of course).
    if (fnTy1->hasErrorResult() && fnTy2->hasErrorResult()) {
      auto error1 = fnTy1->getErrorResult(), error2 = fnTy2->getErrorResult();
  
      if (error1.getConvention() != error2.getConvention())
        return ABIDifference::NeedsThunk;
  
      if (checkForABIDifferences(error1.getType(), error2.getType())
            != ABIDifference::Trivial)
        return ABIDifference::NeedsThunk;
    }
  
    for (unsigned i = 0, e = fnTy1->getParameters().size(); i < e; ++i) {
      auto param1 = fnTy1->getParameters()[i], param2 = fnTy2->getParameters()[i];
      
      if (param1.getConvention() != param2.getConvention())
        return ABIDifference::NeedsThunk;
  
      // Parameters are contravariant and our relation is not symmetric, so
      // make sure to flip the relation around.
      if (!param1.isIndirectResult())
        std::swap(param1, param2);
  
      if (checkForABIDifferences(param1.getType(), param2.getType())
            != ABIDifference::Trivial)
        return ABIDifference::NeedsThunk;
    }
  
    auto rep1 = fnTy1->getRepresentation(), rep2 = fnTy2->getRepresentation();
    if (rep1 != rep2) {
      if (rep1 == SILFunctionTypeRepresentation::Thin &&
          rep2 == SILFunctionTypeRepresentation::Thick)
        return ABIDifference::ThinToThick;
  
      return ABIDifference::NeedsThunk;
    }
  
    return ABIDifference::Trivial;
  }
  