//===--- Expr.h - Swift Language Expression ASTs ----------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the Expr class and subclasses.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_AST_EXPR_H
#define SWIFT_AST_EXPR_H

#include "swift/AST/ArgumentList.h"
#include "swift/AST/Attr.h"
#include "swift/AST/AvailabilityRange.h"
#include "swift/AST/CaptureInfo.h"
#include "swift/AST/ConcreteDeclRef.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DeclContext.h"
#include "swift/AST/DeclNameLoc.h"
#include "swift/AST/FreestandingMacroExpansion.h"
#include "swift/AST/FunctionRefInfo.h"
#include "swift/AST/ProtocolConformanceRef.h"
#include "swift/AST/ThrownErrorDestination.h"
#include "swift/AST/TypeAlignments.h"
#include "swift/Basic/Debug.h"
#include "swift/Basic/InlineBitfield.h"
#include "llvm/Support/TrailingObjects.h"
#include <optional>
#include <utility>

namespace llvm {
  struct fltSemantics;
}

namespace swift {
  enum class AccessKind : unsigned char;
  class ArchetypeType;
  class ASTContext;
  class AvailabilitySpec;
  class DeclRefTypeRepr;
  class Type;
  class TypeRepr;
  class ValueDecl;
  class Decl;
  class DeclRefExpr;
  class OpenedArchetypeType;
  class ParamDecl;
  class Pattern;
  class SubscriptDecl;
  class Stmt;
  class BraceStmt;
  class ASTWalker;
  class Initializer;
  class VarDecl;
  class OpaqueValueExpr;
  class FuncDecl;
  class ConstructorDecl;
  class TypeDecl;
  class PatternBindingDecl;
  class ParameterList;
  class EnumElementDecl;
  class CallExpr;
  class KeyPathExpr;
  class CaptureListExpr;
  class ThenStmt;
  class ReturnStmt;

enum class ExprKind : uint8_t {
#define EXPR(Id, Parent) Id,
#define LAST_EXPR(Id) Last_Expr = Id,
#define EXPR_RANGE(Id, FirstId, LastId) \
  First_##Id##Expr = FirstId, Last_##Id##Expr = LastId,
#include "swift/AST/ExprNodes.def"
};
enum : unsigned { NumExprKindBits =
  countBitsUsed(static_cast<unsigned>(ExprKind::Last_Expr)) };
  
/// Discriminates certain kinds of checked cast that have specialized diagnostic
/// and/or code generation peephole behavior.
///
/// This enumeration should not have any semantic effect on the behavior of a
/// well-typed program, since the runtime can perform all casts that are
/// statically accepted.
enum class CheckedCastKind : unsigned {
  /// The kind has not been determined yet.
  Unresolved,

  /// Valid resolved kinds start here.
  First_Resolved,

  /// The requested cast is an implicit conversion, so this is a coercion.
  Coercion = First_Resolved,
  /// A checked cast with no known specific behavior.
  ValueCast,
  // A downcast from an array type to another array type.
  ArrayDowncast,
  // A downcast from a dictionary type to another dictionary type.
  DictionaryDowncast,
  // A downcast from a set type to another set type.
  SetDowncast,
  /// A bridging conversion that always succeeds.
  BridgingCoercion,

  Last_CheckedCastKind = BridgingCoercion,
};

/// What are the high-level semantics of this access?
enum class AccessSemantics : uint8_t {
  /// On a storage reference, this is a direct access to the underlying
  /// physical storage, bypassing any observers.  The declaration must be 
  /// a variable with storage.
  ///
  /// On a function reference, this is a non-polymorphic access to a
  /// particular implementation.
  DirectToStorage,

  /// On a storage reference, this is a direct access to the concrete
  /// implementation of this storage, bypassing any possibility of override.
  DirectToImplementation,

  /// This is an ordinary access to a declaration, using whatever
  /// polymorphism is expected.
  Ordinary,

  /// This is an access to the underlying storage through a distributed thunk.
  ///
  /// The declaration must be a 'distributed' computed property used outside
  /// of its actor isolation context.
  DistributedThunk,
};

/// Expr - Base class for all expressions in swift.
class alignas(8) Expr : public ASTAllocated<Expr> {
  Expr(const Expr&) = delete;
  void operator=(const Expr&) = delete;

protected:
  // clang-format off
  union { uint64_t OpaqueBits;

  SWIFT_INLINE_BITFIELD_BASE(Expr, bitmax(NumExprKindBits,8)+1,
    /// The subclass of Expr that this is.
    Kind : bitmax(NumExprKindBits,8),
    /// Whether the Expr represents something directly written in source or
    /// it was implicitly generated by the type-checker.
    Implicit : 1
  );

  SWIFT_INLINE_BITFIELD_FULL(CollectionExpr, Expr, 64-NumExprBits,
    /// True if the type of this collection expr was inferred by the collection
    /// fallback type, like [Any].
    IsTypeDefaulted : 1,
    /// Number of comma source locations.
    NumCommas : 32 - 1 - NumExprBits,
    /// Number of entries in the collection. If this is a DictionaryExpr,
    /// each entry is a Tuple with the key and value pair.
    NumSubExprs : 32
  );

  SWIFT_INLINE_BITFIELD_EMPTY(LiteralExpr, Expr);
  SWIFT_INLINE_BITFIELD_EMPTY(IdentityExpr, Expr);
  SWIFT_INLINE_BITFIELD(LookupExpr, Expr, 1+1+1,
    IsSuper : 1,
    IsImplicitlyAsync : 1,
    IsImplicitlyThrows : 1
  );
  SWIFT_INLINE_BITFIELD_EMPTY(DynamicLookupExpr, LookupExpr);

  SWIFT_INLINE_BITFIELD_EMPTY(ParenExpr, IdentityExpr);

  SWIFT_INLINE_BITFIELD(NumberLiteralExpr, LiteralExpr, 1+1,
    IsNegative : 1,
    IsExplicitConversion : 1
  );

  SWIFT_INLINE_BITFIELD(StringLiteralExpr, LiteralExpr, 3+1+1,
    Encoding : 3,
    IsSingleUnicodeScalar : 1,
    IsSingleExtendedGraphemeCluster : 1
  );

  SWIFT_INLINE_BITFIELD_FULL(InterpolatedStringLiteralExpr, LiteralExpr, 32+20,
    : NumPadBits,
    InterpolationCount : 20,
    LiteralCapacity : 32
  );

  SWIFT_INLINE_BITFIELD(DeclRefExpr, Expr, 2+3+1+1,
    Semantics : 2, // an AccessSemantics
    FunctionRefInfo : 3,
    IsImplicitlyAsync : 1,
    IsImplicitlyThrows : 1
  );

  SWIFT_INLINE_BITFIELD(UnresolvedDeclRefExpr, Expr, 2+3,
    DeclRefKind : 2,
    FunctionRefInfo : 3
  );

  SWIFT_INLINE_BITFIELD(MemberRefExpr, LookupExpr, 2,
    Semantics : 2 // an AccessSemantics
  );

  SWIFT_INLINE_BITFIELD_FULL(TupleElementExpr, Expr, 32,
    : NumPadBits,
    FieldNo : 32
  );

  SWIFT_INLINE_BITFIELD_FULL(TupleExpr, Expr, 1+1+32,
    /// Whether this tuple has any labels.
    HasElementNames : 1,

    /// Whether this tuple has label locations.
    HasElementNameLocations : 1,

    : NumPadBits,
    NumElements : 32
  );

  SWIFT_INLINE_BITFIELD(UnresolvedDotExpr, Expr, 3,
    FunctionRefInfo : 3
  );

  SWIFT_INLINE_BITFIELD_FULL(SubscriptExpr, LookupExpr, 2,
    Semantics : 2 // an AccessSemantics
  );

  SWIFT_INLINE_BITFIELD_EMPTY(DynamicSubscriptExpr, DynamicLookupExpr);

  SWIFT_INLINE_BITFIELD_FULL(UnresolvedMemberExpr, Expr, 3,
    FunctionRefInfo : 3
  );

  SWIFT_INLINE_BITFIELD(OverloadSetRefExpr, Expr, 3,
    FunctionRefInfo : 3
  );

  SWIFT_INLINE_BITFIELD(BooleanLiteralExpr, LiteralExpr, 1,
    Value : 1
  );

  SWIFT_INLINE_BITFIELD(MagicIdentifierLiteralExpr, LiteralExpr, 3+1,
    Kind : 3,
    StringEncoding : 1
  );

  SWIFT_INLINE_BITFIELD_FULL(ObjectLiteralExpr, LiteralExpr, 3,
    LitKind : 3
  );

  SWIFT_INLINE_BITFIELD(AbstractClosureExpr, Expr, (16-NumExprBits)+16,
    : 16 - NumExprBits, // Align and leave room for subclasses
    Discriminator : 16
  );

  SWIFT_INLINE_BITFIELD(AutoClosureExpr, AbstractClosureExpr, 2,
    /// If the autoclosure was built for a curry thunk, the thunk kind is
    /// stored here.
    Kind : 2
  );

  SWIFT_INLINE_BITFIELD(ClosureExpr, AbstractClosureExpr, 1+1+1+1+1+1+1,
    /// True if closure parameters were synthesized from anonymous closure
    /// variables.
    HasAnonymousClosureVars : 1,

    /// True if "self" can be captured implicitly without requiring "self."
    /// on each member reference.
    ImplicitSelfCapture : 1,

    /// True if this @Sendable async closure parameter should implicitly
    /// inherit the actor context from where it was formed.
    InheritActorContext : 1,

    /// True if this closure's actor isolation behavior was determined by an
    /// \c \@preconcurrency declaration.
    IsolatedByPreconcurrency : 1,

    /// True if this is a closure literal that is passed to a sending parameter.
    IsPassedToSendingParameter : 1,

    /// True if we're in the common case where the GlobalActorAttributeRequest
    /// request returned a pair of null pointers.
    NoGlobalActorAttribute : 1,

    /// Indicates whether this closure literal would require dynamic actor 
    /// isolation checks when it either specifies or inherits isolation
    /// and was passed as an argument to a function that is not fully 
    /// concurrency checked.
    RequiresDynamicIsolationChecking : 1
  );

  SWIFT_INLINE_BITFIELD_FULL(BindOptionalExpr, Expr, 16,
    : NumPadBits,
    Depth : 16
  );

  SWIFT_INLINE_BITFIELD_EMPTY(ImplicitConversionExpr, Expr);

  SWIFT_INLINE_BITFIELD_FULL(DestructureTupleExpr, ImplicitConversionExpr, 16,
    /// The number of elements in the tuple type being destructured.
    NumElements : 16
  );

  SWIFT_INLINE_BITFIELD(ForceValueExpr, Expr, 1,
    ForcedIUO : 1
  );

  SWIFT_INLINE_BITFIELD(InOutToPointerExpr, ImplicitConversionExpr, 1,
    IsNonAccessing : 1
  );

  SWIFT_INLINE_BITFIELD(ArrayToPointerExpr, ImplicitConversionExpr, 1,
    IsNonAccessing : 1
  );

  SWIFT_INLINE_BITFIELD_FULL(ErasureExpr, ImplicitConversionExpr, 32+20,
    : NumPadBits,
    NumConformances : 32,
    NumArgumentConversions : 20
  );

  SWIFT_INLINE_BITFIELD_FULL(UnresolvedSpecializeExpr, Expr, 32,
    : NumPadBits,
    NumUnresolvedParams : 32
  );

  SWIFT_INLINE_BITFIELD_FULL(CaptureListExpr, Expr, 32,
    : NumPadBits,
    NumCaptures : 32
  );

  SWIFT_INLINE_BITFIELD(ApplyExpr, Expr, 1+1+1+1+1,
    ThrowsIsSet : 1,
    ImplicitlyAsync : 1,
    ImplicitlyThrows : 1,
    NoAsync : 1,
    ShouldApplyDistributedThunk : 1
  );

  SWIFT_INLINE_BITFIELD_EMPTY(CallExpr, ApplyExpr);

  enum { NumCheckedCastKindBits = 4 };
  SWIFT_INLINE_BITFIELD(CheckedCastExpr, Expr, NumCheckedCastKindBits,
    CastKind : NumCheckedCastKindBits
  );
  static_assert(unsigned(CheckedCastKind::Last_CheckedCastKind)
                  < (1 << NumCheckedCastKindBits),
                "unable to fit a CheckedCastKind in the given number of bits");

  SWIFT_INLINE_BITFIELD_EMPTY(CollectionUpcastConversionExpr, Expr);

  SWIFT_INLINE_BITFIELD(ObjCSelectorExpr, Expr, 2,
    /// The selector kind.
    SelectorKind : 2
  );

  SWIFT_INLINE_BITFIELD(KeyPathExpr, Expr, 1,
    /// Whether this is an ObjC stringified keypath.
    IsObjC : 1
  );

  SWIFT_INLINE_BITFIELD_FULL(SequenceExpr, Expr, 32+1,
    : NumPadBits,
    NumElements : 32,
    IsFolded: 1
  );

  SWIFT_INLINE_BITFIELD(OpaqueValueExpr, Expr, 1,
    IsPlaceholder : 1
  );

  SWIFT_INLINE_BITFIELD_FULL(TypeJoinExpr, Expr, 32,
    : NumPadBits,
    NumElements : 32
  );

  } Bits;
  // clang-format on

private:
  /// Ty - This is the type of the expression.
  Type Ty;
 
protected:
  Expr(ExprKind Kind, bool Implicit, Type Ty = Type()) : Ty(Ty) {
    Bits.OpaqueBits = 0;
    Bits.Expr.Kind = unsigned(Kind);
    Bits.Expr.Implicit = Implicit;
  }

public:
  /// Return the kind of this expression.
  ExprKind getKind() const { return ExprKind(Bits.Expr.Kind); }

  /// Retrieve the name of the given expression kind.
  ///
  /// This name should only be used for debugging dumps and other
  /// developer aids, and should never be part of a diagnostic or exposed
  /// to the user of the compiler in any way.
  static StringRef getKindName(ExprKind K);

  /// getType - Return the type of this expression.
  Type getType() const { return Ty; }

  /// setType - Sets the type of this expression.
  void setType(Type T);

  /// Return the source range of the expression.
  SourceRange getSourceRange() const;
  
  /// getStartLoc - Return the location of the start of the expression.
  SourceLoc getStartLoc() const;

  /// Retrieve the location of the last token of the expression.
  SourceLoc getEndLoc() const;
  
  /// getLoc - Return the caret location of this expression.
  SourceLoc getLoc() const;

#define SWIFT_FORWARD_SOURCE_LOCS_TO(SUBEXPR) \
  SourceLoc getStartLoc() const { return (SUBEXPR)->getStartLoc(); } \
  SourceLoc getEndLoc() const { return (SUBEXPR)->getEndLoc(); } \
  SourceLoc getLoc() const { return (SUBEXPR)->getLoc(); } \
  SourceRange getSourceRange() const { return (SUBEXPR)->getSourceRange(); }

  SourceLoc TrailingSemiLoc;

  /// getSemanticsProvidingExpr - Find the smallest subexpression
  /// which obeys the property that evaluating it is exactly
  /// equivalent to evaluating this expression.
  ///
  /// Looks through parentheses.  Would not look through something
  /// like '(foo(), x:bar(), baz()).x'.
  Expr *getSemanticsProvidingExpr();

  const Expr *getSemanticsProvidingExpr() const {
    return const_cast<Expr *>(this)->getSemanticsProvidingExpr();
  }

  /// getValueProvidingExpr - Find the smallest subexpression which is
  /// responsible for generating the value of this expression.
  /// Evaluating the result is not necessarily equivalent to
  /// evaluating this expression because of potential missing
  /// side-effects (which may influence the returned value).
  Expr *getValueProvidingExpr();

  const Expr *getValueProvidingExpr() const {
    return const_cast<Expr *>(this)->getValueProvidingExpr();
  }

  /// Find the original expression value, looking through various
  /// implicit conversions.
  const Expr *findOriginalValue() const;

  /// Find the original type of a value, looking through various implicit
  /// conversions.
  Type findOriginalType() const;

  /// If this is a reference to an operator written as a member of a type (or
  /// extension thereof), return the underlying operator reference.
  DeclRefExpr *getMemberOperatorRef();

  /// This recursively walks the AST rooted at this expression.
  Expr *walk(ASTWalker &walker);
  Expr *walk(ASTWalker &&walker) { return walk(walker); }

  /// Enumerate each immediate child expression of this node, invoking the
  /// specific functor on it.  This ignores statements and other non-expression
  /// children.
  void forEachImmediateChildExpr(llvm::function_ref<Expr *(Expr *)> callback);

  /// Enumerate each expr node within this expression subtree, invoking the
  /// specific functor on it.  This ignores statements and other non-expression
  /// children, and if there is a closure within the expression, this does not
  /// walk into the body of it (unless it is single-expression).
  void forEachChildExpr(llvm::function_ref<Expr *(Expr *)> callback);

  /// Determine whether this expression refers to a type by name.
  ///
  /// This distinguishes static references to types, like Int, from metatype
  /// values, "someTy: Any.Type".
  bool isTypeReference(
      llvm::function_ref<Type(Expr *)> getType = [](Expr *E) -> Type {
        return E->getType();
      },
      llvm::function_ref<Decl *(Expr *)> getDecl = [](Expr *E) -> Decl * {
        return nullptr;
      }) const;

  /// Determine whether this expression refers to a statically-derived metatype.
  ///
  /// This implies `isTypeReference`, but also requires that the referenced type
  /// is not an archetype or dependent type.
  bool isStaticallyDerivedMetatype(
      llvm::function_ref<Type(Expr *)> getType = [](Expr *E) -> Type {
        return E->getType();
      },
      llvm::function_ref<bool(Expr *)> isTypeReference =
          [](Expr *E) { return E->isTypeReference(); }) const;

  /// isImplicit - Determines whether this expression was implicitly-generated,
  /// rather than explicitly written in the AST.
  bool isImplicit() const {
    return Bits.Expr.Implicit;
  }
  void setImplicit(bool Implicit = true);

  /// Retrieves the declaration that is being referenced by this
  /// expression, if any.
  ConcreteDeclRef getReferencedDecl(bool stopAtParenExpr = false) const;

  /// Determine whether this expression is 'super', possibly converted to
  /// a base class.
  bool isSuperExpr() const;

  /// Returns whether the semantically meaningful content of this expression is
  /// an inout expression.
  ///
  /// FIXME(Remove InOutType): This should eventually sub-in for
  /// 'E->getType()->is<InOutType>()' in all cases.
  bool isSemanticallyInOutExpr() const {
    return getSemanticsProvidingExpr()->getKind() == ExprKind::InOut;
  }

  bool printConstExprValue(llvm::raw_ostream *OS, llvm::function_ref<bool(Expr*)> additionalCheck) const;
  bool isSemanticallyConstExpr(llvm::function_ref<bool(Expr*)> additionalCheck = nullptr) const;

  /// Returns false if this expression needs to be wrapped in parens when
  /// used inside of a any postfix expression, true otherwise.
  ///
  /// \param appendingPostfixOperator if the expression being
  /// appended is a postfix operator like '!' or '?'.
  bool canAppendPostfixExpression(bool appendingPostfixOperator = false) const;

  /// Returns true if this is an infix operator of some sort, including
  /// a builtin operator.
  bool isInfixOperator() const;

  /// Returns true if this is a reference to the implicit self of function.
  bool isSelfExprOf(const AbstractFunctionDecl *AFD,
                    bool sameBase = false) const;

  /// If the expression has an argument list, returns it. Otherwise, returns
  /// \c nullptr.
  ArgumentList *getArgs() const;

  /// If the expression has a DeclNameLoc, returns it. Otherwise, returns
  /// an nullp DeclNameLoc.
  DeclNameLoc getNameLoc() const;

  /// Produce a mapping from each subexpression to its parent
  /// expression, with the provided expression serving as the root of
  /// the parent map.
  llvm::DenseMap<Expr *, Expr *> getParentMap();

  /// Whether this expression is a valid parent for a given TypeExpr.
  bool isValidParentOfTypeExpr(Expr *typeExpr) const;

  SWIFT_DEBUG_DUMP;
  void dump(raw_ostream &OS, unsigned Indent = 0) const;
  void dump(raw_ostream &OS, llvm::function_ref<Type(Expr *)> getType,
            llvm::function_ref<Type(TypeRepr *)> getTypeOfTypeRepr,
            llvm::function_ref<Type(KeyPathExpr *E, unsigned index)>
                getTypeOfKeyPathComponent,
            unsigned Indent = 0) const;

  void print(ASTPrinter &Printer, const PrintOptions &Opts) const;
};

/// ErrorExpr - Represents a semantically erroneous subexpression in the AST,
/// typically this will have an ErrorType.
class ErrorExpr : public Expr {
  SourceRange Range;
  Expr *OriginalExpr;
public:
  ErrorExpr(SourceRange Range, Type Ty = Type(), Expr *OriginalExpr = nullptr)
    : Expr(ExprKind::Error, /*Implicit=*/true, Ty), Range(Range),
      OriginalExpr(OriginalExpr) {}

  SourceRange getSourceRange() const { return Range; }
  Expr *getOriginalExpr() const { return OriginalExpr; }
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::Error;
  }
};

/// CodeCompletionExpr - Represents the code completion token in the AST, this
/// can help us preserve the context of the code completion position.
class CodeCompletionExpr : public Expr {
  Expr *Base;
  SourceLoc Loc;

public:
  CodeCompletionExpr(Expr *Base, SourceLoc Loc)
      : Expr(ExprKind::CodeCompletion, /*Implicit=*/true, Type()),
        Base(Base), Loc(Loc) {}

  CodeCompletionExpr(SourceLoc Loc)
      : CodeCompletionExpr(/*Base=*/nullptr, Loc) {}

  Expr *getBase() const { return Base; }
  void setBase(Expr *E) { Base = E; }

  SourceLoc getLoc() const { return Loc; }
  SourceLoc getStartLoc() const { return Base ? Base->getStartLoc() : Loc; }
  SourceLoc getEndLoc() const { return Loc; }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::CodeCompletion;
  }
};

/// LiteralExpr - Common base class between the literals.
class LiteralExpr : public Expr {
  // Set by Sema:
  ConcreteDeclRef Initializer;

public:
  LiteralExpr(ExprKind Kind, bool Implicit) : Expr(Kind, Implicit) {}

  static bool classof(const Expr *E) {
    return E->getKind() >= ExprKind::First_LiteralExpr &&
           E->getKind() <= ExprKind::Last_LiteralExpr;
  }

  /// Retrieve the initializer that will be used to construct the
  /// literal from the result of the initializer.
  ///
  /// Only literals that have no builtin literal conformance will have
  /// this initializer, which will be called on the result of the builtin
  /// initializer.
  ConcreteDeclRef getInitializer() const { return Initializer; }

  /// Set the initializer that will be used to construct the literal.
  void setInitializer(ConcreteDeclRef initializer) {
    Initializer = initializer;
  }

  /// Get description string for the literal expression.
  StringRef getLiteralKindDescription() const;
};

/// BuiltinLiteralExpr - Common base class between all literals
/// that provides BuiltinInitializer
class BuiltinLiteralExpr : public LiteralExpr {
  // Set by Seam:
  ConcreteDeclRef BuiltinInitializer;

public:
  BuiltinLiteralExpr(ExprKind Kind, bool Implicit)
      : LiteralExpr(Kind, Implicit) {}

  static bool classof(const Expr *E) {
    return E->getKind() >= ExprKind::First_BuiltinLiteralExpr &&
           E->getKind() <= ExprKind::Last_BuiltinLiteralExpr;
  }

  /// Retrieve the builtin initializer that will be used to construct the
  /// literal.
  ///
  /// Any type-checked literal will have a builtin initializer, which is
  /// called first to form a concrete Swift type.
  ConcreteDeclRef getBuiltinInitializer() const { return BuiltinInitializer; }

  /// Set the builtin initializer that will be used to construct the
  /// literal.
  void setBuiltinInitializer(ConcreteDeclRef builtinInitializer) {
    BuiltinInitializer = builtinInitializer;
  }
};

/// The 'nil' literal.
///
class NilLiteralExpr : public LiteralExpr {
  SourceLoc Loc;

public:
  NilLiteralExpr(SourceLoc Loc, bool Implicit = false)
  : LiteralExpr(ExprKind::NilLiteral, Implicit), Loc(Loc) {
  }
  
  SourceRange getSourceRange() const {
    return Loc;
  }
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::NilLiteral;
  }
};

/// Abstract base class for numeric literals, potentially with a sign.
class NumberLiteralExpr : public BuiltinLiteralExpr {
  /// The value of the literal as an ASTContext-owned string. Underscores must
  /// be stripped.
  StringRef Val;  // Use StringRef instead of APInt or APFloat, which leak.

protected:
  SourceLoc MinusLoc;
  SourceLoc DigitsLoc;
  
public:
  NumberLiteralExpr(ExprKind Kind, StringRef Val, SourceLoc DigitsLoc,
                    bool Implicit)
      : BuiltinLiteralExpr(Kind, Implicit), Val(Val), DigitsLoc(DigitsLoc) {
    Bits.NumberLiteralExpr.IsNegative = false;
    Bits.NumberLiteralExpr.IsExplicitConversion = false;
  }

  bool isNegative() const { return Bits.NumberLiteralExpr.IsNegative; }
  void setNegative(SourceLoc Loc) {
    MinusLoc = Loc;
    Bits.NumberLiteralExpr.IsNegative = true;
  }

  bool isExplicitConversion() const {
    return Bits.NumberLiteralExpr.IsExplicitConversion;
  }
  void setExplicitConversion(bool isExplicitConversion = true) {
    Bits.NumberLiteralExpr.IsExplicitConversion = isExplicitConversion;
  }

  StringRef getDigitsText() const { return Val; }

  SourceRange getSourceRange() const {
    if (isNegative())
      return { MinusLoc, DigitsLoc };
    else
      return DigitsLoc;
  }

  SourceLoc getMinusLoc() const {
    return MinusLoc;
  }

  SourceLoc getDigitsLoc() const {
    return DigitsLoc;
  }

  static bool classof(const Expr *E) {
    return E->getKind() >= ExprKind::First_NumberLiteralExpr
      && E->getKind() <= ExprKind::Last_NumberLiteralExpr;
  }
};

/// Integer literal with a '+' or '-' sign, like '+4' or '- 2'.
///
/// After semantic analysis assigns types, this is guaranteed to have
/// a BuiltinIntegerType or be a normal type and implicitly be
/// AnyBuiltinIntegerType.
class IntegerLiteralExpr : public NumberLiteralExpr {
public:
  IntegerLiteralExpr(StringRef Val, SourceLoc DigitsLoc, bool Implicit = false)
      : NumberLiteralExpr(ExprKind::IntegerLiteral,
                          Val, DigitsLoc, Implicit)
  {}

  /// Returns a new integer literal expression with the given value.
  /// \p C The AST context.
  /// \p value The integer value.
  /// \return An implicit integer literal expression which evaluates to the value.
  static IntegerLiteralExpr *
  createFromUnsigned(ASTContext &C, unsigned value, SourceLoc loc);

  /// Returns the value of the literal, appropriately constructed in the
  /// target type.
  APInt getValue() const;

  /// Returns the raw value of the literal without any truncation.
  APInt getRawValue() const;

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::IntegerLiteral;
  }
};

/// FloatLiteralExpr - Floating point literal, like '4.0'.  After semantic
/// analysis assigns types, BuiltinTy is guaranteed to only have a
/// BuiltinFloatingPointType.
class FloatLiteralExpr : public NumberLiteralExpr {
  /// This is the type of the builtin literal.
  Type BuiltinTy;

public:
  FloatLiteralExpr(StringRef Val, SourceLoc Loc, bool Implicit = false)
    : NumberLiteralExpr(ExprKind::FloatLiteral, Val, Loc, Implicit)
  {}
  
  APFloat getValue() const;
  static APFloat getValue(StringRef Text, const llvm::fltSemantics &Semantics,
                          bool Negative);
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::FloatLiteral;
  }

  Type getBuiltinType() const { return BuiltinTy; }
  void setBuiltinType(Type ty) { BuiltinTy = ty; }
};

/// A Boolean literal ('true' or 'false')
///
class BooleanLiteralExpr : public BuiltinLiteralExpr {
  SourceLoc Loc;

public:
  BooleanLiteralExpr(bool Value, SourceLoc Loc, bool Implicit = false)
      : BuiltinLiteralExpr(ExprKind::BooleanLiteral, Implicit), Loc(Loc) {
    Bits.BooleanLiteralExpr.Value = Value;
  }

  /// Retrieve the Boolean value of this literal.
  bool getValue() const { return Bits.BooleanLiteralExpr.Value; }

  SourceRange getSourceRange() const {
    return Loc;
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::BooleanLiteral;
  }
};

/// StringLiteralExpr - String literal, like '"foo"'.
class StringLiteralExpr : public BuiltinLiteralExpr {
  StringRef Val;
  SourceRange Range;

public:
  /// The encoding that should be used for the string literal.
  enum Encoding : unsigned {
    /// A UTF-8 string.
    UTF8,

    /// A single UnicodeScalar, passed as an integer.
    OneUnicodeScalar
  };

  StringLiteralExpr(StringRef Val, SourceRange Range, bool Implicit = false);

