text: //===--- ExtInfo.h - Extended information for function types ----*- C++ -*-===//
  //
  // This source file is part of the Swift.org open source project
  //
  // Copyright (c) 2020 Apple Inc. and the Swift project authors
  // Licensed under Apache License v2.0 with Runtime Library Exception
  //
  // See https://swift.org/LICENSE.txt for license information
  // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
  //
  //===----------------------------------------------------------------------===//
  //
  // Defines the ASTExtInfo and SILExtInfo classes, which are used to store
  // the calling convention and related information for function types in the AST
  // and SIL respectively. These types are lightweight and immutable; they are
  // constructed using builder-pattern style APIs to enforce invariants.
  //
  //===----------------------------------------------------------------------===//
  
  #ifndef SWIFT_EXTINFO_H
  #define SWIFT_EXTINFO_H
  
  #include "swift/AST/AutoDiff.h"
  #include "swift/AST/ClangModuleLoader.h"
  
  #include "llvm/ADT/Optional.h"
  #include "llvm/Support/raw_ostream.h"
  
  #include <utility>
  
  namespace clang {
  class Type;
  class ASTContext;
  } // namespace clang
  
  namespace swift {
  class AnyFunctionType;
  class ASTExtInfo;
  class ASTExtInfoBuilder;
  class FunctionType;
  class SILExtInfo;
  class SILExtInfoBuilder;
  class SILFunctionType;
  enum class SILFunctionTypeRepresentation : uint8_t;
  } // namespace swift
  
  namespace swift {
  
  // MARK: - ClangTypeInfo
  /// Wrapper class for storing a clang::Type in an (AST|SIL)ExtInfo.
  class ClangTypeInfo {
    friend AnyFunctionType;
    friend FunctionType;
    friend SILFunctionType;
    friend ASTExtInfoBuilder;
    friend SILExtInfoBuilder;
  
    // [NOTE: ClangTypeInfo-contents]
    // We preserve a full clang::Type *, not a clang::FunctionType * as:
    // 1. We need to keep sugar in case we need to present an error to the user
    //    (for AnyFunctionType).
    // 2. The actual type being stored is [ignoring sugar] either a
    //    clang::PointerType, a clang::BlockPointerType, or a
    //    clang::ReferenceType which points to a clang::FunctionType.
    //
    // When used as a part of SILFunctionType, the type is canonical.
    const clang::Type *type;
  
    constexpr ClangTypeInfo() : type(nullptr) {}
    constexpr ClangTypeInfo(const clang::Type *type) : type(type) {}
  
    friend bool operator==(ClangTypeInfo lhs, ClangTypeInfo rhs);
    friend bool operator!=(ClangTypeInfo lhs, ClangTypeInfo rhs);
    ClangTypeInfo getCanonical() const;
  
  public:
    constexpr const clang::Type *getType() const { return type; }
  
    constexpr bool empty() const { return !type; }
  
    /// Use the ClangModuleLoader to print the Clang type as a string.
    void printType(ClangModuleLoader *cml, llvm::raw_ostream &os) const;
  
    void dump(llvm::raw_ostream &os, const clang::ASTContext &ctx) const;
  };
  
  // MARK: - UnexpectedClangTypeError
  /// Potential errors when trying to store a Clang type in an ExtInfo.
  struct UnexpectedClangTypeError {
    enum class Kind {
      NullForCOrBlock,
      NonnullForNonCOrBlock,
      NotBlockPointer,
      NotFunctionPointerOrReference,
      NonCanonical,
    };
    const Kind errorKind;
    const clang::Type *type;
  
    static Optional<UnexpectedClangTypeError> checkClangType(
      SILFunctionTypeRepresentation fnRep, const clang::Type *type,
      bool expectNonnullForCOrBlock, bool expectCanonical);
  
    void dump();
  };
  
  // MARK: - FunctionTypeRepresentation
  /// The representation form of a function.
  enum class FunctionTypeRepresentation : uint8_t {
    /// A "thick" function that carries a context pointer to reference captured
    /// state. The default native function representation.
    Swift = 0,
  
    /// A thick function that is represented as an Objective-C block.
    Block,
  
    /// A "thin" function that needs no context.
    Thin,
  
    /// A C function pointer (or reference), which is thin and also uses the C
    /// calling convention.
    CFunctionPointer,
  
    /// The value of the greatest AST function representation.
    Last = CFunctionPointer,
  };
  
  // MARK: - SILFunctionTypeRepresentation
  
  /// The representation form of a SIL function.
  ///
  /// This is a superset of FunctionTypeRepresentation. The common representations
  /// must share an enum value.
  ///
  /// TODO: The overlap of SILFunctionTypeRepresentation and
  /// FunctionTypeRepresentation is a total hack necessitated by the way SIL
  /// TypeLowering is currently written. We ought to refactor TypeLowering so that
  /// it is not necessary to distinguish these cases.
  enum class SILFunctionTypeRepresentation : uint8_t {
    /// A freestanding thick function.
    Thick = uint8_t(FunctionTypeRepresentation::Swift),
  
    /// A thick function that is represented as an Objective-C block.
    Block = uint8_t(FunctionTypeRepresentation::Block),
  
    /// A freestanding thin function that needs no context.
    Thin = uint8_t(FunctionTypeRepresentation::Thin),
  
    /// A C function pointer, which is thin and also uses the C calling
    /// convention.
    CFunctionPointer = uint8_t(FunctionTypeRepresentation::CFunctionPointer),
  
    /// The value of the greatest AST function representation.
    LastAST = CFunctionPointer,
  
    /// The value of the least SIL-only function representation.
    FirstSIL = 8,
  
    /// A Swift instance method.
    Method = FirstSIL,
  
    /// An Objective-C method.
    ObjCMethod,
  
    /// A Swift protocol witness.
    WitnessMethod,
  
    /// A closure invocation function that has not been bound to a context.
    Closure,
  };
  
  constexpr SILFunctionTypeRepresentation
  convertRepresentation(FunctionTypeRepresentation rep) {
    switch (rep) {
    case FunctionTypeRepresentation::Swift:
      return SILFunctionTypeRepresentation::Thick;
    case FunctionTypeRepresentation::Block:
      return SILFunctionTypeRepresentation::Block;
    case FunctionTypeRepresentation::Thin:
      return SILFunctionTypeRepresentation::Thin;
    case FunctionTypeRepresentation::CFunctionPointer:
      return SILFunctionTypeRepresentation::CFunctionPointer;
    }
    llvm_unreachable("Unhandled FunctionTypeRepresentation!");
  };
  
  inline Optional<FunctionTypeRepresentation>
  convertRepresentation(SILFunctionTypeRepresentation rep) {
    switch (rep) {
    case SILFunctionTypeRepresentation::Thick:
      return {FunctionTypeRepresentation::Swift};
    case SILFunctionTypeRepresentation::Block:
      return {FunctionTypeRepresentation::Block};
    case SILFunctionTypeRepresentation::Thin:
      return {FunctionTypeRepresentation::Thin};
    case SILFunctionTypeRepresentation::CFunctionPointer:
      return {FunctionTypeRepresentation::CFunctionPointer};
    case SILFunctionTypeRepresentation::Method:
    case SILFunctionTypeRepresentation::ObjCMethod:
    case SILFunctionTypeRepresentation::WitnessMethod:
    case SILFunctionTypeRepresentation::Closure:
      return None;
    }
    llvm_unreachable("Unhandled SILFunctionTypeRepresentation!");
  };
  
  /// Can this calling convention result in a function being called indirectly
  /// through the runtime.
  constexpr bool canBeCalledIndirectly(SILFunctionTypeRepresentation rep) {
    switch (rep) {
    case SILFunctionTypeRepresentation::Thick:
    case SILFunctionTypeRepresentation::Thin:
    case SILFunctionTypeRepresentation::CFunctionPointer:
    case SILFunctionTypeRepresentation::Block:
    case SILFunctionTypeRepresentation::Closure:
      return false;
    case SILFunctionTypeRepresentation::ObjCMethod:
    case SILFunctionTypeRepresentation::Method:
    case SILFunctionTypeRepresentation::WitnessMethod:
      return true;
    }
  
    llvm_unreachable("Unhandled SILFunctionTypeRepresentation in switch.");
  }
  
  template <typename Repr> constexpr bool shouldStoreClangType(Repr repr) {
    static_assert(std::is_same<Repr, FunctionTypeRepresentation>::value ||
                      std::is_same<Repr, SILFunctionTypeRepresentation>::value,
                  "Expected a Representation type as the argument type.");
    switch (static_cast<SILFunctionTypeRepresentation>(repr)) {
    case SILFunctionTypeRepresentation::CFunctionPointer:
    case SILFunctionTypeRepresentation::Block:
      return true;
    case SILFunctionTypeRepresentation::ObjCMethod:
    case SILFunctionTypeRepresentation::Thick:
    case SILFunctionTypeRepresentation::Thin:
    case SILFunctionTypeRepresentation::Method:
    case SILFunctionTypeRepresentation::WitnessMethod:
    case SILFunctionTypeRepresentation::Closure:
      return false;
    }
    llvm_unreachable("Unhandled SILFunctionTypeRepresentation.");
  }
  
  // MARK: - ASTExtInfoBuilder
  /// A builder type for creating an \c ASTExtInfo.
  ///
  /// The main API public includes the \c withXYZ and \p build() methods.
  class ASTExtInfoBuilder {
    friend AnyFunctionType;
    friend ASTExtInfo;
  
    // If bits are added or removed, then TypeBase::AnyFunctionTypeBits
    // and NumMaskBits must be updated, and they must match.
    //
    //   |representation|noEscape|async|throws|differentiability|
    //   |    0 .. 3    |    4   |  5  |   6  |      7 .. 8     |
    //
    enum : unsigned {
      RepresentationMask = 0xF << 0,
      NoEscapeMask = 1 << 4,
      AsyncMask = 1 << 5,
      ThrowsMask = 1 << 6,
      DifferentiabilityMaskOffset = 7,
      DifferentiabilityMask = 0x3 << DifferentiabilityMaskOffset,
      NumMaskBits = 9
    };
  
    unsigned bits; // Naturally sized for speed.
  
    ClangTypeInfo clangTypeInfo;
  
    using Representation = FunctionTypeRepresentation;
  
    ASTExtInfoBuilder(unsigned bits, ClangTypeInfo clangTypeInfo)
        : bits(bits), clangTypeInfo(clangTypeInfo) {}
  
  public:
    /// An ExtInfoBuilder for a typical Swift function: @convention(swift),
    /// @escaping, non-throwing, non-differentiable.
    ASTExtInfoBuilder()
        : ASTExtInfoBuilder(Representation::Swift, false, false,
                            DifferentiabilityKind::NonDifferentiable, nullptr) {}
  
    // Constructor for polymorphic type.
    ASTExtInfoBuilder(Representation rep, bool throws)
        : ASTExtInfoBuilder(rep, false, throws,
                            DifferentiabilityKind::NonDifferentiable, nullptr) {}
  
    // Constructor with no defaults.
    ASTExtInfoBuilder(Representation rep, bool isNoEscape, bool throws,
                      DifferentiabilityKind diffKind, const clang::Type *type)
        : ASTExtInfoBuilder(
              ((unsigned)rep) | (isNoEscape ? NoEscapeMask : 0) |
                  (throws ? ThrowsMask : 0) |
                  (((unsigned)diffKind << DifferentiabilityMaskOffset) &
                   DifferentiabilityMask),
              ClangTypeInfo(type)) {}
  
    void checkInvariants() const;
  
    /// Check if \c this is well-formed and create an ExtInfo.
    ASTExtInfo build() const;
  
    constexpr Representation getRepresentation() const {
      unsigned rawRep = bits & RepresentationMask;
      assert(rawRep <= unsigned(Representation::Last) &&
             "unexpected SIL representation");
      return Representation(rawRep);
    }
  
    constexpr bool isNoEscape() const { return bits & NoEscapeMask; }
  
    constexpr bool isAsync() const { return bits & AsyncMask; }
  
    constexpr bool isThrowing() const { return bits & ThrowsMask; }
  
    constexpr DifferentiabilityKind getDifferentiabilityKind() const {
      return DifferentiabilityKind((bits & DifferentiabilityMask) >>
                                   DifferentiabilityMaskOffset);
    }
  
    constexpr bool isDifferentiable() const {
      return getDifferentiabilityKind() >
             DifferentiabilityKind::NonDifferentiable;
    }
  
    ClangTypeInfo getClangTypeInfo() const { return clangTypeInfo; }
  
    constexpr SILFunctionTypeRepresentation getSILRepresentation() const {
      unsigned rawRep = bits & RepresentationMask;
      return SILFunctionTypeRepresentation(rawRep);
    }
  
    constexpr bool hasSelfParam() const {
      switch (getSILRepresentation()) {
      case SILFunctionTypeRepresentation::Thick:
      case SILFunctionTypeRepresentation::Block:
      case SILFunctionTypeRepresentation::Thin:
      case SILFunctionTypeRepresentation::CFunctionPointer:
      case SILFunctionTypeRepresentation::Closure:
        return false;
      case SILFunctionTypeRepresentation::ObjCMethod:
      case SILFunctionTypeRepresentation::Method:
      case SILFunctionTypeRepresentation::WitnessMethod:
        return true;
      }
      llvm_unreachable("Unhandled SILFunctionTypeRepresentation in switch.");
    }
  
    /// True if the function representation carries context.
    constexpr bool hasContext() const {
      switch (getSILRepresentation()) {
      case SILFunctionTypeRepresentation::Thick:
      case SILFunctionTypeRepresentation::Block:
        return true;
      case SILFunctionTypeRepresentation::Thin:
      case SILFunctionTypeRepresentation::Method:
      case SILFunctionTypeRepresentation::ObjCMethod:
      case SILFunctionTypeRepresentation::WitnessMethod:
      case SILFunctionTypeRepresentation::CFunctionPointer:
      case SILFunctionTypeRepresentation::Closure:
        return false;
      }
      llvm_unreachable("Unhandled SILFunctionTypeRepresentation in switch.");
    }
  
    // Note that we don't have setters. That is by design, use
    // the following with methods instead of mutating these objects.
    LLVM_NODISCARD
    ASTExtInfoBuilder withRepresentation(Representation rep) const {
      return ASTExtInfoBuilder((bits & ~RepresentationMask) | (unsigned)rep,
                               shouldStoreClangType(rep) ? clangTypeInfo
                                                         : ClangTypeInfo());
    }
    LLVM_NODISCARD
    ASTExtInfoBuilder withNoEscape(bool noEscape = true) const {
      return ASTExtInfoBuilder(noEscape ? (bits | NoEscapeMask)
                                        : (bits & ~NoEscapeMask),
                               clangTypeInfo);
    }
    LLVM_NODISCARD
    ASTExtInfoBuilder withAsync(bool async = true) const {
      return ASTExtInfoBuilder(async ? (bits | AsyncMask)
                                     : (bits & ~AsyncMask),
                               clangTypeInfo);
    }
    LLVM_NODISCARD
    ASTExtInfoBuilder withThrows(bool throws = true) const {
      return ASTExtInfoBuilder(
          throws ? (bits | ThrowsMask) : (bits & ~ThrowsMask), clangTypeInfo);
    }
    LLVM_NODISCARD
    ASTExtInfoBuilder
    withDifferentiabilityKind(DifferentiabilityKind differentiability) const {
      return ASTExtInfoBuilder(
          (bits & ~DifferentiabilityMask) |
              ((unsigned)differentiability << DifferentiabilityMaskOffset),
          clangTypeInfo);
    }
    LLVM_NODISCARD
    ASTExtInfoBuilder withClangFunctionType(const clang::Type *type) const {
      return ASTExtInfoBuilder(bits, ClangTypeInfo(type));
    }
  
    /// Put a SIL representation in the ExtInfo.
    ///
    /// SIL type lowering transiently generates AST function types with SIL
    /// representations. However, they shouldn't persist in the AST, and
    /// don't need to be parsed, printed, or serialized.
    LLVM_NODISCARD
    ASTExtInfoBuilder
    withSILRepresentation(SILFunctionTypeRepresentation rep) const {
      return ASTExtInfoBuilder((bits & ~RepresentationMask) | (unsigned)rep,
                               shouldStoreClangType(rep) ? clangTypeInfo
                                                         : ClangTypeInfo());
    }
  
    bool isEqualTo(ASTExtInfoBuilder other, bool useClangTypes) const {
      return bits == other.bits &&
        (useClangTypes ? (clangTypeInfo == other.clangTypeInfo) : true);
    }
  
    constexpr std::pair<unsigned, const void *> getFuncAttrKey() const {
      return std::make_pair(bits, clangTypeInfo.getType());
    }
  }; // end ASTExtInfoBuilder
  
  // MARK: - ASTExtInfo
  /// Calling convention and related information for AnyFunctionType + subclasses.
  ///
  /// New instances can be made from existing instances via \c ASTExtInfoBuilder,
  /// typically using a code pattern like:
  /// \code
  /// extInfo.intoBuilder().withX(x).withY(y).build()
  /// \endcode
  class ASTExtInfo {
    friend ASTExtInfoBuilder;
    friend AnyFunctionType;
  
    ASTExtInfoBuilder builder;
  
    // Only for use by ASTExtInfoBuilder::build. Don't use it elsewhere!
    ASTExtInfo(ASTExtInfoBuilder builder) : builder(builder) {}
  
    ASTExtInfo(unsigned bits, ClangTypeInfo clangTypeInfo)
        : builder(bits, clangTypeInfo) {
      builder.checkInvariants();
    };
  
  public:
    /// An ExtInfo for a typical Swift function: @convention(swift), @escaping,
    /// non-throwing, non-differentiable.
    ASTExtInfo() : builder() { builder.checkInvariants(); };
  
    /// Create a builder with the same state as \c this.
    ASTExtInfoBuilder intoBuilder() const { return builder; }
  
  private:
    constexpr unsigned getBits() const { return builder.bits; }
  
  public:
    constexpr FunctionTypeRepresentation getRepresentation() const {
      return builder.getRepresentation();
    }
  
    constexpr SILFunctionTypeRepresentation getSILRepresentation() const {
      return builder.getSILRepresentation();
    }
  
    constexpr bool isNoEscape() const { return builder.isNoEscape(); }
  
    constexpr bool isAsync() const { return builder.isAsync(); }
  
    constexpr bool isThrowing() const { return builder.isThrowing(); }
  
    constexpr DifferentiabilityKind getDifferentiabilityKind() const {
      return builder.getDifferentiabilityKind();
    }
  
    constexpr bool isDifferentiable() const { return builder.isDifferentiable(); }
  
    ClangTypeInfo getClangTypeInfo() const { return builder.getClangTypeInfo(); }
  
    constexpr bool hasSelfParam() const { return builder.hasSelfParam(); }
  
    constexpr bool hasContext() const { return builder.hasContext(); }
  
    /// Helper method for changing the representation.
    ///
    /// Prefer using \c ASTExtInfoBuilder::withRepresentation for chaining.
    LLVM_NODISCARD
    ASTExtInfo withRepresentation(ASTExtInfoBuilder::Representation rep) const {
      return builder.withRepresentation(rep).build();
    }
  
    /// Helper method for changing only the noEscape field.
    ///
    /// Prefer using \c ASTExtInfoBuilder::withNoEscape for chaining.
    LLVM_NODISCARD
    ASTExtInfo withNoEscape(bool noEscape = true) const {
      return builder.withNoEscape(noEscape).build();
    }
  
    /// Helper method for changing only the throws field.
    ///
    /// Prefer using \c ASTExtInfoBuilder::withThrows for chaining.
    LLVM_NODISCARD
    ASTExtInfo withThrows(bool throws = true) const {
      return builder.withThrows(throws).build();
    }
  
    /// Helper method for changing only the async field.
    ///
    /// Prefer using \c ASTExtInfoBuilder::withAsync for chaining.
    LLVM_NODISCARD
    ASTExtInfo withAsync(bool async = true) const {
      return builder.withAsync(async).build();
    }
  
    bool isEqualTo(ASTExtInfo other, bool useClangTypes) const {
      return builder.isEqualTo(other.builder, useClangTypes);
    }
  
    constexpr std::pair<unsigned, const void *> getFuncAttrKey() const {
      return builder.getFuncAttrKey();
    }
  }; // end ASTExtInfo
  
  // MARK: - SILFunctionLanguage
  
  /// A language-level calling convention.
  enum class SILFunctionLanguage : uint8_t {
    /// A variation of the Swift calling convention.
    Swift = 0,
  
    /// A variation of the C calling convention.
    C,
  };
  
  /// Map a SIL function representation to the base language calling convention
  /// it uses.
  constexpr
  SILFunctionLanguage getSILFunctionLanguage(SILFunctionTypeRepresentation rep) {
    switch (rep) {
    case SILFunctionTypeRepresentation::ObjCMethod:
    case SILFunctionTypeRepresentation::CFunctionPointer:
    case SILFunctionTypeRepresentation::Block:
      return SILFunctionLanguage::C;
    case SILFunctionTypeRepresentation::Thick:
    case SILFunctionTypeRepresentation::Thin:
    case SILFunctionTypeRepresentation::Method:
    case SILFunctionTypeRepresentation::WitnessMethod:
    case SILFunctionTypeRepresentation::Closure:
      return SILFunctionLanguage::Swift;
    }
  
    llvm_unreachable("Unhandled SILFunctionTypeRepresentation in switch.");
  }
  
  // MARK: - SILExtInfoBuilder
  /// A builder type for creating an \c SILExtInfo.
  ///
  /// The main API public includes the \c withXYZ and \p build() methods.
  class SILExtInfoBuilder {
    friend SILExtInfo;
    friend SILFunctionType;
  
    // If bits are added or removed, then TypeBase::SILFunctionTypeBits
    // and NumMaskBits must be updated, and they must match.
  
    //   |representation|pseudogeneric| noescape | async | differentiability|
    //   |    0 .. 3    |      4      |     5    |   6   |      7 .. 8     |
    //
    enum : unsigned {
      RepresentationMask = 0xF << 0,
      PseudogenericMask = 1 << 4,
      NoEscapeMask = 1 << 5,
      AsyncMask = 1 << 6,
      DifferentiabilityMaskOffset = 7,
      DifferentiabilityMask = 0x3 << DifferentiabilityMaskOffset,
      NumMaskBits = 9
    };
  
    unsigned bits; // Naturally sized for speed.
  
    ClangTypeInfo clangTypeInfo;
  
    using Language = SILFunctionLanguage;
    using Representation = SILFunctionTypeRepresentation;
  
    SILExtInfoBuilder(unsigned bits, ClangTypeInfo clangTypeInfo)
        : bits(bits), clangTypeInfo(clangTypeInfo.getCanonical()) {}
  
    static constexpr unsigned makeBits(Representation rep, bool isPseudogeneric,
                                       bool isNoEscape, bool isAsync,
                                       DifferentiabilityKind diffKind) {
      return ((unsigned)rep) | (isPseudogeneric ? PseudogenericMask : 0) |
             (isNoEscape ? NoEscapeMask : 0) | (isAsync ? AsyncMask : 0) |
             (((unsigned)diffKind << DifferentiabilityMaskOffset) &
              DifferentiabilityMask);
    }
  
  public:
    /// An ExtInfoBuilder for a typical Swift function: thick, @escaping,
    /// non-pseudogeneric, non-differentiable.
    SILExtInfoBuilder()
        : SILExtInfoBuilder(makeBits(SILFunctionTypeRepresentation::Thick, false,
                                     false, false,
                                     DifferentiabilityKind::NonDifferentiable),
                            ClangTypeInfo(nullptr)) {}
  
    SILExtInfoBuilder(Representation rep, bool isPseudogeneric, bool isNoEscape,
                      bool isAsync, DifferentiabilityKind diffKind,
                      const clang::Type *type)
        : SILExtInfoBuilder(makeBits(rep, isPseudogeneric, isNoEscape, isAsync,
                                     diffKind),
                            ClangTypeInfo(type)) {}
  
    // Constructor for polymorphic type.
    SILExtInfoBuilder(ASTExtInfoBuilder info, bool isPseudogeneric)
        : SILExtInfoBuilder(makeBits(info.getSILRepresentation(), isPseudogeneric,
                                     info.isNoEscape(), info.isAsync(),
                                     info.getDifferentiabilityKind()),
                            info.getClangTypeInfo()) {}
  
    void checkInvariants() const;
  
    /// Check if \c this is well-formed and create an ExtInfo.
    SILExtInfo build() const;
  
    /// What is the abstract representation of this function value?
    constexpr Representation getRepresentation() const {
      return Representation(bits & RepresentationMask);
    }
  
    constexpr Language getLanguage() const {
      return getSILFunctionLanguage(getRepresentation());
    }
  
    /// Is this function pseudo-generic?  A pseudo-generic function
    /// is not permitted to dynamically depend on its type arguments.
    constexpr bool isPseudogeneric() const { return bits & PseudogenericMask; }
  
    // Is this function guaranteed to be no-escape by the type system?
    constexpr bool isNoEscape() const { return bits & NoEscapeMask; }
  
    constexpr bool isAsync() const { return bits & AsyncMask; }
  
    constexpr DifferentiabilityKind getDifferentiabilityKind() const {
      return DifferentiabilityKind((bits & DifferentiabilityMask) >>
                                   DifferentiabilityMaskOffset);
    }
  
    constexpr bool isDifferentiable() const {
      return getDifferentiabilityKind() !=
             DifferentiabilityKind::NonDifferentiable;
    }
  
    /// Get the underlying ClangTypeInfo value.
    ClangTypeInfo getClangTypeInfo() const { return clangTypeInfo; }
  
    constexpr bool hasSelfParam() const {
      switch (getRepresentation()) {
      case Representation::Thick:
      case Representation::Block:
      case Representation::Thin:
      case Representation::CFunctionPointer:
      case Representation::Closure:
        return false;
      case Representation::ObjCMethod:
      case Representation::Method:
      case Representation::WitnessMethod:
        return true;
      }
      llvm_unreachable("Unhandled Representation in switch.");
    }
  
    /// True if the function representation carries context.
    constexpr bool hasContext() const {
      switch (getRepresentation()) {
      case Representation::Thick:
      case Representation::Block:
        return true;
      case Representation::Thin:
      case Representation::CFunctionPointer:
      case Representation::ObjCMethod:
      case Representation::Method:
      case Representation::WitnessMethod:
      case Representation::Closure:
        return false;
      }
      llvm_unreachable("Unhandled Representation in switch.");
    }
  
    // Note that we don't have setters. That is by design, use
    // the following with methods instead of mutating these objects.
    LLVM_NODISCARD
    SILExtInfoBuilder withRepresentation(Representation rep) const {
      return SILExtInfoBuilder((bits & ~RepresentationMask) | (unsigned)rep,
                               shouldStoreClangType(rep) ? clangTypeInfo
                                                         : ClangTypeInfo());
    }
    LLVM_NODISCARD
    SILExtInfoBuilder withIsPseudogeneric(bool isPseudogeneric = true) const {
      return SILExtInfoBuilder(isPseudogeneric ? (bits | PseudogenericMask)
                                               : (bits & ~PseudogenericMask),
                               clangTypeInfo);
    }
    LLVM_NODISCARD
    SILExtInfoBuilder withNoEscape(bool noEscape = true) const {
      return SILExtInfoBuilder(noEscape ? (bits | NoEscapeMask)
                                        : (bits & ~NoEscapeMask),
                               clangTypeInfo);
    }
    LLVM_NODISCARD
    SILExtInfoBuilder withAsync(bool isAsync = true) const {
      return SILExtInfoBuilder(isAsync ? (bits | AsyncMask) : (bits & ~AsyncMask),
                               clangTypeInfo);
    }
    LLVM_NODISCARD
    SILExtInfoBuilder
    withDifferentiabilityKind(DifferentiabilityKind differentiability) const {
      return SILExtInfoBuilder(
          (bits & ~DifferentiabilityMask) |
              ((unsigned)differentiability << DifferentiabilityMaskOffset),
          clangTypeInfo);
    }
    LLVM_NODISCARD
    SILExtInfoBuilder withClangFunctionType(const clang::Type *type) const {
      return SILExtInfoBuilder(bits, ClangTypeInfo(type).getCanonical());
    }
  
    bool isEqualTo(SILExtInfoBuilder other, bool useClangTypes) const {
      return bits == other.bits &&
             (useClangTypes ? (clangTypeInfo == other.clangTypeInfo) : true);
    }
  
    constexpr std::pair<unsigned, const void *> getFuncAttrKey() const {
      return std::make_pair(bits, clangTypeInfo.getType());
    }
  }; // end SILExtInfoBuilder
  
  // MARK: - SILExtInfo
  /// Calling convention information for SILFunctionType.
  ///
  /// New instances can be made from existing instances via \c SILExtInfoBuilder,
  /// typically using a code pattern like:
  /// \code
  /// extInfo.intoBuilder().withX(x).withY(y).build()
  /// \endcode
  class SILExtInfo {
    friend SILExtInfoBuilder;
    friend SILFunctionType;
  
    SILExtInfoBuilder builder;
  
    // Only for use by SILExtInfoBuilder::build. Don't use it elsewhere!
    SILExtInfo(SILExtInfoBuilder builder) : builder(builder) {}
  
    SILExtInfo(unsigned bits, ClangTypeInfo clangTypeInfo)
        : builder(bits, clangTypeInfo) {
      builder.checkInvariants();
    };
  
  public:
    /// An ExtInfo for a typical Swift function: thick, @escaping,
    /// non-pseudogeneric, non-differentiable.
    SILExtInfo() : builder() { builder.checkInvariants(); };
  
    SILExtInfo(ASTExtInfo info, bool isPseudogeneric)
        : builder(info.intoBuilder(), isPseudogeneric) {
      builder.checkInvariants();
    }
  
    /// A default ExtInfo but with a Thin convention.
    static SILExtInfo getThin() {
      return SILExtInfoBuilder(SILExtInfoBuilder::Representation::Thin, false,
                               false, false,
                               DifferentiabilityKind::NonDifferentiable, nullptr)
          .build();
    }
  
    /// Create a builder with the same state as \c this.
    SILExtInfoBuilder intoBuilder() const { return builder; }
  
  private:
    constexpr unsigned getBits() const { return builder.bits; }
  
  public:
    constexpr SILFunctionTypeRepresentation getRepresentation() const {
      return builder.getRepresentation();
    }
  
    constexpr SILFunctionLanguage getLanguage() const {
      return builder.getLanguage();
    }
  
    constexpr bool isPseudogeneric() const { return builder.isPseudogeneric(); }
  
    constexpr bool isNoEscape() const { return builder.isNoEscape(); }
  
    constexpr bool isAsync() const { return builder.isAsync(); }
  
    constexpr DifferentiabilityKind getDifferentiabilityKind() const {
      return builder.getDifferentiabilityKind();
    }
  
    constexpr bool isDifferentiable() const { return builder.isDifferentiable(); }
  
    ClangTypeInfo getClangTypeInfo() const { return builder.getClangTypeInfo(); }
  
    constexpr bool hasSelfParam() const { return builder.hasSelfParam(); }
  
    constexpr bool hasContext() const { return builder.hasContext(); }
  
    /// Helper method for changing the Representation.
    ///
    /// Prefer using \c SILExtInfoBuilder::withRepresentation for chaining.
    SILExtInfo withRepresentation(SILExtInfoBuilder::Representation rep) const {
      return builder.withRepresentation(rep).build();
    }
  
    /// Helper method for changing only the NoEscape field.
    ///
    /// Prefer using \c SILExtInfoBuilder::withNoEscape for chaining.
    SILExtInfo withNoEscape(bool noEscape = true) const {
      return builder.withNoEscape(noEscape).build();
    }
  
    bool isEqualTo(SILExtInfo other, bool useClangTypes) const {
      return builder.isEqualTo(other.builder, useClangTypes);
    }
  
    constexpr std::pair<unsigned, const void *> getFuncAttrKey() const {
      return builder.getFuncAttrKey();
    }
  
    Optional<UnexpectedClangTypeError> checkClangType() const;
  };
  
  /// Helper function to obtain the useClangTypes parameter for checking equality
  /// of ExtInfos.
  ///
  /// Typically, the argument will be a function type which was used to obtain one
  /// of the ExtInfos.
  template <typename HasContext> bool useClangTypes(HasContext hasContext) {
    return hasContext->getASTContext().LangOpts.UseClangFunctionTypes;
  }
  
  } // end namespace swift
  
  #endif // SWIFT_EXTINFO_H
  