text: //===--- TypeChecker.h - Type Checking Class --------------------*- C++ -*-===//
  //
  // This source file is part of the Swift.org open source project
  //
  // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
  // Licensed under Apache License v2.0 with Runtime Library Exception
  //
  // See https://swift.org/LICENSE.txt for license information
  // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
  //
  //===----------------------------------------------------------------------===//
  //
  //  This file defines the TypeChecking class.
  //
  //===----------------------------------------------------------------------===//
  
  #ifndef TYPECHECKING_H
  #define TYPECHECKING_H
  
  #include "swift/AST/ASTContext.h"
  #include "swift/AST/AccessScope.h"
  #include "swift/AST/AnyFunctionRef.h"
  #include "swift/AST/Availability.h"
  #include "swift/AST/DiagnosticsSema.h"
  #include "swift/AST/KnownProtocols.h"
  #include "swift/AST/LazyResolver.h"
  #include "swift/AST/NameLookup.h"
  #include "swift/AST/TypeRefinementContext.h"
  #include "swift/Parse/Lexer.h"
  #include "swift/Basic/OptionSet.h"
  #include "swift/Config.h"
  #include "llvm/ADT/SetVector.h"
  #include "llvm/ADT/TinyPtrVector.h"
  #include <functional>
  
  namespace swift {
  
  class GenericSignatureBuilder;
  class NominalTypeDecl;
  class NormalProtocolConformance;
  class TopLevelContext;
  class TypeChecker;
  class TypeResolution;
  class TypeResolutionOptions;
  class TypoCorrectionResults;
  class ExprPattern;
  class SynthesizedFunction;
  enum class TypeResolutionStage : uint8_t;
  
  namespace constraints {
    enum class ConstraintKind : char;
    enum class SolutionKind : char;
    class ConstraintSystem;
    class Solution;
  }
  
  /// \brief A mapping from substitutable types to the protocol-conformance
  /// mappings for those types.
  using ConformanceMap =
      llvm::DenseMap<SubstitutableType *, SmallVector<ProtocolConformance *, 2>>;
  
  /// Special-case type checking semantics for certain declarations.
  enum class DeclTypeCheckingSemantics {
    /// A normal declaration.
    Normal,
    
    /// The type(of:) declaration, which performs a "dynamic type" operation,
    /// with different behavior for existential and non-existential arguments.
    TypeOf,
    
    /// The withoutActuallyEscaping(_:do:) declaration, which makes a nonescaping
    /// closure temporarily escapable.
    WithoutActuallyEscaping,
  
    /// The _openExistential(_:do:) declaration, which extracts the value inside
    /// an existential and passes it as a value of its own dynamic type.
    OpenExistential,
  };
  
  /// The result of name lookup.
  class LookupResult {
  private:
    /// The set of results found.
    SmallVector<LookupResultEntry, 4> Results;
    size_t IndexOfFirstOuterResult = 0;
  
  public:
    LookupResult() {}
  
    explicit LookupResult(const SmallVectorImpl<LookupResultEntry> &Results,
                          size_t indexOfFirstOuterResult)
        : Results(Results.begin(), Results.end()),
          IndexOfFirstOuterResult(indexOfFirstOuterResult) {}
  
    using iterator = SmallVectorImpl<LookupResultEntry>::iterator;
    iterator begin() { return Results.begin(); }
    iterator end() {
      return Results.begin() + IndexOfFirstOuterResult;
    }
    unsigned size() const { return innerResults().size(); }
    bool empty() const { return innerResults().empty(); }
  
    ArrayRef<LookupResultEntry> innerResults() const {
      return llvm::makeArrayRef(Results).take_front(IndexOfFirstOuterResult);
    }
  
    ArrayRef<LookupResultEntry> outerResults() const {
      return llvm::makeArrayRef(Results).drop_front(IndexOfFirstOuterResult);
    }
  
    const LookupResultEntry& operator[](unsigned index) const {
      return Results[index];
    }
  
    LookupResultEntry front() const { return innerResults().front(); }
    LookupResultEntry back() const { return innerResults().back(); }
  
    /// Add a result to the set of results.
    void add(LookupResultEntry result, bool isOuter) {
      Results.push_back(result);
      if (!isOuter) {
        IndexOfFirstOuterResult++;
        assert(IndexOfFirstOuterResult == Results.size() &&
               "found an outer result before an inner one");
      } else {
        assert(IndexOfFirstOuterResult > 0 &&
               "found outer results without an inner one");
      }
    }
  
    void clear() { Results.clear(); }
  
    /// Determine whether the result set is nonempty.
    explicit operator bool() const {
      return !empty();
    }
  
    TypeDecl *getSingleTypeResult() const {
      if (size() != 1)
        return nullptr;
  
      return dyn_cast<TypeDecl>(front().getValueDecl());
    }
  
    /// Filter out any results that aren't accepted by the given predicate.
    void
    filter(llvm::function_ref<bool(LookupResultEntry, /*isOuter*/ bool)> pred);
  
    /// Shift down results by dropping inner results while keeping outer
    /// results (if any), the innermost of which are recogized as inner
    /// results afterwards.
    void shiftDownResults();
  };
  
  /// An individual result of a name lookup for a type.
  struct LookupTypeResultEntry {
    TypeDecl *Member;
    Type MemberType;
    /// The associated type that the Member/MemberType were inferred for, but only
    /// if inference happened when creating this entry.
    AssociatedTypeDecl *InferredAssociatedType;
  };
  
  /// The result of name lookup for types.
  class LookupTypeResult {
    /// The set of results found.
    SmallVector<LookupTypeResultEntry, 4> Results;
  
    friend class TypeChecker;
  
  public:
    using iterator = SmallVectorImpl<LookupTypeResultEntry>::iterator;
    iterator begin() { return Results.begin(); }
    iterator end() { return Results.end(); }
    unsigned size() const { return Results.size(); }
  
    LookupTypeResultEntry operator[](unsigned index) const {
      return Results[index];
    }
  
    LookupTypeResultEntry front() const { return Results.front(); }
    LookupTypeResultEntry back() const { return Results.back(); }
  
    /// Add a result to the set of results.
    void addResult(LookupTypeResultEntry result) { Results.push_back(result); }
  
    /// \brief Determine whether this result set is ambiguous.
    bool isAmbiguous() const {
      return Results.size() > 1;
    }
  
    /// Determine whether the result set is nonempty.
    explicit operator bool() const {
      return !Results.empty();
    }
  };
  
  /// This specifies the purpose of the contextual type, when specified to
  /// typeCheckExpression.  This is used for diagnostic generation to produce more
  /// specified error messages when the conversion fails.
  ///
  enum ContextualTypePurpose {
    CTP_Unused,           ///< No contextual type is specified.
    CTP_Initialization,   ///< Pattern binding initialization.
    CTP_ReturnStmt,       ///< Value specified to a 'return' statement.
    CTP_YieldByValue,     ///< By-value yield operand.
    CTP_YieldByReference, ///< By-reference yield operand.
    CTP_ThrowStmt,        ///< Value specified to a 'throw' statement.
    CTP_EnumCaseRawValue, ///< Raw value specified for "case X = 42" in enum.
    CTP_DefaultParameter, ///< Default value in parameter 'foo(a : Int = 42)'.
  
    CTP_CalleeResult,     ///< Constraint is placed on the result of a callee.
    CTP_CallArgument,     ///< Call to function or operator requires type.
    CTP_ClosureResult,    ///< Closure result expects a specific type.
    CTP_ArrayElement,     ///< ArrayExpr wants elements to have a specific type.
    CTP_DictionaryKey,    ///< DictionaryExpr keys should have a specific type.
    CTP_DictionaryValue,  ///< DictionaryExpr values should have a specific type.
    CTP_CoerceOperand,    ///< CoerceExpr operand coerced to specific type.
    CTP_AssignSource,     ///< AssignExpr source operand coerced to result type.
  
    CTP_CannotFail,       ///< Conversion can never fail. abort() if it does.
  };
  
  
  
  /// Flags that can be used to control name lookup.
  enum class TypeCheckExprFlags {
    /// Whether we know that the result of the expression is discarded.  This
    /// disables constraints forcing an lvalue result to be loadable.
    IsDiscarded = 0x01,
  
    /// Whether the client wants to disable the structural syntactic restrictions
    /// that we force for style or other reasons.
    DisableStructuralChecks = 0x02,
  
    /// Set if the client wants diagnostics suppressed.
    SuppressDiagnostics = 0x04,
  
    /// If set, the client wants a best-effort solution to the constraint system,
    /// but can tolerate a solution where all of the constraints are solved, but
    /// not all type variables have been determined.  In this case, the constraint
    /// system is not applied to the expression AST, but the ConstraintSystem is
    /// left in-tact.
    AllowUnresolvedTypeVariables = 0x08,
  
    /// If set, the 'convertType' specified to typeCheckExpression should not
    /// produce a conversion constraint, but it should be used to guide the
    /// solution in terms of performance optimizations of the solver, and in terms
    /// of guiding diagnostics.
    ConvertTypeIsOnlyAHint = 0x10,
  
    /// If set, this expression isn't embedded in a larger expression or
    /// statement. This should only be used for syntactic restrictions, and should
    /// not affect type checking itself.
    IsExprStmt = 0x20,
  
    /// If set, this expression is being re-type checked as part of diagnostics,
    /// and so we should not visit bodies of non-single expression closures.
    SkipMultiStmtClosures = 0x40,
  
    /// If set, don't apply a solution.
    SkipApplyingSolution = 0x100,
  
    /// This is an inout yield.
    IsInOutYield = 0x200,
  
    /// If set, a conversion constraint should be specfied so that the result of
    /// the expression is an optional type.
    ExpressionTypeMustBeOptional = 0x400,
  };
  
  using TypeCheckExprOptions = OptionSet<TypeCheckExprFlags>;
  
  inline TypeCheckExprOptions operator|(TypeCheckExprFlags flag1,
                                        TypeCheckExprFlags flag2) {
    return TypeCheckExprOptions(flag1) | flag2;
  }
  
  /// Flags that can be used to control name lookup.
  enum class NameLookupFlags {
    /// Whether we know that this lookup is always a private dependency.
    KnownPrivate = 0x01,
    /// Whether name lookup should be able to find protocol members.
    ProtocolMembers = 0x02,
    /// Whether we should map the requirement to the witness if we
    /// find a protocol member and the base type is a concrete type.
    ///
    /// If this is not set but ProtocolMembers is set, we will
    /// find protocol extension members, but not protocol requirements
    /// that do not yet have a witness (such as inferred associated
    /// types, or witnesses for derived conformances).
    PerformConformanceCheck = 0x04,
    /// Whether to perform 'dynamic' name lookup that finds @objc
    /// members of any class or protocol.
    DynamicLookup = 0x08,
    /// Whether to ignore access control for this lookup, allowing inaccessible
    /// results to be returned.
    IgnoreAccessControl = 0x10,
    /// Whether to include results from outside the innermost scope that has a
    /// result.
    IncludeOuterResults = 0x20,
  };
  
  /// A set of options that control name lookup.
  using NameLookupOptions = OptionSet<NameLookupFlags>;
  
  inline NameLookupOptions operator|(NameLookupFlags flag1,
                                     NameLookupFlags flag2) {
    return NameLookupOptions(flag1) | flag2;
  }
  
  /// Default options for member name lookup.
  const NameLookupOptions defaultMemberLookupOptions
    = NameLookupFlags::ProtocolMembers |
      NameLookupFlags::PerformConformanceCheck;
  
  /// Default options for constructor lookup.
  const NameLookupOptions defaultConstructorLookupOptions
    = NameLookupFlags::ProtocolMembers |
      NameLookupFlags::PerformConformanceCheck;
  
  /// Default options for member type lookup.
  const NameLookupOptions defaultMemberTypeLookupOptions
    = NameLookupFlags::ProtocolMembers |
      NameLookupFlags::PerformConformanceCheck;
  
  /// Default options for unqualified name lookup.
  const NameLookupOptions defaultUnqualifiedLookupOptions
    = NameLookupFlags::ProtocolMembers |
      NameLookupFlags::PerformConformanceCheck;
  
  /// Describes the result of comparing two entities, of which one may be better
  /// or worse than the other, or they are unordered.
  enum class Comparison {
    /// Neither entity is better than the other.
    Unordered,
    /// The first entity is better than the second.
    Better,
    /// The first entity is worse than the second.
    Worse
  };
  
  /// Specify how we handle the binding of underconstrained (free) type variables
  /// within a solution to a constraint system.
  enum class FreeTypeVariableBinding {
    /// Disallow any binding of such free type variables.
    Disallow,
    /// Allow the free type variables to persist in the solution.
    Allow,
    /// Bind the type variables to UnresolvedType to represent the ambiguity.
    UnresolvedType
  };
  
  /// An abstract interface that can interact with the type checker during
  /// the type checking of a particular expression.
  class ExprTypeCheckListener {
  public:
    virtual ~ExprTypeCheckListener();
  
    /// Callback invoked once the constraint system has been constructed.
    ///
    /// \param cs The constraint system that has been constructed.
    ///
    /// \param expr The pre-checked expression from which the constraint system
    /// was generated.
    ///
    /// \returns true if an error occurred that is not itself part of the
    /// constraint system, or false otherwise.
    virtual bool builtConstraints(constraints::ConstraintSystem &cs, Expr *expr);
  
    /// Callback invoked once a solution has been found.
    ///
    /// The callback may further alter the expression, returning either a
    /// new expression (to replace the result) or a null pointer to indicate
    /// failure.
    virtual Expr *foundSolution(constraints::Solution &solution, Expr *expr);
  
    /// Callback invokes once the chosen solution has been applied to the
    /// expression.
    ///
    /// The callback may further alter the expression, returning either a
    /// new expression (to replace the result) or a null pointer to indicate
    /// failure.
    virtual Expr *appliedSolution(constraints::Solution &solution,
                                  Expr *expr);
  };
  
  /// A conditional conformance that implied some other requirements. That is, \c
  /// ConformingType conforming to \c Protocol may have required additional
  /// requirements to be satisfied.
  ///
  /// This is designed to be used in a stack of such requirements, which can be
  /// formatted with \c diagnoseConformanceStack.
  struct ParentConditionalConformance {
    Type ConformingType;
    ProtocolType *Protocol;
  
    /// Format the stack \c conformances as a series of notes that trace a path of
    /// conditional conformances that lead to some other failing requirement (that
    /// is not in \c conformances).
    ///
    /// The end of \c conformances is the active end of the stack, i.e. \c
    /// conformances[0] is a conditional conformance that requires \c
    /// conformances[1], etc.
    static void
    diagnoseConformanceStack(DiagnosticEngine &diags, SourceLoc location,
                             ArrayRef<ParentConditionalConformance> conformances);
  };
  
  /// An abstract interface that is used by `checkGenericArguments`.
  class GenericRequirementsCheckListener {
  public:
    virtual ~GenericRequirementsCheckListener();
  
    /// Callback invoked before trying to check generic requirement placed
    /// between given types. Note: if either of the types assigned to the
    /// requirement is generic parameter or dependent member, this callback
    /// method is going to get their substitutions.
    ///
    /// \param kind The kind of generic requirement to check.
    ///
    /// \param first The left-hand side type assigned to the requirement,
    /// possibly represented by its generic substitute.
    ///
    /// \param second The right-hand side type assigned to the requirement,
    /// possibly represented by its generic substitute.
    ///
    ///
    /// \returns true if it's ok to validate requirement, false otherwise.
    virtual bool shouldCheck(RequirementKind kind, Type first, Type second);
  
    /// Callback to report the result of a satisfied conformance requirement.
    ///
    /// \param depTy The dependent type, from the signature.
    /// \param replacementTy The type \c depTy was replaced with.
    /// \param conformance The conformance itself.
    virtual void satisfiedConformance(Type depTy, Type replacementTy,
                                      ProtocolConformanceRef conformance);
  
    /// Callback to diagnose problem with unsatisfied generic requirement.
    ///
    /// \param req The unsatisfied generic requirement.
    ///
    /// \param first The left-hand side type assigned to the requirement,
    /// possibly represented by its generic substitute.
    ///
    /// \param second The right-hand side type assigned to the requirement,
    /// possibly represented by its generic substitute.
    ///
    /// \returns true if problem has been diagnosed, false otherwise.
    virtual bool diagnoseUnsatisfiedRequirement(
        const Requirement &req, Type first, Type second,
        ArrayRef<ParentConditionalConformance> parents);
  };
  
  /// The result of `checkGenericRequirement`.
  enum class RequirementCheckResult {
    Success, Failure, SubstitutionFailure
  };
  
  /// Flags that control protocol conformance checking.
  enum class ConformanceCheckFlags {
    /// Whether we're performing the check from within an expression.
    InExpression = 0x01,
    /// Whether we will be using the conformance in the AST.
    ///
    /// This implies that the conformance will have to be complete.
    Used = 0x02,
    /// Whether to suppress dependency tracking entirely.
    ///
    /// FIXME: This deals with some oddities with the
    /// _ObjectiveCBridgeable conformances.
    SuppressDependencyTracking = 0x04,
    /// Whether to skip the check for any conditional conformances.
    ///
    /// When set, the caller takes responsibility for any
    /// conditional requirements required for the conformance to be
    /// correctly used. Otherwise (the default), all of the conditional
    /// requirements will be checked.
    SkipConditionalRequirements = 0x08,
  
    /// Whether to require that the conditional requirements have been computed.
    ///
    /// When set, if the conditional requirements aren't available, they are just
    /// skipped, and the caller is responsible for detecting and handling this
    /// case (likely via another call to getConditionalRequirementsIfAvailable).
    AllowUnavailableConditionalRequirements = 0x10,
  };
  
  /// Options that control protocol conformance checking.
  using ConformanceCheckOptions = OptionSet<ConformanceCheckFlags>;
  
  inline ConformanceCheckOptions operator|(ConformanceCheckFlags lhs,
                                           ConformanceCheckFlags rhs) {
    return ConformanceCheckOptions(lhs) | rhs;
  }
  
  /// Describes the kind of checked cast operation being performed.
  enum class CheckedCastContextKind {
    /// None: we're just establishing how to perform the checked cast. This
    /// is useful when we don't care to produce any diagnostics.
    None,
    /// A forced cast, with "as!".
    ForcedCast,
    /// A conditional cast, with "as?".
    ConditionalCast,
    /// An "is" expression.
    IsExpr,
    /// An "is" pattern.
    IsPattern,
    /// An enum-element pattern.
    EnumElementPattern,
  };
  
  /// The Swift type checker, which takes a parsed AST and performs name binding,
  /// type checking, and semantic analysis to produce a type-annotated AST.
  class TypeChecker final : public LazyResolver {
  public:
    ASTContext &Context;
    DiagnosticEngine &Diags;
  
    /// \brief The list of function definitions we've encountered.
    std::vector<AbstractFunctionDecl *> definedFunctions;
  
    /// Declarations that need their conformances checked.
    llvm::SmallVector<Decl *, 8> ConformanceContexts;
  
    /// The list of protocol conformances that were "used" and will need to be
    /// completed before type checking is considered complete.
    llvm::SetVector<NormalProtocolConformance *> UsedConformances;
  
    /// The list of protocol conformances whose requirements could not be
    /// fully checked and, therefore, should be checked again at the top
    /// level.
    llvm::SetVector<NormalProtocolConformance *> PartiallyCheckedConformances;
  
    /// The list of declarations that we've done at least partial validation
    /// of during type-checking, but which will need to be finalized before
    /// we can hand them off to SILGen etc.
    llvm::SetVector<ValueDecl *> DeclsToFinalize;
  
    /// Track the index of the next declaration that needs to be finalized,
    /// from the \c DeclsToFinalize set.
    unsigned NextDeclToFinalize = 0;
  
    /// The list of functions that need to have their bodies synthesized.
    llvm::MapVector<FuncDecl*, SynthesizedFunction> FunctionsToSynthesize;
  
    /// The list of protocols that need their requirement signatures computed,
    /// because they were first validated by validateDeclForNameLookup(),
    /// which skips this step.
    llvm::SetVector<ProtocolDecl *> DelayedRequirementSignatures;
  
    /// The list of types whose circularity checks were delayed.
    SmallVector<NominalTypeDecl*, 8> DelayedCircularityChecks;
  
    // Caches whether a given declaration is "as specialized" as another.
    llvm::DenseMap<std::tuple<ValueDecl *, ValueDecl *,
                              /*isDynamicOverloadComparison*/ unsigned>,
                   bool>
        specializedOverloadComparisonCache;
  
    /// A list of closures for the most recently type-checked function, which we
    /// will need to compute captures for.
    std::vector<AnyFunctionRef> ClosuresWithUncomputedCaptures;
  
    /// Local functions that have been captured before their definitions.
    ///
    /// We need this to guard against functions that would transitively capture
    /// variables before their definition, e.g.:
    ///
    /// func outer() {
    ///   func first() {
    ///     second()
    ///   }
    ///   second()
    ///   var x
    ///   func second() {
    ///     use(x)
    ///   }
    /// }
  
    llvm::SmallDenseMap<AnyFunctionRef, SmallVector<AnyFunctionRef, 4>, 4>
      ForwardCapturedFuncs;
  
    /// A set of local functions from which C function pointers are derived.
    ///
    /// This is used to diagnose the use of local functions with captured context
    /// as C function pointers when the function's captures have not yet been
    /// computed.
    llvm::DenseMap<AnyFunctionRef, std::vector<Expr*>> LocalCFunctionPointers;
  
  private:
    /// Return statements with functions as return values.
    llvm::DenseMap<AbstractFunctionDecl *, llvm::DenseSet<ReturnStmt *>>
      FunctionAsReturnValue;
  
    /// Function apply expressions with a certain function as an argument.
    llvm::DenseMap<AbstractFunctionDecl *, llvm::DenseSet<ApplyExpr *>>
      FunctionAsEscapingArg;
  
    /// The # of times we have performed typo correction.
    unsigned NumTypoCorrections = 0;
  
  public:
    /// Record an occurrence of a function that captures inout values as an
    /// argument.
    ///
    /// \param decl the function that occurs as an argument.
    ///
    /// \param apply the expression in which the function appears.
    void addEscapingFunctionAsArgument(AbstractFunctionDecl *decl,
                                       ApplyExpr *apply) {
      FunctionAsEscapingArg[decl].insert(apply);
    }
  
    /// Find occurrences of a function that captures inout values as arguments.
    ///
    /// \param decl the function that occurs as an argument.
    ///
    /// \returns Expressions in which the function appears as arguments.
    llvm::DenseSet<ApplyExpr *> &
    getEscapingFunctionAsArgument(AbstractFunctionDecl *decl) {
      return FunctionAsEscapingArg[decl];
    }
  
    /// Record an occurrence of a function that captures inout values as a return
    /// value
    ///
    /// \param decl the function that occurs as a return value.
    ///
    /// \param stmt the expression in which the function appears.
    void addEscapingFunctionAsReturnValue(AbstractFunctionDecl *decl,
                                          ReturnStmt *stmt) {
      FunctionAsReturnValue[decl].insert(stmt);
    }
  
    /// Find occurrences of a function that captures inout values as return
    /// values.
    ///
    /// \param decl the function that occurs as a return value.
    ///
    /// \returns Expressions in which the function appears as arguments.
    llvm::DenseSet<ReturnStmt *> &
    getEscapingFunctionAsReturnValue(AbstractFunctionDecl *decl) {
      return FunctionAsReturnValue[decl];
    }
  
  private:
    Type IntLiteralType;
    Type MaxIntegerType;
    Type FloatLiteralType;
    Type BooleanLiteralType;
    Type UnicodeScalarType;
    Type ExtendedGraphemeClusterType;
    Type StringLiteralType;
    Type ArrayLiteralType;
    Type DictionaryLiteralType;
    Type ColorLiteralType;
    Type ImageLiteralType;
    Type FileReferenceLiteralType;
    Type StringType;
    Type SubstringType;
    Type IntType;
    Type Int8Type;
    Type UInt8Type;
    Type NSObjectType;
    Type NSNumberType;
    Type NSValueType;
    Type ObjCSelectorType;
    Type ExceptionType;
  
    /// The \c Swift.UnsafeMutablePointer<T> declaration.
    Optional<NominalTypeDecl *> ArrayDecl;
  
    /// The set of expressions currently being analyzed for failures.
    llvm::DenseMap<Expr*, Expr*> DiagnosedExprs;
  
    ModuleDecl *StdlibModule = nullptr;
  
    /// The index of the next response metavariable to bind to a REPL result.
    unsigned NextResponseVariableIndex = 0;
  
    /// If non-zero, warn when a function body takes longer than this many
    /// milliseconds to type-check.
    ///
    /// Intended for debugging purposes only.
    unsigned WarnLongFunctionBodies = 0;
  
    /// If non-zero, warn when type-checking an expression takes longer
    /// than this many milliseconds.
    ///
    /// Intended for debugging purposes only.
    unsigned WarnLongExpressionTypeChecking = 0;
  
    /// If non-zero, abort the expression type checker if it takes more
    /// than this many seconds.
    unsigned ExpressionTimeoutThreshold = 600;
  
    /// If non-zero, abort the switch statement exhaustiveness checker if
    /// the Space::minus function is called more than this many times.
    ///
    /// Why this number? Times out in about a second on a 2017 iMac, Retina 5K,
    // 4.2 GHz Intel Core i7.
    // (It's arbitrary, but will keep the compiler from taking too much time.)
    unsigned SwitchCheckingInvocationThreshold = 200000;
  
    /// If true, the time it takes to type-check each function will be dumped
    /// to llvm::errs().
    bool DebugTimeFunctionBodies = false;
  
    /// If true, the time it takes to type-check each expression will be
    /// dumped to llvm::errs().
    bool DebugTimeExpressions = false;
  
    /// Indicate that the type checker is checking code that will be
    /// immediately executed. This will suppress certain warnings
    /// when executing scripts.
    bool InImmediateMode = false;
  
    /// A helper to construct and typecheck call to super.init().
    ///
    /// \returns NULL if the constructed expression does not typecheck.
    Expr* constructCallToSuperInit(ConstructorDecl *ctor, ClassDecl *ClDecl);
  
  public:
    TypeChecker(ASTContext &Ctx) : TypeChecker(Ctx, Ctx.Diags) { }
    TypeChecker(ASTContext &Ctx, DiagnosticEngine &Diags);
    TypeChecker(const TypeChecker&) = delete;
    TypeChecker& operator=(const TypeChecker&) = delete;
    ~TypeChecker();
  
    LangOptions &getLangOpts() const { return Context.LangOpts; }
  
    /// Dump the time it takes to type-check each function to llvm::errs().
    void enableDebugTimeFunctionBodies() {
      DebugTimeFunctionBodies = true;
    }
  
    /// Dump the time it takes to type-check each function to llvm::errs().
    void enableDebugTimeExpressions() {
      DebugTimeExpressions = true;
    }
  
    bool getDebugTimeExpressions() {
      return DebugTimeExpressions;
    }
  
    /// If \p timeInMS is non-zero, warn when a function body takes longer than
    /// this many milliseconds to type-check.
    ///
    /// Intended for debugging purposes only.
    void setWarnLongFunctionBodies(unsigned timeInMS) {
      WarnLongFunctionBodies = timeInMS;
    }
  
    /// If \p timeInMS is non-zero, warn when type-checking an expression
    /// takes longer than this many milliseconds.
    ///
    /// Intended for debugging purposes only.
    void setWarnLongExpressionTypeChecking(unsigned timeInMS) {
      WarnLongExpressionTypeChecking = timeInMS;
    }
  
    /// Return the current setting for the number of milliseconds
    /// threshold we use to determine whether to warn about an
    /// expression taking a long time.
    unsigned getWarnLongExpressionTypeChecking() {
      return WarnLongExpressionTypeChecking;
    }
  
    /// Set the threshold that determines the upper bound for the number
    /// of seconds we'll let the expression type checker run before
    /// considering an expression "too complex".
    void setExpressionTimeoutThreshold(unsigned timeInSeconds) {
      ExpressionTimeoutThreshold = timeInSeconds;
    }
  
    /// Return the current setting for the threshold that determines
    /// the upper bound for the number of seconds we'll let the
    /// expression type checker run before considering an expression
    /// "too complex".
    /// If zero, do not limit the checking.
    unsigned getExpressionTimeoutThresholdInSeconds() {
      return ExpressionTimeoutThreshold;
    }
  
    /// Get the threshold that determines the upper bound for the number
    /// of times we'll let the Space::minus routine run before
    /// considering a switch statement "too complex".
    /// If zero, do not limit the checking.
    unsigned getSwitchCheckingInvocationThreshold() const {
      return SwitchCheckingInvocationThreshold;
    }
  
    /// Set the threshold that determines the upper bound for the number
    /// of times we'll let the Space::minus routine run before
    /// considering a switch statement "too complex".
    void setSwitchCheckingInvocationThreshold(unsigned invocationCount) {
      SwitchCheckingInvocationThreshold = invocationCount;
    }
  
    bool getInImmediateMode() {
      return InImmediateMode;
    }
  
    void setInImmediateMode(bool InImmediateMode) {
      this->InImmediateMode = InImmediateMode;
    }
  
    template<typename ...ArgTypes>
    InFlightDiagnostic diagnose(ArgTypes &&...Args) {
      return Diags.diagnose(std::forward<ArgTypes>(Args)...);
    }
  
    static Type getArraySliceType(SourceLoc loc, Type elementType);
    static Type getDictionaryType(SourceLoc loc, Type keyType, Type valueType);
    static Type getOptionalType(SourceLoc loc, Type elementType);
    Type getUnsafePointerType(SourceLoc loc, Type pointeeType);
    Type getUnsafeMutablePointerType(SourceLoc loc, Type pointeeType);
    Type getStringType(DeclContext *dc);
    Type getSubstringType(DeclContext *dc);
    Type getIntType(DeclContext *dc);
    Type getInt8Type(DeclContext *dc);
    Type getUInt8Type(DeclContext *dc);
    Type getMaxIntegerType(DeclContext *dc);
    Type getNSObjectType(DeclContext *dc);
    Type getObjCSelectorType(DeclContext *dc);
    Type getExceptionType(DeclContext *dc, SourceLoc loc);
    
    /// \brief Try to resolve an IdentTypeRepr, returning either the referenced
    /// Type or an ErrorType in case of error.
    static Type resolveIdentifierType(TypeResolution resolution,
                                      IdentTypeRepr *IdType,
                                      TypeResolutionOptions options);
  
    /// Bind an UnresolvedDeclRefExpr by performing name lookup and
    /// returning the resultant expression.  Context is the DeclContext used
    /// for the lookup.
    Expr *resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *Context);
  
    /// \brief Validate the given type.
    ///
    /// Type validation performs name binding, checking of generic arguments,
    /// and so on to determine whether the given type is well-formed and can
    /// be used as a type.
    ///
    /// \param Loc The type (with source location information) to validate.
    /// If the type has already been validated, returns immediately.
    ///
    /// \param resolution The type resolution being performed.
    ///
    /// \param options Options that alter type resolution.
    ///
    /// \returns true if type validation failed, or false otherwise.
    bool validateType(TypeLoc &Loc, TypeResolution resolution,
                      TypeResolutionOptions options);
  
    /// Check for unsupported protocol types in the given declaration.
    void checkUnsupportedProtocolType(Decl *decl);
  
    /// Check for unsupported protocol types in the given statement.
    void checkUnsupportedProtocolType(Stmt *stmt);
  
    /// Expose TypeChecker's handling of GenericParamList to SIL parsing.
    GenericEnvironment *handleSILGenericParams(GenericParamList *genericParams,
                                               DeclContext *DC);
  
    void validateDecl(ValueDecl *D);
    void validateDecl(OperatorDecl *decl);
    void validateDecl(PrecedenceGroupDecl *decl);
  
    /// Perform just enough validation for looking up names using the Decl.
    void validateDeclForNameLookup(ValueDecl *D);
  
    /// Validate the given extension declaration, ensuring that it
    /// properly extends the nominal type it names.
    void validateExtension(ExtensionDecl *ext);
  
    /// Request that type containing the given member needs to have all
    /// members validated after everythign in the translation unit has
    /// been processed.
    void requestMemberLayout(ValueDecl *member);
  
    /// Request that the given class needs to have all members validated
    /// after everything in the translation unit has been processed.
    void requestNominalLayout(NominalTypeDecl *nominalDecl);
  
    /// Request that the superclass of the given class, if any, needs to have
    /// all members validated after everything in the translation unit has
    /// been processed.
    void requestSuperclassLayout(ClassDecl *classDecl);
  
    /// Perform final validation of a declaration after everything in the
    /// translation unit has been processed.
    void finalizeDecl(ValueDecl *D);
  
    /// Resolve a reference to the given type declaration within a particular
    /// context.
    ///
    /// This routine aids unqualified name lookup for types by performing the
    /// resolution necessary to rectify the declaration found by name lookup with
    /// the declaration context from which name lookup started.
    ///
    /// \param typeDecl The type declaration found by name lookup.
    /// \param isSpecialized Whether the type will have generic arguments applied.
    /// \param resolution The resolution to perform.
    ///
    /// \returns the resolved type.
    static Type resolveTypeInContext(TypeDecl *typeDecl,
                                     DeclContext *foundDC,
                                     TypeResolution resolution,
                                     TypeResolutionOptions options,
                                     bool isSpecialized);
  
    /// Apply generic arguments to the given type.
    ///
    /// This function emits diagnostics about an invalid type or the wrong number
    /// of generic arguments, whereas applyUnboundGenericArguments requires this
    /// to be in a correct and valid form.
    ///
    /// \param type The generic type to which to apply arguments.
    /// \param loc The source location for diagnostic reporting.
    /// \param resolution The type resolution to perform.
    /// \param generic The arguments to apply with the angle bracket range for
    /// diagnostics.
    /// \param options The type resolution context.
    ///
    /// \returns A BoundGenericType bound to the given arguments, or null on
    /// error.
    ///
    /// \see applyUnboundGenericArguments
    static Type applyGenericArguments(Type type, SourceLoc loc,
                                      TypeResolution resolution,
                                      GenericIdentTypeRepr *generic,
                                      TypeResolutionOptions options);
  
    /// Apply generic arguments to the given type.
    ///
    /// This function requires a valid unbound generic type with the correct
    /// number of generic arguments given, whereas applyGenericArguments emits
    /// diagnostics in those cases.
    ///
    /// \param unboundType The unbound generic type to which to apply arguments.
    /// \param decl The declaration of the type.
    /// \param loc The source location for diagnostic reporting.
    /// \param resolution The type resolution.
    /// \param genericArgs The list of generic arguments to apply to the type.
    ///
    /// \returns A BoundGenericType bound to the given arguments, or null on
    /// error.
    ///
    /// \see applyGenericArguments
    static Type applyUnboundGenericArguments(UnboundGenericType *unboundType,
                                             GenericTypeDecl *decl,
                                             SourceLoc loc,
                                             TypeResolution resolution,
                                             ArrayRef<Type> genericArgs);
  
    /// \brief Substitute the given base type into the type of the given nested type,
    /// producing the effective type that the nested type will have.
    ///
    /// \param module The module in which the substitution will be performed.
    /// \param member The member whose type projection is being computed.
    /// \param baseTy The base type that will be substituted for the 'Self' of the
    /// member.
    /// \param useArchetypes Whether to use context archetypes for outer generic
    /// parameters if the class is nested inside a generic function.
    static Type substMemberTypeWithBase(ModuleDecl *module, TypeDecl *member,
                                        Type baseTy, bool useArchetypes = true);
  
    /// \brief Retrieve the superclass type of the given type, or a null type if
    /// the type has no supertype.
    Type getSuperClassOf(Type type);
  
    /// \brief Determine whether one type is a subtype of another.
    ///
    /// \param t1 The potential subtype.
    /// \param t2 The potential supertype.
    /// \param dc The context of the check.
    ///
    /// \returns true if \c t1 is a subtype of \c t2.
    bool isSubtypeOf(Type t1, Type t2, DeclContext *dc);
  
    /// \brief Determine whether one type is a subclass of another.
    ///
    /// \param t1 The potential subtype.
    /// \param t2 The potential supertype.
    /// \param dc The context of the check.
    ///
    /// \returns true if \c t1 is a subtype of \c t2.
    bool isSubclassOf(Type t1, Type t2, DeclContext *dc);
    
    /// \brief Determine whether one type is implicitly convertible to another.
    ///
    /// \param t1 The potential source type of the conversion.
    ///
    /// \param t2 The potential destination type of the conversion.
    ///
    /// \param dc The context of the conversion.
    ///
    /// \param unwrappedIUO If non-null, will be set to indicate whether the
    /// conversion force-unwrapped an implicitly-unwrapped optional.
    ///
    /// \returns true if \c t1 can be implicitly converted to \c t2.
    bool isConvertibleTo(Type t1, Type t2, DeclContext *dc,
                         bool *unwrappedIUO = nullptr);
  
    /// \brief Determine whether one type is explicitly convertible to another,
    /// i.e. using an 'as' expression.
    ///
    /// \param t1 The potential source type of the conversion.
    ///
    /// \param t2 The potential destination type of the conversion.
    ///
    /// \param dc The context of the conversion.
    ///
    /// \returns true if \c t1 can be explicitly converted to \c t2.
    bool isExplicitlyConvertibleTo(Type t1, Type t2, DeclContext *dc);
  
    /// \brief Determine whether one type is bridged to another type.
    ///
    /// \param t1 The potential source type of the conversion.
    ///
    /// \param t2 The potential destination type of the conversion.
    ///
    /// \param dc The context of the conversion.
    ///
    /// \param unwrappedIUO If non-null, will be set to indicate whether the
    /// conversion force-unwrapped an implicitly-unwrapped optional.
    ///
    /// \returns true if \c t1 can be explicitly converted to \c t2.
    bool isObjCBridgedTo(Type t1, Type t2, DeclContext *dc,
                         bool *unwrappedIUO = nullptr);
  
    /// \brief Return true if performing a checked cast from one type to another
    /// with the "as!" operator could possibly succeed.
    ///
    /// \param t1 The potential source type of the cast.
    ///
    /// \param t2 The potential destination type of the cast.
    ///
    /// \param dc The context of the cast.
    ///
    /// \returns true if a checked cast from \c t1 to \c t2 may succeed, and
    /// false if it will certainly fail, e.g. because the types are unrelated.
    bool checkedCastMaySucceed(Type t1, Type t2, DeclContext *dc);
  
    /// \brief Determine whether a constraint of the given kind can be satisfied
    /// by the two types.
    ///
    /// \param t1 The first type of the constraint.
    ///
    /// \param t2 The second type of the constraint.
    ///
    /// \param openArchetypes If true, archetypes are replaced with type
    /// variables, and the result can be interpreted as whether or not the
    /// two types can possibly equal at runtime.
    ///
    /// \param dc The context of the conversion.
    ///
    /// \param unwrappedIUO   If non-null, will be set to \c true if the coercion
    /// or bridge operation force-unwraps an implicitly-unwrapped optional.
    ///
    /// \returns true if \c t1 and \c t2 satisfy the constraint.
    bool typesSatisfyConstraint(Type t1, Type t2,
                                bool openArchetypes,
                                constraints::ConstraintKind kind,
                                DeclContext *dc,
                                bool *unwrappedIUO = nullptr);
  
    /// If the inputs to an apply expression use a consistent "sugar" type
    /// (that is, a typealias or shorthand syntax) equivalent to the result type
    /// of the function, set the result type of the expression to that sugar type.
    Expr *substituteInputSugarTypeForResult(ApplyExpr *E);
  
    bool typeCheckAbstractFunctionBodyUntil(AbstractFunctionDecl *AFD,
                                            SourceLoc EndTypeCheckLoc);
    bool typeCheckAbstractFunctionBody(AbstractFunctionDecl *AFD);
    bool typeCheckFunctionBodyUntil(FuncDecl *FD, SourceLoc EndTypeCheckLoc);
    bool typeCheckConstructorBodyUntil(ConstructorDecl *CD,
                                       SourceLoc EndTypeCheckLoc);
    bool typeCheckDestructorBodyUntil(DestructorDecl *DD,
                                      SourceLoc EndTypeCheckLoc);
  
    bool typeCheckClosureBody(ClosureExpr *closure);
  
    void typeCheckTopLevelCodeDecl(TopLevelCodeDecl *TLCD);
  
    void processREPLTopLevel(SourceFile &SF, TopLevelContext &TLC,
                             unsigned StartElem);
    Identifier getNextResponseVariableName(DeclContext *DC);
  
    void typeCheckDecl(Decl *D);
  
    void checkDeclAttributesEarly(Decl *D);
    void checkDeclAttributes(Decl *D);
    void checkTypeModifyingDeclAttributes(VarDecl *var);
  
    void checkReferenceOwnershipAttr(VarDecl *D, ReferenceOwnershipAttr *attr);
  
    /// Check the default arguments that occur within this value decl.
    void checkDefaultArguments(ParameterList *params, ValueDecl *VD);
  
    virtual void resolveDeclSignature(ValueDecl *VD) override {
      validateDeclForNameLookup(VD);
    }
  
    virtual void resolveProtocolEnvironment(ProtocolDecl *proto) override {
      validateDecl(proto);
    }
  
    virtual void bindExtension(ExtensionDecl *ext) override;
  
    virtual void resolveExtension(ExtensionDecl *ext) override {
      validateExtension(ext);
    }
  
    virtual void resolveImplicitConstructors(NominalTypeDecl *nominal) override {
      addImplicitConstructors(nominal);
    }
  
    virtual void resolveImplicitMember(NominalTypeDecl *nominal, DeclName member) override {
      synthesizeMemberForLookup(nominal, member);
    }
  
    /// Infer default value witnesses for all requirements in the given protocol.
    void inferDefaultWitnesses(ProtocolDecl *proto);
  
    /// Perform semantic checks on the given generic parameter list.
    void prepareGenericParamList(GenericParamList *genericParams,
                                 DeclContext *dc);
  
    /// Compute the generic signature, generic environment and interface type
    /// of a generic function.
    void validateGenericFuncSignature(AbstractFunctionDecl *func);
  
    /// Compute the generic signature, generic environment and interface type
    /// of a generic subscript.
    void validateGenericSubscriptSignature(SubscriptDecl *subscript);
  
    /// For a generic requirement in a protocol, make sure that the requirement
    /// set didn't add any requirements to Self or its associated types.
    void checkProtocolSelfRequirements(ValueDecl *decl);
  
    /// All generic parameters of a generic function must be referenced in the
    /// declaration's type, otherwise we have no way to infer them.
    void checkReferencedGenericParams(GenericContext *dc);
  
    /// Construct a new generic environment for the given declaration context.
    ///
    /// \param genericParams The generic parameters to validate.
    ///
    /// \param dc The declaration context in which to perform the validation.
    ///
    /// \param outerSignature The generic signature of the outer
    /// context, if not available as part of the \c dc argument (used
    /// for SIL parsing).
    ///
    /// \param ext The extension for which we're checking the generic
    /// environment, or null if we're not checking an extension.
    ///
    /// \param inferRequirements When non-empty, callback that will be invoked
    /// to perform any additional requirement inference that contributes to the
    /// generic environment..
    ///
    /// \returns the resulting generic environment.
    GenericEnvironment *checkGenericEnvironment(
                          GenericParamList *genericParams,
                          DeclContext *dc,
                          GenericSignature *outerSignature,
                          bool allowConcreteGenericParams,
                          ExtensionDecl *ext,
                          llvm::function_ref<void(GenericSignatureBuilder &)>
                            inferRequirements,
                          bool mustInferRequirements);
  
    /// Construct a new generic environment for the given declaration context.
    ///
    /// \param genericParams The generic parameters to validate.
    ///
    /// \param dc The declaration context in which to perform the validation.
    ///
    /// \param outerSignature The generic signature of the outer
    /// context, if not available as part of the \c dc argument (used
    /// for SIL parsing).
    /// \returns the resulting generic environment.
    GenericEnvironment *checkGenericEnvironment(
                          GenericParamList *genericParams,
                          DeclContext *dc,
                          GenericSignature *outerSignature,
                          bool allowConcreteGenericParams,
                          ExtensionDecl *ext) {
      return checkGenericEnvironment(genericParams, dc, outerSignature,
                                     allowConcreteGenericParams, ext,
                                     [&](GenericSignatureBuilder &) { },
                                     /*mustInferRequirements=*/false);
    }
  
    /// Validate the signature of a generic type.
    ///
    /// \param nominal The generic type.
    void validateGenericTypeSignature(GenericTypeDecl *nominal);
  
    /// Create a text string that describes the bindings of generic parameters
    /// that are relevant to the given set of types, e.g.,
    /// "[with T = Bar, U = Wibble]".
    ///
    /// \param types The types that will be scanned for generic type parameters,
    /// which will be used in the resulting type.
    ///
    /// \param genericParams The generic parameters to use to resugar any
    /// generic parameters that occur within the types.
    ///
    /// \param substitutions The generic parameter -> generic argument
    /// substitutions that will have been applied to these types.
    /// These are used to produce the "parameter = argument" bindings in the test.
    static std::string
    gatherGenericParamBindingsText(ArrayRef<Type> types,
                                TypeArrayView<GenericTypeParamType> genericParams,
                                TypeSubstitutionFn substitutions);
  
    /// Check the given set of generic arguments against the requirements in a
    /// generic signature.
    ///
    /// \param dc The context in which the generic arguments should be checked.
    /// \param loc The location at which any diagnostics should be emitted.
    /// \param noteLoc The location at which any notes will be printed.
    /// \param owner The type that owns the generic signature.
    /// \param genericParams The generic parameters being substituted.
    /// \param requirements The requirements against which the generic arguments
    /// should be checked.
    /// \param substitutions Substitutions from interface types of the signature.
    /// \param conformanceOptions The flags to use when checking conformance
    /// requirement.
    /// \param listener The generic check listener used to pick requirements and
    /// notify callers about diagnosed errors.
    static RequirementCheckResult checkGenericArguments(
        DeclContext *dc, SourceLoc loc, SourceLoc noteLoc, Type owner,
        TypeArrayView<GenericTypeParamType> genericParams,
        ArrayRef<Requirement> requirements,
        TypeSubstitutionFn substitutions,
        LookupConformanceFn conformances,
        ConformanceCheckOptions conformanceOptions = ConformanceCheckFlags::Used,
        GenericRequirementsCheckListener *listener = nullptr,
        SubstOptions options = None);
  
    /// Diagnose if the class has no designated initializers.
    void maybeDiagnoseClassWithoutInitializers(ClassDecl *classDecl);
  
    ///
    /// \brief Add any implicitly-defined constructors required for the given
    /// struct or class.
    void addImplicitConstructors(NominalTypeDecl *typeDecl);
  
    /// Synthesize the member with the given name on the target if applicable,
    /// i.e. if the member is synthesizable and has not yet been added to the
    /// target.
    void synthesizeMemberForLookup(NominalTypeDecl *target, DeclName member);
  
    /// The specified AbstractStorageDecl \c storage was just found to satisfy
    /// the protocol property \c requirement.  Ensure that it has the full
    /// complement of accessors.
    void synthesizeWitnessAccessorsForStorage(AbstractStorageDecl *requirement,
                                              AbstractStorageDecl *storage);
  
    void synthesizeFunctionBody(SynthesizedFunction fn);
  
    /// Provide storage and accessor implementations for the given property,
    /// which must be lazy.
    void completeLazyVarImplementation(VarDecl *lazyVar);
    
    /// Instantiate the storage implementation for a behavior-backed property.
    void completePropertyBehaviorStorage(VarDecl *VD,
                                 VarDecl *BehaviorStorage,
                                 FuncDecl *DefaultInitStorage,
                                 FuncDecl *ParamInitStorage,
                                 Type SelfTy,
                                 Type StorageTy,
                                 NormalProtocolConformance *BehaviorConformance,
                                 SubstitutionMap interfaceMap,
                                 SubstitutionMap contextMap);
    
    /// Instantiate the parameter implementation for a behavior-backed
    /// property.
    void completePropertyBehaviorParameter(VarDecl *VD,
                                 FuncDecl *BehaviorParameter,
                                 NormalProtocolConformance *BehaviorConformance,
                                 SubstitutionMap interfaceMap);
    
    /// Instantiate the accessor implementations for a behavior-backed
    /// property.
    void completePropertyBehaviorAccessors(VarDecl *VD,
                                       VarDecl *ValueImpl,
                                       Type valueTy,
                                       SubstitutionMap interfaceMap,
                                       SubstitutionMap contextMap);
  
    /// Pre-check the expression, validating any types that occur in the
    /// expression and folding sequence expressions.
    bool preCheckExpression(Expr *&expr, DeclContext *dc);
  
    /// \name Name lookup
    ///
    /// Routines that perform name lookup.
    ///
    /// During type checking, these routines should be used instead of
    /// \c MemberLookup and \c UnqualifiedLookup, because these routines will
    /// lazily introduce declarations and (FIXME: eventually) perform recursive
    /// type-checking that the AST-level lookup routines don't.
    ///
    /// @{
  private:
    Optional<Type> boolType;
  
  public:
    /// \brief Define the default constructor for the given struct or class.
    void defineDefaultConstructor(NominalTypeDecl *decl);
  
    /// \brief Fold the given sequence expression into an (unchecked) expression
    /// tree.
    Expr *foldSequence(SequenceExpr *expr, DeclContext *dc);
  
    /// \brief Type check the given expression.
    ///
    /// \param expr The expression to type-check, which will be modified in
    /// place.
    ///
    /// \param convertTypePurpose When convertType is specified, this indicates
    /// what the conversion is doing.  This allows diagnostics generation to
    /// produce more specific and helpful error messages when the conversion fails
    /// to be possible.
    ///
    /// \param convertType The type that the expression is being converted to,
    /// or null if the expression is standalone.  If the 'ConvertTypeIsOnlyAHint'
    /// option is specified, then this is only a hint, it doesn't produce a full
    /// conversion constraint. The location information is only used for
    /// diagnostics should the conversion fail; it is safe to pass a TypeLoc
    /// without location information.
    ///
    /// \param options Options that control how type checking is performed.
    ///
    /// \param listener If non-null, a listener that will be notified of important
    /// events in the type checking of this expression, and which can introduce
    /// additional constraints.
    ///
    /// \param baseCS If this type checking process is the simplification of
    /// another constraint system, set the original constraint system. \c null
    /// otherwise
    ///
    /// \returns The type of the top-level expression, or Type() if an
    ///          error occurred.
    Type
    typeCheckExpression(Expr *&expr, DeclContext *dc,
                        TypeLoc convertType = TypeLoc(),
                        ContextualTypePurpose convertTypePurpose = CTP_Unused,
                        TypeCheckExprOptions options = TypeCheckExprOptions(),
                        ExprTypeCheckListener *listener = nullptr,
                        constraints::ConstraintSystem *baseCS = nullptr);
  
    Type typeCheckExpression(Expr *&expr, DeclContext *dc,
                             ExprTypeCheckListener *listener) {
      return typeCheckExpression(expr, dc, TypeLoc(), CTP_Unused,
                                 TypeCheckExprOptions(), listener);
    }
  
  
    /// \brief Type check the given expression and return its type without
    /// applying the solution.
    ///
    /// \param expr The expression to type-check.
    ///
    /// \param referencedDecl Will be set to the declaration that is referenced by
    /// the expression.
    ///
    /// \param allowFreeTypeVariables Whether free type variables are allowed in
    /// the solution, and what to do with them.
    ///
    /// \param listener If non-null, a listener that will be notified of important
    /// events in the type checking of this expression, and which can introduce
    /// additional constraints.
    ///
    /// \returns the type of \p expr on success, Type() otherwise.
    /// FIXME: expr may still be modified...
    Type getTypeOfExpressionWithoutApplying(
        Expr *&expr, DeclContext *dc,
        ConcreteDeclRef &referencedDecl,
        FreeTypeVariableBinding allowFreeTypeVariables =
                                FreeTypeVariableBinding::Disallow,
        ExprTypeCheckListener *listener = nullptr);
  
    void getPossibleTypesOfExpressionWithoutApplying(
        Expr *&expr, DeclContext *dc, SmallPtrSetImpl<TypeBase *> &types,
        FreeTypeVariableBinding allowFreeTypeVariables =
            FreeTypeVariableBinding::Disallow,
        ExprTypeCheckListener *listener = nullptr);
  
    bool typeCheckCompletionSequence(Expr *&expr, DeclContext *DC);
  
    /// \brief Type check the given expression assuming that its children
    /// have already been fully type-checked.
    ///
    /// \param expr The expression to type-check, which will be modified in
    /// place.
    ///
    /// \returns true if an error occurred, false otherwise.
    bool typeCheckExpressionShallow(Expr *&expr, DeclContext *dc);
  
    /// Check the key-path expression.
    ///
    /// Returns the type of the last component of the key-path.
    Optional<Type> checkObjCKeyPathExpr(DeclContext *dc, KeyPathExpr *expr,
                                        bool requireResultType = false);
  
    /// \brief Type check whether the given type declaration includes members of
    /// unsupported recursive value types.
    ///
    /// \param decl The declaration to be type-checked. This process will not
    /// modify the declaration.
    void checkDeclCircularity(NominalTypeDecl *decl);
  
    /// \brief Type check whether the given switch statement exhaustively covers
    /// its domain.
    ///
    /// \param stmt The switch statement to be type-checked.  No modification of
    /// the statement occurs.
    /// \param DC The decl context containing \p stmt.
    /// \param limitChecking The checking process relies on the switch statement
    /// being well-formed.  If it is not, pass true to this flag to run a limited
    /// form of analysis.
    void checkSwitchExhaustiveness(const SwitchStmt *stmt, const DeclContext *DC,
                                   bool limitChecking);
  
    /// \brief Type check the given expression as a condition, which converts
    /// it to a logic value.
    ///
    /// \param expr The expression to type-check, which will be modified in place
    /// to return a logic value (builtin i1).
    ///
    /// \returns true if an error occurred, false otherwise.
    bool typeCheckCondition(Expr *&expr, DeclContext *dc);
  
    /// \brief Type check the given 'if' or 'while' statement condition, which
    /// either converts an expression to a logic value or bind variables to the
    /// contents of an Optional.
    ///
    /// \param cond The condition to type-check, which will be modified in place.
    ///
    /// \returns true if an error occurred, false otherwise.
    bool typeCheckStmtCondition(StmtCondition &cond, DeclContext *dc,
                                Diag<> diagnosticForAlwaysTrue);
  
    /// \brief Determine the semantics of a checked cast operation.
    ///
    /// \param fromType       The source type of the cast.
    /// \param toType         The destination type of the cast.
    /// \param dc             The context of the cast.
    /// \param diagLoc        The location at which to report diagnostics.
    /// \param fromExpr       The expression describing the input operand.
    /// \param diagToRange    The source range of the destination type.
    ///
    /// \returns a CheckedCastKind indicating the semantics of the cast. If the
    /// cast is invalid, Unresolved is returned. If the cast represents an implicit
    /// conversion, Coercion is returned.
    CheckedCastKind typeCheckCheckedCast(Type fromType,
                                         Type toType,
                                         CheckedCastContextKind contextKind,
                                         DeclContext *dc,
                                         SourceLoc diagLoc,
                                         Expr *fromExpr,
                                         SourceRange diagToRange);
  
    /// Find the Objective-C class that bridges between a value of the given
    /// dynamic type and the given value type.
    ///
    /// \param dc The declaration context from which we will look for
    /// bridging.
    ///
    /// \param dynamicType A dynamic type from which we are bridging. Class and
    /// Objective-C protocol types can be used for bridging.
    ///
    /// \param valueType The value type being queried, e.g., String.
    ///
    /// \returns the Objective-C class type that represents the value
    /// type as an Objective-C class, e.g., \c NSString represents \c
    /// String, or a null type if there is no such type or if the
    /// dynamic type isn't something we can start from.
    Type getDynamicBridgedThroughObjCClass(DeclContext *dc,
                                           Type dynamicType,
                                           Type valueType);
  
    /// \brief Resolve ambiguous pattern/expr productions inside a pattern using
    /// name lookup information. Must be done before type-checking the pattern.
    Pattern *resolvePattern(Pattern *P, DeclContext *dc,
                            bool isStmtCondition);
  
    /// Type check the given pattern.
    ///
    /// \param P The pattern to type check.
    /// \param dc The context in which type checking occurs.
    /// \param options Options that control type resolution.
    ///
    /// \returns true if any errors occurred during type checking.
    bool typeCheckPattern(Pattern *P, DeclContext *dc,
                          TypeResolutionOptions options);
  
    bool typeCheckCatchPattern(CatchStmt *S, DeclContext *dc);
  
    /// Request nominal layout for any types that could be sources of typemetadata
    /// or conformances.
    void requestRequiredNominalTypeLayoutForParameters(ParameterList *PL);
  
    /// Type check a parameter list.
    bool typeCheckParameterList(ParameterList *PL, TypeResolution resolution,
                                TypeResolutionOptions options);
  
    /// Coerce a pattern to the given type.
    ///
    /// \param P The pattern, which may be modified by this coercion.
    /// \param resolution The type resolution.
    /// \param type the type to coerce the pattern to.
    /// \param options Options describing how to perform this coercion.
    ///
    /// \returns true if an error occurred, false otherwise.
    bool coercePatternToType(Pattern *&P, TypeResolution resolution, Type type,
                             TypeResolutionOptions options,
                             TypeLoc tyLoc = TypeLoc());
    bool typeCheckExprPattern(ExprPattern *EP, DeclContext *DC,
                              Type type);
  
    /// Coerce the specified parameter list of a ClosureExpr to the specified
    /// contextual type.
    ///
    /// \returns true if an error occurred, false otherwise.
    bool coerceParameterListToType(ParameterList *P, ClosureExpr *CE, AnyFunctionType *FN);
  
    
    /// Type-check an initialized variable pattern declaration.
    bool typeCheckBinding(Pattern *&P, Expr *&Init, DeclContext *DC,
                          bool skipApplyingSolution);
    bool typeCheckPatternBinding(PatternBindingDecl *PBD, unsigned patternNumber,
                                 bool skipApplyingSolution);
  
    /// Type-check a for-each loop's pattern binding and sequence together.
    bool typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt);
  
    /// \brief Lazily diagnose conversions to C function pointers of closures
    /// with captures.
    void maybeDiagnoseCaptures(Expr *E, AnyFunctionRef AFR);
  
    /// \brief Compute the set of captures for the given function or closure.
    void computeCaptures(AnyFunctionRef AFR);
  
    /// \brief Change the context of closures in the given initializer
    /// expression to the given context.
    ///
    /// \returns true if any closures were found
    static bool contextualizeInitializer(Initializer *DC, Expr *init);
    static void contextualizeTopLevelCode(TopLevelContext &TLC,
                                          ArrayRef<Decl*> topLevelDecls);
  
    /// Return the type-of-reference of the given value.
    ///
    /// \param baseType if non-null, return the type of a member reference to
    ///   this value when the base has the given type
    ///
    /// \param UseDC The context of the access.  Some variables have different
    ///   types depending on where they are used.
    ///
    /// \param base The optional base expression of this value reference
    ///
    /// \param wantInterfaceType Whether we want the interface type, if available.
    ///
    /// \param getType Optional callback to extract a type for given declaration.
    Type getUnopenedTypeOfReference(VarDecl *value, Type baseType,
                                    DeclContext *UseDC,
                                    llvm::function_ref<Type(VarDecl *)> getType,
                                    const DeclRefExpr *base = nullptr,
                                    bool wantInterfaceType = false);
  
    /// Return the type-of-reference of the given value.
    ///
    /// \param baseType if non-null, return the type of a member reference to
    ///   this value when the base has the given type
    ///
    /// \param UseDC The context of the access.  Some variables have different
    ///   types depending on where they are used.
    ///
    /// \param base The optional base expression of this value reference
    ///
    /// \param wantInterfaceType Whether we want the interface type, if available.
    Type getUnopenedTypeOfReference(VarDecl *value, Type baseType,
                                    DeclContext *UseDC,
                                    const DeclRefExpr *base = nullptr,
                                    bool wantInterfaceType = false) {
      return getUnopenedTypeOfReference(
          value, baseType, UseDC,
          [&](VarDecl *var) -> Type {
            validateDecl(var);
  
            if (!var->hasValidSignature() || var->isInvalid())
              return ErrorType::get(Context);
  
            return wantInterfaceType ? value->getInterfaceType()
                                     : value->getType();
          },
          base, wantInterfaceType);
    }
  
    /// \brief Retrieve the default type for the given protocol.
    ///
    /// Some protocols, particularly those that correspond to literals, have
    /// default types associated with them. This routine retrieves that default
    /// type.
    ///
    /// \returns the default type, or null if there is no default type for
    /// this protocol.
    Type getDefaultType(ProtocolDecl *protocol, DeclContext *dc);
  
    /// \brief Convert the given expression to the given type.
    ///
    /// \param expr The expression, which will be updated in place.
    /// \param type The type to convert to.
    /// \param typeFromPattern Optionally, the caller can specify the pattern
    ///   from where the toType is derived, so that we can deliver better fixit.
    ///
    /// \returns true if an error occurred, false otherwise.
    bool convertToType(Expr *&expr, Type type, DeclContext *dc,
                       Optional<Pattern*> typeFromPattern = None);
  
    /// \brief Coerce the given expression to materializable type, if it
    /// isn't already.
    Expr *coerceToRValue(Expr *expr,
                         llvm::function_ref<Type(Expr *)> getType
                           = [](Expr *expr) { return expr->getType(); },
                         llvm::function_ref<void(Expr *, Type)> setType
                           = [](Expr *expr, Type type) {
                             expr->setType(type);
                           });
  
    /// \brief Add implicit load expression to given AST, this is sometimes
    /// more complicated than simplify wrapping given root in newly created
    /// `LoadExpr`, because `ForceValueExpr` and `ParenExpr` supposed to appear
    /// only at certain positions in AST.
    Expr *addImplicitLoadExpr(Expr *expr,
                              std::function<Type(Expr *)> getType,
                              std::function<void(Expr *, Type)> setType);
  
    /// Require that the library intrinsics for working with Optional<T>
    /// exist.
    bool requireOptionalIntrinsics(SourceLoc loc);
  
    /// Require that the library intrinsics for working with
    /// UnsafeMutablePointer<T> exist.
    bool requirePointerArgumentIntrinsics(SourceLoc loc);
  
    /// Require that the library intrinsics for creating
    /// array literals exist.
    bool requireArrayLiteralIntrinsics(SourceLoc loc);
  
    /// \brief Retrieve the witness type with the given name.
    ///
    /// \param type The type that conforms to the given protocol.
    ///
    /// \param protocol The protocol through which we're looking.
    ///
    /// \param conformance The protocol conformance.
    ///
    /// \param name The name of the associated type.
    ///
    /// \param brokenProtocolDiag Diagnostic to emit if the type cannot be
    /// accessed.
    ///
    /// \return the witness type, or null if an error occurs or the type
    /// returned would contain an ErrorType.
    Type getWitnessType(Type type, ProtocolDecl *protocol,
                        ProtocolConformanceRef conformance,
                        Identifier name,
                        Diag<> brokenProtocolDiag);
  
    /// \brief Build a call to the witness with the given name and arguments.
    ///
    /// \param base The base expression, whose witness will be invoked.
    ///
    /// \param protocol The protocol to call through.
    ///
    /// \param conformance The conformance of the base type to the given
    /// protocol.
    ///
    /// \param name The name of the method to call.
    ///
    /// \param arguments The arguments to the witness.
    ///
    /// \param brokenProtocolDiag Diagnostic to emit if the protocol is broken.
    ///
    /// \returns a fully type-checked call, or null if the protocol was broken.
    Expr *callWitness(Expr *base, DeclContext *dc,
                      ProtocolDecl *protocol,
                      ProtocolConformanceRef conformance,
                      DeclName name,
                      MutableArrayRef<Expr *> arguments,
                      Diag<> brokenProtocolDiag);
  
    /// \brief Determine whether the given type contains the given protocol.
    ///
    /// \param DC The context in which to check conformance. This affects, for
    /// example, extension visibility.
    ///
    /// \param options Options that control the conformance check.
    ///
    /// \returns the conformance, if \c T conforms to the protocol \c Proto, or
    /// an empty optional.
    static Optional<ProtocolConformanceRef> containsProtocol(
                                               Type T, ProtocolDecl *Proto,
                                               DeclContext *DC,
                                               ConformanceCheckOptions options);
  
    /// \brief Determine whether the given type conforms to the given protocol.
    ///
    /// Unlike subTypeOfProtocol(), this will return false for existentials of
    /// non-self conforming protocols.
    ///
    /// \param DC The context in which to check conformance. This affects, for
    /// example, extension visibility.
    ///
    /// \param options Options that control the conformance check.
    ///
    /// \param ComplainLoc If valid, then this function will emit diagnostics if
    /// T does not conform to the given protocol. The primary diagnostic will
    /// be placed at this location, with notes for each of the protocol
    /// requirements not satisfied.
    ///
    /// \returns The protocol conformance, if \c T conforms to the
    /// protocol \c Proto, or \c None.
    static Optional<ProtocolConformanceRef> conformsToProtocol(
                                             Type T,
                                             ProtocolDecl *Proto,
                                             DeclContext *DC,
                                             ConformanceCheckOptions options,
                                             SourceLoc ComplainLoc = SourceLoc());
  
    /// Mark the given protocol conformance as "used" from the given declaration
    /// context.
    void markConformanceUsed(ProtocolConformanceRef conformance,
                             DeclContext *dc) override final;
  
    /// Functor class suitable for use as a \c LookupConformanceFn to look up a
    /// conformance through a particular declaration context using the given
    /// type checker.
    class LookUpConformance {
      DeclContext *dc;
  
    public:
      explicit LookUpConformance(DeclContext *dc) : dc(dc) { }
  
      Optional<ProtocolConformanceRef>
      operator()(CanType dependentType,
                 Type conformingReplacementType,
                 ProtocolDecl *conformedProtocol) const;
    };
  
    /// Completely check the given conformance.
    void checkConformance(NormalProtocolConformance *conformance);
  
    /// Check the requirement signature of the given conformance.
    void checkConformanceRequirements(NormalProtocolConformance *conformance);
  
    /// Check all of the conformances in the given context.
    void checkConformancesInContext(DeclContext *dc,
                                    IterableDeclContext *idc);
  
    /// Check that the type of the given property conforms to NSCopying.
    ///
    /// Return true if there was an error.
    bool checkConformanceToNSCopying(VarDecl *var);
  
    /// Mark any _BridgedNSError/_BridgedStoredNSError/related
    /// conformances in the given type as "used".
    void useBridgedNSErrorConformances(DeclContext *dc, Type type);
  
    /// Derive an implicit declaration to satisfy a requirement of a derived
    /// protocol conformance.
    ///
    /// \param DC           The declaration context where the conformance was
    ///                     defined, either the type itself or an extension
    /// \param TypeDecl     The type for which the requirement is being derived.
    /// \param Requirement  The protocol requirement.
    ///
    /// \returns nullptr if the derivation failed, or the derived declaration
    ///          if it succeeded. If successful, the derived declaration is added
    ///          to TypeDecl's body.
    ValueDecl *deriveProtocolRequirement(DeclContext *DC,
                                         NominalTypeDecl *TypeDecl,
                                         ValueDecl *Requirement);
  
    /// Derive an implicit type witness for the given associated type in
    /// the conformance of the given nominal type to some known
    /// protocol.
    Type deriveTypeWitness(DeclContext *DC,
                           NominalTypeDecl *nominal,
                           AssociatedTypeDecl *assocType);
  
    /// Record the witness information into the given conformance that maps
    /// the given requirement to the given witness declaration.
    ///
    /// Use this routine only when the given witness is known to satisfy the
    /// requirement, e.g., because the witness itself was synthesized. This
    /// function is not allowed to fail.
    void recordKnownWitness(NormalProtocolConformance *conformance,
                            ValueDecl *req, ValueDecl *witness);
  
    /// Perform unqualified name lookup at the given source location
    /// within a particular declaration context.
    ///
    /// \param dc The declaration context in which to perform name lookup.
    /// \param name The name of the entity to look for.
    /// \param loc The source location at which name lookup occurs.
    /// \param options Options that control name lookup.
    static LookupResult lookupUnqualified(DeclContext *dc, DeclName name,
                                          SourceLoc loc,
                                          NameLookupOptions options
                                            = defaultUnqualifiedLookupOptions);
  
    /// Perform unqualified type lookup at the given source location
    /// within a particular declaration context.
    ///
    /// \param dc The declaration context in which to perform name lookup.
    /// \param name The name of the entity to look for.
    /// \param loc The source location at which name lookup occurs.
    /// \param options Options that control name lookup.
    LookupResult
    static lookupUnqualifiedType(DeclContext *dc, DeclName name, SourceLoc loc,
                                 NameLookupOptions options
                                   = defaultUnqualifiedLookupOptions);
  
    /// \brief Lookup a member in the given type.
    ///
    /// \param dc The context that needs the member.
    /// \param type The type in which we will look for a member.
    /// \param name The name of the member to look for.
    /// \param options Options that control name lookup.
    ///
    /// \returns The result of name lookup.
    static LookupResult lookupMember(DeclContext *dc, Type type, DeclName name,
                                     NameLookupOptions options
                                       = defaultMemberLookupOptions);
  
    /// \brief Check whether the given declaration can be written as a
    /// member of the given base type.
    static bool isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl);
  
    /// \brief Look up a member type within the given type.
    ///
    /// This routine looks for member types with the given name within the
    /// given type.
    ///
    /// \param dc The context that needs the member.
    /// \param type The type in which we will look for a member type.
    /// \param name The name of the member to look for.
    /// \param options Options that control name lookup.
    ///
    /// \returns The result of name lookup.
    static LookupTypeResult lookupMemberType(DeclContext *dc, Type type,
                                             Identifier name,
                                             NameLookupOptions options
                                               = defaultMemberTypeLookupOptions);
  
    /// \brief Look up the constructors of the given type.
    ///
    /// \param dc The context that needs the constructor.
    /// \param type The type for which we will look for constructors.
    /// \param options Options that control name lookup.
    ///
    /// \returns the constructors found for this type.
    LookupResult lookupConstructors(DeclContext *dc, Type type,
                                    NameLookupOptions options
                                      = defaultConstructorLookupOptions);
  
    /// Given an expression that's known to be an infix operator,
    /// look up its precedence group.
    PrecedenceGroupDecl *
    lookupPrecedenceGroupForInfixOperator(DeclContext *dc, Expr *op);
  
    PrecedenceGroupDecl *lookupPrecedenceGroup(DeclContext *dc, Identifier name,
                                               SourceLoc nameLoc);
  
    /// \brief Look up the Bool type in the standard library.
    Type lookupBoolType(const DeclContext *dc);
  
    /// @}
  
    /// \name Overload resolution
    ///
    /// Routines that perform overload resolution or provide diagnostics related
    /// to overload resolution.
    /// @{
  
    /// Compare two declarations to determine whether one is more specialized
    /// than the other.
    ///
    /// A declaration is more specialized than another declaration if its type
    /// is a subtype of the other declaration's type (ignoring the 'self'
    /// parameter of function declarations) and if
    Comparison compareDeclarations(DeclContext *dc,
                                   ValueDecl *decl1,
                                   ValueDecl *decl2);
  
    /// \brief Build a type-checked reference to the given value.
    Expr *buildCheckedRefExpr(VarDecl *D, DeclContext *UseDC,
                              DeclNameLoc nameLoc, bool Implicit);
  
    /// \brief Build a reference to a declaration, where name lookup returned
    /// the given set of declarations.
    Expr *buildRefExpr(ArrayRef<ValueDecl *> Decls, DeclContext *UseDC,
                       DeclNameLoc NameLoc, bool Implicit,
                       FunctionRefKind functionRefKind);
    /// @}
  
    /// \brief Retrieve a specific, known protocol.
    ///
    /// \param loc The location at which we need to look for the protocol.
    /// \param kind The known protocol we're looking for.
    ///
    /// \returns null if the protocol is not available. This represents a
    /// problem with the Standard Library.
    ProtocolDecl *getProtocol(SourceLoc loc, KnownProtocolKind kind);
  
    /// \brief Retrieve the literal protocol for the given expression.
    ///
    /// \returns the literal protocol, if known and available, or null if the
    /// expression does not have an associated literal protocol.
    ProtocolDecl *getLiteralProtocol(Expr *expr);
  
    DeclName getObjectLiteralConstructorName(ObjectLiteralExpr *expr);
  
    Type getObjectLiteralParameterType(ObjectLiteralExpr *expr,
                                       ConstructorDecl *ctor);
  
    /// Get the module appropriate for looking up standard library types.
    ///
    /// This is "Swift", if that module is imported, or the current module if
    /// we're parsing the standard library.
    ModuleDecl *getStdlibModule(const DeclContext *dc);
  
    /// \name Lazy resolution.
    ///
    /// Routines that perform lazy resolution as required for AST operations.
    /// @{
    void resolveTypeWitness(const NormalProtocolConformance *conformance,
                            AssociatedTypeDecl *assocType) override;
    void resolveWitness(const NormalProtocolConformance *conformance,
                        ValueDecl *requirement) override;
  
    /// \name Resilience diagnostics
  
    void diagnoseInlinableLocalType(const NominalTypeDecl *NTD);
  
    /// Used in diagnostic %selects.
    enum class FragileFunctionKind : unsigned {
      Transparent,
      InlineAlways,
      Inlinable,
      DefaultArgument,
      PropertyInitializer
    };
  
    bool diagnoseInlinableDeclRef(SourceLoc loc, const ValueDecl *D,
                                  const DeclContext *DC,
                                  FragileFunctionKind Kind,
                                  bool TreatUsableFromInlineAsPublic);
  
    /// Given that \p DC is within a fragile context for some reason, describe
    /// why.
    ///
    /// The second element of the pair is true if references to @usableFromInline
    /// declarations are permitted.
    ///
    /// \see FragileFunctionKind
    std::pair<FragileFunctionKind, bool>
    getFragileFunctionKind(const DeclContext *DC);
  
    /// \name Availability checking
    ///
    /// Routines that perform API availability checking and type checking of
    /// potentially unavailable API elements
    /// @{
  
    /// \brief Returns true if the availability of the witness
    /// is sufficient to safely conform to the requirement in the context
    /// the provided conformance. On return, requiredAvailability holds th
    /// availability levels required for conformance.
    bool
    isAvailabilitySafeForConformance(ProtocolDecl *proto, ValueDecl *requirement,
                                     ValueDecl *witness, DeclContext *dc,
                                     AvailabilityContext &requiredAvailability);
  
    /// Returns an over-approximation of the range of operating system versions
    /// that could the passed-in location could be executing upon for
    /// the target platform. If MostRefined != nullptr, set to the most-refined
    /// TRC found while approximating.
    AvailabilityContext
    overApproximateAvailabilityAtLocation(SourceLoc loc, const DeclContext *DC,
                                          const TypeRefinementContext **MostRefined=nullptr);
  
    /// Walk the AST to build the hierarchy of TypeRefinementContexts
    ///
    /// \param StartElem Where to start for incremental building of refinement
    /// contexts
    void buildTypeRefinementContextHierarchy(SourceFile &SF,
                                             unsigned StartElem);
  
    /// Build the hierarchy of TypeRefinementContexts for the entire
    /// source file, if it has not already been built. Returns the root
    /// TypeRefinementContext for the source file.
    TypeRefinementContext *getOrBuildTypeRefinementContext(SourceFile *SF);
  
    /// Returns a diagnostic indicating why the declaration cannot be annotated
    /// with an @available() attribute indicating it is potentially unavailable
    /// or None if this is allowed.
    Optional<Diag<>>
    diagnosticIfDeclCannotBePotentiallyUnavailable(const Decl *D);
  
    /// Checks whether a declaration is available when referred to at the given
    /// location (this reference location must be in the passed-in
    /// reference DeclContext).
    /// If the declaration is available, return true.
    /// If the declaration is not available, return false and write the
    /// declaration's availability info to the out parameter
    /// \p OutAvailableRange.
    bool isDeclAvailable(const Decl *D, SourceLoc referenceLoc,
                         const DeclContext *referenceDC,
                         AvailabilityContext &OutAvailableRange);
  
    /// Checks whether a declaration should be considered unavailable when
    /// referred to at the given location and, if so, returns the reason why the
    /// declaration is unavailable. Returns None is the declaration is
    /// definitely available.
    Optional<UnavailabilityReason>
    checkDeclarationAvailability(const Decl *D, SourceLoc referenceLoc,
                                 const DeclContext *referenceDC);
  
    /// Checks an "ignored" expression to see if it's okay for it to be ignored.
    ///
    /// An ignored expression is one that is not nested within a larger
    /// expression or statement.
    void checkIgnoredExpr(Expr *E);
  
    // Emits a diagnostic, if necessary, for a reference to a declaration
    // that is potentially unavailable at the given source location.
    void diagnosePotentialUnavailability(const ValueDecl *D,
                                         SourceRange ReferenceRange,
                                         const DeclContext *ReferenceDC,
                                         const UnavailabilityReason &Reason);
  
    // Emits a diagnostic, if necessary, for a reference to a declaration
    // that is potentially unavailable at the given source location, using
    // Name as the diagnostic name.
    void diagnosePotentialUnavailability(const Decl *D, DeclName Name,
                                         SourceRange ReferenceRange,
                                         const DeclContext *ReferenceDC,
                                         const UnavailabilityReason &Reason);
  
    /// Emits a diagnostic for a reference to a storage accessor that is
    /// potentially unavailable.
    void diagnosePotentialAccessorUnavailability(
        AccessorDecl *Accessor, SourceRange ReferenceRange,
        const DeclContext *ReferenceDC, const UnavailabilityReason &Reason,
        bool ForInout);
  
    /// Returns the availability attribute indicating deprecation if the
    /// declaration is deprecated or null otherwise.
    static const AvailableAttr *getDeprecated(const Decl *D);
  
    /// Emits a diagnostic for a reference to a declaration that is deprecated.
    /// Callers can provide a lambda that adds additional information (such as a
    /// fixit hint) to the deprecation diagnostic, if it is emitted.
    void diagnoseIfDeprecated(SourceRange SourceRange,
                              const DeclContext *ReferenceDC,
                              const ValueDecl *DeprecatedDecl,
                              const ApplyExpr *Call);
    /// @}
  
    /// If LangOptions::DebugForbidTypecheckPrefix is set and the given decl
    /// has a name with that prefix, an llvm fatal_error is triggered.
    /// This is for testing purposes.
    void checkForForbiddenPrefix(const Decl *D);
    void checkForForbiddenPrefix(const UnresolvedDeclRefExpr *E);
    void checkForForbiddenPrefix(Identifier Ident);
    void checkForForbiddenPrefix(StringRef Name);
  
    bool hasEnabledForbiddenTypecheckPrefix() const {
      return !Context.LangOpts.DebugForbidTypecheckPrefix.empty();
    }
  
    /// Check error handling in the given type-checked top-level code.
    void checkTopLevelErrorHandling(TopLevelCodeDecl *D);
    void checkFunctionErrorHandling(AbstractFunctionDecl *D);
    void checkInitializerErrorHandling(Initializer *I, Expr *E);
    void checkEnumElementErrorHandling(EnumElementDecl *D);
  
    void addExprForDiagnosis(Expr *E1, Expr *Result) {
      DiagnosedExprs[E1] = Result;
    }
    bool isExprBeingDiagnosed(Expr *E) {
      return DiagnosedExprs.count(E);
    }
    Expr *getExprBeingDiagnosed(Expr *E) {
      return DiagnosedExprs[E];
    }
  
    /// If an expression references 'self.init' or 'super.init' in an
    /// initializer context, returns the implicit 'self' decl of the constructor.
    /// Otherwise, return nil.
    VarDecl *getSelfForInitDelegationInConstructor(DeclContext *DC,
                                                   UnresolvedDotExpr *ctorRef);
  
    /// Diagnose assigning variable to itself.
    bool diagnoseSelfAssignment(const Expr *E);
  
    /// Builds a string representing a "default" generic argument list for
    /// \p typeDecl. In general, this means taking the bound of each generic
    /// parameter. The \p getPreferredType callback can be used to provide a
    /// different type from the bound.
    ///
    /// It may not always be possible to find a single appropriate type for a
    /// particular parameter (say, if it has two bounds). In this case, an
    /// Xcode-style placeholder will be used instead.
    ///
    /// Returns true if the arguments list could be constructed, false if for
    /// some reason it could not.
    static bool getDefaultGenericArgumentsString(
        SmallVectorImpl<char> &buf,
        const GenericTypeDecl *typeDecl,
        llvm::function_ref<Type(const GenericTypeParamDecl *)> getPreferredType =
            [](const GenericTypeParamDecl *) { return Type(); });
  
    /// Attempt to omit needless words from the name of the given declaration.
    Optional<DeclName> omitNeedlessWords(AbstractFunctionDecl *afd);
  
    /// Attempt to omit needless words from the name of the given declaration.
    Optional<Identifier> omitNeedlessWords(VarDecl *var);
  
    /// Check for a typo correction.
    void performTypoCorrection(DeclContext *DC,
                               DeclRefKind refKind,
                               Type baseTypeOrNull,
                               NameLookupOptions lookupOptions,
                               TypoCorrectionResults &corrections,
                               GenericSignatureBuilder *gsb = nullptr,
                               unsigned maxResults = 4);
  
    /// Check if the given decl has a @_semantics attribute that gives it
    /// special case type-checking behavior.
    DeclTypeCheckingSemantics getDeclTypeCheckingSemantics(ValueDecl *decl);
  };
  
  /// Temporary on-stack storage and unescaping for encoded diagnostic
  /// messages.
  ///
  ///
  class EncodedDiagnosticMessage {
    llvm::SmallString<128> Buf;
  
  public:
    /// \param S A string with an encoded message
    EncodedDiagnosticMessage(StringRef S)
        : Message(Lexer::getEncodedStringSegment(S, Buf)) {}
  
    /// The unescaped message to display to the user.
    const StringRef Message;
  };
  
  /// Given a subscript defined as "subscript(dynamicMember:)->T", return true if
  /// it is an acceptable implementation of the @dynamicMemberLookup attribute's
  /// requirement.
  bool isAcceptableDynamicMemberLookupSubscript(SubscriptDecl *decl,
                                                DeclContext *DC,
                                                TypeChecker &TC);
  
  /// Determine whether this is a "pass-through" typealias, which has the
  /// same type parameters as the nominal type it references and specializes
  /// the underlying nominal type with exactly those type parameters.
  /// For example, the following typealias \c GX is a pass-through typealias:
  ///
  /// \code
  /// struct X<T, U> { }
  /// typealias GX<A, B> = X<A, B>
  /// \endcode
  ///
  /// whereas \c GX2 and \c GX3 are not pass-through because \c GX2 has
  /// different type parameters and \c GX3 doesn't pass its type parameters
  /// directly through.
  ///
  /// \code
  /// typealias GX2<A> = X<A, A>
  /// typealias GX3<A, B> = X<B, A>
  /// \endcode
  bool isPassThroughTypealias(TypeAliasDecl *typealias);
  
  /// Determine whether overriding the given declaration requires a keyword.
  bool overrideRequiresKeyword(ValueDecl *overridden);
  
  /// Compute the type of a member that will be used for comparison when
  /// performing override checking.
  Type getMemberTypeForComparison(ASTContext &ctx, ValueDecl *member,
                                  ValueDecl *derivedDecl = nullptr);
  
  /// Determine whether the given declaration is an override by comparing type
  /// information.
  bool isOverrideBasedOnType(ValueDecl *decl, Type declTy,
                             ValueDecl *parentDecl, Type parentDeclTy);
  
  /// Determine whether the given declaration is an operator defined in a
  /// protocol. If \p type is not null, check specifically whether \p decl
  /// could fulfill a protocol requirement for it.
  bool isMemberOperator(FuncDecl *decl, Type type);
  
  } // end namespace swift
  
  #endif
  