  StringRef getValue() const { return Val; }
  SourceRange getSourceRange() const { return Range; }

  /// Determine the encoding that should be used for this string literal.
  Encoding getEncoding() const {
    return static_cast<Encoding>(Bits.StringLiteralExpr.Encoding);
  }

  /// Set the encoding that should be used for this string literal.
  void setEncoding(Encoding encoding) {
    Bits.StringLiteralExpr.Encoding = static_cast<unsigned>(encoding);
  }

  bool isSingleUnicodeScalar() const {
    return Bits.StringLiteralExpr.IsSingleUnicodeScalar;
  }

  bool isSingleExtendedGraphemeCluster() const {
    return Bits.StringLiteralExpr.IsSingleExtendedGraphemeCluster;
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::StringLiteral;
  }
};

/// Runs a series of statements which use or modify \c SubExpr
/// before it is given to the rest of the expression.
///
/// \c Body should begin with a \c VarDecl; this defines the variable
/// \c TapExpr will initialize at the beginning and read a result
/// from at the end. \c TapExpr creates a separate scope, then
/// assigns the result of \c SubExpr to the variable and runs \c Body
/// in it, returning the value of the variable after the \c Body runs.
///
/// (The design here could be a bit cleaner, particularly where the VarDecl
/// is concerned.)
class TapExpr : public Expr {
  Expr *SubExpr;
  BraceStmt *Body;

public:
  TapExpr(Expr *SubExpr, BraceStmt *Body);

  Expr * getSubExpr() const { return SubExpr; }
  void setSubExpr(Expr * se) { SubExpr = se; }

  /// The variable which will be accessed and possibly modified by
  /// the \c Body. This is the first \c ASTNode in the \c Body.
  VarDecl * getVar() const;

  BraceStmt * getBody() const { return Body; }
  void setBody(BraceStmt * b) { Body = b; }

  SourceLoc getLoc() const { return SubExpr ? SubExpr->getLoc() : SourceLoc(); }

  SourceRange getSourceRange() const;

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::Tap;
  }
};

/// InterpolatedStringLiteral - An interpolated string literal.
///
/// An interpolated string literal mixes expressions (which are evaluated and
/// converted into string form) within a string literal.
///
/// \code
/// "[\(min)..\(max)]"
/// \endcode
class InterpolatedStringLiteralExpr : public LiteralExpr {
  /// Points at the beginning quote.
  SourceLoc Loc;
  TapExpr *AppendingExpr;

  // Set by Sema:
  OpaqueValueExpr *interpolationExpr = nullptr;
  ConcreteDeclRef builderInit;
  Expr *interpolationCountExpr = nullptr;
  Expr *literalCapacityExpr = nullptr;

public:
  InterpolatedStringLiteralExpr(SourceLoc Loc,
                                unsigned LiteralCapacity,
                                unsigned InterpolationCount,
                                TapExpr *AppendingExpr)
      : LiteralExpr(ExprKind::InterpolatedStringLiteral, /*Implicit=*/false),
        Loc(Loc),
        AppendingExpr(AppendingExpr) {
    Bits.InterpolatedStringLiteralExpr.InterpolationCount = InterpolationCount;
    Bits.InterpolatedStringLiteralExpr.LiteralCapacity = LiteralCapacity;
  }

  // Sets the constructor for the interpolation type.
  void setBuilderInit(ConcreteDeclRef decl) { builderInit = decl; }
  ConcreteDeclRef getBuilderInit() const { return builderInit; }

  /// Sets the OpaqueValueExpr that is passed into AppendingExpr as the SubExpr
  /// that the tap operates on.
  void setInterpolationExpr(OpaqueValueExpr *expr) { interpolationExpr = expr; }
  OpaqueValueExpr *getInterpolationExpr() const { return interpolationExpr; }

  /// Store a builtin integer literal expr wrapping getInterpolationCount().
  /// This is an arg to builderInit.
  void setInterpolationCountExpr(Expr *expr) { interpolationCountExpr = expr; }
  Expr *getInterpolationCountExpr() const { return interpolationCountExpr; }

  /// Store a builtin integer literal expr wrapping getLiteralCapacity().
  /// This is an arg to builderInit.
  void setLiteralCapacityExpr(Expr *expr) { literalCapacityExpr = expr; }
  Expr *getLiteralCapacityExpr() const { return literalCapacityExpr; }

  /// Retrieve the value of the literalCapacity parameter to the
  /// initializer.
  unsigned getLiteralCapacity() const {
    return Bits.InterpolatedStringLiteralExpr.LiteralCapacity;
  }

  /// Retrieve the value of the interpolationCount parameter to the
  /// initializer.
  unsigned getInterpolationCount() const {
    return Bits.InterpolatedStringLiteralExpr.InterpolationCount;
  }

  /// A block containing expressions which call
  /// \c StringInterpolationProtocol methods to append segments to the
  /// string interpolation. The first node in \c Body should be an uninitialized
  /// \c VarDecl; the other statements should append to it.
  TapExpr * getAppendingExpr() const { return AppendingExpr; }
  void setAppendingExpr(TapExpr * AE) { AppendingExpr = AE; }
  
  SourceLoc getStartLoc() const {
    return Loc;
  }
  SourceLoc getEndLoc() const {
    // SourceLocs are token based, and the interpolated string is one string
    // token, so the range should be (Start == End).
    return Loc;
  }
  
  /// Call the \c callback with information about each segment in turn.
  void forEachSegment(ASTContext &Ctx,
                      llvm::function_ref<void(bool, CallExpr *)> callback);
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::InterpolatedStringLiteral;
  }
};

/// The opaque kind of a RegexLiteralExpr feature, which should only be
/// interpreted by the compiler's regex parsing library.
class RegexLiteralPatternFeatureKind final {
  unsigned RawValue;

public:
  RegexLiteralPatternFeatureKind(unsigned rawValue) : RawValue(rawValue) {}

  unsigned getRawValue() const { return RawValue; }

  AvailabilityRange getAvailability(ASTContext &ctx) const;
  StringRef getDescription(ASTContext &ctx) const;

  friend llvm::hash_code
  hash_value(const RegexLiteralPatternFeatureKind &kind) {
    return llvm::hash_value(kind.getRawValue());
  }

  friend bool operator==(const RegexLiteralPatternFeatureKind &lhs,
                         const RegexLiteralPatternFeatureKind &rhs) {
    return lhs.getRawValue() == rhs.getRawValue();
  }

  friend bool operator!=(const RegexLiteralPatternFeatureKind &lhs,
                         const RegexLiteralPatternFeatureKind &rhs) {
    return !(lhs == rhs);
  }
};

/// A specific feature used in a RegexLiteralExpr, needed for availability
/// diagnostics.
class RegexLiteralPatternFeature final {
  RegexLiteralPatternFeatureKind Kind;
  CharSourceRange Range;

public:
  RegexLiteralPatternFeature(RegexLiteralPatternFeatureKind kind,
                             CharSourceRange range)
      : Kind(kind), Range(range) {}

  RegexLiteralPatternFeatureKind getKind() const { return Kind; }
  CharSourceRange getRange() const { return Range; }
};

/// A regular expression literal e.g '(a|c)*'.
class RegexLiteralExpr : public LiteralExpr {
  ASTContext *Ctx;
  SourceLoc Loc;
  StringRef ParsedRegexText;

  RegexLiteralExpr(ASTContext *ctx, SourceLoc loc, StringRef parsedRegexText,
                   bool isImplicit)
      : LiteralExpr(ExprKind::RegexLiteral, isImplicit), Ctx(ctx), Loc(loc),
        ParsedRegexText(parsedRegexText) {}

public:
  static RegexLiteralExpr *createParsed(ASTContext &ctx, SourceLoc loc,
                                        StringRef regexText);

  ASTContext &getASTContext() const { return *Ctx; }

  /// Retrieve the raw parsed regex text.
  StringRef getParsedRegexText() const { return ParsedRegexText; }

  /// Retrieve the regex pattern to emit.
  StringRef getRegexToEmit() const;

  /// Retrieve the computed type for the regex.
  Type getRegexType() const;

  /// Retrieve the version of the regex string.
  unsigned getVersion() const;

  /// Retrieve any features used in the regex pattern.
  ArrayRef<RegexLiteralPatternFeature> getPatternFeatures() const;

  SourceRange getSourceRange() const { return Loc; }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::RegexLiteral;
  }
};

/// MagicIdentifierLiteralExpr - A magic identifier like #file which expands
/// out to a literal at SILGen time.
class MagicIdentifierLiteralExpr : public BuiltinLiteralExpr {
public:
  enum Kind : unsigned {
#define MAGIC_IDENTIFIER(NAME, STRING, SYNTAX_KIND) NAME,
#include "swift/AST/MagicIdentifierKinds.def"
  };

  static StringRef getKindString(MagicIdentifierLiteralExpr::Kind value) {
    switch (value) {
#define MAGIC_IDENTIFIER(NAME, STRING, SYNTAX_KIND) case NAME: return STRING;
#include "swift/AST/MagicIdentifierKinds.def"
    }

    llvm_unreachable("Unhandled MagicIdentifierLiteralExpr in getKindString.");
  }

private:
  SourceLoc Loc;

public:
  MagicIdentifierLiteralExpr(Kind kind, SourceLoc loc, bool implicit = false)
      : BuiltinLiteralExpr(ExprKind::MagicIdentifierLiteral, implicit),
        Loc(loc) {
    Bits.MagicIdentifierLiteralExpr.Kind = static_cast<unsigned>(kind);
    Bits.MagicIdentifierLiteralExpr.StringEncoding
      = static_cast<unsigned>(StringLiteralExpr::UTF8);
  }

  Kind getKind() const {
    return static_cast<Kind>(Bits.MagicIdentifierLiteralExpr.Kind);
  }

  bool isString() const {
    switch (getKind()) {
#define MAGIC_STRING_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \
    case NAME: \
      return true;
#define MAGIC_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \
    case NAME: \
      return false;
#include "swift/AST/MagicIdentifierKinds.def"
    }
    llvm_unreachable("bad Kind");
  }

  SourceRange getSourceRange() const { return Loc; }

  // For a magic identifier that produces a string literal, retrieve the
  // encoding for that string literal.
  StringLiteralExpr::Encoding getStringEncoding() const {
    assert(isString() && "Magic identifier literal has non-string encoding");
    return static_cast<StringLiteralExpr::Encoding>(
             Bits.MagicIdentifierLiteralExpr.StringEncoding);
  }

  // For a magic identifier that produces a string literal, set the encoding
  // for the string literal.
  void setStringEncoding(StringLiteralExpr::Encoding encoding) {
    assert(isString() && "Magic identifier literal has non-string encoding");
    Bits.MagicIdentifierLiteralExpr.StringEncoding
      = static_cast<unsigned>(encoding);
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::MagicIdentifierLiteral;
  }
};

// ObjectLiteralExpr - An expression of the form
// '#colorLiteral(red: 1, blue: 0, green: 0, alpha: 1)' with a name and a list
// argument. The components of the list argument are meant to be themselves
// constant.
class ObjectLiteralExpr final : public LiteralExpr {
public:
  /// The kind of object literal.
  enum LiteralKind : unsigned {
#define POUND_OBJECT_LITERAL(Name, Desc, Proto) Name,
#include "swift/AST/TokenKinds.def"
  };

  static StringRef
  getLiteralKindPlainName(ObjectLiteralExpr::LiteralKind kind);

private:
  ArgumentList *ArgList;
  SourceLoc PoundLoc;

  ObjectLiteralExpr(SourceLoc poundLoc, LiteralKind litKind, ArgumentList *args,
                    bool implicit);

public:
  /// Create a new object literal expression.
  static ObjectLiteralExpr *create(ASTContext &ctx, SourceLoc poundLoc,
                                   LiteralKind kind, ArgumentList *args,
                                   bool implicit);

  LiteralKind getLiteralKind() const {
    return static_cast<LiteralKind>(Bits.ObjectLiteralExpr.LitKind);
  }

  ArgumentList *getArgs() const { return ArgList; }
  void setArgs(ArgumentList *newArgs) { ArgList = newArgs; }

  SourceLoc getSourceLoc() const { return PoundLoc; }
  SourceRange getSourceRange() const {
    return SourceRange(PoundLoc, ArgList->getEndLoc());
  }

  /// Return the string form of the literal name.
  StringRef getLiteralKindRawName() const;

  StringRef getLiteralKindPlainName() const;

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::ObjectLiteral;
  }
};

/// DiscardAssignmentExpr - A '_' in the left-hand side of an assignment, which
/// discards the corresponding tuple element on the right-hand side.
class DiscardAssignmentExpr : public Expr {
  SourceLoc Loc;

public:
  DiscardAssignmentExpr(SourceLoc Loc, bool Implicit)
    : Expr(ExprKind::DiscardAssignment, Implicit), Loc(Loc) {}
  
  SourceRange getSourceRange() const { return Loc; }
  SourceLoc getLoc() const { return Loc; }
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::DiscardAssignment;
  }
};

/// DeclRefExpr - A reference to a value, "x".
class DeclRefExpr : public Expr {
  /// The declaration pointer.
  ConcreteDeclRef D;
  DeclNameLoc Loc;
  ActorIsolation implicitActorHopTarget;

  /// Destination information for a thrown error, which includes any
  /// necessary conversions from the actual type thrown to the type that
  /// is expected by the enclosing context.
  ThrownErrorDestination ThrowDest;

public:
  DeclRefExpr(ConcreteDeclRef D, DeclNameLoc Loc, bool Implicit,
              AccessSemantics semantics = AccessSemantics::Ordinary,
              Type Ty = Type())
    : Expr(ExprKind::DeclRef, Implicit, Ty), D(D), Loc(Loc),
      implicitActorHopTarget(ActorIsolation::forUnspecified()) {
    Bits.DeclRefExpr.Semantics = (unsigned)semantics;
    Bits.DeclRefExpr.IsImplicitlyAsync = false;
    Bits.DeclRefExpr.IsImplicitlyThrows = false;
    setFunctionRefInfo(FunctionRefInfo::unapplied(Loc));
  }

  /// Retrieve the declaration to which this expression refers.
  ValueDecl *getDecl() const {
    return getDeclRef().getDecl();
  }

  /// Return true if this access is direct, meaning that it does not call the
  /// getter or setter.
  AccessSemantics getAccessSemantics() const {
    return (AccessSemantics) Bits.DeclRefExpr.Semantics;
  }

  /// Determine whether this reference needs to happen asynchronously, i.e.,
  /// guarded by hop_to_executor, and if so describe the target.
  std::optional<ActorIsolation> isImplicitlyAsync() const {
    if (!Bits.DeclRefExpr.IsImplicitlyAsync)
      return std::nullopt;

    return implicitActorHopTarget;
  }

  /// Note that this reference is implicitly async and set the target.
  void setImplicitlyAsync(ActorIsolation target) {
    Bits.DeclRefExpr.IsImplicitlyAsync = true;
    implicitActorHopTarget = target;
  }

  /// Determine whether this reference needs may implicitly throw.
  ///
  /// This is the case for non-throwing `distributed func` declarations,
  /// which are cross-actor invoked, because such calls actually go over the
  /// transport/network, and may throw from this, rather than the function
  /// implementation itself..
  bool isImplicitlyThrows() const {
    return Bits.DeclRefExpr.IsImplicitlyThrows;
  }

  /// The error thrown from this access.
  ThrownErrorDestination throws() const { return ThrowDest; }

  void setThrows(ThrownErrorDestination throws) {
    assert(!ThrowDest);
    ThrowDest = throws;
  }

  /// Set whether this reference must account for a `throw` occurring for reasons
  /// other than the function implementation itself throwing, e.g. an
  /// `DistributedActorSystem` implementing a `distributed func` call throwing a
  /// networking error.
  void setImplicitlyThrows(bool isImplicitlyThrows) {
    Bits.DeclRefExpr.IsImplicitlyThrows = isImplicitlyThrows;
  }

  /// Retrieve the concrete declaration reference.
  ConcreteDeclRef getDeclRef() const {
    return D;
  }

  SourceRange getSourceRange() const { return Loc.getSourceRange(); }
  SourceLoc getLoc() const { return Loc.getBaseNameLoc(); }
  DeclNameLoc getNameLoc() const { return Loc; }

  /// Retrieve the kind of function reference.
  FunctionRefInfo getFunctionRefInfo() const {
    return FunctionRefInfo::fromOpaque(Bits.DeclRefExpr.FunctionRefInfo);
  }

  /// Set the kind of function reference.
  void setFunctionRefInfo(FunctionRefInfo refKind) {
    Bits.DeclRefExpr.FunctionRefInfo = refKind.getOpaqueValue();
    ASSERT(refKind == getFunctionRefInfo() && "FunctionRefInfo truncated");
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::DeclRef;
  }
};
  
/// A reference to 'super'. References to members of 'super' resolve to members
/// of a superclass of 'self'.
class SuperRefExpr : public Expr {
  VarDecl *Self;
  SourceLoc Loc;
  
public:
  SuperRefExpr(VarDecl *Self, SourceLoc Loc, bool Implicit,
               Type SuperTy = Type())
    : Expr(ExprKind::SuperRef, Implicit, SuperTy), Self(Self), Loc(Loc) {}
  
  VarDecl *getSelf() const { return Self; }
  void setSelf(VarDecl *self) { Self = self; }
  
  SourceLoc getSuperLoc() const { return Loc; }
  SourceRange getSourceRange() const { return Loc; }
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::SuperRef;
  }
};

/// A reference to a type in expression context.
///
/// The type of this expression is always \c MetatypeType.
class TypeExpr : public Expr {
  TypeRepr *Repr;
public:
  /// Create a \c TypeExpr from a parsed \c TypeRepr.
  TypeExpr(TypeRepr *Ty);

  /// Retrieves the corresponding instance type of the type referenced by this
  /// expression.
  ///
  /// If this node has no type, the resulting instance type is also the
  /// null \c Type(). If the type of this node is not a \c MetatypeType, the
  /// resulting instance type is \c ErrorType.
  Type getInstanceType() const;

public:
  /// Create an implicit \c TypeExpr.
  ///
  /// The given type is required to be non-null and must be not be
  /// a \c MetatypeType as this function will wrap the given type in one.
  ///
  /// FIXME: This behavior is bizarre.
  static TypeExpr *createImplicit(Type Ty, ASTContext &C);

  /// Create an implicit \c TypeExpr that has artificial
  /// location information attached.
  ///
  /// The given type is required to be non-null and must be not be
  /// a \c MetatypeType as this function will wrap the given type in one.
  ///
  /// FIXME: This behavior is bizarre.
  ///
  /// Due to limitations in the modeling of certain AST elements, implicit
  /// \c TypeExpr nodes are often the only source of location information the
  /// expression checker has when it comes time to diagnose an error.
  static TypeExpr *createImplicitHack(SourceLoc Loc, Type Ty, ASTContext &C);

  /// Create an implicit \c TypeExpr for a given \c TypeDecl at the specified location.
  ///
  /// The given type is required to be non-null and must be not be
  /// a \c MetatypeType as this function will wrap the given type in one.
  ///
  /// FIXME: This behavior is bizarre.
  ///
  /// Unlike the non-implicit case, the given location is not required to be
  /// valid.
  static TypeExpr *createImplicitForDecl(DeclNameLoc Loc, TypeDecl *D,
                                         DeclContext *DC, Type ty);

public:
  /// Create a \c TypeExpr for a given \c TypeDecl at the specified location.
  ///
  /// The given location must be valid. If it is not, you must use
  /// \c TypeExpr::createImplicitForDecl instead.
  static TypeExpr *createForDecl(DeclNameLoc Loc, TypeDecl *D, DeclContext *DC);

  /// Create a TypeExpr for a member TypeDecl of the given parent TypeDecl.
  static TypeExpr *createForMemberDecl(DeclNameLoc ParentNameLoc,
                                       TypeDecl *Parent,
                                       DeclNameLoc NameLoc,
                                       TypeDecl *Decl);

  /// Create a \c TypeExpr for a member \c TypeDecl of the given parent
  /// \c TypeRepr.
  static TypeExpr *createForMemberDecl(TypeRepr *ParentTR, DeclNameLoc NameLoc,
                                       TypeDecl *Decl);

  /// Create a \c TypeExpr from an \c DeclRefTypeRepr with the given arguments
  /// applied at the specified location.
  ///
  /// Returns nullptr if the reference cannot be formed, which is a hack due
  /// to limitations in how we model generic typealiases.
  static TypeExpr *createForSpecializedDecl(DeclRefTypeRepr *ParentTR,
                                            ArrayRef<TypeRepr *> Args,
                                            SourceRange AngleLocs,
                                            ASTContext &C);

  TypeRepr *getTypeRepr() const { return Repr; }
  // NOTE: TypeExpr::getType() returns the type of the expr node, which is the
  // metatype of what is stored as an operand type.
  
  SourceRange getSourceRange() const;
  // TODO: optimize getStartLoc() and getEndLoc() when TypeLoc allows it.

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::Type;
  }
};

class TypeValueExpr : public Expr {
  TypeLoc paramTypeLoc;

public:
  /// Create a \c TypeValueExpr from an underlying parameter \c TypeRepr.
  TypeValueExpr(TypeRepr *paramRepr) :
      Expr(ExprKind::TypeValue, /*implicit*/ false), paramTypeLoc(paramRepr) {}

  /// Create a \c TypeValueExpr for a given \c TypeDecl at the specified
  /// location.
  ///
  /// The given location must be valid. If it is not, you must use
  /// \c TypeExpr::createImplicitForDecl instead.
  static TypeValueExpr *createForDecl(DeclNameLoc Loc, TypeDecl *D,
                                      DeclContext *DC);

  TypeRepr *getParamTypeRepr() const {
    return paramTypeLoc.getTypeRepr();
  }

  /// Retrieves the corresponding parameter type of the value referenced by this
  /// expression.
  ArchetypeType *getParamType() const {
    return paramTypeLoc.getType()->castTo<ArchetypeType>();
  }

  /// Sets the corresponding parameter type of the value referenced by this
  /// expression.
  void setParamType(Type paramType) {
    paramTypeLoc.setType(paramType);
  }

  SourceRange getSourceRange() const {
    return paramTypeLoc.getSourceRange();
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::TypeValue;
  }
};

/// A reference to another initializer from within a constructor body,
/// either to a delegating initializer or to a super.init invocation.
/// For a reference type, this semantically references a different constructor
/// entry point, called the 'initializing constructor', from the 'allocating
/// constructor' entry point referenced by a 'new' expression.
class OtherConstructorDeclRefExpr : public Expr {
  ConcreteDeclRef Ctor;
  DeclNameLoc Loc;
  
public:
  OtherConstructorDeclRefExpr(ConcreteDeclRef Ctor, DeclNameLoc Loc,
                              bool Implicit, Type Ty = {})
    : Expr(ExprKind::OtherConstructorDeclRef, Implicit, Ty),
      Ctor(Ctor), Loc(Loc)
  {}
  
  ConstructorDecl *getDecl() const;
  ConcreteDeclRef getDeclRef() const { return Ctor; }

  SourceLoc getLoc() const { return Loc.getBaseNameLoc(); }
  DeclNameLoc getConstructorLoc() const { return Loc; }
  SourceRange getSourceRange() const { return Loc.getSourceRange(); }
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::OtherConstructorDeclRef;
  }
};

/// OverloadSetRefExpr - A reference to an overloaded set of values with a
/// single name.
///
/// This is an abstract class that covers the various different kinds of
/// overload sets.
class OverloadSetRefExpr : public Expr {
  ArrayRef<ValueDecl*> Decls;

protected:
  OverloadSetRefExpr(ExprKind Kind, ArrayRef<ValueDecl*> decls,
                     FunctionRefInfo functionRefInfo, bool Implicit, Type Ty)
      : Expr(Kind, Implicit, Ty), Decls(decls) {
    setFunctionRefInfo(functionRefInfo);
  }

public:
  ArrayRef<ValueDecl*> getDecls() const { return Decls; }

  void setDecls(ArrayRef<ValueDecl *> domain) {
    Decls = domain;
  }

  /// getBaseType - Determine the type of the base object provided for the
  /// given overload set, which is only non-null when dealing with an overloaded
  /// member reference.
  Type getBaseType() const;

  /// hasBaseObject - Determine whether this overloaded expression has a
  /// concrete base object (which is not a metatype).
  bool hasBaseObject() const;

  /// Retrieve the kind of function reference.
  FunctionRefInfo getFunctionRefInfo() const {
    return FunctionRefInfo::fromOpaque(Bits.OverloadSetRefExpr.FunctionRefInfo);
  }

  /// Set the kind of function reference.
  void setFunctionRefInfo(FunctionRefInfo refKind) {
    Bits.OverloadSetRefExpr.FunctionRefInfo = refKind.getOpaqueValue();
    ASSERT(refKind == getFunctionRefInfo() && "FunctionRefInfo truncated");
  }

  static bool classof(const Expr *E) {
    return E->getKind() >= ExprKind::First_OverloadSetRefExpr &&
           E->getKind() <= ExprKind::Last_OverloadSetRefExpr;
  }
};

/// OverloadedDeclRefExpr - A reference to an overloaded name that should
/// eventually be resolved (by overload resolution) to a value reference.
class OverloadedDeclRefExpr final : public OverloadSetRefExpr {
  DeclNameLoc Loc;

public:
  OverloadedDeclRefExpr(ArrayRef<ValueDecl*> Decls, DeclNameLoc Loc,
                        FunctionRefInfo functionRefInfo,
                        bool Implicit, Type Ty = Type())
      : OverloadSetRefExpr(ExprKind::OverloadedDeclRef, Decls, functionRefInfo,
                           Implicit, Ty),
        Loc(Loc) {
  }
  
  DeclNameLoc getNameLoc() const { return Loc; }
  SourceLoc getLoc() const { return Loc.getBaseNameLoc(); }
  SourceRange getSourceRange() const { return Loc.getSourceRange(); }

  bool isForOperator() const { return getDecls().front()->isOperator(); }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::OverloadedDeclRef;
  }
};

/// UnresolvedDeclRefExpr - This represents use of an undeclared identifier,
/// which may ultimately be a use of something that hasn't been defined yet, it
/// may be a use of something that got imported (which will be resolved during
/// sema), or may just be a use of an unknown identifier.
///
class UnresolvedDeclRefExpr : public Expr {
  DeclNameRef Name;
  DeclNameLoc Loc;

public:
  UnresolvedDeclRefExpr(DeclNameRef name, DeclRefKind refKind, DeclNameLoc loc)
      : Expr(ExprKind::UnresolvedDeclRef, /*Implicit=*/loc.isInvalid()),
        Name(name), Loc(loc) {
    Bits.UnresolvedDeclRefExpr.DeclRefKind = static_cast<unsigned>(refKind);
    setFunctionRefInfo(FunctionRefInfo::unapplied(loc));
  }

  static UnresolvedDeclRefExpr *createImplicit(
      ASTContext &C, DeclName name,
      DeclRefKind refKind = DeclRefKind::Ordinary) {
    return new (C) UnresolvedDeclRefExpr(DeclNameRef(name), refKind,
                                         DeclNameLoc());
  }

  static UnresolvedDeclRefExpr *createImplicit(
      ASTContext &C, DeclBaseName baseName, ArrayRef<Identifier> argLabels) {
    return UnresolvedDeclRefExpr::createImplicit(C,
        DeclName(C, baseName, argLabels));
  }

  static UnresolvedDeclRefExpr *createImplicit(
      ASTContext &C, DeclBaseName baseName, ParameterList *paramList) {
    return UnresolvedDeclRefExpr::createImplicit(C,
        DeclName(C, baseName, paramList));
  }

  bool hasName() const { return static_cast<bool>(Name); }
  DeclNameRef getName() const { return Name; }

  DeclRefKind getRefKind() const {
    return static_cast<DeclRefKind>(Bits.UnresolvedDeclRefExpr.DeclRefKind);
  }

  /// Retrieve the kind of function reference.
  FunctionRefInfo getFunctionRefInfo() const {
    return FunctionRefInfo::fromOpaque(
        Bits.UnresolvedDeclRefExpr.FunctionRefInfo);
  }

  /// Set the kind of function reference.
  void setFunctionRefInfo(FunctionRefInfo refKind) {
    Bits.UnresolvedDeclRefExpr.FunctionRefInfo = refKind.getOpaqueValue();
    ASSERT(refKind == getFunctionRefInfo() && "FunctionRefInfo truncated");
  }

  DeclNameLoc getNameLoc() const { return Loc; }

  SourceRange getSourceRange() const { return Loc.getSourceRange(); }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::UnresolvedDeclRef;
  }
};

/// LookupExpr - This abstract class represents 'a.b', 'a[]', etc where we
/// are referring to a member of a type, such as a property, variable, etc.
class LookupExpr : public Expr {
  Expr *Base;
  ConcreteDeclRef Member;
  ActorIsolation implicitActorHopTarget;

protected:
  explicit LookupExpr(ExprKind Kind, Expr *base, ConcreteDeclRef member,
                          bool Implicit)
      : Expr(Kind, Implicit), Base(base), Member(member),
        implicitActorHopTarget(ActorIsolation::forUnspecified()) {
    Bits.LookupExpr.IsSuper = false;
    Bits.LookupExpr.IsImplicitlyAsync = false;
    Bits.LookupExpr.IsImplicitlyThrows = false;
    assert(Base);
  }

  /// Destination information for a thrown error, which includes any
  /// necessary conversions from the actual type thrown to the type that
  /// is expected by the enclosing context.
  ThrownErrorDestination ThrowDest;

public:
  /// Retrieve the base of the expression.
  Expr *getBase() const { return Base; }

  /// Replace the base of the expression.
  void setBase(Expr *E) { Base = E; }

  /// Retrieve the member to which this access refers.
  ConcreteDeclRef getMember() const { return Member; }

  /// Determine whether the operation has a known underlying declaration or not.
  bool hasDecl() const { return static_cast<bool>(Member); }

  /// Retrieve the declaration that this /// operation refers to.
  /// Only valid when \c hasDecl() is true.
  ConcreteDeclRef getDecl() const {
    assert(hasDecl() && "No subscript declaration known!");
    return getMember();
  }

  /// Determine whether this reference refers to the superclass's property.
  bool isSuper() const { return Bits.LookupExpr.IsSuper; }

  /// Set whether this reference refers to the superclass's property.
  void setIsSuper(bool isSuper) { Bits.LookupExpr.IsSuper = isSuper; }

  /// Determine whether this reference needs to happen asynchronously, i.e.,
  /// guarded by hop_to_executor, and if so describe the target.
  std::optional<ActorIsolation> isImplicitlyAsync() const {
    if (!Bits.LookupExpr.IsImplicitlyAsync)
      return std::nullopt;

    return implicitActorHopTarget;
  }

  /// Note that this reference is implicitly async and set the target.
  void setImplicitlyAsync(ActorIsolation target) {
    Bits.LookupExpr.IsImplicitlyAsync = true;
    implicitActorHopTarget = target;
  }

  /// The error thrown from this access.
  ThrownErrorDestination throws() const { return ThrowDest; }

  void setThrows(ThrownErrorDestination throws) {
    assert(!ThrowDest);
    ThrowDest = throws;
  }

  /// Determine whether this reference needs may implicitly throw.
  ///
  /// This is the case for non-throwing `distributed func` declarations,
  /// which are cross-actor invoked, because such calls actually go over the
  /// transport/network, and may throw from this, rather than the function
  /// implementation itself..
  bool isImplicitlyThrows() const { return Bits.LookupExpr.IsImplicitlyThrows; }

  /// Set whether this reference must account for a `throw` occurring for reasons
  /// other than the function implementation itself throwing, e.g. an
  /// `DistributedActorSystem` implementing a `distributed func` call throwing a
  /// networking error.
  void setImplicitlyThrows(bool isImplicitlyThrows) {
    Bits.LookupExpr.IsImplicitlyThrows = isImplicitlyThrows;
  }

  static bool classof(const Expr *E) {
    return E->getKind() >= ExprKind::First_LookupExpr &&
           E->getKind() <= ExprKind::Last_LookupExpr;
  }
};

/// MemberRefExpr - This represents 'a.b' where we are referring to a member
/// of a type, such as a property or variable.
///
/// Note that methods found via 'dot' syntax are expressed as DotSyntaxCallExpr
/// nodes, because 'a.f' is actually an application of 'a' (the implicit object
/// argument) to the function 'f'.
class MemberRefExpr : public LookupExpr {
  SourceLoc DotLoc;
  DeclNameLoc NameLoc;
  
public:
  MemberRefExpr(Expr *base, SourceLoc dotLoc, ConcreteDeclRef member,
                DeclNameLoc loc, bool Implicit,
                AccessSemantics semantics = AccessSemantics::Ordinary);
  SourceLoc getDotLoc() const { return DotLoc; }
  DeclNameLoc getNameLoc() const { return NameLoc; }
  
  /// Return true if this member access is direct, meaning that it
  /// does not call the getter or setter.
  AccessSemantics getAccessSemantics() const {
    return (AccessSemantics) Bits.MemberRefExpr.Semantics;
  }

  /// Informs IRGen to that this member should be applied via its distributed
  /// thunk, rather than invoking it directly.
  ///
  /// Only intended to be set on distributed get-only computed properties.
  void setAccessViaDistributedThunk() {
    Bits.MemberRefExpr.Semantics = (unsigned)AccessSemantics::DistributedThunk;
  }

  SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); }
  SourceLoc getStartLoc() const {
    SourceLoc BaseStartLoc = getBase()->getStartLoc();
    if (BaseStartLoc.isInvalid() || NameLoc.isInvalid()) {
      return NameLoc.getBaseNameLoc();
    } else {
      return BaseStartLoc;
    }
  }
  SourceLoc getEndLoc() const {
    return NameLoc.getSourceRange().End;
  }
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::MemberRef;
  }
};
  
/// Common base for expressions that involve dynamic lookup, which
/// determines at runtime whether a particular method, property, or
/// subscript is available.
class DynamicLookupExpr : public LookupExpr {
protected:
  explicit DynamicLookupExpr(ExprKind kind, ConcreteDeclRef member, Expr *base)
    : LookupExpr(kind, base, member, /*Implicit=*/false) { }

public:
  static bool classof(const Expr *E) {
    return E->getKind() >= ExprKind::First_DynamicLookupExpr &&
           E->getKind() <= ExprKind::Last_DynamicLookupExpr;
  }
};

/// A reference to a member of an object that was found via dynamic lookup.
///
/// A member found via dynamic lookup may not actually be available at runtime.
/// Therefore, a reference to that member always returns an optional instance.
/// Users can then propagate the optional (via ?) or assert that the member is
/// always available (via !). For example:
///
/// \code
/// class C {
///   func @objc foo(i : Int) -> String { ... }
/// };
///
/// var x : AnyObject = <some value>
/// print(x.foo!(17)) // x.foo has type ((i : Int) -> String)?
/// \endcode
class DynamicMemberRefExpr : public DynamicLookupExpr {
  SourceLoc DotLoc;
  DeclNameLoc NameLoc;

public:
  DynamicMemberRefExpr(Expr *base, SourceLoc dotLoc,
                       ConcreteDeclRef member,
                       DeclNameLoc nameLoc)
    : DynamicLookupExpr(ExprKind::DynamicMemberRef, member, base),
      DotLoc(dotLoc), NameLoc(nameLoc) {
    }

  /// Retrieve the location of the member name.
  DeclNameLoc getNameLoc() const { return NameLoc; }

  /// Retrieve the location of the '.'.
  SourceLoc getDotLoc() const { return DotLoc; }

  SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); }

  SourceLoc getStartLoc() const {
    SourceLoc BaseStartLoc = getBase()->getStartLoc();
    if (BaseStartLoc.isInvalid() || NameLoc.isInvalid()) {
      return NameLoc.getBaseNameLoc();
    } else {
      return BaseStartLoc;
    }
  }
  SourceLoc getEndLoc() const { return NameLoc.getSourceRange().End; }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::DynamicMemberRef;
  }
};

/// A subscript on an object with dynamic lookup type.
///
/// A subscript found via dynamic lookup may not actually be available
/// at runtime.  Therefore, the result of performing the subscript
/// operation always returns an optional instance.Users can then
/// propagate the optional (via ?) or assert that the member is always
/// available (via !). For example:
///
/// \code
/// class C {
///   @objc subscript (i : Int) -> String {
///     get {
///       ...
///     }
///   }
/// };
///
/// var x : AnyObject = <some value>
/// print(x[27]! // x[27] has type String?
/// \endcode
class DynamicSubscriptExpr final : public DynamicLookupExpr {
  ArgumentList *ArgList;

  DynamicSubscriptExpr(Expr *base, ArgumentList *argList,
                       ConcreteDeclRef member, bool implicit);

public:
  static DynamicSubscriptExpr *create(ASTContext &ctx, Expr *base,
                                      ArgumentList *argList,
                                      ConcreteDeclRef member, bool implicit);

  ArgumentList *getArgs() const { return ArgList; }
  void setArgs(ArgumentList *newArgs) { ArgList = newArgs; }

  SourceLoc getLoc() const { return getArgs()->getStartLoc(); }

  SourceLoc getStartLoc() const { return getBase()->getStartLoc(); }
  SourceLoc getEndLoc() const { return getArgs()->getEndLoc(); }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::DynamicSubscript;
  }
};

/// UnresolvedMemberExpr - This represents '.foo', an unresolved reference to a
/// member, which is to be resolved with context sensitive type information into
/// bar.foo.  These always have unresolved type.
class UnresolvedMemberExpr final
    : public Expr {
  SourceLoc DotLoc;
  DeclNameLoc NameLoc;
  DeclNameRef Name;

public:
  UnresolvedMemberExpr(SourceLoc dotLoc, DeclNameLoc nameLoc, DeclNameRef name,
                       bool implicit)
    : Expr(ExprKind::UnresolvedMember, implicit), DotLoc(dotLoc),
      NameLoc(nameLoc), Name(name) {
    setFunctionRefInfo(FunctionRefInfo::unapplied(nameLoc));
  }

  DeclNameRef getName() const { return Name; }
  DeclNameLoc getNameLoc() const { return NameLoc; }
  SourceLoc getDotLoc() const { return DotLoc; }

  SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); }

  SourceLoc getStartLoc() const { return DotLoc; }
  SourceLoc getEndLoc() const { return NameLoc.getSourceRange().End; }

  /// Retrieve the kind of function reference.
  FunctionRefInfo getFunctionRefInfo() const {
    return FunctionRefInfo::fromOpaque(
        Bits.UnresolvedMemberExpr.FunctionRefInfo);
  }

  /// Set the kind of function reference.
  void setFunctionRefInfo(FunctionRefInfo refKind) {
    Bits.UnresolvedMemberExpr.FunctionRefInfo = refKind.getOpaqueValue();
    ASSERT(refKind == getFunctionRefInfo() && "FunctionRefInfo truncated");
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::UnresolvedMember;
  }
};

/// AnyTryExpr - An abstract superclass for 'try' and 'try!'.
///
/// These are like IdentityExpr in some ways, but they're a bit too
/// semantic differentiated to just always look through.
class AnyTryExpr : public Expr {
  Expr *SubExpr;
  SourceLoc TryLoc;

public:
  AnyTryExpr(ExprKind kind, SourceLoc tryLoc, Expr *sub,
             Type type, bool implicit)
    : Expr(kind, implicit, type), SubExpr(sub), TryLoc(tryLoc) {}

  SourceLoc getLoc() const { return SubExpr->getLoc(); }
  Expr *getSubExpr() const { return SubExpr; }
  void setSubExpr(Expr *E) { SubExpr = E; }

  SourceLoc getTryLoc() const { return TryLoc; }

  SourceLoc getStartLoc() const { return TryLoc; }
  SourceLoc getEndLoc() const { return getSubExpr()->getEndLoc(); }

  static bool classof(const Expr *e) {
    return e->getKind() >= ExprKind::First_AnyTryExpr
        && e->getKind() <= ExprKind::Last_AnyTryExpr;
  }
};

/// TryExpr - A 'try' surrounding an expression, marking that the
/// expression contains code which might throw.
///
/// getSemanticsProvidingExpr() looks through this because it doesn't
/// provide the value and only very specific clients care where the
/// 'try' was written.
class TryExpr : public AnyTryExpr {
public:
  TryExpr(SourceLoc tryLoc, Expr *sub, Type type = Type(),
          bool implicit = false)
    : AnyTryExpr(ExprKind::Try, tryLoc, sub, type, implicit) {}

  static bool classof(const Expr *e) {
    return e->getKind() == ExprKind::Try;
  }

  static TryExpr *createImplicit(ASTContext &ctx, SourceLoc tryLoc, Expr *sub,
                                 Type type = Type()) {
    return new (ctx) TryExpr(tryLoc, sub, type, /*implicit=*/true);
  }
};

/// ForceTryExpr - A 'try!' surrounding an expression, marking that
/// the expression contains code which might throw, but that the code
/// should dynamically assert if it does.
class ForceTryExpr final : public AnyTryExpr {
  SourceLoc ExclaimLoc;
  Type thrownError;

public:
  ForceTryExpr(SourceLoc tryLoc, Expr *sub, SourceLoc exclaimLoc,
               Type type = Type(), bool implicit = false)
    : AnyTryExpr(ExprKind::ForceTry, tryLoc, sub, type, implicit),
      ExclaimLoc(exclaimLoc) {}

  SourceLoc getExclaimLoc() const { return ExclaimLoc; }

  /// Retrieve the type of the error thrown from the subexpression.
  Type getThrownError() const { return thrownError; }

  /// Set the type of the error thrown from the subexpression.
  void setThrownError(Type type) {
    assert(!thrownError || thrownError->isEqual(type));
    thrownError = type;
  }

  static bool classof(const Expr *e) {
    return e->getKind() == ExprKind::ForceTry;
  }
};

/// A 'try?' surrounding an expression, marking that the expression contains
/// code which might throw, and that the result should be injected into an
/// Optional. If the code does throw, \c nil is produced.
class OptionalTryExpr final : public AnyTryExpr {
  SourceLoc QuestionLoc;
  Type thrownError;

public:
  OptionalTryExpr(SourceLoc tryLoc, Expr *sub, SourceLoc questionLoc,
                  Type type = Type(), bool implicit = false)
    : AnyTryExpr(ExprKind::OptionalTry, tryLoc, sub, type, implicit),
      QuestionLoc(questionLoc) {}

  SourceLoc getQuestionLoc() const { return QuestionLoc; }

  /// Retrieve the type of the error thrown from the subexpression.
  Type getThrownError() const { return thrownError; }

  /// Set the type of the error thrown from the subexpression.
  void setThrownError(Type type) {
    assert(!thrownError || thrownError->isEqual(type));
    thrownError = type;
  }

  static bool classof(const Expr *e) {
    return e->getKind() == ExprKind::OptionalTry;
  }
};

/// An expression node that does not affect the evaluation of its subexpression.
class IdentityExpr : public Expr {
  Expr *SubExpr;
public:
  IdentityExpr(ExprKind kind,
               Expr *subExpr, Type ty = Type(),
               bool implicit = false)
    : Expr(kind, implicit, ty), SubExpr(subExpr)
  {}
  
  SourceLoc getLoc() const { return SubExpr->getLoc(); }
  Expr *getSubExpr() const { return SubExpr; }
  void setSubExpr(Expr *E) { SubExpr = E; }
  
  static bool classof(const Expr *E) {
    return E->getKind() >= ExprKind::First_IdentityExpr
        && E->getKind() <= ExprKind::Last_IdentityExpr;
  }
};
  
/// The '.self' pseudo-property, which has no effect except to
/// satisfy the syntactic requirement that type values appear only as part of
/// a property chain.
class DotSelfExpr : public IdentityExpr {
  SourceLoc DotLoc;
  SourceLoc SelfLoc;
  
public:
  DotSelfExpr(Expr *subExpr, SourceLoc dot, SourceLoc self,
              Type ty = Type())
    : IdentityExpr(ExprKind::DotSelf, subExpr, ty),
      DotLoc(dot), SelfLoc(self)
  {}
  
  SourceLoc getDotLoc() const { return DotLoc; }
  SourceLoc getSelfLoc() const { return SelfLoc; }

  SourceLoc getStartLoc() const { return getSubExpr()->getStartLoc(); }
  SourceLoc getEndLoc() const { return SelfLoc; }
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::DotSelf;
  }
};
  
/// A parenthesized expression like '(x+x)'.  Syntactically,
/// this is just a TupleExpr with exactly one element that has no label.
/// Semantically, however, it serves only as grouping parentheses and
/// does not form an expression of tuple type (unless the sub-expression
/// has tuple type, of course).
class ParenExpr : public IdentityExpr {
  SourceLoc LParenLoc, RParenLoc;
  
public:
  ParenExpr(SourceLoc lploc, Expr *subExpr, SourceLoc rploc, Type ty = Type())
      : IdentityExpr(ExprKind::Paren, subExpr, ty), LParenLoc(lploc),
        RParenLoc(rploc) {
    assert(lploc.isValid() == rploc.isValid() &&
           "Mismatched source location information");
  }

  SourceLoc getLParenLoc() const { return LParenLoc; }
  SourceLoc getRParenLoc() const { return RParenLoc; }

  // When the locations of the parens are invalid, ask our
  // subexpression for its source range instead.  This isn't a
  // hot path and so we don't both optimizing for it.

  SourceLoc getStartLoc() const {
    return (LParenLoc.isInvalid() ? getSubExpr()->getStartLoc() : LParenLoc);
  }
  SourceLoc getEndLoc() const {
    if (RParenLoc.isInvalid())
      return getSubExpr()->getEndLoc();
    return RParenLoc;
  }

  static bool classof(const Expr *E) { return E->getKind() == ExprKind::Paren; }
};

/// Represents the result of a chain of accesses or calls hanging off of an
/// \c UnresolvedMemberExpr at the root. This is only used during type checking
/// to give the result type of such a chain representation in the AST. This
/// expression type is always implicit.
class UnresolvedMemberChainResultExpr : public IdentityExpr {
  /// The base of this chain of member accesses.
  UnresolvedMemberExpr *ChainBase;
public:
  UnresolvedMemberChainResultExpr(Expr *subExpr, UnresolvedMemberExpr *base,
                                  Type ty = Type())
    : IdentityExpr(ExprKind::UnresolvedMemberChainResult, subExpr, ty,
                   /*isImplicit=*/true),
      ChainBase(base) {
    assert(base);
  }

  UnresolvedMemberExpr *getChainBase() const { return ChainBase; }

  SWIFT_FORWARD_SOURCE_LOCS_TO(getSubExpr())

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::UnresolvedMemberChainResult;
  }
};
  
/// AwaitExpr - An 'await' surrounding an expression, marking that the
/// expression contains code which is a coroutine that may block.
///
/// getSemanticsProvidingExpr() looks through this because it doesn't
/// provide the value and only very specific clients care where the
/// 'await' was written.
class AwaitExpr final : public IdentityExpr {
  SourceLoc AwaitLoc;
public:
  AwaitExpr(SourceLoc awaitLoc, Expr *sub, Type type = Type(),
            bool implicit = false)
    : IdentityExpr(ExprKind::Await, sub, type, implicit), AwaitLoc(awaitLoc) {
  }

  static AwaitExpr *createImplicit(ASTContext &ctx, SourceLoc awaitLoc, Expr *sub, Type type = Type()) {
    return new (ctx) AwaitExpr(awaitLoc, sub, type, /*implicit=*/true);
  }

  SourceLoc getLoc() const { return AwaitLoc; }
  
  SourceLoc getAwaitLoc() const { return AwaitLoc; }
  SourceLoc getStartLoc() const { return AwaitLoc; }
  SourceLoc getEndLoc() const { return getSubExpr()->getEndLoc(); }

  static bool classof(const Expr *e) {
    return e->getKind() == ExprKind::Await;
  }
};

/// UnsafeExpr - An 'unsafe' surrounding an expression, marking that the
/// expression contains uses of unsafe declarations.
///
/// getSemanticsProvidingExpr() looks through this because it doesn't
/// provide the value and only very specific clients care where the
/// 'unsafe' was written.
class UnsafeExpr final : public IdentityExpr {
  SourceLoc UnsafeLoc;
public:
  UnsafeExpr(SourceLoc unsafeLoc, Expr *sub, Type type = Type(),
            bool implicit = false)
    : IdentityExpr(ExprKind::Unsafe, sub, type, implicit),
      UnsafeLoc(unsafeLoc) {
  }

  static UnsafeExpr *createImplicit(ASTContext &ctx, SourceLoc unsafeLoc, Expr *sub, Type type = Type()) {
    return new (ctx) UnsafeExpr(unsafeLoc, sub, type, /*implicit=*/true);
  }

  SourceLoc getLoc() const { return UnsafeLoc; }

  SourceLoc getUnsafeLoc() const { return UnsafeLoc; }
  SourceLoc getStartLoc() const { return UnsafeLoc; }
  SourceLoc getEndLoc() const { return getSubExpr()->getEndLoc(); }

  static bool classof(const Expr *e) {
    return e->getKind() == ExprKind::Unsafe;
  }
};

/// ConsumeExpr - A 'consume' surrounding an lvalue expression marking the
/// lvalue as needing to be moved.
class ConsumeExpr final : public Expr {
  Expr *SubExpr;
  SourceLoc ConsumeLoc;

public:
  ConsumeExpr(SourceLoc consumeLoc, Expr *sub, Type type = Type(),
              bool implicit = false)
      : Expr(ExprKind::Consume, implicit, type), SubExpr(sub),
        ConsumeLoc(consumeLoc) {}

  static ConsumeExpr *createImplicit(ASTContext &ctx, SourceLoc moveLoc,
                                     Expr *sub, Type type = Type()) {
    return new (ctx) ConsumeExpr(moveLoc, sub, type, /*implicit=*/true);
  }

  SourceLoc getLoc() const { return ConsumeLoc; }

  Expr *getSubExpr() const { return SubExpr; }
  void setSubExpr(Expr *E) { SubExpr = E; }

  SourceLoc getStartLoc() const { return getLoc(); }
  SourceLoc getEndLoc() const { return getSubExpr()->getEndLoc(); }

  static bool classof(const Expr *e) {
    return e->getKind() == ExprKind::Consume;
  }
};

/// CopyExpr - A 'copy' surrounding an lvalue expression marking the lvalue as
/// needing a semantic copy. Used to force a copy of a no implicit copy type.
class CopyExpr final : public Expr {
  Expr *SubExpr;
  SourceLoc CopyLoc;

public:
  CopyExpr(SourceLoc copyLoc, Expr *sub, Type type = Type(),
           bool implicit = false)
      : Expr(ExprKind::Copy, implicit, type), SubExpr(sub), CopyLoc(copyLoc) {}

  static CopyExpr *createImplicit(ASTContext &ctx, SourceLoc copyLoc, Expr *sub,
                                  Type type = Type()) {
    return new (ctx) CopyExpr(copyLoc, sub, type, /*implicit=*/true);
  }

  SourceLoc getLoc() const { return CopyLoc; }

  Expr *getSubExpr() const { return SubExpr; }
  void setSubExpr(Expr *E) { SubExpr = E; }

  SourceLoc getStartLoc() const { return CopyLoc; }
  SourceLoc getEndLoc() const { return getSubExpr()->getEndLoc(); }

  static bool classof(const Expr *e) { return e->getKind() == ExprKind::Copy; }
};

/// BorrowExpr - A 'borrow' surrounding an lvalue/accessor expression at an
/// apply site marking the lvalue/accessor as being borrowed when passed to the
/// callee.
///
/// getSemanticsProvidingExpr() looks through this because it doesn't
/// provide the value and only very specific clients care where the
/// 'borrow' was written.
class BorrowExpr final : public IdentityExpr {
  SourceLoc BorrowLoc;

public:
  BorrowExpr(SourceLoc borrowLoc, Expr *sub, Type type = Type(),
             bool implicit = false)
      : IdentityExpr(ExprKind::Borrow, sub, type, implicit),
        BorrowLoc(borrowLoc) {}

  static BorrowExpr *createImplicit(ASTContext &ctx, SourceLoc borrowLoc,
                                    Expr *sub, Type type = Type()) {
    return new (ctx) BorrowExpr(borrowLoc, sub, type, /*implicit=*/true);
  }

  SourceLoc getLoc() const { return BorrowLoc; }

  SourceLoc getStartLoc() const { return BorrowLoc; }
  SourceLoc getEndLoc() const { return getSubExpr()->getEndLoc(); }

  static bool classof(const Expr *e) {
    return e->getKind() == ExprKind::Borrow;
  }
};

/// TupleExpr - Parenthesized expressions like '(a: x+x)' and '(x, y, 4)'. Note
/// that expressions like '(4)' are represented with a ParenExpr.
class TupleExpr final : public Expr,
    private llvm::TrailingObjects<TupleExpr, Expr *, Identifier, SourceLoc> {
  friend TrailingObjects;

  SourceLoc LParenLoc;
  SourceLoc RParenLoc;

  size_t numTrailingObjects(OverloadToken<Expr *>) const {
    return getNumElements();
  }
  size_t numTrailingObjects(OverloadToken<Identifier>) const {
    return hasElementNames() ? getNumElements() : 0;
  }
  size_t numTrailingObjects(OverloadToken<SourceLoc>) const {
    return hasElementNames() ? getNumElements() : 0;
  }

  /// Retrieve the buffer containing the element names.
  MutableArrayRef<Identifier> getElementNamesBuffer() {
    if (!hasElementNames())
      return { };

    return { getTrailingObjects<Identifier>(), getNumElements() };
  }

  /// Retrieve the buffer containing the element name locations.
  MutableArrayRef<SourceLoc> getElementNameLocsBuffer() {
    if (!hasElementNameLocs())
      return { };
    
    return { getTrailingObjects<SourceLoc>(), getNumElements() };
  }

  TupleExpr(SourceLoc LParenLoc, SourceLoc RParenLoc,
            ArrayRef<Expr *> SubExprs, ArrayRef<Identifier> ElementNames,
            ArrayRef<SourceLoc> ElementNameLocs, bool Implicit, Type Ty);

public:
  /// Create a tuple.
  static TupleExpr *create(ASTContext &ctx,
                           SourceLoc LParenLoc, 
                           ArrayRef<Expr *> SubExprs,
                           ArrayRef<Identifier> ElementNames, 
                           ArrayRef<SourceLoc> ElementNameLocs,
                           SourceLoc RParenLoc, bool Implicit,
                           Type Ty = Type());

  /// Create an empty tuple.
  static TupleExpr *createEmpty(ASTContext &ctx, SourceLoc LParenLoc, 
                                SourceLoc RParenLoc, bool Implicit);

  /// Create an implicit tuple with no source information.
  static TupleExpr *createImplicit(ASTContext &ctx, ArrayRef<Expr *> SubExprs,
                                   ArrayRef<Identifier> ElementNames);

  SourceLoc getLParenLoc() const { return LParenLoc; }
  SourceLoc getRParenLoc() const { return RParenLoc; }

  SourceRange getSourceRange() const;

  /// Retrieve the elements of this tuple.
  MutableArrayRef<Expr*> getElements() {
    return { getTrailingObjects<Expr *>(), getNumElements() };
  }

  /// Retrieve the elements of this tuple.
  ArrayRef<Expr*> getElements() const {
    return { getTrailingObjects<Expr *>(), getNumElements() };
  }

  unsigned getNumElements() const { return Bits.TupleExpr.NumElements; }

  Expr *getElement(unsigned i) const {
    return getElements()[i];
  }
  void setElement(unsigned i, Expr *e) {
    getElements()[i] = e;
  }

  /// Whether this tuple has element names.
  bool hasElementNames() const { 
    return Bits.TupleExpr.HasElementNames;
  }

  /// Retrieve the element names for a tuple.
  ArrayRef<Identifier> getElementNames() const { 
    return const_cast<TupleExpr *>(this)->getElementNamesBuffer();
  }
  
  /// Retrieve the ith element name.
  Identifier getElementName(unsigned i) const {
    return hasElementNames() ? getElementNames()[i] : Identifier();
  }
  
  /// Whether this tuple has element name locations.
  bool hasElementNameLocs() const { 
    return Bits.TupleExpr.HasElementNameLocations;
  }

  /// Retrieve the locations of the element names for a tuple.
  ArrayRef<SourceLoc> getElementNameLocs() const {
    return const_cast<TupleExpr *>(this)->getElementNameLocsBuffer();
  }

  /// Retrieve the location of the ith label, if known.
  SourceLoc getElementNameLoc(unsigned i) const {
    if (hasElementNameLocs())
      return getElementNameLocs()[i];
    
    return SourceLoc();
  }

  static bool classof(const Expr *E) { return E->getKind() == ExprKind::Tuple; }
};

/// A collection literal expression.
///
/// The subexpression is represented as a TupleExpr or ParenExpr and
/// passed on to the appropriate semantics-providing conversion
/// operation.
class CollectionExpr : public Expr {
  SourceLoc LBracketLoc;
  SourceLoc RBracketLoc;
  ConcreteDeclRef Initializer;

  /// Retrieve the intrusive pointer storage from the subtype
  Expr *const *getTrailingObjectsPointer() const;
  Expr **getTrailingObjectsPointer() {
    const CollectionExpr *temp = this;
    return const_cast<Expr**>(temp->getTrailingObjectsPointer());
  }

  /// Retrieve the intrusive pointer storage from the subtype
  const SourceLoc *getTrailingSourceLocs() const;
  SourceLoc *getTrailingSourceLocs() {
    const CollectionExpr *temp = this;
    return const_cast<SourceLoc*>(temp->getTrailingSourceLocs());
  }

protected:
  CollectionExpr(ExprKind Kind, SourceLoc LBracketLoc,
                 ArrayRef<Expr*> Elements, ArrayRef<SourceLoc> CommaLocs,
                 SourceLoc RBracketLoc, Type Ty)
    : Expr(Kind, /*Implicit=*/false, Ty),
      LBracketLoc(LBracketLoc), RBracketLoc(RBracketLoc) {
    Bits.CollectionExpr.IsTypeDefaulted = false;
    Bits.CollectionExpr.NumSubExprs = Elements.size();
    Bits.CollectionExpr.NumCommas = CommaLocs.size();
    assert(Bits.CollectionExpr.NumCommas == CommaLocs.size() && "Truncation");
    std::uninitialized_copy(Elements.begin(), Elements.end(),
                            getTrailingObjectsPointer());
    std::uninitialized_copy(CommaLocs.begin(), CommaLocs.end(),
                            getTrailingSourceLocs());
  }

public:

  /// Retrieve the elements stored in the collection.
  ArrayRef<Expr *> getElements() const {
    return {getTrailingObjectsPointer(), Bits.CollectionExpr.NumSubExprs};
  }
  MutableArrayRef<Expr *> getElements() {
    return {getTrailingObjectsPointer(), Bits.CollectionExpr.NumSubExprs};
  }
  Expr *getElement(unsigned i) const { return getElements()[i]; }
  void setElement(unsigned i, Expr *E) { getElements()[i] = E; }
  unsigned getNumElements() const { return Bits.CollectionExpr.NumSubExprs; }

  /// Retrieve the comma source locations stored in the collection. Please note
  /// that trailing commas are currently allowed, and that invalid code may have
  /// stray or missing commas.
  MutableArrayRef<SourceLoc> getCommaLocs() {
    return {getTrailingSourceLocs(), static_cast<size_t>(Bits.CollectionExpr.NumCommas)};
  }
  ArrayRef<SourceLoc> getCommaLocs() const {
    return {getTrailingSourceLocs(), static_cast<size_t>(Bits.CollectionExpr.NumCommas)};
  }
  unsigned getNumCommas() const { return Bits.CollectionExpr.NumCommas; }

  bool isTypeDefaulted() const { return Bits.CollectionExpr.IsTypeDefaulted; }
  void setIsTypeDefaulted(bool value = true) {
    Bits.CollectionExpr.IsTypeDefaulted = value;
  }

  SourceLoc getLBracketLoc() const { return LBracketLoc; }
  SourceLoc getRBracketLoc() const { return RBracketLoc; }
  SourceRange getSourceRange() const {
    return SourceRange(LBracketLoc, RBracketLoc);
  }

  static bool classof(const Expr *e) {
    return e->getKind() >= ExprKind::First_CollectionExpr &&
           e->getKind() <= ExprKind::Last_CollectionExpr;
  }

  /// Retrieve the initializer that will be used to construct the 'array'
  /// literal from the result of the initializer.
  ConcreteDeclRef getInitializer() const { return Initializer; }

  /// Set the initializer that will be used to construct the 'array' literal.
  void setInitializer(ConcreteDeclRef initializer) {
    Initializer = initializer;
  }
};
 
/// An array literal expression [a, b, c].
class ArrayExpr final : public CollectionExpr,
    private llvm::TrailingObjects<ArrayExpr, Expr*, SourceLoc> {
  friend TrailingObjects;
  friend CollectionExpr;

  size_t numTrailingObjects(OverloadToken<Expr *>) const {
    return getNumElements();
  }
  size_t numTrailingObjects(OverloadToken<SourceLoc>) const {
    return getNumCommas();
  }

  ArrayExpr(SourceLoc LBracketLoc, ArrayRef<Expr*> Elements,
            ArrayRef<SourceLoc> CommaLocs,
            SourceLoc RBracketLoc, Type Ty)
  : CollectionExpr(ExprKind::Array, LBracketLoc, Elements, CommaLocs,
                   RBracketLoc, Ty) { }
public:
  static ArrayExpr *create(ASTContext &C, SourceLoc LBracketLoc,
                           ArrayRef<Expr*> Elements,
                           ArrayRef<SourceLoc> CommaLocs,
                           SourceLoc RBracketLoc,
                           Type Ty = Type());

  static bool classof(const Expr *e) {
    return e->getKind() == ExprKind::Array;
  }

  Type getElementType();
};

/// A dictionary literal expression [a : x, b : y, c : z].
class DictionaryExpr final : public CollectionExpr,
    private llvm::TrailingObjects<DictionaryExpr, Expr*, SourceLoc> {
  friend TrailingObjects;
  friend CollectionExpr;

  size_t numTrailingObjects(OverloadToken<Expr *>) const {
    return getNumElements();
  }
  size_t numTrailingObjects(OverloadToken<SourceLoc>) const {
    return getNumCommas();
  }

  DictionaryExpr(SourceLoc LBracketLoc, ArrayRef<Expr*> Elements,
                 ArrayRef<SourceLoc> CommaLocs,
                 SourceLoc RBracketLoc, Type Ty)
    : CollectionExpr(ExprKind::Dictionary, LBracketLoc, Elements, CommaLocs,
                     RBracketLoc, Ty) { }
public:

  static DictionaryExpr *create(ASTContext &C, SourceLoc LBracketLoc,
                                ArrayRef<Expr*> Elements,
                                ArrayRef<SourceLoc> CommaLocs,
                                SourceLoc RBracketLoc,
                                Type Ty = Type());

  static bool classof(const Expr *e) {
    return e->getKind() == ExprKind::Dictionary;
  }

  Type getElementType();
};

/// Subscripting expressions like a[i] that refer to an element within a
/// container.
///
/// There is no built-in subscripting in the language. Rather, a fully
/// type-checked and well-formed subscript expression refers to a subscript
/// declaration, which provides a getter and (optionally) a setter that will
/// be used to perform reads/writes.
class SubscriptExpr final : public LookupExpr {
  ArgumentList *ArgList;

  SubscriptExpr(Expr *base, ArgumentList *argList, ConcreteDeclRef decl,
                bool implicit, AccessSemantics semantics);

public:
  /// Create a new subscript.
  static SubscriptExpr *
  create(ASTContext &ctx, Expr *base, ArgumentList *argList,
         ConcreteDeclRef decl = ConcreteDeclRef(), bool implicit = false,
         AccessSemantics semantics = AccessSemantics::Ordinary);

  ArgumentList *getArgs() const { return ArgList; }
  void setArgs(ArgumentList *newArgs) { ArgList = newArgs; }

  /// Determine whether this subscript reference should bypass the
  /// ordinary accessors.
  AccessSemantics getAccessSemantics() const {
    return (AccessSemantics) Bits.SubscriptExpr.Semantics;
  }

  SourceLoc getLoc() const { return getArgs()->getStartLoc(); }
  SourceLoc getStartLoc() const { return getBase()->getStartLoc(); }
  SourceLoc getEndLoc() const {
    auto end = getArgs()->getEndLoc();
    return end.isValid() ? end : getBase()->getEndLoc();
  }
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::Subscript;
  }
};

/// Subscripting expression that applies a keypath to a base.
class KeyPathApplicationExpr : public Expr {
  Expr *Base;
  Expr *KeyPath;
  SourceLoc LBracketLoc, RBracketLoc;
  
public:
  KeyPathApplicationExpr(Expr *base, SourceLoc lBracket, Expr *keyPath,
                         SourceLoc rBracket, Type ty, bool implicit)
    : Expr(ExprKind::KeyPathApplication, implicit, ty),
      Base(base), KeyPath(keyPath), LBracketLoc(lBracket), RBracketLoc(rBracket)
  {}
  
  SourceLoc getLoc() const { return LBracketLoc; }
  SourceLoc getStartLoc() const { return Base->getStartLoc(); }
  SourceLoc getEndLoc() const { return RBracketLoc; }
  
  Expr *getBase() const { return Base; }
  void setBase(Expr *E) { Base = E; }
  Expr *getKeyPath() const { return KeyPath; }
  void setKeyPath(Expr *E) { KeyPath = E; }
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::KeyPathApplication;
  }
};

/// A member access (foo.bar) on an expression with unresolved type.
class UnresolvedDotExpr : public Expr {
  Expr *SubExpr;
  SourceLoc DotLoc;
  DeclNameLoc NameLoc;
  DeclNameRef Name;
  ArrayRef<ValueDecl *> OuterAlternatives;

public:
  UnresolvedDotExpr(
      Expr *subexpr, SourceLoc dotloc, DeclNameRef name, DeclNameLoc nameloc,
      bool Implicit,
      ArrayRef<ValueDecl *> outerAlternatives = ArrayRef<ValueDecl *>())
      : Expr(ExprKind::UnresolvedDot, Implicit), SubExpr(subexpr),
        DotLoc(dotloc), NameLoc(nameloc), Name(name),
        OuterAlternatives(outerAlternatives) {
    setFunctionRefInfo(FunctionRefInfo::unapplied(nameloc));
  }

  static UnresolvedDotExpr *createImplicit(
      ASTContext &C, Expr *base, DeclName name) {
    return new (C) UnresolvedDotExpr(base, SourceLoc(),
                                     DeclNameRef(name), DeclNameLoc(),
                                     /*implicit=*/true);
  }

  static UnresolvedDotExpr *createImplicit(
      ASTContext &C, Expr *base,
      DeclBaseName baseName, ArrayRef<Identifier> argLabels) {
    return UnresolvedDotExpr::createImplicit(C, base,
                                             DeclName(C, baseName, argLabels));
  }

  static UnresolvedDotExpr *createImplicit(
      ASTContext &C, Expr *base,
      DeclBaseName baseName, ParameterList *paramList) {
    return UnresolvedDotExpr::createImplicit(C, base,
                                             DeclName(C, baseName, paramList));
  }

  SourceLoc getLoc() const {
    if (NameLoc.isValid())
      return NameLoc.getBaseNameLoc();
    else if (DotLoc.isValid())
      return DotLoc;
    else
      return SubExpr->getEndLoc();
  }

  SourceLoc getStartLoc() const {
    auto SubLoc = SubExpr->getStartLoc();
    if (SubLoc.isValid())
      return SubLoc;
    else if (DotLoc.isValid())
      return DotLoc;
    else
      return NameLoc.getSourceRange().Start;
  }
  SourceLoc getEndLoc() const {
    if (NameLoc.isValid())
      return NameLoc.getSourceRange().End;
    else if (DotLoc.isValid())
      return DotLoc;
    else
      return SubExpr->getEndLoc();
  }

  SourceLoc getDotLoc() const { return DotLoc; }
  Expr *getBase() const { return SubExpr; }
  void setBase(Expr *e) { SubExpr = e; }

  DeclNameRef getName() const { return Name; }
  DeclNameLoc getNameLoc() const { return NameLoc; }

  ArrayRef<ValueDecl *> getOuterAlternatives() const {
    return OuterAlternatives;
  }

  /// Retrieve the kind of function reference.
  FunctionRefInfo getFunctionRefInfo() const {
    return FunctionRefInfo::fromOpaque(Bits.UnresolvedDotExpr.FunctionRefInfo);
  }

  /// Set the kind of function reference.
  void setFunctionRefInfo(FunctionRefInfo refKind) {
    Bits.UnresolvedDotExpr.FunctionRefInfo = refKind.getOpaqueValue();
    ASSERT(refKind == getFunctionRefInfo() && "FunctionRefInfo truncated");
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::UnresolvedDot;
  }
};

/// TupleElementExpr - Refer to an element of a tuple,
/// e.g. "(1,field:2).field".
class TupleElementExpr : public Expr {
  Expr *SubExpr;
  SourceLoc NameLoc;
  SourceLoc DotLoc;

public:
  TupleElementExpr(Expr *SubExpr, SourceLoc DotLoc, unsigned FieldNo,
                   SourceLoc NameLoc, Type Ty)
    : Expr(ExprKind::TupleElement, /*Implicit=*/false, Ty), SubExpr(SubExpr),
      NameLoc(NameLoc), DotLoc(DotLoc) {
    Bits.TupleElementExpr.FieldNo = FieldNo;
  }

  SourceLoc getLoc() const { return NameLoc; }
  Expr *getBase() const { return SubExpr; }
  void setBase(Expr *e) { SubExpr = e; }

  unsigned getFieldNumber() const { return Bits.TupleElementExpr.FieldNo; }
  SourceLoc getNameLoc() const { return NameLoc; }  
  SourceLoc getDotLoc() const { return DotLoc; }
  
  SourceLoc getStartLoc() const { return getBase()->getStartLoc(); }
  SourceLoc getEndLoc() const { return getNameLoc(); }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::TupleElement;
  }
};

/// Describes a monadic bind from T? to T.
///
/// In a ?-chain expression, this is the part that's spelled with a
/// postfix ?.
///
/// A BindOptionalExpr must always appear within a
/// OptionalEvaluationExpr.  If the operand of the BindOptionalExpr
/// evaluates to a missing value, the OptionalEvaluationExpr
/// immediately completes and produces a missing value in the result
/// type.
///
/// The depth of the BindOptionalExpr indicates which
/// OptionalEvaluationExpr is completed, in case the BindOptionalExpr
/// is contained within more than one such expression.
class BindOptionalExpr : public Expr {
  Expr *SubExpr;
  SourceLoc QuestionLoc;

public:
  BindOptionalExpr(Expr *subExpr, SourceLoc questionLoc,
                   unsigned depth, Type ty = Type())
    : Expr(ExprKind::BindOptional, /*Implicit=*/ questionLoc.isInvalid(), ty),
      SubExpr(subExpr), QuestionLoc(questionLoc) {
    Bits.BindOptionalExpr.Depth = depth;
    assert(Bits.BindOptionalExpr.Depth == depth && "bitfield truncation");
  }

  SourceRange getSourceRange() const {
    if (QuestionLoc.isInvalid())
      return SubExpr->getSourceRange();
    return SourceRange(SubExpr->getStartLoc(), QuestionLoc);
  }
  SourceLoc getStartLoc() const {
    return SubExpr->getStartLoc();
  }
  SourceLoc getEndLoc() const {
    return (QuestionLoc.isInvalid() ? SubExpr->getEndLoc() : QuestionLoc);
  }
  SourceLoc getLoc() const { 
    if (isImplicit())
      return SubExpr->getLoc();

    return getQuestionLoc(); 
  }
  SourceLoc getQuestionLoc() const { return QuestionLoc; }

  unsigned getDepth() const { return Bits.BindOptionalExpr.Depth; }
  void setDepth(unsigned depth) {
    Bits.BindOptionalExpr.Depth = depth;
  }

  Expr *getSubExpr() const { return SubExpr; }
  void setSubExpr(Expr *expr) { SubExpr = expr; }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::BindOptional;
  }
};

/// Describes the outer limits of an operation containing
/// monadic binds of T? to T.
///
/// In a ?-chain expression, this is implicitly formed at the outer
/// limits of the chain.  For example, in (foo?.bar?().baz).fred,
/// this is nested immediately within the parens.
///
/// This expression will always have optional type.
class OptionalEvaluationExpr : public Expr {
  Expr *SubExpr;

public:
  OptionalEvaluationExpr(Expr *subExpr, Type ty = Type())
    : Expr(ExprKind::OptionalEvaluation, /*Implicit=*/ true, ty),
      SubExpr(subExpr) {}

  SWIFT_FORWARD_SOURCE_LOCS_TO(SubExpr)

  Expr *getSubExpr() const { return SubExpr; }
  void setSubExpr(Expr *expr) { SubExpr = expr; }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::OptionalEvaluation;
  }
};

/// An expression that forces an optional to its underlying value.
///
/// \code
/// func parseInt(s : String) -> Int? { ... }
///
/// var maybeInt = parseInt("5")     // returns an Int?
/// var forcedInt = parseInt("5")!   // returns an Int; fails on empty optional
/// \endcode
///
class ForceValueExpr : public Expr {
  Expr *SubExpr;
  SourceLoc ExclaimLoc;

public:
  ForceValueExpr(Expr *subExpr, SourceLoc exclaimLoc, bool forcedIUO = false)
    : Expr(ExprKind::ForceValue, /*Implicit=*/exclaimLoc.isInvalid(), Type()),
      SubExpr(subExpr), ExclaimLoc(exclaimLoc) {
    Bits.ForceValueExpr.ForcedIUO = forcedIUO;
  }

  SourceRange getSourceRange() const {
    if (ExclaimLoc.isInvalid())
      return SubExpr->getSourceRange();

    return SourceRange(SubExpr->getStartLoc(), ExclaimLoc);
  }
  SourceLoc getStartLoc() const {
    return SubExpr->getStartLoc();
  }
  SourceLoc getEndLoc() const {
    return (isImplicit() ? SubExpr->getEndLoc() : getExclaimLoc());
  }
  SourceLoc getLoc() const {
    if (!isImplicit())
      return getExclaimLoc();
    
    return SubExpr->getLoc();
  }
  SourceLoc getExclaimLoc() const { return ExclaimLoc; }

  Expr *getSubExpr() const { return SubExpr; }
  void setSubExpr(Expr *expr) { SubExpr = expr; }

  bool isForceOfImplicitlyUnwrappedOptional() const {
    return Bits.ForceValueExpr.ForcedIUO;
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::ForceValue;
  }
};

/// An expression that grants temporary escapability to a nonescaping
/// closure value.
///
/// This expression is formed by the type checker when a call to the
/// `withoutActuallyEscaping` declaration is made.
class MakeTemporarilyEscapableExpr : public Expr {
  Expr *NonescapingClosureValue;
  OpaqueValueExpr *EscapingClosureValue;
  Expr *SubExpr;
  SourceLoc NameLoc, LParenLoc, RParenLoc;
  Expr *OriginalExpr;

public:
  MakeTemporarilyEscapableExpr(SourceLoc NameLoc,
                               SourceLoc LParenLoc,
                               Expr *NonescapingClosureValue,
                               Expr *SubExpr,
                               SourceLoc RParenLoc,
                               OpaqueValueExpr *OpaqueValueForEscapingClosure,
                               Expr *OriginalExpr,
                               bool implicit = false)
    : Expr(ExprKind::MakeTemporarilyEscapable, implicit, Type()),
      NonescapingClosureValue(NonescapingClosureValue),
      EscapingClosureValue(OpaqueValueForEscapingClosure),
      SubExpr(SubExpr),
      NameLoc(NameLoc), LParenLoc(LParenLoc), RParenLoc(RParenLoc),
      OriginalExpr(OriginalExpr)
  {}
  
  SourceLoc getStartLoc() const {
    return NameLoc;
  }
  SourceLoc getEndLoc() const {
    return RParenLoc;
  }
  
  SourceLoc getLoc() const {
    return NameLoc;
  }
  
  /// Retrieve the opaque value representing the escapable copy of the
  /// closure.
  OpaqueValueExpr *getOpaqueValue() const { return EscapingClosureValue; }
  
  /// Retrieve the nonescaping closure expression.
  Expr *getNonescapingClosureValue() const {
    return NonescapingClosureValue;
  }
  void setNonescapingClosureValue(Expr *e) {
    NonescapingClosureValue = e;
  }
  
  /// Retrieve the subexpression that has access to the escapable copy of the
  /// closure.
  Expr *getSubExpr() const {
    return SubExpr;
  }
  void setSubExpr(Expr *e) {
    SubExpr = e;
  }

  /// Retrieve the original 'withoutActuallyEscaping(closure) { ... }'
  //  expression.
  Expr *getOriginalExpr() const {
    return OriginalExpr;
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::MakeTemporarilyEscapable;
  }
};

/// An expression that opens up a value of protocol or protocol
/// composition type and gives a name to its dynamic type.
///
/// This expression is implicitly created by the type checker when
/// calling a method on a protocol. In the future, this may become an
/// actual operation within the language.
class OpenExistentialExpr : public Expr {
  Expr *ExistentialValue;
  OpaqueValueExpr *OpaqueValue;
  Expr *SubExpr;
  SourceLoc ExclaimLoc;

public:
  OpenExistentialExpr(Expr *existentialValue,
                      OpaqueValueExpr *opaqueValue,
                      Expr *subExpr,
                      Type subExprTy)
    : Expr(ExprKind::OpenExistential, /*Implicit=*/ true, subExprTy),
      ExistentialValue(existentialValue), OpaqueValue(opaqueValue), 
      SubExpr(subExpr) { }

  SWIFT_FORWARD_SOURCE_LOCS_TO(SubExpr)

  /// Retrieve the expression that is being evaluated using the
  /// archetype value.
  ///
  /// This subexpression (and no other) may refer to the archetype
  /// type or the opaque value that stores the archetype's value.
  Expr *getSubExpr() const { return SubExpr; }

  /// Set the subexpression that is being evaluated.
  void setSubExpr(Expr *expr) { SubExpr = expr; }

  /// Retrieve the existential value that is being opened.
  Expr *getExistentialValue() const { return ExistentialValue; }

  /// Set the existential val ue that is being opened.
  void setExistentialValue(Expr *expr) { ExistentialValue = expr; }

  /// Retrieve the opaque value representing the value (of archetype
  /// type) stored in the existential.
  OpaqueValueExpr *getOpaqueValue() const { return OpaqueValue; }

  /// Retrieve the opened archetype, which can only be referenced
  /// within this expression's subexpression.
  OpenedArchetypeType *getOpenedArchetype() const;

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::OpenExistential;
  }
};

/// ImplicitConversionExpr - An abstract class for expressions which
/// implicitly convert the value of an expression in some way.
class ImplicitConversionExpr : public Expr {
  Expr *SubExpr;

protected:
  ImplicitConversionExpr(ExprKind kind, Expr *subExpr, Type ty)
    : Expr(kind, /*Implicit=*/true, ty), SubExpr(subExpr) {}

public:
  SWIFT_FORWARD_SOURCE_LOCS_TO(SubExpr)

  Expr *getSubExpr() const { return SubExpr; }
  void setSubExpr(Expr *e) { SubExpr = e; }

  Expr *getSyntacticSubExpr() const {
    if (auto *ICE = dyn_cast<ImplicitConversionExpr>(SubExpr))
      return ICE->getSyntacticSubExpr();
    return SubExpr;
  }

  static bool classof(const Expr *E) {
    return E->getKind() >= ExprKind::First_ImplicitConversionExpr &&
           E->getKind() <= ExprKind::Last_ImplicitConversionExpr;
  }
};

/// The implicit conversion from a class metatype to AnyObject.
class ClassMetatypeToObjectExpr : public ImplicitConversionExpr {
public:
  ClassMetatypeToObjectExpr(Expr *subExpr, Type ty)
    : ImplicitConversionExpr(ExprKind::ClassMetatypeToObject, subExpr, ty) {}
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::ClassMetatypeToObject;
  }
};

/// The implicit conversion from a class existential metatype to AnyObject.
class ExistentialMetatypeToObjectExpr : public ImplicitConversionExpr {
public:
  ExistentialMetatypeToObjectExpr(Expr *subExpr, Type ty)
    : ImplicitConversionExpr(ExprKind::ExistentialMetatypeToObject, subExpr, ty) {}
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::ExistentialMetatypeToObject;
  }
};
  
/// The implicit conversion from a protocol value metatype to ObjC's Protocol
/// class type.
class ProtocolMetatypeToObjectExpr : public ImplicitConversionExpr {
public:
  ProtocolMetatypeToObjectExpr(Expr *subExpr, Type ty)
    : ImplicitConversionExpr(ExprKind::ProtocolMetatypeToObject, subExpr, ty) {}
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::ProtocolMetatypeToObject;
  }
};
  
/// InjectIntoOptionalExpr - The implicit conversion from T to T?.
class InjectIntoOptionalExpr : public ImplicitConversionExpr {
public:
  InjectIntoOptionalExpr(Expr *subExpr, Type ty)
    : ImplicitConversionExpr(ExprKind::InjectIntoOptional, subExpr, ty) {}

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::InjectIntoOptional;
  }
};
  
/// Convert the address of an inout property to a pointer.
class InOutToPointerExpr : public ImplicitConversionExpr {
public:
  InOutToPointerExpr(Expr *subExpr, Type ty)
      : ImplicitConversionExpr(ExprKind::InOutToPointer, subExpr, ty) {
    Bits.InOutToPointerExpr.IsNonAccessing = false;
  }

  /// Is this conversion "non-accessing"?  That is, is it only using the
  /// pointer for its identity, as opposed to actually accessing the memory?
  bool isNonAccessing() const {
    return Bits.InOutToPointerExpr.IsNonAccessing;
  }
  void setNonAccessing(bool nonAccessing = true) {
    Bits.InOutToPointerExpr.IsNonAccessing = nonAccessing;
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::InOutToPointer;
  }
};
  
/// Convert the address of an array to a pointer.
class ArrayToPointerExpr : public ImplicitConversionExpr {
public:
  ArrayToPointerExpr(Expr *subExpr, Type ty)
      : ImplicitConversionExpr(ExprKind::ArrayToPointer, subExpr, ty) {
    Bits.ArrayToPointerExpr.IsNonAccessing = false;
  }
  
  /// Is this conversion "non-accessing"?  That is, is it only using the
  /// pointer for its identity, as opposed to actually accessing the memory?
  bool isNonAccessing() const {
    return Bits.ArrayToPointerExpr.IsNonAccessing;
  }
  void setNonAccessing(bool nonAccessing = true) {
    Bits.ArrayToPointerExpr.IsNonAccessing = nonAccessing;
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::ArrayToPointer;
  }
};
  
/// Convert the a string to a pointer referencing its encoded representation.
class StringToPointerExpr : public ImplicitConversionExpr {
public:
  StringToPointerExpr(Expr *subExpr, Type ty)
    : ImplicitConversionExpr(ExprKind::StringToPointer, subExpr, ty) {}
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::StringToPointer;
  }
};
  
/// Convert a pointer to a different kind of pointer.
class PointerToPointerExpr : public ImplicitConversionExpr {
public:
  PointerToPointerExpr(Expr *subExpr, Type ty)
    : ImplicitConversionExpr(ExprKind::PointerToPointer, subExpr, ty) {}
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::PointerToPointer;
  }
};

/// Convert between a foreign object and its corresponding Objective-C object.
class ForeignObjectConversionExpr : public ImplicitConversionExpr {
public:
  ForeignObjectConversionExpr(Expr *subExpr, Type ty)
    : ImplicitConversionExpr(ExprKind::ForeignObjectConversion, subExpr, ty) {}
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::ForeignObjectConversion;
  }
};

/// Construct an unevaluated instance of the underlying metatype.
class UnevaluatedInstanceExpr : public ImplicitConversionExpr {
public:
  UnevaluatedInstanceExpr(Expr *subExpr, Type ty)
    : ImplicitConversionExpr(ExprKind::UnevaluatedInstance, subExpr, ty) {}

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::UnevaluatedInstance;
  }
};

class DifferentiableFunctionExpr : public ImplicitConversionExpr {
public:
  DifferentiableFunctionExpr(Expr *subExpr, Type ty)
      : ImplicitConversionExpr(ExprKind::DifferentiableFunction, subExpr, ty) {}

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::DifferentiableFunction;
  }
};

class LinearFunctionExpr : public ImplicitConversionExpr {
public:
  LinearFunctionExpr(Expr *subExpr, Type ty)
      : ImplicitConversionExpr(ExprKind::LinearFunction, subExpr, ty) {}

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::LinearFunction;
  }
};

class DifferentiableFunctionExtractOriginalExpr
    : public ImplicitConversionExpr {
public:
  DifferentiableFunctionExtractOriginalExpr(Expr *subExpr, Type ty)
      : ImplicitConversionExpr(ExprKind::DifferentiableFunctionExtractOriginal,
                               subExpr, ty) {}

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::DifferentiableFunctionExtractOriginal;
  }
};

class LinearFunctionExtractOriginalExpr : public ImplicitConversionExpr {
public:
  LinearFunctionExtractOriginalExpr(Expr *subExpr, Type ty)
      : ImplicitConversionExpr(ExprKind::LinearFunctionExtractOriginal,
                               subExpr, ty) {}

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::LinearFunctionExtractOriginal;
  }
};

class LinearToDifferentiableFunctionExpr : public ImplicitConversionExpr {
public:
  LinearToDifferentiableFunctionExpr(Expr *subExpr, Type ty)
      : ImplicitConversionExpr(
            ExprKind::LinearToDifferentiableFunction, subExpr, ty) {}

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::LinearToDifferentiableFunction;
  }
};

/// Use an opaque type to abstract a value of the underlying concrete type,
/// possibly nested inside other types. E.g. can perform conversions "T --->
/// (opaque type)" and "S<T> ---> S<(opaque type)>".
class UnderlyingToOpaqueExpr : public ImplicitConversionExpr {
public:
  /// The substitutions to be applied to the opaque type declaration to
  /// produce the resulting type.
  const SubstitutionMap substitutions;

  UnderlyingToOpaqueExpr(Expr *subExpr, Type ty, SubstitutionMap substitutions)
    : ImplicitConversionExpr(ExprKind::UnderlyingToOpaque, subExpr, ty),
      substitutions(substitutions) {}
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::UnderlyingToOpaque;
  }
};

/// DestructureTupleExpr - Destructure a tuple value produced by a source
/// expression, binding the elements to OpaqueValueExprs, then evaluate the
/// result expression written in terms of the OpaqueValueExprs.
class DestructureTupleExpr final : public ImplicitConversionExpr,
    private llvm::TrailingObjects<DestructureTupleExpr, OpaqueValueExpr *> {
  friend TrailingObjects;

  size_t numTrailingObjects(OverloadToken<OpaqueValueExpr *>) const {
    return Bits.DestructureTupleExpr.NumElements;
  }

private:
  Expr *DstExpr;

  DestructureTupleExpr(ArrayRef<OpaqueValueExpr *> destructuredElements,
                       Expr *srcExpr, Expr *dstExpr, Type ty)
    : ImplicitConversionExpr(ExprKind::DestructureTuple, srcExpr, ty),
      DstExpr(dstExpr) {
    Bits.DestructureTupleExpr.NumElements = destructuredElements.size();
    std::uninitialized_copy(destructuredElements.begin(),
                            destructuredElements.end(),
                            getTrailingObjects<OpaqueValueExpr *>());
  }

public:
  /// Create a tuple destructuring. The type of srcExpr must be a tuple type,
  /// and the number of elements must equal the size of destructureElements.
  static DestructureTupleExpr *
  create(ASTContext &ctx,
         ArrayRef<OpaqueValueExpr *> destructuredElements,
         Expr *srcExpr, Expr *dstExpr, Type ty);

  ArrayRef<OpaqueValueExpr *> getDestructuredElements() const {
    return {getTrailingObjects<OpaqueValueExpr *>(),
            static_cast<size_t>(Bits.DestructureTupleExpr.NumElements)};
  }

  Expr *getResultExpr() const {
    return DstExpr;
  }

  void setResultExpr(Expr *dstExpr) {
    DstExpr = dstExpr;
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::DestructureTuple;
  }
};

/// LoadExpr - Turn an l-value into an r-value by performing a "load"
/// operation.  This operation may actually be a logical operation,
/// i.e. one implemented using a call to a potentially user-defined
/// function instead of a simple memory transaction.
class LoadExpr : public ImplicitConversionExpr {
public:
  LoadExpr(Expr *subExpr, Type type)
    : ImplicitConversionExpr(ExprKind::Load, subExpr, type) { }

  static bool classof(const Expr *E) { return E->getKind() == ExprKind::Load; }
};

/// ABISafeConversion - models a type conversion on an l-value that has no
/// material affect on the ABI of the type, while *preserving* the l-valueness
/// of the type.
class ABISafeConversionExpr : public ImplicitConversionExpr {
public:
  ABISafeConversionExpr(Expr *subExpr, Type type)
    : ImplicitConversionExpr(ExprKind::ABISafeConversion, subExpr, type) {}

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::ABISafeConversion;
  }
};

/// This is a conversion from an expression of UnresolvedType to an arbitrary
/// other type, and from an arbitrary type to UnresolvedType.  This node does
/// not appear in valid code, only in code involving diagnostics.
class UnresolvedTypeConversionExpr : public ImplicitConversionExpr {
public:
  UnresolvedTypeConversionExpr(Expr *subExpr, Type type)
  : ImplicitConversionExpr(ExprKind::UnresolvedTypeConversion, subExpr, type) {}

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::UnresolvedTypeConversion;
  }
};

/// FunctionConversionExpr - Convert a function to another function type,
/// which might involve renaming the parameters or handling substitutions
/// of subtypes (in the return) or supertypes (in the input).
///
/// FIXME: This should be a CapturingExpr.
class FunctionConversionExpr : public ImplicitConversionExpr {
public:
  FunctionConversionExpr(Expr *subExpr, Type type)
    : ImplicitConversionExpr(ExprKind::FunctionConversion, subExpr, type) {}
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::FunctionConversion;
  }
};

/// Perform a function conversion from one function that to one that has a
/// covariant result type.
///
/// This conversion is technically unsafe; however, semantic analysis will
/// only introduce such a conversion in cases where other language features
/// (i.e., Self returns) enforce static safety. Additionally, this conversion
/// avoids changing the ABI of the function in question.
class CovariantFunctionConversionExpr : public ImplicitConversionExpr {
public:
  CovariantFunctionConversionExpr(Expr *subExpr, Type type)
    : ImplicitConversionExpr(ExprKind::CovariantFunctionConversion, subExpr,
                             type) { }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::CovariantFunctionConversion;
  }
};

/// Perform a conversion from a superclass to a subclass for a call to
/// a method with a covariant result type.
///
/// This conversion is technically unsafe; however, semantic analysis will
/// only introduce such a conversion in cases where other language features
/// (i.e., Self returns) enforce static safety.
class CovariantReturnConversionExpr : public ImplicitConversionExpr {
public:
  CovariantReturnConversionExpr(Expr *subExpr, Type type)
    : ImplicitConversionExpr(ExprKind::CovariantReturnConversion, subExpr,
                             type) { }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::CovariantReturnConversion;
  }
};

/// MetatypeConversionExpr - Convert a metatype to another metatype
/// using essentially a derived-to-base conversion.
class MetatypeConversionExpr : public ImplicitConversionExpr {
public:
  MetatypeConversionExpr(Expr *subExpr, Type type)
    : ImplicitConversionExpr(ExprKind::MetatypeConversion, subExpr, type) {}
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::MetatypeConversion;
  }
};
  
/// CollectionUpcastConversionExpr - Convert a collection whose
/// elements have some type T to the same kind of collection whose
/// elements have type U, where U is a subtype of T.
class CollectionUpcastConversionExpr : public ImplicitConversionExpr {
public:
  struct ConversionPair {
    OpaqueValueExpr *OrigValue;
    Expr *Conversion;

    explicit operator bool() const { return OrigValue != nullptr; }
  };
private:
  ConversionPair KeyConversion;
  ConversionPair ValueConversion;
public:
  CollectionUpcastConversionExpr(Expr *subExpr, Type type,
                                 ConversionPair keyConversion,
                                 ConversionPair valueConversion)
    : ImplicitConversionExpr(
        ExprKind::CollectionUpcastConversion, subExpr, type),
      KeyConversion(keyConversion), ValueConversion(valueConversion) {
    assert((!KeyConversion || ValueConversion)
           && "key conversion without value conversion");
  }

  /// Returns the expression that should be used to perform a
  /// conversion of the collection's values; null if the conversion
  /// is formally trivial because the key type does not change.
  const ConversionPair &getKeyConversion() const {
    return KeyConversion;
  }
  void setKeyConversion(const ConversionPair &pair) {
    KeyConversion = pair;
  }

  /// Returns the expression that should be used to perform a
  /// conversion of the collection's values; null if the conversion
  /// is formally trivial because the value type does not change.
  const ConversionPair &getValueConversion() const {
    return ValueConversion;
  }
  void setValueConversion(const ConversionPair &pair) {
    ValueConversion = pair;
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::CollectionUpcastConversion;
  }
};
  
/// ErasureExpr - Perform type erasure by converting a value to existential
/// type. For example:
///
/// \code
/// protocol Printable {}
/// struct Book {}
///
/// var printable: Printable = Book() // erases type
/// var printableType: Printable.Type = Book.self // erases metatype
/// \endcode
///
/// The type of the expression should always satisfy isAnyExistentialType().
///
/// The type of the sub-expression should always be either:
///   - a non-existential type of the appropriate kind or
///   - an existential type of the appropriate kind which is a subtype
///     of the result type.
///
/// "Appropriate kind" means e.g. a concrete/existential metatype if the
/// result is an existential metatype.
class ErasureExpr final : public ImplicitConversionExpr,
    private llvm::TrailingObjects<ErasureExpr, ProtocolConformanceRef,
                                  CollectionUpcastConversionExpr::ConversionPair> {
  friend TrailingObjects;
  using ConversionPair = CollectionUpcastConversionExpr::ConversionPair;

  ErasureExpr(Expr *subExpr, Type type,
              ArrayRef<ProtocolConformanceRef> conformances,
              ArrayRef<ConversionPair> argConversions)
    : ImplicitConversionExpr(ExprKind::Erasure, subExpr, type) {
    Bits.ErasureExpr.NumConformances = conformances.size();
    std::uninitialized_copy(conformances.begin(), conformances.end(),
                            getTrailingObjects<ProtocolConformanceRef>());

    Bits.ErasureExpr.NumArgumentConversions = argConversions.size();
    std::uninitialized_copy(argConversions.begin(), argConversions.end(),
                            getTrailingObjects<ConversionPair>());

    assert(llvm::all_of(conformances, [](ProtocolConformanceRef ref) {
      return !ref.isInvalid();
    }));
  }

public:
  static ErasureExpr *create(ASTContext &ctx, Expr *subExpr, Type type,
                             ArrayRef<ProtocolConformanceRef> conformances,
                             ArrayRef<ConversionPair> argConversions);

  size_t numTrailingObjects(OverloadToken<ProtocolConformanceRef>) const {
    return Bits.ErasureExpr.NumConformances;
  }
  size_t numTrailingObjects(OverloadToken<ConversionPair>) const {
    return Bits.ErasureExpr.NumArgumentConversions;
  }

  /// Retrieve the mapping specifying how the type of the subexpression
  /// maps to the resulting existential type. If the resulting existential
  /// type involves several different protocols, there will be mappings for each
  /// of those protocols, in the order in which the existential type expands
  /// its properties.
  ///
  /// The entries in this array may be null, indicating that the conformance
  /// to the corresponding protocol is trivial (because the source
  /// type is either an archetype or an existential type that conforms to
  /// that corresponding protocol).
  ArrayRef<ProtocolConformanceRef> getConformances() const {
    return {getTrailingObjects<ProtocolConformanceRef>(),
            Bits.ErasureExpr.NumConformances };
  }

  /// Retrieve the conversion expressions mapping requirements from any
  /// parameterized existentials involved in this erasure.
  ///
  /// If the destination type is not a parameterized protocol type,
  /// this array will be empty
  ArrayRef<ConversionPair> getArgumentConversions() const {
    return {getTrailingObjects<ConversionPair>(),
            static_cast<size_t>(Bits.ErasureExpr.NumArgumentConversions) };
  }

  /// Retrieve the conversion expressions mapping requirements from any
  /// parameterized existentials involved in this erasure.
  ///
  /// If the destination type is not a parameterized protocol type,
  /// this array will be empty
  MutableArrayRef<ConversionPair> getArgumentConversions() {
    return {getTrailingObjects<ConversionPair>(),
            static_cast<size_t>(Bits.ErasureExpr.NumArgumentConversions) };
  }

  void setArgumentConversion(unsigned i, const ConversionPair &p) {
    getArgumentConversions()[i] = p;
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::Erasure;
  }
};

/// AnyHashableErasureExpr - Perform type erasure by converting a value
/// to AnyHashable type.
///
/// The type of the sub-expression should always be a type that implements
/// the Hashable protocol.
class AnyHashableErasureExpr : public ImplicitConversionExpr {
  ProtocolConformanceRef Conformance;

public:
  AnyHashableErasureExpr(Expr *subExpr, Type type,
                         ProtocolConformanceRef conformance)
    : ImplicitConversionExpr(ExprKind::AnyHashableErasure, subExpr, type),
      Conformance(conformance) {}

  /// Retrieve the mapping specifying how the type of the
  /// subexpression conforms to the Hashable protocol.
  ProtocolConformanceRef getConformance() const {
    return Conformance;
  }
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::AnyHashableErasure;
  }
};

/// ConditionalBridgeFromObjCExpr - Bridge a value from a non-native
/// representation.
class ConditionalBridgeFromObjCExpr : public ImplicitConversionExpr {
  ConcreteDeclRef Conversion;

public:
  ConditionalBridgeFromObjCExpr(Expr *subExpr, Type type,
                                ConcreteDeclRef conversion)
    : ImplicitConversionExpr(ExprKind::ConditionalBridgeFromObjC, subExpr, type),
      Conversion(conversion) {
  }

  /// Retrieve the conversion function.
  ConcreteDeclRef getConversion() const {
    return Conversion;
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::ConditionalBridgeFromObjC;
  }
};

/// BridgeFromObjCExpr - Bridge a value from a non-native representation.
class BridgeFromObjCExpr : public ImplicitConversionExpr {
public:
  BridgeFromObjCExpr(Expr *subExpr, Type type)
    : ImplicitConversionExpr(ExprKind::BridgeFromObjC, subExpr, type) {}

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::BridgeFromObjC;
  }
};

/// BridgeToObjCExpr - Bridge a value to a non-native representation.
class BridgeToObjCExpr : public ImplicitConversionExpr {
public:
  BridgeToObjCExpr(Expr *subExpr, Type type)
    : ImplicitConversionExpr(ExprKind::BridgeToObjC, subExpr, type) {}

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::BridgeToObjC;
  }
};

/// ActorIsolationErasureExpr - A special kind of function conversion that
/// drops actor isolation.
class ActorIsolationErasureExpr : public ImplicitConversionExpr {
public:
  ActorIsolationErasureExpr(Expr *subExpr, Type type)
      : ImplicitConversionExpr(ExprKind::ActorIsolationErasure, subExpr, type) {
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::ActorIsolationErasure;
  }
};

/// UnsafeCastExpr - A special kind of conversion that performs an unsafe
/// bitcast from one type to the other.
///
/// Note that this is an unsafe operation and type-checker is allowed to
/// use this only in a limited number of cases like: `any Sendable` -> `Any`
/// conversions in some positions, covariant conversions of function and
/// function result types.
class UnsafeCastExpr : public ImplicitConversionExpr {
public:
  UnsafeCastExpr(Expr *subExpr, Type type)
      : ImplicitConversionExpr(ExprKind::UnsafeCast, subExpr, type) {
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::UnsafeCast;
  }
};

/// Extracts the isolation of a dynamically isolated function value.
class ExtractFunctionIsolationExpr : public Expr {
  /// The function value expression from which to extract the
  /// isolation. The type of `fnExpr` must be an ``@isolated(any)`
  /// funciton.
  Expr *fnExpr;

  /// The source location of `.isolation`
  SourceLoc isolationLoc;

public:
  ExtractFunctionIsolationExpr(Expr *fnExpr, SourceLoc isolationLoc,
                               Type type, bool implicit = false)
      : Expr(ExprKind::ExtractFunctionIsolation, implicit, type),
        fnExpr(fnExpr), isolationLoc(isolationLoc) {}

  Expr *getFunctionExpr() const {
    return fnExpr;
  }

  void setFunctionExpr(Expr *fnExpr) {
    this->fnExpr = fnExpr;
  }

  SourceLoc getStartLoc() const {
    return fnExpr->getStartLoc();
  }

  SourceLoc getEndLoc() const {
    return isolationLoc;
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::ExtractFunctionIsolation;
  }
};

/// UnresolvedSpecializeExpr - Represents an explicit specialization using
/// a type parameter list (e.g. "Vector<Int>") that has not been resolved.
class UnresolvedSpecializeExpr final : public Expr,
    private llvm::TrailingObjects<UnresolvedSpecializeExpr, TypeRepr *> {
  friend TrailingObjects;

  Expr *SubExpr;
  SourceLoc LAngleLoc;
  SourceLoc RAngleLoc;

  UnresolvedSpecializeExpr(Expr *SubExpr,
                           SourceLoc LAngleLoc,
                           ArrayRef<TypeRepr *> UnresolvedParams,
                           SourceLoc RAngleLoc)
    : Expr(ExprKind::UnresolvedSpecialize, /*Implicit=*/false),
      SubExpr(SubExpr), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {
    Bits.UnresolvedSpecializeExpr.NumUnresolvedParams = UnresolvedParams.size();
    std::uninitialized_copy(UnresolvedParams.begin(), UnresolvedParams.end(),
                            getTrailingObjects<TypeRepr *>());
  }

public:
  static UnresolvedSpecializeExpr *
  create(ASTContext &ctx, Expr *SubExpr, SourceLoc LAngleLoc,
         ArrayRef<TypeRepr *> UnresolvedParams, SourceLoc RAngleLoc);
  
  Expr *getSubExpr() const { return SubExpr; }
  void setSubExpr(Expr *e) { SubExpr = e; }
  
  /// Retrieve the list of type parameters. These parameters have not yet
  /// been bound to archetypes of the entity to be specialized.
  ArrayRef<TypeRepr *> getUnresolvedParams() const {
    return {getTrailingObjects<TypeRepr *>(),
            Bits.UnresolvedSpecializeExpr.NumUnresolvedParams};
  }
  
  SourceLoc getLoc() const { return LAngleLoc; }
  SourceLoc getLAngleLoc() const { return LAngleLoc; }
  SourceLoc getRAngleLoc() const { return RAngleLoc; }

  SourceLoc getStartLoc() const { return SubExpr->getStartLoc(); }
  SourceLoc getEndLoc() const { return RAngleLoc; }
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::UnresolvedSpecialize;
  }
};

/// Describes an implicit conversion from a subclass to one of its
/// superclasses.
class DerivedToBaseExpr : public ImplicitConversionExpr {
public:
  DerivedToBaseExpr(Expr *subExpr, Type type)
    : ImplicitConversionExpr(ExprKind::DerivedToBase, subExpr, type) {}

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::DerivedToBase;
  }
};

/// Describes an implicit conversion from a value of archetype type to
/// its concrete superclass.
class ArchetypeToSuperExpr : public ImplicitConversionExpr {
public:
  ArchetypeToSuperExpr(Expr *subExpr, Type type)
    : ImplicitConversionExpr(ExprKind::ArchetypeToSuper, subExpr, type) {}

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::ArchetypeToSuper;
  }
};

/// An expression that models an implicit conversion from an uninhabited value
/// to any type. It cannot be evaluated.
class UnreachableExpr : public ImplicitConversionExpr {
  UnreachableExpr(Expr *subExpr, Type ty)
      : ImplicitConversionExpr(ExprKind::Unreachable, subExpr, ty) {}

public:
  static UnreachableExpr *create(ASTContext &ctx, Expr *subExpr, Type ty) {
    return new (ctx) UnreachableExpr(subExpr, ty);
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::Unreachable;
  }
};

/// The builtin unary '&' operator, which converts the
/// given lvalue into an 'inout' argument value.
class InOutExpr : public Expr {
  Expr *SubExpr;
  SourceLoc OperLoc;

public:
  InOutExpr(SourceLoc operLoc, Expr *subExpr, Type baseType,
            bool isImplicit = false);

  SourceLoc getStartLoc() const { return OperLoc; }
  SourceLoc getEndLoc() const { return SubExpr->getEndLoc(); }
  SourceLoc getLoc() const { return OperLoc; }

  Expr *getSubExpr() const { return SubExpr; }
  void setSubExpr(Expr *e) { SubExpr = e; }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::InOut;
  }
};

/// The not-yet-actually-surfaced '...' varargs expansion operator,
/// which splices an array into a sequence of variadic arguments.
class VarargExpansionExpr : public Expr {
  Expr *SubExpr;

  VarargExpansionExpr(Expr *subExpr, bool implicit, Type type = Type())
    : Expr(ExprKind::VarargExpansion, implicit, type), SubExpr(subExpr) {}

public:
  static VarargExpansionExpr *createParamExpansion(ASTContext &ctx, Expr *E);
  static VarargExpansionExpr *createArrayExpansion(ASTContext &ctx, ArrayExpr *AE);

  SWIFT_FORWARD_SOURCE_LOCS_TO(SubExpr)

  Expr *getSubExpr() const { return SubExpr; }
  void setSubExpr(Expr *subExpr) { SubExpr = subExpr; }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::VarargExpansion;
  }
};

/// A pack element expression spelled with the contextual \c each
/// keyword applied to a pack reference expression.
///
/// \code
///  func zip<T..., U...>(t: (each T)..., u: (each U)...) {
///    let zipped = (each t, each u)...
///  }
/// \endcode
///
/// Pack elements can only appear in the pattern expression of a
/// \c PackExpansionExpr.
class PackElementExpr final : public Expr {
  SourceLoc EachLoc;
  Expr *PackRefExpr;

  PackElementExpr(SourceLoc eachLoc, Expr *packRefExpr,
                  bool implicit = false, Type type = Type())
      : Expr(ExprKind::PackElement, implicit, type),
        EachLoc(eachLoc), PackRefExpr(packRefExpr) {}

public:
  static PackElementExpr *create(ASTContext &ctx, SourceLoc eachLoc,
                                 Expr *packRefExpr, bool implicit = false,
                                 Type type = Type());

  Expr *getPackRefExpr() const { return PackRefExpr; }

  void setPackRefExpr(Expr *packRefExpr) {
    PackRefExpr = packRefExpr;
  }

  SourceLoc getStartLoc() const {
    return EachLoc;
  }

  SourceLoc getEndLoc() const {
    return PackRefExpr->getEndLoc();
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::PackElement;
  }
};

/// A pack expansion expression is a pattern expression followed by
/// the expansion operator '...'. The pattern expression contains
/// references to parameter packs of length N, and the expansion
/// operator will repeat the pattern N times.
///
/// Pack expansion expressions are permitted in expression contexts
/// that naturally accept a comma-separated list of values, including
/// call argument lists, the elements of a tuple value, and the source
/// of a for-in loop.
class PackExpansionExpr final : public Expr {
  SourceLoc RepeatLoc;
  Expr *PatternExpr;
  GenericEnvironment *Environment;

  PackExpansionExpr(SourceLoc repeatLoc,
                    Expr *patternExpr,
                    GenericEnvironment *environment,
                    bool implicit, Type type)
    : Expr(ExprKind::PackExpansion, implicit, type),
      RepeatLoc(repeatLoc), PatternExpr(patternExpr),
      Environment(environment) {}

public:
  static PackExpansionExpr *create(ASTContext &ctx,
                                   SourceLoc repeatLoc,
                                   Expr *patternExpr,
                                   GenericEnvironment *environment,
                                   bool implicit = false,
                                   Type type = Type());

  Expr *getPatternExpr() const { return PatternExpr; }

  void setPatternExpr(Expr *patternExpr) {
    PatternExpr = patternExpr;
  }

  GenericEnvironment *getGenericEnvironment() {
    return Environment;
  }

  void setGenericEnvironment(GenericEnvironment *env) {
    Environment = env;
  }

  SourceLoc getStartLoc() const {
    return RepeatLoc;
  }

  SourceLoc getEndLoc() const {
    return PatternExpr->getEndLoc();
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::PackExpansion;
  }
};

/// An expression to materialize a pack from a tuple containing a pack
/// expansion.
///
/// These nodes are created by CSApply and should only appear in a
/// type-checked AST in the context of a \c PackExpansionExpr .
class MaterializePackExpr final : public Expr {
  /// The expression from which to materialize a pack.
  Expr *FromExpr;

  /// The source location of (deprecated) \c .element
  SourceLoc ElementLoc;

  MaterializePackExpr(Expr *fromExpr, SourceLoc elementLoc,
                      Type type, bool implicit)
      : Expr(ExprKind::MaterializePack, implicit, type),
        FromExpr(fromExpr), ElementLoc(elementLoc) {}

public:
  static MaterializePackExpr *create(ASTContext &ctx, Expr *fromExpr,
                                     SourceLoc elementLoc, Type type,
                                     bool implicit = false);

  Expr *getFromExpr() const { return FromExpr; }

  void setFromExpr(Expr *fromExpr) {
    FromExpr = fromExpr;
  }

  SourceLoc getStartLoc() const {
    return FromExpr->getStartLoc();
  }

  SourceLoc getEndLoc() const {
    return ElementLoc.isValid() ? ElementLoc : FromExpr->getEndLoc();
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::MaterializePack;
  }
};

/// SequenceExpr - A list of binary operations which has not yet been
/// folded into a tree.  The operands all have even indices, while the
/// subexpressions with odd indices are all (potentially overloaded)
/// references to binary operators.
class SequenceExpr final : public Expr,
    private llvm::TrailingObjects<SequenceExpr, Expr *> {
  friend TrailingObjects;

  SequenceExpr(ArrayRef<Expr*> elements)
    : Expr(ExprKind::Sequence, /*Implicit=*/false) {
    Bits.SequenceExpr.NumElements = elements.size();
    assert(Bits.SequenceExpr.NumElements > 0 && "zero-length sequence!");
    std::uninitialized_copy(elements.begin(), elements.end(),
                            getTrailingObjects<Expr*>());
  }

public:
  static SequenceExpr *create(ASTContext &ctx, ArrayRef<Expr*> elements);

  SourceLoc getStartLoc() const {
    return getElement(0)->getStartLoc();
  }
  SourceLoc getEndLoc() const {
    return getElement(getNumElements() - 1)->getEndLoc();
  }
  
  unsigned getNumElements() const { return Bits.SequenceExpr.NumElements; }

  MutableArrayRef<Expr*> getElements() {
    return {getTrailingObjects<Expr*>(), Bits.SequenceExpr.NumElements};
  }

  ArrayRef<Expr*> getElements() const {
    return {getTrailingObjects<Expr*>(), Bits.SequenceExpr.NumElements};
  }

  Expr *getElement(unsigned i) const {
    return getElements()[i];
  }
  void setElement(unsigned i, Expr *e) {
    getElements()[i] = e;
  }

  bool isFolded() const {
    return static_cast<bool>(Bits.SequenceExpr.IsFolded);
  }
  void setFolded(bool folded) {
    Bits.SequenceExpr.IsFolded = static_cast<unsigned>(folded);
  }

  // Implement isa/cast/dyncast/etc.
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::Sequence;
  }
};

/// A base class for closure expressions.
class AbstractClosureExpr : public DeclContext, public Expr {
  CaptureInfo Captures;

  /// The set of parameters.
  ParameterList *parameterList;

  /// Actor isolation of the closure.
  ActorIsolation actorIsolation;

public:
  AbstractClosureExpr(ExprKind Kind, Type FnType, bool Implicit,
                      DeclContext *Parent)
      : DeclContext(DeclContextKind::AbstractClosureExpr, Parent),
        Expr(Kind, Implicit, FnType),
        parameterList(nullptr),
        actorIsolation(ActorIsolation::forUnspecified()) {
    Bits.AbstractClosureExpr.Discriminator = InvalidDiscriminator;
  }

  /// If we find that a capture x of this AbstractClosureExpr belongs to a
  /// different isolation domain than the closure, add an ApplyIsolationCrossing
  /// to foundIsolationCrossing.
  ///
  /// \p foundIsolationCrossings an out parameter that contains the
  /// ApplyIsolationCrossing if any of the captures are isolation crossing and
  /// the index of the capture in the capture array. We return the index since
  /// all captures may not cross isolation boundaries and we may need to be able
  /// to look up the corresponding capture at the SIL level by index.
  void getIsolationCrossing(
      SmallVectorImpl<
          std::tuple<CapturedValue, unsigned, ApplyIsolationCrossing>>
          &foundIsolationCrossings);

  CaptureInfo getCaptureInfo() const {
    assert(Captures.hasBeenComputed());
    return Captures;
  }

  std::optional<CaptureInfo> getCachedCaptureInfo() const {
    if (!Captures.hasBeenComputed())
      return std::nullopt;
    return Captures;
  }

  void setCaptureInfo(CaptureInfo captures) {
    assert(captures.hasBeenComputed());
    Captures = captures;
  }

  /// Retrieve the parameters of this closure.
  ParameterList *getParameters() { return parameterList; }
  const ParameterList *getParameters() const { return parameterList; }
  void setParameterList(ParameterList *P);

  // Expose this to users.
  using DeclContext::setParent;

  /// Returns a discriminator which determines this expression's index
  /// in the sequence of closure expressions within the current
  /// function.
  ///
  /// There are separate sequences for explicit and implicit closures.
  /// This allows explicit closures to maintain a stable numbering
  /// across simple edits that introduce auto closures above them,
  /// which is the best we can reasonably do.
  ///
  /// (Autoclosures are likely to be eliminated immediately, even in
  /// unoptimized builds, so their names are fairly unimportant.  It's
  /// much more likely that explicit closures will survive
  /// optimization and therefore make it into e.g. stack traces.
  /// Having their symbol names be stable across minor code changes is
  /// therefore pretty useful for debugging.)
  unsigned getDiscriminator() const;

  /// Retrieve the raw discriminator, which may not have been computed yet.
  ///
  /// Only use this for queries that are checking for (e.g.) reentrancy or
  /// intentionally do not want to initiate verification.
  unsigned getRawDiscriminator() const {
    return Bits.AbstractClosureExpr.Discriminator;
  }

  void setDiscriminator(unsigned discriminator) {
    assert(getRawDiscriminator() == InvalidDiscriminator);
    assert(discriminator != InvalidDiscriminator);
    Bits.AbstractClosureExpr.Discriminator = discriminator;
  }
  enum : unsigned { InvalidDiscriminator = 0xFFFF };

  /// Retrieve the result type of this closure.
  Type getResultType(llvm::function_ref<Type(Expr *)> getType =
                         [](Expr *E) -> Type { return E->getType(); }) const;

  /// Return whether this closure is throwing when fully applied.
  bool isBodyThrowing() const;

  /// Retrieve the "effective" thrown interface type, or std::nullopt if
  /// this closure cannot throw.
  ///
  /// Closures with untyped throws will produce "any Error", functions that
  /// cannot throw or are specified to throw "Never" will return std::nullopt.
  std::optional<Type> getEffectiveThrownType() const;

  /// \brief Return whether this closure is async when fully applied.
  bool isBodyAsync() const;

  /// Whether this closure is Sendable.
  bool isSendable() const;

  /// Whether this closure consists of a single expression.
  bool hasSingleExpressionBody() const;

  /// Retrieve the body for closure that has a single expression for
  /// its body, or \c nullptr if there is no single expression body.
  Expr *getSingleExpressionBody() const;

  /// Returns the body of closures that have a body
  /// returns nullptr if the closure doesn't have a body
  BraceStmt *getBody() const;

  /// Returns a boolean value indicating whether the body, if any, contains
  /// an explicit `return` statement.
  ///
  /// \returns `true` if the body contains an explicit `return` statement,
  /// `false` otherwise.
  bool bodyHasExplicitReturnStmt() const;

  /// Finds occurrences of explicit `return` statements within the body, if any.
  ///
  /// \param results An out container to which the results are added.
  void getExplicitReturnStmts(SmallVectorImpl<ReturnStmt *> &results) const;

  ActorIsolation getActorIsolation() const {
    return actorIsolation;
  }

  void setActorIsolation(ActorIsolation actorIsolation) {
    this->actorIsolation = actorIsolation;
  }

  static bool classof(const Expr *E) {
    return E->getKind() >= ExprKind::First_AbstractClosureExpr &&
           E->getKind() <= ExprKind::Last_AbstractClosureExpr;
  }

  static bool classof(const DeclContext *DC) {
    return DC->getContextKind() == DeclContextKind::AbstractClosureExpr;
  }

  using DeclContext::operator new;
  using DeclContext::operator delete;
  using Expr::dump;
};

/// SerializedAbstractClosureExpr - This represents what was originally an
/// AbstractClosureExpr during serialization. It is preserved only to maintain
/// the correct AST structure and remangling after deserialization.
class SerializedAbstractClosureExpr : public DeclContext {
  const Type Ty;
  llvm::PointerIntPair<Type, 1> TypeAndImplicit;
  const unsigned Discriminator;

public:
  SerializedAbstractClosureExpr(Type Ty, bool Implicit, unsigned Discriminator,
                                DeclContext *Parent)
    : DeclContext(DeclContextKind::SerializedAbstractClosure, Parent),
      TypeAndImplicit(llvm::PointerIntPair<Type, 1>(Ty, Implicit)),
      Discriminator(Discriminator) {}

  Type getType() const {
    return TypeAndImplicit.getPointer();
  }

  unsigned getDiscriminator() const {
    return Discriminator;
  }

  bool isImplicit() const {
    return TypeAndImplicit.getInt();
  }

  static bool classof(const DeclContext *DC) {
    return DC->getContextKind() == DeclContextKind::SerializedAbstractClosure;
  }
};

/// An explicit unnamed function expression, which can optionally have
/// named arguments.
///
/// \code
///     { $0 + $1 }
///     { a, b -> Int in a + b }
///     { (a : Int, b : Int) -> Int in a + b }
///     { [weak c] (a : Int) -> Int in a + c!.getFoo() }
/// \endcode
class ClosureExpr : public AbstractClosureExpr {
  friend class ExplicitCaughtTypeRequest;

public:
  enum class BodyState {
    /// The body was parsed.
    Parsed,

    /// The body was type-checked.
    TypeChecked,
  };

private:
  /// The attributes attached to the closure.
  DeclAttributes Attributes;

  /// The range of the brackets of the capture list, if present.
  SourceRange BracketRange;
    
  /// The (possibly null) VarDecl captured by this closure with the literal name
  /// "self". In order to recover this information at the time of name lookup,
  /// we must be able to access it from the associated DeclContext.
  /// Because the DeclContext inside a closure is the closure itself (and not
  /// the CaptureListExpr which would normally maintain this sort of
  /// information about captured variables), we need to have some way to access
  /// this information directly on the ClosureExpr.
  VarDecl *CapturedSelfDecl;

  /// The location of the "async", if present.
  SourceLoc AsyncLoc;

  /// The location of the "throws", if present.
  SourceLoc ThrowsLoc;
  
  /// The location of the '->' denoting an explicit return type,
  /// if present.
  SourceLoc ArrowLoc;

  /// The location of the "in", if present.
  SourceLoc InLoc;

  /// The explicitly-specified thrown type.
  TypeExpr *ThrownType;

  /// The explicitly-specified result type.
  llvm::PointerIntPair<TypeExpr *, 2, BodyState> ExplicitResultTypeAndBodyState;

  /// The body of the closure.
  BraceStmt *Body;

  friend class GlobalActorAttributeRequest;

  bool hasNoGlobalActorAttribute() const {
    return Bits.ClosureExpr.NoGlobalActorAttribute;
  }

  void setHasNoGlobalActorAttribute() {
    Bits.ClosureExpr.NoGlobalActorAttribute = true;
  }

public:
  ClosureExpr(const DeclAttributes &attributes,
              SourceRange bracketRange, VarDecl *capturedSelfDecl,
              ParameterList *params, SourceLoc asyncLoc, SourceLoc throwsLoc,
              TypeExpr *thrownType, SourceLoc arrowLoc, SourceLoc inLoc,
              TypeExpr *explicitResultType, DeclContext *parent)
    : AbstractClosureExpr(ExprKind::Closure, Type(), /*Implicit=*/false,
                          parent),
      Attributes(attributes), BracketRange(bracketRange),
      CapturedSelfDecl(capturedSelfDecl),
      AsyncLoc(asyncLoc), ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc),
      InLoc(inLoc), ThrownType(thrownType),
      ExplicitResultTypeAndBodyState(explicitResultType, BodyState::Parsed),
      Body(nullptr) {
    setParameterList(params);
    Bits.ClosureExpr.HasAnonymousClosureVars = false;
    Bits.ClosureExpr.ImplicitSelfCapture = false;
    Bits.ClosureExpr.InheritActorContext = false;
    Bits.ClosureExpr.IsPassedToSendingParameter = false;
    Bits.ClosureExpr.NoGlobalActorAttribute = false;
    Bits.ClosureExpr.RequiresDynamicIsolationChecking = false;
  }

  SourceRange getSourceRange() const;
  SourceLoc getStartLoc() const;
  SourceLoc getEndLoc() const;
  SourceLoc getLoc() const;

  BraceStmt *getBody() const { return Body; }
  void setBody(BraceStmt *S) { Body = S; }

  DeclAttributes &getAttrs() { return Attributes; }
  const DeclAttributes &getAttrs() const { return Attributes; }

  /// Determine whether the parameters of this closure are actually
  /// anonymous closure variables.
  bool hasAnonymousClosureVars() const {
    return Bits.ClosureExpr.HasAnonymousClosureVars;
  }

  /// Set the parameters of this closure along with a flag indicating
  /// whether these parameters are actually anonymous closure variables.
  void setHasAnonymousClosureVars() {
    Bits.ClosureExpr.HasAnonymousClosureVars = true;
  }

  /// Whether this closure allows "self" to be implicitly captured without
  /// required "self." on each reference.
  bool allowsImplicitSelfCapture() const {
    return Bits.ClosureExpr.ImplicitSelfCapture;
  }

  void setAllowsImplicitSelfCapture(bool value = true) {
    Bits.ClosureExpr.ImplicitSelfCapture = value;
  }

  /// Whether this closure should implicitly inherit the actor context from
  /// where it was formed. This only affects @Sendable and sendable async
  /// closures.
  bool inheritsActorContext() const {
    return Bits.ClosureExpr.InheritActorContext;
  }

  void setInheritsActorContext(bool value = true) {
    Bits.ClosureExpr.InheritActorContext = value;
  }

  /// Whether the closure's concurrency behavior was determined by an
  /// \c \@preconcurrency declaration.
  bool isIsolatedByPreconcurrency() const {
    return Bits.ClosureExpr.IsolatedByPreconcurrency;
  }

  void setIsolatedByPreconcurrency(bool value = true) {
    Bits.ClosureExpr.IsolatedByPreconcurrency = value;
  }

  /// Whether the closure is a closure literal that is passed to a sending
  /// parameter.
  bool isPassedToSendingParameter() const {
    return Bits.ClosureExpr.IsPassedToSendingParameter;
  }

  void setIsPassedToSendingParameter(bool value = true) {
    Bits.ClosureExpr.IsPassedToSendingParameter = value;
  }

  /// True if this is an isolated closure literal that is passed 
  /// to a callee that has not been concurrency checked.
  bool requiresDynamicIsolationChecking() const {
    return Bits.ClosureExpr.RequiresDynamicIsolationChecking;
  }

  void setRequiresDynamicIsolationChecking(bool value = true) {
    Bits.ClosureExpr.RequiresDynamicIsolationChecking = value;
  }

  /// Determine whether this closure expression has an
  /// explicitly-specified result type.
  bool hasExplicitResultType() const { return ArrowLoc.isValid(); }

  /// Retrieve the range of the \c '[' and \c ']' that enclose the capture list.
  SourceRange getBracketRange() const { return BracketRange; }
  
  /// Retrieve the location of the \c '->' for closures with an
  /// explicit result type.
  SourceLoc getArrowLoc() const {
    assert(hasExplicitResultType() && "No arrow location");
    return ArrowLoc;
  }

  /// Retrieve the location of the \c in for a closure that has it.
  SourceLoc getInLoc() const {
    return InLoc;
  }

  /// Retrieve the location of the 'async' for a closure that has it.
  SourceLoc getAsyncLoc() const {
    return AsyncLoc;
  }

  /// Retrieve the location of the 'throws' for a closure that has it.
  SourceLoc getThrowsLoc() const {
    return ThrowsLoc;
  }

  /// Retrieve the explicitly-thrown type.
  Type getExplicitThrownType() const;

  /// Retrieve the explicitly-thrown type representation.
  TypeRepr *getExplicitThrownTypeRepr() const {
    if (ThrownType)
      return ThrownType->getTypeRepr();

    return nullptr;
  }

  Type getExplicitResultType() const {
    assert(hasExplicitResultType() && "No explicit result type");
    return ExplicitResultTypeAndBodyState.getPointer()->getInstanceType();
  }
  void setExplicitResultType(Type ty);

  TypeRepr *getExplicitResultTypeRepr() const {
    assert(hasExplicitResultType() && "No explicit result type");
    return ExplicitResultTypeAndBodyState.getPointer()->getTypeRepr();
  }

  /// Determine whether the closure has a single expression for its
  /// body.
  ///
  /// This will be true for closures such as, e.g.,
  /// \code
  ///   { $0 + 1 }
  /// \endcode
  ///
  /// or
  ///
  /// \code
  ///   { x, y in x > y }
  /// \endcode
  ///
  /// ... even if the closure has been coerced to return Void by the type
  /// checker. This function does not return true for empty closures.
  bool hasSingleExpressionBody() const {
    return getSingleExpressionBody();
  }

  /// Retrieve the body for closure that has a single expression for
  /// its body, or \c nullptr if there is no single expression body.
  Expr *getSingleExpressionBody() const;

  /// Is this a completely empty closure?
  bool hasEmptyBody() const;

  /// VarDecl captured by this closure under the literal name \c self , if any.
  VarDecl *getCapturedSelfDecl() const {
    return CapturedSelfDecl;
  }

  /// Get the type checking state of this closure's body.
  BodyState getBodyState() const {
    return ExplicitResultTypeAndBodyState.getInt();
  }
  void setBodyState(BodyState v) {
    ExplicitResultTypeAndBodyState.setInt(v);
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::Closure;
  }
  static bool classof(const AbstractClosureExpr *E) {
    return E->getKind() == ExprKind::Closure;
  }
  static bool classof(const DeclContext *C) {
    return isa<AbstractClosureExpr>(C) && classof(cast<AbstractClosureExpr>(C));
  }
};

/// This is an implicit closure of the contained subexpression that is usually
/// formed when a scalar expression is converted to @autoclosure function type.
/// \code
///   func f(x : @autoclosure () -> Int)
///   f(42)  // AutoclosureExpr convert from Int to ()->Int
/// \endcode
class AutoClosureExpr : public AbstractClosureExpr {
  BraceStmt *Body;

public:
  enum class Kind : uint8_t {
    // An autoclosure with type () -> Result. Formed from type checking an
    // @autoclosure argument in a function call.
    None = 0,

    // An autoclosure with type (Args...) -> Result. Formed from type checking a
    // partial application.
    SingleCurryThunk = 1,

    // An autoclosure with type (Self) -> (Args...) -> Result. Formed from type
    // checking a partial application.
    DoubleCurryThunk = 2,

    // An autoclosure with type () -> Result that was formed for an async let.
    AsyncLet = 3,
  };

  AutoClosureExpr(Expr *Body, Type ResultTy, DeclContext *Parent)
      : AbstractClosureExpr(ExprKind::AutoClosure, ResultTy, /*Implicit=*/true,
                            Parent) {
    if (Body != nullptr)
      setBody(Body);

    Bits.AutoClosureExpr.Kind = 0;
  }

  Kind getThunkKind() const {
    return Kind(Bits.AutoClosureExpr.Kind);
  }

  void setThunkKind(Kind K) {
    Bits.AutoClosureExpr.Kind = uint8_t(K);
  }

  SourceRange getSourceRange() const;
  SourceLoc getStartLoc() const;
  SourceLoc getEndLoc() const;
  SourceLoc getLoc() const;

  BraceStmt *getBody() const { return Body; }
  void setBody(Expr *E);

  // Expose this to users.
  using DeclContext::setParent;

  /// Returns the body of the autoclosure as an \c Expr.
  ///
  /// The body of an autoclosure always consists of a single expression.
  Expr *getSingleExpressionBody() const;

  /// Unwraps a curry thunk. Basically, this gives you what the old AST looked
  /// like, before Sema started building curry thunks. This is really only
  /// meant for legacy usages.
  ///
  /// The behavior is as follows, based on the kind:
  /// - for double curry thunks, returns the original DeclRefExpr.
  /// - for single curry thunks, returns the ApplyExpr for the self call.
  /// - otherwise, returns nullptr for convenience.
  Expr *getUnwrappedCurryThunkExpr() const;

  // Implement isa/cast/dyncast/etc.
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::AutoClosure;
  }
  static bool classof(const AbstractClosureExpr *E) {
    return E->getKind() == ExprKind::AutoClosure;
  }
  static bool classof(const DeclContext *C) {
    return isa<AbstractClosureExpr>(C) && classof(cast<AbstractClosureExpr>(C));
  }
};

/// Instances of this structure represent elements of the capture list that can
/// optionally occur in a capture expression.
struct CaptureListEntry {
  PatternBindingDecl *PBD;

  explicit CaptureListEntry(PatternBindingDecl *PBD);

  VarDecl *getVar() const;
  bool isSimpleSelfCapture(bool excludeWeakCaptures = true) const;
};

/// CaptureListExpr - This expression represents the capture list on an explicit
/// closure.  Because the capture list is evaluated outside of the closure, this
/// CaptureList wraps the ClosureExpr.  The dynamic semantics are that evaluates
/// the variable bindings from the capture list, then evaluates the
/// subexpression (the closure itself) and returns the result.
class CaptureListExpr final : public Expr,
    private llvm::TrailingObjects<CaptureListExpr, CaptureListEntry> {
  friend TrailingObjects;

  AbstractClosureExpr *closureBody;

  CaptureListExpr(ArrayRef<CaptureListEntry> captureList,
                  AbstractClosureExpr *closureBody)
    : Expr(ExprKind::CaptureList, /*Implicit=*/false, Type()),
      closureBody(closureBody) {
    assert(closureBody);
    Bits.CaptureListExpr.NumCaptures = captureList.size();
    std::uninitialized_copy(captureList.begin(), captureList.end(),
                            getTrailingObjects<CaptureListEntry>());
  }

public:
  static CaptureListExpr *create(ASTContext &ctx,
                                 ArrayRef<CaptureListEntry> captureList,
                                 AbstractClosureExpr *closureBody);

  ArrayRef<CaptureListEntry> getCaptureList() {
    return {getTrailingObjects<CaptureListEntry>(),
            Bits.CaptureListExpr.NumCaptures};
  }
  AbstractClosureExpr *getClosureBody() { return closureBody; }
  const AbstractClosureExpr *getClosureBody() const { return closureBody; }

  void setClosureBody(AbstractClosureExpr *body) { closureBody = body; }

  /// This is a bit weird, but the capture list is lexically contained within
  /// the closure, so the ClosureExpr has the full source range.
  SWIFT_FORWARD_SOURCE_LOCS_TO(closureBody)

  // Implement isa/cast/dyncast/etc.
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::CaptureList;
  }
};

/// DynamicTypeExpr - "type(of: base)" - Produces a metatype value.
///
/// The metatype value comes from evaluating an expression then retrieving the
/// metatype of the result.
class DynamicTypeExpr : public Expr {
  SourceLoc KeywordLoc;
  SourceLoc LParenLoc;
  Expr *Base;
  SourceLoc RParenLoc;

public:
  explicit DynamicTypeExpr(SourceLoc KeywordLoc, SourceLoc LParenLoc,
                           Expr *Base, SourceLoc RParenLoc, Type Ty)
    : Expr(ExprKind::DynamicType, /*Implicit=*/false, Ty),
      KeywordLoc(KeywordLoc), LParenLoc(LParenLoc), Base(Base),
      RParenLoc(RParenLoc) { }

  Expr *getBase() const { return Base; }
  void setBase(Expr *base) { Base = base; }

  SourceLoc getLoc() const { return KeywordLoc; }
  SourceRange getSourceRange() const {
    return SourceRange(KeywordLoc, RParenLoc);
  }
  
  SourceLoc getStartLoc() const {
    return KeywordLoc;
  }
  SourceLoc getEndLoc() const {
    return RParenLoc;
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::DynamicType;
  }
};

/// An expression referring to an opaque object of a fixed type.
///
/// Opaque value expressions occur when a particular value within the AST
/// needs to be re-used without being re-evaluated or for a value that is
/// a placeholder. OpaqueValueExpr nodes are introduced by some other AST
/// node (say, an \c OpenExistentialExpr) and can only be used within the
/// subexpressions of that AST node.
class OpaqueValueExpr : public Expr {
  SourceRange Range;

public:
  explicit OpaqueValueExpr(SourceRange Range, Type Ty,
                           bool isPlaceholder = false)
      : Expr(ExprKind::OpaqueValue, /*Implicit=*/true, Ty), Range(Range) {
    Bits.OpaqueValueExpr.IsPlaceholder = isPlaceholder;
  }

  static OpaqueValueExpr *
  createImplicit(ASTContext &ctx, Type Ty, bool isPlaceholder = false,
                 AllocationArena arena = AllocationArena::Permanent);

  /// Whether this opaque value expression represents a placeholder that
  /// is injected before type checking to act as a placeholder for some
  /// value to be specified later.
  bool isPlaceholder() const { return Bits.OpaqueValueExpr.IsPlaceholder; }

  void setIsPlaceholder(bool value) {
    Bits.OpaqueValueExpr.IsPlaceholder = value;
  }

  SourceRange getSourceRange() const { return Range; }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::OpaqueValue;
  }
};

/// A placeholder to substitute with a \c wrappedValue initialization expression
/// for a property with an attached property wrapper.
///
/// Wrapped value placeholder expressions are injected around the
/// \c wrappedValue argument in a synthesized \c init(wrappedValue:)
/// call. This injection happens for properties with attached property wrappers
/// that can be initialized out-of-line with a wrapped value expression, rather
/// than calling \c init(wrappedValue:) explicitly.
///
/// Wrapped value placeholders store the original initialization expression
/// if one exists, along with an opaque value placeholder that can be bound
/// to a different wrapped value expression.
class PropertyWrapperValuePlaceholderExpr : public Expr {
  SourceRange Range;
  OpaqueValueExpr *Placeholder;
  Expr *WrappedValue;
  bool IsAutoClosure = false;

  PropertyWrapperValuePlaceholderExpr(SourceRange Range, Type Ty,
                                      OpaqueValueExpr *placeholder,
                                      Expr *wrappedValue,
                                      bool isAutoClosure)
      : Expr(ExprKind::PropertyWrapperValuePlaceholder, /*Implicit=*/true, Ty),
        Range(Range), Placeholder(placeholder), WrappedValue(wrappedValue),
        IsAutoClosure(isAutoClosure) {}

public:
  static PropertyWrapperValuePlaceholderExpr *
  create(ASTContext &ctx, SourceRange range, Type ty, Expr *wrappedValue,
         bool isAutoClosure = false);

  /// The original wrappedValue initialization expression provided via
  /// \c = on a property with attached property wrappers.
  Expr *getOriginalWrappedValue() const {
    return WrappedValue;
  }

  void setOriginalWrappedValue(Expr *value) {
    WrappedValue = value;
  }

  /// An opaque value placeholder that will be used to substitute in a
  /// different wrapped value expression for out-of-line initialization.
  OpaqueValueExpr *getOpaqueValuePlaceholder() const {
    return Placeholder;
  }

  void setOpaqueValuePlaceholder(OpaqueValueExpr *placeholder) {
    Placeholder = placeholder;
  }

  bool isAutoClosure() const { return IsAutoClosure; }

  SourceRange getSourceRange() const { return Range; }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::PropertyWrapperValuePlaceholder;
  }
};

/// An implicit applied property wrapper expression.
class AppliedPropertyWrapperExpr final : public Expr {
public:
  enum class ValueKind {
    WrappedValue,
    ProjectedValue
  };

private:
  /// The concrete callee which owns the property wrapper.
  ConcreteDeclRef Callee;

  /// The owning declaration.
  const ParamDecl *Param;

  /// The source location of the argument list.
  SourceLoc Loc;

  /// The value to which the property wrapper is applied for initialization.
  Expr *Value;

  /// The kind of value that the property wrapper is applied to.
  ValueKind Kind;

  AppliedPropertyWrapperExpr(ConcreteDeclRef callee, const ParamDecl *param, SourceLoc loc,
                             Type Ty, Expr *value, ValueKind kind)
      : Expr(ExprKind::AppliedPropertyWrapper, /*Implicit=*/true, Ty),
        Callee(callee), Param(param), Loc(loc), Value(value), Kind(kind) {}

public:
  static AppliedPropertyWrapperExpr *
  create(ASTContext &ctx, ConcreteDeclRef callee, const ParamDecl *param, SourceLoc loc,
         Type Ty, Expr *value, ValueKind kind);

  SourceRange getSourceRange() const { return Loc; }

  ConcreteDeclRef getCallee() { return Callee; }

  /// Returns the parameter declaration with the attached property wrapper.
  const ParamDecl *getParamDecl() const { return Param; };

  /// Returns the value that the property wrapper is applied to.
  Expr *getValue() { return Value; }

  /// Sets the value that the property wrapper is applied to.
  void setValue(Expr *value) { Value = value; }

  /// Returns the kind of value, between wrapped value and projected
  /// value, the property wrapper is applied to.
  ValueKind getValueKind() const { return Kind; }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::AppliedPropertyWrapper;
  }
};

/// An expression referring to a default argument left unspecified at the
/// call site.
///
/// A DefaultArgumentExpr must only appear as a direct child of a
/// ParenExpr or a TupleExpr that is itself a call argument.
class DefaultArgumentExpr final : public Expr {
  friend class CallerSideDefaultArgExprRequest;

  /// The owning declaration.
  ConcreteDeclRef DefaultArgsOwner;

  /// The caller parameter index.
  unsigned ParamIndex;

  /// The source location of the argument list.
  SourceLoc Loc;

  /// Stores either a DeclContext or, upon type-checking, the caller-side
  /// default expression.
  PointerUnion<DeclContext *, Expr *> ContextOrCallerSideExpr;

  /// Whether this default argument is evaluated asynchronously because
  /// it's isolated to the callee's isolation domain.
  bool implicitlyAsync = false;

public:
  explicit DefaultArgumentExpr(ConcreteDeclRef defaultArgsOwner,
                               unsigned paramIndex, SourceLoc loc, Type Ty,
                               DeclContext *dc)
    : Expr(ExprKind::DefaultArgument, /*Implicit=*/true, Ty),
      DefaultArgsOwner(defaultArgsOwner), ParamIndex(paramIndex), Loc(loc),
      ContextOrCallerSideExpr(dc) { }

  SourceRange getSourceRange() const { return Loc; }

  ConcreteDeclRef getDefaultArgsOwner() const {
    return DefaultArgsOwner;
  }

  unsigned getParamIndex() const {
    return ParamIndex;
  }

  /// Retrieves the parameter declaration for this default argument.
  const ParamDecl *getParamDecl() const;

  /// Checks whether this is a caller-side default argument that is emitted
  /// directly at the call site.
  bool isCallerSide() const;

  /// For a caller-side default argument, retrieves the fully type-checked
  /// expression within the context of the call site.
  Expr *getCallerSideDefaultExpr() const;

  /// Get the required actor isolation for evaluating this default argument
  /// synchronously. If the caller does not meet the required isolation, the
  /// argument must be written explicitly at the call-site.
  ActorIsolation getRequiredIsolation() const;

  /// Whether this default argument is evaluated asynchronously because
  /// it's isolated to the callee's isolation domain.
  bool isImplicitlyAsync() const {
    return implicitlyAsync;
  }

  void setImplicitlyAsync() {
    implicitlyAsync = true;
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::DefaultArgument;
  }
};

/// ApplyExpr - Superclass of various function calls, which apply an argument to
/// a function to get a result.
class ApplyExpr : public Expr {
  /// The function being called.
  Expr *Fn;

  /// The list of arguments to call the function with.
  ArgumentList *ArgList;

  // If this apply crosses isolation boundaries, record the callee and caller
  // isolations in this struct.
  std::optional<ApplyIsolationCrossing> IsolationCrossing;

  /// Destination information for a thrown error, which includes any
  /// necessary conversions from the actual type thrown to the type that
  /// is expected by the enclosing context.
  ThrownErrorDestination ThrowDest;

protected:
  ApplyExpr(ExprKind kind, Expr *fn, ArgumentList *argList, bool implicit,
            Type ty = Type())
      : Expr(kind, implicit, ty), Fn(fn), ArgList(argList) {
    assert(ArgList);
    assert(classof((Expr*)this) && "ApplyExpr::classof out of date");
    Bits.ApplyExpr.ThrowsIsSet = false;
    Bits.ApplyExpr.ImplicitlyAsync = false;
    Bits.ApplyExpr.ImplicitlyThrows = false;
    Bits.ApplyExpr.NoAsync = false;
    Bits.ApplyExpr.ShouldApplyDistributedThunk = false;
  }

public:
  Expr *getFn() const { return Fn; }
  void setFn(Expr *e) { Fn = e; }
  Expr *getSemanticFn() const { return Fn->getSemanticsProvidingExpr(); }

  ArgumentList *getArgs() const { return ArgList; }
  void setArgs(ArgumentList *newArgList) { ArgList = newArgList; }

  /// Has the type-checker set the 'throws' bit yet?
  ///
  /// In general, this should only be used for debugging purposes.
  bool isThrowsSet() const { return Bits.ApplyExpr.ThrowsIsSet; }

  /// Does this application throw?  This is only meaningful after
  /// complete type-checking.
  ///
  /// Returns the thrown error destination, which includes both the type
  /// thrown from this application as well as the context's error type,
  /// which may be different.
  ThrownErrorDestination throws() const {
    assert(Bits.ApplyExpr.ThrowsIsSet);
    return ThrowDest;
  }

  void setThrows(ThrownErrorDestination throws) {
    assert(!Bits.ApplyExpr.ThrowsIsSet);
    Bits.ApplyExpr.ThrowsIsSet = true;
    ThrowDest = throws;
  }

  /// Is this a 'rethrows' function that is known not to throw?
  bool isNoThrows() const { return !throws(); }

  /// Is this a 'reasync' function that is known not to 'await'?
  bool isNoAsync() const { return Bits.ApplyExpr.NoAsync; }
  void setNoAsync(bool noAsync) {
    Bits.ApplyExpr.NoAsync = noAsync;
  }

  // Return the optionally stored ApplyIsolationCrossing instance - set iff this
  // ApplyExpr crosses isolation domains
  const std::optional<ApplyIsolationCrossing> getIsolationCrossing() const {
    return IsolationCrossing;
  }

  // Record that this apply crosses isolation domains, noting the isolation of
  // the caller and callee by storing them into the IsolationCrossing field
  void setIsolationCrossing(
      ActorIsolation callerIsolation, ActorIsolation calleeIsolation) {
    assert(!IsolationCrossing.has_value()
             && "IsolationCrossing should not be set twice");
    IsolationCrossing = {callerIsolation, calleeIsolation};
  }

  /// Is this application _implicitly_ required to be an async call?
  /// That is, does it need to be guarded by hop_to_executor.
  /// Note that this is _not_ a check for whether the callee is async!
  /// Only meaningful after complete type-checking.
  ///
  /// Generally, this comes up only when we have a non-self call to an actor
  /// instance's synchronous method. Such calls are conceptually treated as if
  /// they are wrapped with an async closure. For example,
  ///
  ///   act.syncMethod(a, b) 
  ///
  /// is equivalent to the eta-expanded version of act.syncMethod,
  ///
  ///   { (a1, b1) async in act.syncMethod(a1, b1) }(a, b)
  ///
  /// where the new closure is declared to be async.
  ///
  /// When the application is implicitly async, the result describes
  /// the actor to which we need to need to hop.
  std::optional<ActorIsolation> isImplicitlyAsync() const {
    if (!Bits.ApplyExpr.ImplicitlyAsync)
      return std::nullopt;

    auto isolationCrossing = getIsolationCrossing();
    assert(isolationCrossing.has_value()
           && "Implicitly async ApplyExprs should always "
              "have had IsolationCrossing set");

    return isolationCrossing.value().CalleeIsolation;
  }

  /// Note that this application is implicitly async and set the target.
  void setImplicitlyAsync(ActorIsolation target) {
    assert(getIsolationCrossing().has_value()
           && "ApplyExprs should always call setIsolationCrossing"
              " before setImplicitlyAsync");
    Bits.ApplyExpr.ImplicitlyAsync = true;
  }

  /// Is this application _implicitly_ required to be a throwing call?
  /// This can happen if the function is actually a distributed thunk
  /// invocation, which may throw, regardless of the target function throwing,
  /// e.g. a distributed instance method call on a 'remote' actor, may throw due
  /// to network issues reported by the transport, regardless if the actual
  /// target function can throw.
  bool implicitlyThrows() const {
    return Bits.ApplyExpr.ImplicitlyThrows;
  }
  void setImplicitlyThrows(bool flag) {
    Bits.ApplyExpr.ImplicitlyThrows = flag;
  }

  /// Informs IRGen to that this expression should be applied as its distributed
  /// thunk, rather than invoking the function directly.
  bool shouldApplyDistributedThunk() const {
    return Bits.ApplyExpr.ShouldApplyDistributedThunk;
  }
  void setShouldApplyDistributedThunk(bool flag) {
    Bits.ApplyExpr.ShouldApplyDistributedThunk = flag;
  }

  ValueDecl *getCalledValue(bool skipFunctionConversions = false) const;

  static bool classof(const Expr *E) {
    return E->getKind() >= ExprKind::First_ApplyExpr &&
           E->getKind() <= ExprKind::Last_ApplyExpr;
  }
};

/// CallExpr - Application of an argument to a function, which occurs
/// syntactically through juxtaposition with a TupleExpr whose
/// leading '(' is unspaced.
class CallExpr final : public ApplyExpr {
  CallExpr(Expr *fn, ArgumentList *argList, bool implicit, Type ty);

public:
  /// Create a new call expression.
  ///
  /// \param fn The function being called
  /// \param argList The argument list.
  static CallExpr *create(ASTContext &ctx, Expr *fn, ArgumentList *argList,
                          bool implicit);

  /// Create a new implicit call expression without any source-location
  /// information.
  ///
  /// \param fn The function being called.
  /// \param argList The argument list.
  static CallExpr *createImplicit(ASTContext &ctx, Expr *fn,
                                  ArgumentList *argList) {
    return create(ctx, fn, argList, /*implicit*/ true);
  }

  /// Create a new implicit call expression with no arguments and no
  /// source-location information.
  ///
  /// \param fn The nullary function being called.
  static CallExpr *createImplicitEmpty(ASTContext &ctx, Expr *fn);

  SourceLoc getStartLoc() const {
    SourceLoc fnLoc = getFn()->getStartLoc();
    return (fnLoc.isValid() ? fnLoc : getArgs()->getStartLoc());
  }
  SourceLoc getEndLoc() const {
    SourceLoc argLoc = getArgs()->getEndLoc();
    return (argLoc.isValid() ? argLoc : getFn()->getEndLoc());
  }
  
  SourceLoc getLoc() const { 
    SourceLoc FnLoc = getFn()->getLoc(); 
    return FnLoc.isValid() ? FnLoc : getArgs()->getStartLoc();
  }

  /// Retrieve the expression that directly represents the callee.
  ///
  /// The "direct" callee is the expression representing the callee
  /// after looking through top-level constructs that don't affect the
  /// identity of the callee, e.g., extra parentheses, optional
  /// unwrapping (?)/forcing (!), etc.
  Expr *getDirectCallee() const;

  static bool classof(const Expr *E) { return E->getKind() == ExprKind::Call; }
};
  
/// PrefixUnaryExpr - Prefix unary expressions like '!y'.
class PrefixUnaryExpr : public ApplyExpr {
  PrefixUnaryExpr(Expr *fn, ArgumentList *argList, Type ty = Type())
      : ApplyExpr(ExprKind::PrefixUnary, fn, argList, /*implicit*/ false, ty) {
    assert(argList->isUnlabeledUnary());
  }

public:
  static PrefixUnaryExpr *create(ASTContext &ctx, Expr *fn, Expr *operand,
                                 Type ty = Type());

  SourceLoc getLoc() const { return getFn()->getStartLoc(); }

  SourceLoc getStartLoc() const {
    return getFn()->getStartLoc();
  }
  SourceLoc getEndLoc() const { return getOperand()->getEndLoc(); }

  Expr *getOperand() const { return getArgs()->getExpr(0); }
  void setOperand(Expr *E) { getArgs()->setExpr(0, E); }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::PrefixUnary;
  }
};

/// PostfixUnaryExpr - Postfix unary expressions like 'y!'.
class PostfixUnaryExpr : public ApplyExpr {
  PostfixUnaryExpr(Expr *fn, ArgumentList *argList, Type ty = Type())
      : ApplyExpr(ExprKind::PostfixUnary, fn, argList, /*implicit*/ false, ty) {
    assert(argList->isUnlabeledUnary());
  }

public:
  static PostfixUnaryExpr *create(ASTContext &ctx, Expr *fn, Expr *operand,
                                  Type ty = Type());

  SourceLoc getLoc() const { return getFn()->getStartLoc(); }

  SourceLoc getStartLoc() const { return getOperand()->getStartLoc(); }
  SourceLoc getEndLoc() const {
    return getFn()->getEndLoc();
  }

  Expr *getOperand() const { return getArgs()->getExpr(0); }
  void setOperand(Expr *E) { getArgs()->setExpr(0, E); }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::PostfixUnary;
  }
};
  
/// BinaryExpr - Infix binary expressions like 'x+y'.  The argument is always
/// an implicit tuple expression of the type expected by the function.
class BinaryExpr : public ApplyExpr {
  BinaryExpr(Expr *fn, ArgumentList *argList, bool implicit, Type ty = Type())
      : ApplyExpr(ExprKind::Binary, fn, argList, implicit, ty) {
    assert(argList->size() == 2);
  }

public:
  static BinaryExpr *create(ASTContext &ctx, Expr *lhs, Expr *fn, Expr *rhs,
                            bool implicit, Type ty = Type());

  /// The left-hand argument of the binary operation.
  Expr *getLHS() const { return getArgs()->getExpr(0); }

  /// The right-hand argument of the binary operation.
  Expr *getRHS() const { return getArgs()->getExpr(1); }

  SourceLoc getLoc() const { return getFn()->getLoc(); }

  SourceRange getSourceRange() const { return getArgs()->getSourceRange(); }
  SourceLoc getStartLoc() const { return getArgs()->getStartLoc(); }
  SourceLoc getEndLoc() const { return getArgs()->getEndLoc(); }

  static bool classof(const Expr *E) { return E->getKind() == ExprKind::Binary;}
};

/// SelfApplyExpr - Abstract application that provides the 'self' pointer for
/// a method curried as (this : Self) -> (params) -> result.
///
/// The application of a curried method to 'self' semantically differs from
/// normal function application because the 'self' parameter can be implicitly
/// materialized from an rvalue.
class SelfApplyExpr : public ApplyExpr {
protected:
  SelfApplyExpr(ExprKind kind, Expr *fnExpr, ArgumentList *argList, Type ty)
      : ApplyExpr(kind, fnExpr, argList, fnExpr->isImplicit(), ty) {
    assert(argList->isUnary());
  }

public:
  Expr *getBase() const { return getArgs()->getExpr(0); }
  void setBase(Expr *E) { getArgs()->setExpr(0, E); }

  static bool classof(const Expr *E) {
    return E->getKind() >= ExprKind::First_SelfApplyExpr &&
           E->getKind() <= ExprKind::Last_SelfApplyExpr;
  }
};

/// DotSyntaxCallExpr - Refer to a method of a type, e.g. P.x.  'x'
/// is modeled as a DeclRefExpr or OverloadSetRefExpr on the method.
class DotSyntaxCallExpr : public SelfApplyExpr {
  SourceLoc DotLoc;

  DotSyntaxCallExpr(Expr *fnExpr, SourceLoc dotLoc, ArgumentList *argList,
                    Type ty = Type())
      : SelfApplyExpr(ExprKind::DotSyntaxCall, fnExpr, argList, ty),
        DotLoc(dotLoc) {
    setImplicit(DotLoc.isInvalid());
  }

public:
  /// Create a new method reference to \p fnExpr on the base value \p baseArg.
  /// 
  /// If this is for a 'mutating' method, \p baseArg should be created using
  /// \c Argument::implicitInOut. Otherwise, \p Argument::unlabeled should be
  /// used. \p baseArg must not be labeled.
  static DotSyntaxCallExpr *create(ASTContext &ctx, Expr *fnExpr,
                                   SourceLoc dotLoc, Argument baseArg,
                                   Type ty = Type());

  SourceLoc getDotLoc() const { return DotLoc; }

  SourceLoc getLoc() const;
  SourceLoc getStartLoc() const;
  SourceLoc getEndLoc() const;

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::DotSyntaxCall;
  }
};

/// ConstructorRefCallExpr - Refer to a constructor for a type P.  The
/// actual reference to function which returns the constructor is modeled
/// as a DeclRefExpr.
class ConstructorRefCallExpr : public SelfApplyExpr {
  ConstructorRefCallExpr(Expr *fnExpr, ArgumentList *argList, Type ty = Type())
      : SelfApplyExpr(ExprKind::ConstructorRefCall, fnExpr, argList, ty) {}

public:
  static ConstructorRefCallExpr *create(ASTContext &ctx, Expr *fnExpr,
                                        Expr *baseExpr, Type ty = Type());

  SourceLoc getLoc() const { return getFn()->getLoc(); }
  SourceLoc getStartLoc() const { return getBase()->getStartLoc(); }
  SourceLoc getEndLoc() const { return getFn()->getEndLoc(); }
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::ConstructorRefCall;
  }
};
  
/// DotSyntaxBaseIgnoredExpr - When a.b resolves to something that does not need
/// the actual value of the base (e.g. when applied to a metatype, module, or
/// the base of a 'static' function) this expression node is created.  The
/// semantics are that its base is evaluated and discarded, then 'b' is
/// evaluated and returned as the result of the expression.
class DotSyntaxBaseIgnoredExpr : public Expr {
  Expr *LHS;
  SourceLoc DotLoc;
  Expr *RHS;
public:
  DotSyntaxBaseIgnoredExpr(Expr *LHS, SourceLoc DotLoc, Expr *RHS, Type rhsTy)
    : Expr(ExprKind::DotSyntaxBaseIgnored, /*Implicit=*/false, rhsTy),
      LHS(LHS), DotLoc(DotLoc), RHS(RHS) {
  }
  
  Expr *getLHS() const { return LHS; }
  void setLHS(Expr *E) { LHS = E; }
  SourceLoc getDotLoc() const { return DotLoc; }
  Expr *getRHS() const { return RHS; }
  void setRHS(Expr *E) { RHS = E; }

  SourceLoc getStartLoc() const {
    return DotLoc.isValid() ? LHS->getStartLoc() : RHS->getStartLoc();
  }
  SourceLoc getEndLoc() const { return RHS->getEndLoc(); }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::DotSyntaxBaseIgnored;
  }
};
  
/// Represents an explicit cast, 'a as T' or 'a is T', where "T" is a
/// type, and "a" is the expression that will be converted to the type.
class ExplicitCastExpr : public Expr {
  Expr *SubExpr;
  SourceLoc AsLoc;
  TypeExpr *const CastTy;

protected:
  ExplicitCastExpr(ExprKind kind, Expr *sub, SourceLoc AsLoc, TypeExpr *castTy)
      : Expr(kind, /*Implicit=*/false), SubExpr(sub), AsLoc(AsLoc),
        CastTy(castTy) {}

public:
  Expr *getSubExpr() const { return SubExpr; }

  /// Get the type syntactically spelled in the cast. For some forms of checked
  /// cast this is different from the result type of the expression.
  Type getCastType() const { return CastTy->getInstanceType(); }
  void setCastType(Type type);

  TypeRepr *getCastTypeRepr() const { return CastTy->getTypeRepr(); }

  void setSubExpr(Expr *E) { SubExpr = E; }

  SourceLoc getLoc() const {
    if (AsLoc.isValid())
      return AsLoc;

    return SubExpr->getLoc();
  }

  SourceLoc getAsLoc() const {
    return AsLoc;
  }

  SourceRange getSourceRange() const {
    const SourceRange castTyRange = CastTy->getSourceRange();
    if (castTyRange.isInvalid())
      return SubExpr->getSourceRange();
    
    auto startLoc = SubExpr ? SubExpr->getStartLoc() : AsLoc;
    auto endLoc = castTyRange.End;
    
    return {startLoc, endLoc};
  }
  
  /// True if the node has been processed by SequenceExpr folding.
  bool isFolded() const { return SubExpr; }
  
  static bool classof(const Expr *E) {
    return E->getKind() >= ExprKind::First_ExplicitCastExpr &&
           E->getKind() <= ExprKind::Last_ExplicitCastExpr;
  }
};

/// Return a string representation of a CheckedCastKind.
StringRef getCheckedCastKindName(CheckedCastKind kind);
  
/// Abstract base class for checked casts 'as' and 'is'. These represent
/// casts that can dynamically fail.
class CheckedCastExpr : public ExplicitCastExpr {
protected:
  CheckedCastExpr(ExprKind kind, Expr *sub, SourceLoc asLoc, TypeExpr *castTy)
      : ExplicitCastExpr(kind, sub, asLoc, castTy) {
    Bits.CheckedCastExpr.CastKind = unsigned(CheckedCastKind::Unresolved);
  }

public:
  /// Return the semantic kind of cast performed.
  CheckedCastKind getCastKind() const {
    return CheckedCastKind(Bits.CheckedCastExpr.CastKind);
  }
  void setCastKind(CheckedCastKind kind) {
    Bits.CheckedCastExpr.CastKind = unsigned(kind);
  }
  
  /// True if the cast has been type-checked and its kind has been set.
  bool isResolved() const {
    return getCastKind() >= CheckedCastKind::First_Resolved;
  }
  
  static bool classof(const Expr *E) {
    return E->getKind() >= ExprKind::First_CheckedCastExpr
        && E->getKind() <= ExprKind::Last_CheckedCastExpr;
  }
};

/// Represents an explicit forced checked cast, which converts
/// from a value of some type to some specified subtype and fails dynamically
/// if the value does not have that type.
/// Spelled 'a as! T' and produces a value of type 'T'.
class ForcedCheckedCastExpr final : public CheckedCastExpr {
  SourceLoc ExclaimLoc;

  ForcedCheckedCastExpr(Expr *sub, SourceLoc asLoc, SourceLoc exclaimLoc,
                        TypeExpr *type)
      : CheckedCastExpr(ExprKind::ForcedCheckedCast, sub, asLoc, type),
        ExclaimLoc(exclaimLoc) {}

public:
  static ForcedCheckedCastExpr *create(ASTContext &ctx, SourceLoc asLoc,
                                       SourceLoc exclaimLoc, TypeRepr *tyRepr);

  static ForcedCheckedCastExpr *createImplicit(ASTContext &ctx, Expr *sub,
                                               Type castTy);

  /// Retrieve the location of the '!' that follows 'as'.
  SourceLoc getExclaimLoc() const { return ExclaimLoc; }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::ForcedCheckedCast;
  }
};

/// Represents an explicit conditional checked cast, which converts
/// from a type to some subtype and produces an Optional value, which will be
/// .some(x) if the cast succeeds, or .none if the cast fails.
/// Spelled 'a as? T' and produces a value of type 'T?'.
class ConditionalCheckedCastExpr final : public CheckedCastExpr {
  SourceLoc QuestionLoc;

  ConditionalCheckedCastExpr(Expr *sub, SourceLoc asLoc, SourceLoc questionLoc,
                             TypeExpr *type)
      : CheckedCastExpr(ExprKind::ConditionalCheckedCast, sub, asLoc, type),
        QuestionLoc(questionLoc) {}

public:
  static ConditionalCheckedCastExpr *create(ASTContext &ctx, SourceLoc asLoc,
                                            SourceLoc questionLoc,
                                            TypeRepr *tyRepr);

  static ConditionalCheckedCastExpr *createImplicit(ASTContext &ctx, Expr *sub,
                                                    Type castTy);

  /// Retrieve the location of the '?' that follows 'as'.
  SourceLoc getQuestionLoc() const { return QuestionLoc; }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::ConditionalCheckedCast;
  }
};

/// Represents a runtime type check query, 'a is T', where 'T' is a type
/// and 'a' is a value of some related type. Evaluates to a Bool true if 'a' is
/// of the type and 'a as T' would succeed, false otherwise.
///
/// FIXME: We should support type queries with a runtime metatype value too.
class IsExpr final : public CheckedCastExpr {
  IsExpr(Expr *sub, SourceLoc isLoc, TypeExpr *type)
      : CheckedCastExpr(ExprKind::Is, sub, isLoc, type) {}

public:
  static IsExpr *create(ASTContext &ctx, SourceLoc isLoc, TypeRepr *tyRepr);

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::Is;
  }
};

/// Represents an explicit coercion from a value to a specific type.
///
/// Spelled 'a as T' and produces a value of type 'T'.
class CoerceExpr final : public ExplicitCastExpr {
  /// Since there is already `asLoc` location,
  /// we use it to store `start` of the initializer
  /// call source range to save some storage.
  SourceLoc InitRangeEnd;

  CoerceExpr(Expr *sub, SourceLoc asLoc, TypeExpr *type)
      : ExplicitCastExpr(ExprKind::Coerce, sub, asLoc, type) {}

  CoerceExpr(SourceRange initRange, Expr *literal, TypeExpr *type)
      : ExplicitCastExpr(ExprKind::Coerce, literal, initRange.Start, type),
        InitRangeEnd(initRange.End) {}

public:
  static CoerceExpr *create(ASTContext &ctx, SourceLoc asLoc, TypeRepr *tyRepr);

  static CoerceExpr *createImplicit(ASTContext &ctx, Expr *sub, Type castTy);

  /// Create an implicit coercion expression for literal initialization
  /// preserving original source information, this way original call
  /// could be recreated if needed.
  static CoerceExpr *forLiteralInit(ASTContext &ctx, Expr *literal,
                                    SourceRange range, TypeRepr *literalTyRepr);

  bool isLiteralInit() const { return InitRangeEnd.isValid(); }

  SourceRange getSourceRange() const {
    return isLiteralInit()
            ? SourceRange(getAsLoc(), InitRangeEnd)
            : ExplicitCastExpr::getSourceRange();
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::Coerce;
  }
};

/// Represents two expressions joined by the arrow operator '->', which
/// may be preceded by the 'throws' keyword. Currently this only exists to be
/// transformed into a FunctionTypeRepr by simplifyTypeExpr() in Sema.
class ArrowExpr : public Expr {
  SourceLoc AsyncLoc;
  SourceLoc ThrowsLoc;
  SourceLoc ArrowLoc;
  Expr *Args;
  Expr *Result;
  Expr *ThrownType;

public:
  ArrowExpr(Expr *Args, SourceLoc AsyncLoc, SourceLoc ThrowsLoc,
            Expr *ThrownType, SourceLoc ArrowLoc, Expr *Result)
    : Expr(ExprKind::Arrow, /*implicit=*/false, Type()),
      AsyncLoc(AsyncLoc), ThrowsLoc(ThrowsLoc), ArrowLoc(ArrowLoc), Args(Args),
      Result(Result), ThrownType(ThrownType)
  { }

  ArrowExpr(SourceLoc AsyncLoc, SourceLoc ThrowsLoc, Expr *ThrownType,
            SourceLoc ArrowLoc)
    : Expr(ExprKind::Arrow, /*implicit=*/false, Type()),
      AsyncLoc(AsyncLoc), ThrowsLoc(ThrowsLoc), ArrowLoc(ArrowLoc),
      Args(nullptr), Result(nullptr), ThrownType(ThrownType)
  { }

  Expr *getArgsExpr() const { return Args; }
  void setArgsExpr(Expr *E) { Args = E; }
  Expr *getResultExpr() const { return Result; }
  void setResultExpr(Expr *E) { Result = E; }
  Expr *getThrownTypeExpr() const { return ThrownType; }
  void setThrownTypeExpr(Expr *E) { ThrownType = E; }

  SourceLoc getAsyncLoc() const { return AsyncLoc; }
  SourceLoc getThrowsLoc() const { return ThrowsLoc; }
  SourceLoc getArrowLoc() const { return ArrowLoc; }
  bool isFolded() const { return Args != nullptr && Result != nullptr; }

  SourceLoc getSourceLoc() const { return ArrowLoc; }
  SourceLoc getStartLoc() const {
    return isFolded() ? Args->getStartLoc() :
           AsyncLoc.isValid() ? AsyncLoc :
           ThrowsLoc.isValid() ? ThrowsLoc : ArrowLoc;
  }
  SourceLoc getEndLoc() const {
    return isFolded() ? Result->getEndLoc() : ArrowLoc;
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::Arrow;
  }
};

/// Represents the rebinding of 'self' in a constructor that calls out
/// to another constructor. The result of the subexpression is assigned to
/// 'self', and the expression returns void.
///
/// When a super.init or delegating initializer is invoked, 'self' is
/// reassigned to the result of the initializer (after being downcast in the
/// case of super.init).
///
/// This is needed for reference types with ObjC interop, where
/// reassigning 'self' is a supported feature, and for value type delegating
/// constructors, where the delegatee constructor is responsible for
/// initializing 'self' in-place before the delegator's logic executes.
class RebindSelfInConstructorExpr : public Expr {
  Expr *SubExpr;
  VarDecl *Self;
public:
  RebindSelfInConstructorExpr(Expr *SubExpr, VarDecl *Self);
  
  SWIFT_FORWARD_SOURCE_LOCS_TO(SubExpr)
  
  VarDecl *getSelf() const { return Self; }
  Expr *getSubExpr() const { return SubExpr; }
  void setSubExpr(Expr *Sub) { SubExpr = Sub; }

  OtherConstructorDeclRefExpr *getCalledConstructor(bool &isChainToSuper) const;
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::RebindSelfInConstructor;
  }
};

/// The ternary conditional expression 'x ? y : z'.
class TernaryExpr : public Expr {
  Expr *CondExpr, *ThenExpr, *ElseExpr;
  SourceLoc QuestionLoc, ColonLoc;
public:
  TernaryExpr(Expr *CondExpr, SourceLoc QuestionLoc, Expr *ThenExpr,
              SourceLoc ColonLoc, Expr *ElseExpr, Type Ty = Type())
      : Expr(ExprKind::Ternary, /*Implicit=*/false, Ty), CondExpr(CondExpr),
        ThenExpr(ThenExpr), ElseExpr(ElseExpr), QuestionLoc(QuestionLoc),
        ColonLoc(ColonLoc) {}

  TernaryExpr(SourceLoc QuestionLoc, Expr *ThenExpr, SourceLoc ColonLoc)
      : TernaryExpr(nullptr, QuestionLoc, ThenExpr, ColonLoc, nullptr) {}

  SourceLoc getLoc() const { return QuestionLoc; }
  SourceLoc getStartLoc() const {
    return (isFolded() ? CondExpr->getStartLoc() : QuestionLoc);
  }
  SourceLoc getEndLoc() const {
    return (isFolded() ? ElseExpr->getEndLoc() : ColonLoc);
  }
  SourceLoc getQuestionLoc() const { return QuestionLoc; }
  SourceLoc getColonLoc() const { return ColonLoc; }
  
  Expr *getCondExpr() const { return CondExpr; }
  void setCondExpr(Expr *E) { CondExpr = E; }
  
  Expr *getThenExpr() const { return ThenExpr; }
  void setThenExpr(Expr *E) { ThenExpr = E; }
  
  Expr *getElseExpr() const { return ElseExpr; }
  void setElseExpr(Expr *E) { ElseExpr = E; }
  
  /// True if the node has been processed by binary expression folding.
  bool isFolded() const { return CondExpr && ElseExpr; }
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::Ternary;
  }
};

/// EnumIsCaseExpr - A boolean expression that is true if an enum value is of
/// a particular case.
class EnumIsCaseExpr : public Expr {
  Expr *SubExpr;
  TypeRepr *CaseRepr;
  EnumElementDecl *Element;
  
public:
  EnumIsCaseExpr(Expr *SubExpr, TypeRepr *CaseRepr, EnumElementDecl *Element)
      : Expr(ExprKind::EnumIsCase, /*implicit*/ true), SubExpr(SubExpr),
        CaseRepr(CaseRepr), Element(Element) {}

  Expr *getSubExpr() const { return SubExpr; }
  void setSubExpr(Expr *e) { SubExpr = e; }

  TypeRepr *getCaseTypeRepr() const { return CaseRepr; }

  EnumElementDecl *getEnumElement() const { return Element; }

  SourceLoc getLoc() const { return SubExpr->getLoc(); }
  SourceLoc getStartLoc() const { return SubExpr->getStartLoc(); }
  SourceLoc getEndLoc() const { return SubExpr->getEndLoc(); }
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::EnumIsCase;
  }
};

/// AssignExpr - A value assignment, like "x = y".
class AssignExpr : public Expr {
  Expr *Dest;
  Expr *Src;
  SourceLoc EqualLoc;

public:  
  AssignExpr(Expr *Dest, SourceLoc EqualLoc, Expr *Src, bool Implicit)
    : Expr(ExprKind::Assign, Implicit),
      Dest(Dest), Src(Src), EqualLoc(EqualLoc) {}
  
  AssignExpr(SourceLoc EqualLoc)
    : AssignExpr(nullptr, EqualLoc, nullptr, /*Implicit=*/false)
  {}

  Expr *getDest() const { return Dest; }
  void setDest(Expr *e) { Dest = e; }
  Expr *getSrc() const { return Src; }
  void setSrc(Expr *e) { Src = e; }
  
  SourceLoc getEqualLoc() const { return EqualLoc; }
  
  SourceLoc getLoc() const {
    SourceLoc loc = EqualLoc;
    if (loc.isValid()) {
      return loc;
    }
    return getStartLoc();
  }
  SourceLoc getStartLoc() const {
    if (!isFolded()) return EqualLoc;
    return ( Dest->getStartLoc().isValid()
           ? Dest->getStartLoc()
           : Src->getStartLoc());
  }
  SourceLoc getEndLoc() const {
    if (!isFolded()) return EqualLoc;
    auto SrcEnd = Src->getEndLoc();
    return (SrcEnd.isValid() ? SrcEnd : Dest->getEndLoc());
  }
  
  /// True if the node has been processed by binary expression folding.
  bool isFolded() const { return Dest && Src; }
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::Assign;
  }
};

/// A pattern production that has been parsed but hasn't been resolved
/// into a complete pattern. Pattern checking converts these into standalone pattern
/// nodes or raises an error if a pattern production appears in an invalid
/// position.
class UnresolvedPatternExpr : public Expr {
  Pattern *subPattern;

public:
  explicit UnresolvedPatternExpr(Pattern *subPattern)
    : Expr(ExprKind::UnresolvedPattern, /*Implicit=*/false),
      subPattern(subPattern) { }
  
  const Pattern *getSubPattern() const { return subPattern; }
  Pattern *getSubPattern() { return subPattern; }
  void setSubPattern(Pattern *p) { subPattern = p; }
  
  SourceRange getSourceRange() const;
  SourceLoc getStartLoc() const;
  SourceLoc getEndLoc() const;
  SourceLoc getLoc() const;
  
  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::UnresolvedPattern;
  }
};


/// An editor placeholder (<#such as this#>) that occurred in an expression
/// context. If the placeholder is a typed one (see \c EditorPlaceholderData)
/// its type string will be typechecked and will be associated with this expr.
class EditorPlaceholderExpr : public Expr {
  Identifier Placeholder;
  SourceLoc Loc;
  TypeRepr *PlaceholderTy;
  TypeRepr *ExpansionTyR;
  Expr *SemanticExpr;

public:
  EditorPlaceholderExpr(Identifier Placeholder, SourceLoc Loc,
                        TypeRepr *PlaceholderTy, TypeRepr *ExpansionTyR)
      : Expr(ExprKind::EditorPlaceholder, /*Implicit=*/false),
        Placeholder(Placeholder), Loc(Loc), PlaceholderTy(PlaceholderTy),
        ExpansionTyR(ExpansionTyR), SemanticExpr(nullptr) {}

  Identifier getPlaceholder() const { return Placeholder; }
  SourceRange getSourceRange() const { return Loc; }
  TypeRepr *getPlaceholderTypeRepr() const { return PlaceholderTy; }

  /// The TypeRepr to be considered for placeholder expansion.
  TypeRepr *getTypeForExpansion() const { return ExpansionTyR; }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::EditorPlaceholder;
  }

  Expr *getSemanticExpr() const { return SemanticExpr; }
  void setSemanticExpr(Expr *SE) { SemanticExpr = SE; }
};

/// A LazyInitializerExpr is used to embed an existing typechecked
/// expression --- like the initializer of a lazy variable --- into an
/// untypechecked AST.
class LazyInitializerExpr : public Expr {
  Expr *SubExpr;
public:
  LazyInitializerExpr(Expr *subExpr)
    : Expr(ExprKind::LazyInitializer, /*implicit*/ true),
      SubExpr(subExpr) {}

  SourceRange getSourceRange() const { return SubExpr->getSourceRange(); }
  SourceLoc getStartLoc() const { return SubExpr->getStartLoc(); }
  SourceLoc getEndLoc() const { return SubExpr->getEndLoc(); }
  SourceLoc getLoc() const { return SubExpr->getLoc(); }

  Expr *getSubExpr() const { return SubExpr; }
  void setSubExpr(Expr *subExpr) { SubExpr = subExpr; }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::LazyInitializer;
  }
};

/// Produces the Objective-C selector of the referenced method.
///
/// \code
/// #selector(UIView.insertSubview(_:aboveSubview:))
/// \endcode
class ObjCSelectorExpr : public Expr {
  SourceLoc KeywordLoc;
  SourceLoc LParenLoc;
  SourceLoc ModifierLoc;
  Expr *SubExpr;
  SourceLoc RParenLoc;
  AbstractFunctionDecl *ResolvedMethod = nullptr;

public:
  /// The kind of #selector expression this is.
  enum ObjCSelectorKind {
    Method, Getter, Setter
  };

  ObjCSelectorExpr(ObjCSelectorKind kind, SourceLoc keywordLoc,
                   SourceLoc lParenLoc, SourceLoc modifierLoc, Expr *subExpr,
                   SourceLoc rParenLoc)
    : Expr(ExprKind::ObjCSelector, /*Implicit=*/false),
      KeywordLoc(keywordLoc), LParenLoc(lParenLoc),
      ModifierLoc(modifierLoc), SubExpr(subExpr), RParenLoc(rParenLoc) {
    Bits.ObjCSelectorExpr.SelectorKind = static_cast<unsigned>(kind);
  }

  Expr *getSubExpr() const { return SubExpr; }
  void setSubExpr(Expr *expr) { SubExpr = expr; }

  /// Whether this selector references a property getter or setter.
  bool isPropertySelector() const {
    switch (getSelectorKind()) {
    case ObjCSelectorKind::Method:
      return false;

    case ObjCSelectorKind::Getter:
    case ObjCSelectorKind::Setter:
      return true;
    }

    llvm_unreachable("Unhandled ObjcSelectorKind in switch.");
  }

  /// Whether this selector references a method.
  bool isMethodSelector() const {
    switch (getSelectorKind()) {
    case ObjCSelectorKind::Method:
      return true;

    case ObjCSelectorKind::Getter:
    case ObjCSelectorKind::Setter:
      return false;
    }
  }

  /// Retrieve the Objective-C method to which this expression refers.
  AbstractFunctionDecl *getMethod() const { return ResolvedMethod; }

  /// Set the Objective-C method to which this expression refers.
  void setMethod(AbstractFunctionDecl *method) { ResolvedMethod = method; }

  SourceLoc getLoc() const { return KeywordLoc; }
  SourceRange getSourceRange() const {
    return SourceRange(KeywordLoc, RParenLoc);
  }

  /// The location at which the getter: or setter: starts. Requires the selector
  /// to be a getter or setter.
  SourceLoc getModifierLoc() const {
    assert(isPropertySelector() && "Modifiers only set on property selectors");
    return ModifierLoc;
  }

  /// Retrieve the kind of the selector (method, getter, setter)
  ObjCSelectorKind getSelectorKind() const {
    return static_cast<ObjCSelectorKind>(Bits.ObjCSelectorExpr.SelectorKind);
  }

  /// Override the selector kind.
  ///
  /// Used by the type checker to recover from ill-formed #selector
  /// expressions.
  void overrideObjCSelectorKind(ObjCSelectorKind newKind,
                                SourceLoc modifierLoc) {
    Bits.ObjCSelectorExpr.SelectorKind = static_cast<unsigned>(newKind);
    ModifierLoc = modifierLoc;
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::ObjCSelector;
  }
};

/// Produces a keypath string for the given referenced property.
///
/// \code
/// #keyPath(Person.friends.firstName)
/// \endcode
class KeyPathExpr : public Expr {
  SourceLoc StartLoc;
  SourceLoc LParenLoc;
  SourceLoc EndLoc;
  Expr *ObjCStringLiteralExpr = nullptr;

  // The parsed root of a Swift keypath (the section before an unusual dot, like
  // Foo.Bar in \Foo.Bar.?.baz).
  Expr *ParsedRoot = nullptr;
  // The parsed path of a Swift keypath (the section after an unusual dot, like
  // ?.baz in \Foo.Bar.?.baz).
  Expr *ParsedPath = nullptr;

  // The processed/resolved type, like Foo.Bar in \Foo.Bar.?.baz.
  TypeRepr *RootType = nullptr;

  /// Determines whether a key path starts with '.' which denotes necessity for
  /// a contextual root type.
  bool HasLeadingDot = false;

public:
  /// A single stored component, which will be one of:
  /// - an unresolved DeclNameRef, which has to be type-checked
  /// - a resolved ValueDecl, referring to
  /// - a subscript index expression, which may or may not be resolved
  /// - an optional chaining, forcing, or wrapping component
  /// - a code completion token
  class Component {
  public:
    enum class Kind: unsigned {
      Invalid,
      UnresolvedProperty,
      UnresolvedSubscript,
      Property,
      Subscript,
      OptionalForce,
      OptionalChain,
      OptionalWrap,
      Identity,
      TupleElement,
      DictionaryKey,
      CodeCompletion,
    };
  
  private:
    union DeclNameOrRef {
      DeclNameRef UnresolvedName;
      ConcreteDeclRef ResolvedDecl;
      
      DeclNameOrRef() : UnresolvedName{} {}
      DeclNameOrRef(DeclNameRef un) : UnresolvedName(un) {}
      DeclNameOrRef(ConcreteDeclRef rd) : ResolvedDecl(rd) {}
    } Decl;

    ArgumentList *SubscriptArgList;
    const ProtocolConformanceRef *SubscriptHashableConformancesData;

    unsigned TupleIndex;
    Kind KindValue;
    Type ComponentType;
    SourceLoc Loc;

    // Private constructor for subscript component.
    explicit Component(DeclNameOrRef decl, ArgumentList *argList,
                       ArrayRef<ProtocolConformanceRef> indexHashables,
                       Kind kind, Type type, SourceLoc loc);

    // Private constructor for property or #keyPath dictionary key.
    explicit Component(DeclNameOrRef decl, Kind kind, Type type, SourceLoc loc)
        : Component(kind, type, loc) {
      assert(kind == Kind::Property || kind == Kind::UnresolvedProperty ||
             kind == Kind::DictionaryKey);
      Decl = decl;
    }

    // Private constructor for tuple element kind.
    explicit Component(unsigned tupleIndex, Type elementType, SourceLoc loc)
        : Component(Kind::TupleElement, elementType, loc) {
      TupleIndex = tupleIndex;
    }

    // Private constructor for basic components with no additional information.
    explicit Component(Kind kind, Type type, SourceLoc loc)
        : Decl(), KindValue(kind), ComponentType(type), Loc(loc) {}

  public:
    Component() : Component(Kind::Invalid, Type(), SourceLoc()) {}

    /// Create an unresolved component for a property.
    static Component forUnresolvedProperty(DeclNameRef UnresolvedName,
                                           SourceLoc Loc) {
      return Component(UnresolvedName, Kind::UnresolvedProperty, Type(), Loc);
    }
    
    /// Create an unresolved component for a subscript.
    static Component forUnresolvedSubscript(ASTContext &ctx,
                                            ArgumentList *argList);

    /// Create an unresolved optional force `!` component.
    static Component forUnresolvedOptionalForce(SourceLoc BangLoc) {
      return Component(Kind::OptionalForce, Type(), BangLoc);
    }
    
    /// Create an unresolved optional chain `?` component.
    static Component forUnresolvedOptionalChain(SourceLoc QuestionLoc) {
      return Component(Kind::OptionalChain, Type(), QuestionLoc);
    }
    
    /// Create a component for a property.
    static Component forProperty(ConcreteDeclRef property,
                                 Type propertyType,
                                 SourceLoc loc) {
      return Component(property, Kind::Property, propertyType, loc);
    }

    /// Create a component for a dictionary key (#keyPath only).
    static Component forDictionaryKey(DeclNameRef UnresolvedName,
                                      Type valueType,
                                      SourceLoc loc) {
      return Component(UnresolvedName, Kind::DictionaryKey, valueType, loc);
    }
    
    /// Create a component for a subscript.
    static Component
    forSubscript(ASTContext &ctx, ConcreteDeclRef subscript,
                 ArgumentList *argList, Type elementType,
                 ArrayRef<ProtocolConformanceRef> indexHashables);

    /// Create an optional-forcing `!` component.
    static Component forOptionalForce(Type forcedType, SourceLoc bangLoc) {
      return Component(Kind::OptionalForce, forcedType, bangLoc);
    }
    
    /// Create an optional-chaining `?` component.
    static Component forOptionalChain(Type unwrappedType,
                                      SourceLoc questionLoc) {
      return Component(Kind::OptionalChain, unwrappedType, questionLoc);
    }
    
    /// Create an optional-wrapping component. This doesn't have a surface
    /// syntax but may appear when the non-optional result of an optional chain
    /// is implicitly wrapped.
    static Component forOptionalWrap(Type wrappedType) {
      return Component(Kind::OptionalWrap, wrappedType, SourceLoc());
    }
    
    static Component forIdentity(SourceLoc selfLoc) {
      return Component(Kind::Identity, Type(), selfLoc);
    }
    
    static Component forTupleElement(unsigned fieldNumber,
                                     Type elementType,
                                     SourceLoc loc) {
      return Component(fieldNumber, elementType, loc);
    }

    static Component forCodeCompletion(SourceLoc Loc) {
      return Component(Kind::CodeCompletion, Type(), Loc);
    }

    SourceLoc getLoc() const {
      return Loc;
    }
    
    SourceRange getSourceRange() const {
      if (auto *args = getSubscriptArgs()) {
        return args->getSourceRange();
      }
      return Loc;
    }
    
    Kind getKind() const {
      return KindValue;
    }
    
    bool isValid() const {
      return getKind() != Kind::Invalid;
    }

    bool isResolved() const {
      if (!getComponentType())
        return false;

      switch (getKind()) {
      case Kind::Subscript:
      case Kind::OptionalChain:
      case Kind::OptionalWrap:
      case Kind::OptionalForce:
      case Kind::Property:
      case Kind::Identity:
      case Kind::TupleElement:
      case Kind::DictionaryKey:
        return true;

      case Kind::UnresolvedSubscript:
      case Kind::UnresolvedProperty:
      case Kind::Invalid:
      case Kind::CodeCompletion:
        return false;
      }
      llvm_unreachable("unhandled kind");
    }

    ArgumentList *getSubscriptArgs() const {
      switch (getKind()) {
      case Kind::Subscript:
      case Kind::UnresolvedSubscript:
        return SubscriptArgList;

      case Kind::Invalid:
      case Kind::OptionalChain:
      case Kind::OptionalWrap:
      case Kind::OptionalForce:
      case Kind::UnresolvedProperty:
      case Kind::Property:
      case Kind::Identity:
      case Kind::TupleElement:
      case Kind::DictionaryKey:
      case Kind::CodeCompletion:
        return nullptr;
      }
      llvm_unreachable("unhandled kind");
    }

    void setSubscriptArgs(ArgumentList *newArgs) {
      assert(getSubscriptArgs() && "Should be replacing existing args");
      SubscriptArgList = newArgs;
    }

    ArrayRef<ProtocolConformanceRef>
    getSubscriptIndexHashableConformances() const {
      switch (getKind()) {
      case Kind::Subscript:
        if (!SubscriptHashableConformancesData)
          return {};
        return {SubscriptHashableConformancesData, SubscriptArgList->size()};

      case Kind::UnresolvedSubscript:
      case Kind::Invalid:
      case Kind::OptionalChain:
      case Kind::OptionalWrap:
      case Kind::OptionalForce:
      case Kind::UnresolvedProperty:
      case Kind::Property:
      case Kind::Identity:
      case Kind::TupleElement:
      case Kind::DictionaryKey:
      case Kind::CodeCompletion:
        return {};
      }
      llvm_unreachable("unhandled kind");
    }

    DeclNameRef getUnresolvedDeclName() const {
      switch (getKind()) {
      case Kind::UnresolvedProperty:
      case Kind::DictionaryKey:
        return Decl.UnresolvedName;

      case Kind::Invalid:
      case Kind::Subscript:
      case Kind::UnresolvedSubscript:
      case Kind::OptionalChain:
      case Kind::OptionalWrap:
      case Kind::OptionalForce:
      case Kind::Property:
      case Kind::Identity:
      case Kind::TupleElement:
      case Kind::CodeCompletion:
        llvm_unreachable("no unresolved name for this kind");
      }
      llvm_unreachable("unhandled kind");
    }

    bool hasDeclRef() const {
      switch (getKind()) {
      case Kind::Property:
      case Kind::Subscript:
        return true;

      case Kind::Invalid:
      case Kind::UnresolvedProperty:
      case Kind::UnresolvedSubscript:
      case Kind::OptionalChain:
      case Kind::OptionalWrap:
      case Kind::OptionalForce:
      case Kind::Identity:
      case Kind::TupleElement:
      case Kind::DictionaryKey:
      case Kind::CodeCompletion:
        return false;
      }
      llvm_unreachable("unhandled kind");
    }

    ConcreteDeclRef getDeclRef() const {
      switch (getKind()) {
      case Kind::Property:
      case Kind::Subscript:
        return Decl.ResolvedDecl;

      case Kind::Invalid:
      case Kind::UnresolvedProperty:
      case Kind::UnresolvedSubscript:
      case Kind::OptionalChain:
      case Kind::OptionalWrap:
      case Kind::OptionalForce:
      case Kind::Identity:
      case Kind::TupleElement:
      case Kind::DictionaryKey:
      case Kind::CodeCompletion:
        llvm_unreachable("no decl ref for this kind");
      }
      llvm_unreachable("unhandled kind");
    }
      
    unsigned getTupleIndex() const {
      switch (getKind()) {
        case Kind::TupleElement:
          return TupleIndex;
                
        case Kind::Invalid:
        case Kind::UnresolvedProperty:
        case Kind::UnresolvedSubscript:
        case Kind::OptionalChain:
        case Kind::OptionalWrap:
        case Kind::OptionalForce:
        case Kind::Identity:
        case Kind::Property:
        case Kind::Subscript:
        case Kind::DictionaryKey:
        case Kind::CodeCompletion:
          llvm_unreachable("no field number for this kind");
      }
      llvm_unreachable("unhandled kind");
    }

    Type getComponentType() const {
      return ComponentType;
    }
    
    void setComponentType(Type t) {
      ComponentType = t;
    }
  };

private:
  llvm::MutableArrayRef<Component> Components;

  KeyPathExpr(SourceLoc startLoc, Expr *parsedRoot, Expr *parsedPath,
              SourceLoc endLoc, bool hasLeadingDot, bool isObjC,
              bool isImplicit);

  /// Create a key path with unresolved root and path expressions.
  KeyPathExpr(SourceLoc backslashLoc, Expr *parsedRoot, Expr *parsedPath,
              bool hasLeadingDot, bool isImplicit);

  /// Create a key path with components.
  KeyPathExpr(ASTContext &ctx, SourceLoc startLoc,
              ArrayRef<Component> components, SourceLoc endLoc, bool isObjC,
              bool isImplicit);

public:
  /// Create a new parsed Swift key path expression.
  static KeyPathExpr *createParsed(ASTContext &ctx, SourceLoc backslashLoc,
     Expr *parsedRoot, Expr *parsedPath,
     bool hasLeadingDot);

  /// Create a new parsed #keyPath expression.
  static KeyPathExpr *createParsedPoundKeyPath(ASTContext &ctx,
                                               SourceLoc keywordLoc,
                                               SourceLoc lParenLoc,
                                               ArrayRef<Component> components,
                                               SourceLoc rParenLoc);

  /// Create an implicit Swift key path expression with a set of resolved
  /// components.
  static KeyPathExpr *createImplicit(ASTContext &ctx, SourceLoc backslashLoc,
                                     ArrayRef<Component> components,
                                     SourceLoc endLoc);

  /// Create an implicit Swift key path expression with a root and path
  /// expression to be resolved.
  static KeyPathExpr *createImplicit(ASTContext &ctx, SourceLoc backslashLoc,
                                     Expr *parsedRoot, Expr *parsedPath,
                                     bool hasLeadingDot);

  SourceLoc getLoc() const { return StartLoc; }
  SourceRange getSourceRange() const { return SourceRange(StartLoc, EndLoc); }

  /// Get the components array.
  ArrayRef<Component> getComponents() const {
    return Components;
  }
  MutableArrayRef<Component> getMutableComponents() {
    return Components;
  }
  
  /// Set the key path components. This copies over the components from the
  /// argument array.
  void setComponents(ASTContext &C, ArrayRef<Component> newComponents);

  /// Indicates if the key path expression is composed by a single invalid
  /// component. e.g. missing component `\Root`
  bool hasSingleInvalidComponent() const {
    if (ParsedRoot && ParsedRoot->getKind() == ExprKind::Type) {
      return Components.size() == 1 && !Components.front().isValid();
    }
    return false;
  }

  /// If the provided expression appears as an argument to a subscript component
  /// of the key path, returns the index of that component. Otherwise, returns
  /// \c None.
  std::optional<unsigned> findComponentWithSubscriptArg(Expr *arg);

  /// Retrieve the string literal expression, which will be \c NULL prior to
  /// type checking and a string literal after type checking for an
  /// @objc key path.
  Expr *getObjCStringLiteralExpr() const {
    return ObjCStringLiteralExpr;
  }

  /// Set the semantic expression.
  void setObjCStringLiteralExpr(Expr *expr) {
    ObjCStringLiteralExpr = expr;
  }

  Expr *getParsedRoot() const {
    assert(!isObjC() && "cannot get parsed root of ObjC keypath");
    return ParsedRoot;
  }
  void setParsedRoot(Expr *root) {
    assert(!isObjC() && "cannot get parsed root of ObjC keypath");
    ParsedRoot = root;
  }

  Expr *getParsedPath() const {
    assert(!isObjC() && "cannot get parsed path of ObjC keypath");
    return ParsedPath;
  }
  void setParsedPath(Expr *path) {
    assert(!isObjC() && "cannot set parsed path of ObjC keypath");
    ParsedPath = path;
  }

  TypeRepr *getExplicitRootType() const {
    assert(!isObjC() && "cannot get root type of ObjC keypath");
    return RootType;
  }
  void setExplicitRootType(TypeRepr *rootType) {
    assert(!isObjC() && "cannot set root type of ObjC keypath");
    RootType = rootType;
  }

  /// True if this is an ObjC key path expression.
  bool isObjC() const { return Bits.KeyPathExpr.IsObjC; }

  /// True if this key path expression has a leading dot.
  bool expectsContextualRoot() const { return HasLeadingDot; }

  BoundGenericType *getKeyPathType() const;

  Type getRootType() const;
  Type getValueType() const;

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::KeyPath;
  }
};

/// Provides a value of type `(any Actor)?` that represents the actor
/// isolation of the current context, or `nil` if this is non-isolated
/// code.
///
/// This expression node is implicitly created by the type checker, and
/// has no in-source spelling.
class CurrentContextIsolationExpr : public Expr {
  Expr *actorExpr = nullptr;
  SourceLoc implicitLoc;

public:
  CurrentContextIsolationExpr(SourceLoc implicitLoc, Type type)
      : Expr(ExprKind::CurrentContextIsolation, /*isImplicit=*/true, type),
        implicitLoc(implicitLoc) {}

  /// The expression that produces the actor isolation value.
  Expr *getActor() const { return actorExpr; }

  void setActor(Expr *expr) {
    actorExpr = expr;
  }

  SourceLoc getLoc() const { return implicitLoc; }

  SourceRange getSourceRange() const {
    return SourceRange(implicitLoc, implicitLoc);
  }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::CurrentContextIsolation;
  }
};

/// Represents the unusual behavior of a . in a \ keypath expression, such as
/// \.[0] and \Foo.?.
class KeyPathDotExpr : public Expr {
  SourceLoc DotLoc;

public:
  KeyPathDotExpr(SourceLoc dotLoc)
      : Expr(ExprKind::KeyPathDot, /*isImplicit=*/true), DotLoc(dotLoc) {}

  SourceLoc getLoc() const { return DotLoc; }
  SourceRange getSourceRange() const { return SourceRange(DotLoc, DotLoc); }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::KeyPathDot;
  }
};

/// An expression that may wrap a statement which produces a single value.
class SingleValueStmtExpr : public Expr {
public:
  enum class Kind {
    If, Switch, Do, DoCatch
  };

private:
  Stmt *S;
  DeclContext *DC;

  SingleValueStmtExpr(Stmt *S, DeclContext *DC)
      : Expr(ExprKind::SingleValueStmt, /*isImplicit*/ true), S(S), DC(DC) {}

  /// Creates a new SingleValueStmtExpr wrapping a statement.
  static SingleValueStmtExpr *create(ASTContext &ctx, Stmt *S, DeclContext *DC);

public:
  /// Creates a new SingleValueStmtExpr wrapping a statement, and recursively
  /// attempts to wrap any branches of that statement that can become single
  /// value statement expressions.
  ///
  /// If \p mustBeExpr is true, branches will be eagerly wrapped even if they
  /// may not be valid SingleValueStmtExprs (which Sema will later diagnose).
  static SingleValueStmtExpr *createWithWrappedBranches(ASTContext &ctx,
                                                        Stmt *S,
                                                        DeclContext *DC,
                                                        bool mustBeExpr);

  /// Attempt to look through valid parent expressions to a child
  /// SingleValueStmtExpr.
  static SingleValueStmtExpr *tryDigOutSingleValueStmtExpr(Expr *E);

  /// Whether the last ASTNode in the given BraceStmt can potentially be used as
  /// the implicit result for a SingleValueStmtExpr. If \p mustBeSingleValueStmt
  /// is \c true, a result will be considered even if it may not be valid.
  static bool isLastElementImplicitResult(BraceStmt *BS, ASTContext &ctx,
                                          bool mustBeSingleValueStmt);

  /// Retrieves a resulting ThenStmt from the given BraceStmt, or \c nullptr if
  /// the brace does not have a resulting ThenStmt.
  static ThenStmt *getThenStmtFrom(BraceStmt *BS);

  /// Whether the given BraceStmt has a result to be produced from a parent
  /// SingleValueStmtExpr. Note this does not consider elements that may
  /// implicitly become results, check \c isLastElementImplicitResult for that.
  static bool hasResult(BraceStmt *BS) {
    return getThenStmtFrom(BS);
  }

  /// Retrieve the wrapped statement.
  Stmt *getStmt() const { return S; }
  void setStmt(Stmt *newS) { S = newS; }

  /// Retrieve the kind of statement being wrapped.
  Kind getStmtKind() const;

  /// Retrieve the complete set of branches for the underlying statement.
  ArrayRef<Stmt *> getBranches(SmallVectorImpl<Stmt *> &scratch) const;

  /// Retrieve the resulting ThenStmts from each branch of the
  /// SingleValueStmtExpr.
  ArrayRef<ThenStmt *>
  getThenStmts(SmallVectorImpl<ThenStmt *> &scratch) const;

  /// Retrieve the result expressions from each branch of the
  /// SingleValueStmtExpr.
  ArrayRef<Expr *>
  getResultExprs(SmallVectorImpl<Expr *> &scratch) const;

  DeclContext *getDeclContext() const { return DC; }

  SourceRange getSourceRange() const;

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::SingleValueStmt;
  }
};

class TypeJoinExpr final : public Expr,
                           private llvm::TrailingObjects<TypeJoinExpr, Expr *> {
  friend TrailingObjects;

  DeclRefExpr *Var;

  /// If this is joining the expression branches for a SingleValueStmtExpr,
  /// this holds the expr node. Otherwise, it is \c nullptr.
  SingleValueStmtExpr *SVE;

  size_t numTrailingObjects() const {
    return getNumElements();
  }

  MutableArrayRef<Expr *> getMutableElements() {
    return { getTrailingObjects<Expr *>(), getNumElements() };
  }

  TypeJoinExpr(llvm::PointerUnion<DeclRefExpr *, TypeBase *> result,
               ArrayRef<Expr *> elements, SingleValueStmtExpr *SVE);

  static TypeJoinExpr *
  createImpl(ASTContext &ctx,
             llvm::PointerUnion<DeclRefExpr *, TypeBase *> varOrType,
             ArrayRef<Expr *> elements,
             AllocationArena arena = AllocationArena::Permanent,
             SingleValueStmtExpr *SVE = nullptr);

public:
  static TypeJoinExpr *
  create(ASTContext &ctx, DeclRefExpr *var, ArrayRef<Expr *> exprs,
         AllocationArena arena = AllocationArena::Permanent) {
    return createImpl(ctx, var, exprs, arena);
  }

  static TypeJoinExpr *
  create(ASTContext &ctx, Type joinType, ArrayRef<Expr *> exprs,
         AllocationArena arena = AllocationArena::Permanent) {
    return createImpl(ctx, joinType.getPointer(), exprs, arena);
  }

  /// Create a join for the branch types of a SingleValueStmtExpr.
  static TypeJoinExpr *
  forBranchesOfSingleValueStmtExpr(ASTContext &ctx, Type joinType,
                                   SingleValueStmtExpr *SVE,
                                   AllocationArena arena);

  SourceLoc getLoc() const { return SourceLoc(); }
  SourceRange getSourceRange() const { return SourceRange(); }

  DeclRefExpr *getVar() const { return Var; }

  void setVar(DeclRefExpr *var) {
    assert(var && "cannot set variable reference to null");
    Var = var;
  }

  ArrayRef<Expr *> getElements() const {
    return { getTrailingObjects<Expr *>(), getNumElements() };
  }

  Expr *getElement(unsigned i) const {
    return getElements()[i];
  }

  void setElement(unsigned i, Expr *E) {
    getMutableElements()[i] = E;
  }

  /// If this is joining the expression branches for a SingleValueStmtExpr,
  /// this returns the expr node. Otherwise, returns \c nullptr.
  SingleValueStmtExpr *getSingleValueStmtExpr() const { return SVE; }

  unsigned getNumElements() const { return Bits.TypeJoinExpr.NumElements; }

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::TypeJoin;
  }
};

/// An invocation of a macro expansion, spelled with `#` for freestanding
/// macros or `@` for attached macros.
class MacroExpansionExpr final : public Expr,
                                 public FreestandingMacroExpansion {
private:
  DeclContext *DC;
  Expr *Rewritten;
  MacroRoles Roles;
  MacroExpansionDecl *SubstituteDecl;

public:
  enum : unsigned { InvalidDiscriminator = 0xFFFF };

  explicit MacroExpansionExpr(DeclContext *dc, MacroExpansionInfo *info,
                              MacroRoles roles, bool isImplicit = false,
                              Type ty = Type())
      : Expr(ExprKind::MacroExpansion, isImplicit, ty),
        FreestandingMacroExpansion(FreestandingMacroKind::Expr, info), DC(dc),
        Rewritten(nullptr), Roles(roles), SubstituteDecl(nullptr) {
  }

  static MacroExpansionExpr *
  create(DeclContext *dc, SourceLoc sigilLoc,
         DeclNameRef moduleName, DeclNameLoc moduleNameLoc,
         DeclNameRef macroName, DeclNameLoc macroNameLoc,
         SourceLoc leftAngleLoc,
         ArrayRef<TypeRepr *> genericArgs, SourceLoc rightAngleLoc,
         ArgumentList *argList, MacroRoles roles, bool isImplicit = false,
         Type ty = Type());

  Expr *getRewritten() const { return Rewritten; }
  void setRewritten(Expr *rewritten) { Rewritten = rewritten; }

  ArgumentList *getArgs() const {
    return FreestandingMacroExpansion::getArgs();
  }

  MacroRoles getMacroRoles() const { return Roles; }

  SourceLoc getLoc() const { return getPoundLoc(); }

  DeclContext *getDeclContext() const { return DC; }
  void setDeclContext(DeclContext *dc) { DC = dc; }

  SourceRange getSourceRange() const {
    return getExpansionInfo()->getSourceRange();
  }

  MacroExpansionDecl *createSubstituteDecl();
  MacroExpansionDecl *getSubstituteDecl() const;

  static bool classof(const Expr *E) {
    return E->getKind() == ExprKind::MacroExpansion;
  }
  static bool classof(const FreestandingMacroExpansion *expansion) {
    return expansion->getFreestandingMacroKind() == FreestandingMacroKind::Expr;
  }
};

inline bool Expr::isInfixOperator() const {
  return isa<BinaryExpr>(this) || isa<TernaryExpr>(this) ||
         isa<AssignExpr>(this) || isa<ExplicitCastExpr>(this);
}

inline Expr *const *CollectionExpr::getTrailingObjectsPointer() const {
  if (auto ty = dyn_cast<ArrayExpr>(this))
    return ty->getTrailingObjects<Expr*>();
  if (auto ty = dyn_cast<DictionaryExpr>(this))
    return ty->getTrailingObjects<Expr*>();
  llvm_unreachable("Unhandled CollectionExpr!");
}

inline const SourceLoc *CollectionExpr::getTrailingSourceLocs() const {
  if (auto ty = dyn_cast<ArrayExpr>(this))
    return ty->getTrailingObjects<SourceLoc>();
  if (auto ty = dyn_cast<DictionaryExpr>(this))
    return ty->getTrailingObjects<SourceLoc>();
  llvm_unreachable("Unhandled CollectionExpr!");
}

#undef SWIFT_FORWARD_SOURCE_LOCS_TO

void simple_display(llvm::raw_ostream &out, const ClosureExpr *CE);
void simple_display(llvm::raw_ostream &out, const DefaultArgumentExpr *expr);
void simple_display(llvm::raw_ostream &out, const Expr *expr);

SourceLoc extractNearestSourceLoc(const ClosureExpr *expr);
SourceLoc extractNearestSourceLoc(const Expr *expr);

} // end namespace swift

#endif
