| //===--- 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; |
| enum class TypeResolutionStage : uint8_t; |
| |
| namespace constraints { |
| enum class ConstraintKind : char; |
| enum class SolutionKind : char; |
| class ConstraintSystem; |
| class Solution; |
| } |
| |
| /// 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); } |
| |
| /// 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_ReturnSingleExpr, ///< Value implicitly returned from a function. |
| 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_SubscriptAssignSource, ///< AssignExpr source operand coerced to subscript |
| ///< result type. |
| CTP_Condition, ///< Condition expression of various statements e.g. |
| ///< `if`, `for`, `while` etc. |
| |
| 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, |
| |
| /// 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, |
| |
| /// This is an inout yield. |
| IsInOutYield = 0x100, |
| |
| /// If set, a conversion constraint should be specified so that the result of |
| /// the expression is an optional type. |
| ExpressionTypeMustBeOptional = 0x200, |
| |
| /// FIXME(diagnostics): Once diagnostics are completely switched to new |
| /// framework, this flag could be removed as obsolete. |
| /// |
| /// If set, this is a sub-expression, and it is being re-typechecked |
| /// as part of the expression diagnostics, which is attempting to narrow |
| /// down failure location. |
| SubExpressionDiagnostics = 0x400, |
| |
| /// If set, the 'convertType' specified to typeCheckExpression is the opaque |
| /// return type of the declaration being checked. The archetype should be |
| /// opened into a type variable to provide context to the expression, and |
| /// the resulting type will be a candidate for binding the underlying |
| /// type. |
| ConvertTypeIsOpaqueReturnType = 0x800, |
| }; |
| |
| 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, |
| /// Whether to consider synonyms declared through @_implements(). |
| IncludeAttributeImplements = 0x40, |
| }; |
| |
| /// 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); |
| |
| /// Callback invoked if expression is structurally unsound and can't |
| /// be correctly processed by the constraint solver. |
| virtual void preCheckFailed(Expr *expr); |
| |
| /// Callback invoked if constraint system failed to generate |
| /// constraints for a given expression. |
| virtual void constraintGenerationFailed(Expr *expr); |
| |
| /// Callback invoked if application of chosen solution to |
| /// expression has failed. |
| virtual void applySolutionFailed(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 to suppress dependency tracking entirely. |
| /// |
| /// FIXME: This deals with some oddities with the |
| /// _ObjectiveCBridgeable conformances. |
| SuppressDependencyTracking = 0x02, |
| /// 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 = 0x04, |
| }; |
| |
| /// 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, |
| }; |
| |
| enum class FunctionBuilderClosurePreCheck : uint8_t { |
| /// There were no problems pre-checking the closure. |
| Okay, |
| |
| /// There was an error pre-checking the closure. |
| Error, |
| |
| /// The closure has a return statement. |
| HasReturnStmt, |
| }; |
| |
| /// 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; |
| |
| /// The list of function definitions we've encountered. |
| std::vector<AbstractFunctionDecl *> definedFunctions; |
| |
| /// Declarations that need their conformances checked. |
| llvm::SmallVector<Decl *, 8> ConformanceContexts; |
| |
| // 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<AbstractClosureExpr *> ClosuresWithUncomputedCaptures; |
| |
| private: |
| /// The # of times we have performed typo correction. |
| unsigned NumTypoCorrections = 0; |
| |
| private: |
| Type MaxIntegerType; |
| Type NSObjectType; |
| Type NSNumberType; |
| Type NSValueType; |
| Type ObjCSelectorType; |
| |
| /// The set of expressions currently being analyzed for failures. |
| llvm::DenseMap<Expr*, Expr*> DiagnosedExprs; |
| |
| /// 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; |
| |
| /// Indicate that the type checker should skip type-checking non-inlinable |
| /// function bodies. |
| bool SkipNonInlinableFunctionBodies = false; |
| |
| /// Closure expressions whose bodies have already been prechecked as |
| /// part of trying to apply a function builder. |
| llvm::DenseMap<ClosureExpr *, FunctionBuilderClosurePreCheck> |
| precheckedFunctionBuilderClosures; |
| |
| TypeChecker(ASTContext &Ctx); |
| friend class ASTContext; |
| friend class constraints::ConstraintSystem; |
| friend class TypeCheckFunctionBodyUntilRequest; |
| |
| public: |
| /// Create a new type checker instance for the given ASTContext, if it |
| /// doesn't already have one. |
| /// |
| /// \returns a reference to the type vchecker. |
| static TypeChecker &createForContext(ASTContext &ctx); |
| |
| 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; |
| } |
| |
| void setSkipNonInlinableBodies(bool skip) { |
| SkipNonInlinableFunctionBodies = skip; |
| } |
| |
| bool canSkipNonInlinableBodies() const { |
| return SkipNonInlinableFunctionBodies; |
| } |
| |
| 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)...); |
| } |
| |
| void diagnoseWithNotes(InFlightDiagnostic parentDiag, |
| llvm::function_ref<void(void)> builder) { |
| CompoundDiagnosticTransaction transaction(Diags); |
| parentDiag.flush(); |
| builder(); |
| } |
| |
| static Type getArraySliceType(SourceLoc loc, Type elementType); |
| static Type getDictionaryType(SourceLoc loc, Type keyType, Type valueType); |
| static Type getOptionalType(SourceLoc loc, Type elementType); |
| Type getStringType(DeclContext *dc); |
| Type getSubstringType(DeclContext *dc); |
| Type getIntType(DeclContext *dc); |
| Type getInt8Type(DeclContext *dc); |
| Type getUInt8Type(DeclContext *dc); |
| Type getNSObjectType(DeclContext *dc); |
| Type getObjCSelectorType(DeclContext *dc); |
| Type getExceptionType(DeclContext *dc, SourceLoc loc); |
| |
| /// 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); |
| |
| /// 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. |
| static bool validateType(ASTContext &Ctx, 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); |
| |
| /// Check for unsupported protocol types in the given generic requirement |
| /// list. |
| void checkUnsupportedProtocolType(TrailingWhereClause *whereClause); |
| |
| /// Check for unsupported protocol types in the given generic requirement |
| /// list. |
| void checkUnsupportedProtocolType(GenericParamList *genericParams); |
| |
| /// Expose TypeChecker's handling of GenericParamList to SIL parsing. |
| GenericEnvironment *handleSILGenericParams(GenericParamList *genericParams, |
| DeclContext *DC); |
| |
| void validateDecl(ValueDecl *D); |
| |
| /// Validate the given extension declaration, ensuring that it |
| /// properly extends the nominal type it names. |
| void validateExtension(ExtensionDecl *ext); |
| |
| /// 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); |
| |
| /// 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); |
| |
| /// 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 |
| static bool isPassThroughTypealias(TypeAliasDecl *typealias, |
| Type underlyingType, |
| NominalTypeDecl *nominal); |
| |
| /// 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); |
| |
| /// 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); |
| |
| /// 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); |
| |
| /// 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); |
| |
| /// 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); |
| |
| /// 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); |
| |
| BraceStmt *applyFunctionBuilderBodyTransform(FuncDecl *FD, |
| BraceStmt *body, |
| Type builderType); |
| bool typeCheckClosureBody(ClosureExpr *closure); |
| |
| bool typeCheckTapBody(TapExpr *expr, DeclContext *DC); |
| |
| Type typeCheckParameterDefault(Expr *&defaultValue, DeclContext *DC, |
| Type paramType, bool isAutoClosure = false, |
| bool canFail = true); |
| |
| void typeCheckTopLevelCodeDecl(TopLevelCodeDecl *TLCD); |
| |
| void processREPLTopLevel(SourceFile &SF, TopLevelContext &TLC, |
| unsigned StartElem); |
| Identifier getNextResponseVariableName(DeclContext *DC); |
| |
| void typeCheckDecl(Decl *D); |
| |
| static void addImplicitDynamicAttribute(Decl *D); |
| void checkDeclAttributes(Decl *D); |
| void checkParameterAttributes(ParameterList *params); |
| static ValueDecl *findReplacedDynamicFunction(const ValueDecl *d); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // TODO(TF-789): Figure out the proper way to typecheck these. |
| void checkDeclDifferentiableAttributes(Decl *D); |
| |
| Type checkReferenceOwnershipAttr(VarDecl *D, Type interfaceType, |
| ReferenceOwnershipAttr *attr); |
| |
| virtual void resolveDeclSignature(ValueDecl *VD) override { |
| validateDecl(VD); |
| } |
| |
| 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); |
| |
| /// 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 allowConcreteGenericParams Whether or not to allow |
| /// same-type constraints between generic parameters and concrete types. |
| /// |
| /// \param additionalRequirements Additional requirements to add |
| /// directly to the GSB. |
| /// |
| /// \param inferenceSources Additional types to infer requirements from. |
| /// |
| /// \returns the resulting generic signature. |
| static GenericSignature checkGenericSignature( |
| GenericParamList *genericParams, |
| DeclContext *dc, |
| GenericSignature outerSignature, |
| bool allowConcreteGenericParams, |
| SmallVector<Requirement, 2> additionalRequirements = {}, |
| SmallVector<TypeLoc, 2> inferenceSources = {}); |
| |
| /// 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, |
| GenericRequirementsCheckListener *listener = nullptr, |
| SubstOptions options = None); |
| |
| /// Diagnose if the class has no designated initializers. |
| void maybeDiagnoseClassWithoutInitializers(ClassDecl *classDecl); |
| |
| /// |
| /// 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); |
| |
| /// Pre-check the expression, validating any types that occur in the |
| /// expression and folding sequence expressions. |
| bool preCheckExpression(Expr *&expr, DeclContext *dc); |
| |
| /// Pre-check the body of the given closure, which we are about to |
| /// generate constraints for. |
| /// |
| /// This mutates the body of the closure, but only in ways that should be |
| /// valid even if we end up not actually applying the function-builder |
| /// transform: it just does a normal pre-check of all the expressions in |
| /// the closure. |
| FunctionBuilderClosurePreCheck |
| preCheckFunctionBuilderClosureBody(ClosureExpr *closure); |
| |
| /// \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: |
| /// Define the default constructor for the given struct or class. |
| static void defineDefaultConstructor(NominalTypeDecl *decl); |
| |
| /// Fold the given sequence expression into an (unchecked) expression |
| /// tree. |
| Expr *foldSequence(SequenceExpr *expr, DeclContext *dc); |
| |
| /// 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); |
| } |
| |
| /// Quote the given typed expression by creating a snippet of code that at |
| /// runtime will approximate the given expression using the data structures |
| /// from the Quote module. This functionality implements #quote(...). |
| /// |
| /// The exact runtime representation, and the way how it is constructed are |
| /// not set in stone and are undergoing rapid evolution. |
| /// |
| /// For example, in the current terminology of the Quote model, calling this |
| /// method on an expression representing `42` will return an expression |
| /// representing `Quote<Int>(Literal(42, TypeName("Int", "s:Si")))`. |
| /// |
| /// \param expr Typed expression to be quoted. |
| /// |
| /// \param dc Declaration context in which the result will be typechecked. |
| /// |
| /// \returns If successful, a typechecked expression that at runtime will |
| /// approximate the given expression. If not successful, nullptr (appropriate |
| /// error messages will also be emitted as a side effect). |
| Expr *quoteExpr(Expr *expr, DeclContext *dc); |
| |
| /// Compute the type of quoteExpr given the type of expression. |
| /// |
| /// This does not require running quoteExpr and can be expressed |
| /// by the following rules (where on the left we have the type of expression, |
| /// and on the right we have the type of quoteExpr): |
| /// |
| /// 1) (T1, ..., Tn) -> R => FunctionQuoteN<T1, ... Tn, R> |
| /// 2) T => Quote<T> |
| /// |
| /// TODO(TF-735): In the future, we may implement more complicated rules |
| /// based on something like ExpressibleByQuoteLiteral. |
| Type getTypeOfQuoteExpr(Type exprType, SourceLoc loc); |
| |
| /// Compute the type of #unquote given the type of expression. |
| /// |
| /// This can be expressed by the following rules (where on the left we have |
| /// the type of expression, and on the right we have the type of #unquote): |
| /// |
| /// 1) FunctionQuoteN<T1, ... Tn, R> => (T1, ..., Tn) -> R |
| /// 2) Quote<T> => T |
| /// 3) T => <error> |
| /// |
| /// TODO(TF-735): In the future, we may implement more complicated rules |
| /// based on something like ExpressibleByQuoteLiteral. |
| Type getTypeOfUnquoteExpr(Type exprType, SourceLoc loc); |
| |
| /// Quote the given typed declaration by creating a snippet of code that at |
| /// runtime will approximate the given declaration using the data structures |
| /// from the Quote module. This functionality implements @quoted. |
| /// |
| /// The exact runtime representation, and the way how it is constructed are |
| /// not set in stone and are undergoing rapid evolution. |
| /// |
| /// \param decl Typed declaration to be quoted. |
| /// |
| /// \param dc Declaration context in which the result will be typechecked. |
| /// |
| /// \returns If successful, a typechecked expression that at runtime will |
| /// approximate the given declaration. If not successful, nullptr (appropriate |
| /// error messages will also be emitted as a side effect). |
| Expr *quoteDecl(Decl *decl, DeclContext *dc); |
| |
| /// Compute the type of quoteDecl. |
| /// |
| /// At the moment, this is simply `Tree` from the Quote model. |
| /// |
| /// TODO(TF-736): In the future, we may want to infer more precise type |
| /// based on the shape of the quoted declaration. |
| Type getTypeOfQuoteDecl(SourceLoc loc); |
| |
| private: |
| Type typeCheckExpressionImpl(Expr *&expr, DeclContext *dc, |
| TypeLoc convertType, |
| ContextualTypePurpose convertTypePurpose, |
| TypeCheckExprOptions options, |
| ExprTypeCheckListener &listener, |
| constraints::ConstraintSystem *baseCS); |
| |
| public: |
| /// 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); |
| |
| /// Return the type of operator function for specified LHS, or a null |
| /// \c Type on error. |
| FunctionType *getTypeOfCompletionOperator(DeclContext *DC, Expr *LHS, |
| Identifier opName, |
| DeclRefKind refKind, |
| ConcreteDeclRef &referencedDecl); |
| |
| /// 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); |
| |
| /// 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); |
| |
| /// 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); |
| |
| /// 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); |
| |
| /// 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); |
| |
| /// 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); |
| |
| /// 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); |
| |
| /// Type check a parameter list. |
| bool typeCheckParameterList(ParameterList *PL, DeclContext *dc, |
| 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. |
| void coerceParameterListToType(ParameterList *P, ClosureExpr *CE, AnyFunctionType *FN); |
| |
| /// Type-check an initialized variable pattern declaration. |
| bool typeCheckBinding(Pattern *&P, Expr *&Init, DeclContext *DC); |
| bool typeCheckPatternBinding(PatternBindingDecl *PBD, unsigned patternNumber); |
| |
| /// Type-check a for-each loop's pattern binding and sequence together. |
| bool typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt); |
| |
| /// Compute the set of captures for the given function or closure. |
| static void computeCaptures(AnyFunctionRef AFR); |
| |
| /// Check for invalid captures from stored property initializers. |
| static void checkPatternBindingCaptures(NominalTypeDecl *typeDecl); |
| |
| /// 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, |
| TopLevelCodeDecl *TLCD); |
| |
| /// 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 { |
| if (!var->getInterfaceType() || var->isInvalid()) |
| return ErrorType::get(Context); |
| |
| return wantInterfaceType ? value->getInterfaceType() |
| : value->getType(); |
| }, |
| base, wantInterfaceType); |
| } |
| |
| /// 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); |
| |
| /// 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); |
| |
| /// 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); |
| }); |
| |
| /// 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); |
| |
| /// 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); |
| |
| /// 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()); |
| |
| /// 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 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. |
| Optional<ProtocolConformanceRef> checkConformanceToNSCopying(VarDecl *var); |
| |
| /// 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); |
| |
| /// 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); |
| |
| /// 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); |
| |
| /// Check whether the given declaration can be written as a |
| /// member of the given base type. |
| static bool isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl); |
| |
| /// 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); |
| |
| /// 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. |
| static 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. |
| static PrecedenceGroupDecl * |
| lookupPrecedenceGroupForInfixOperator(DeclContext *dc, Expr *op); |
| |
| static PrecedenceGroupDecl *lookupPrecedenceGroup(DeclContext *dc, |
| Identifier name, |
| SourceLoc nameLoc); |
| |
| /// Given an pre-folded expression, find LHS from the expression if a binary |
| /// operator \c name appended to the expression. |
| Expr *findLHS(DeclContext *DC, Expr *E, Identifier name); |
| |
| /// @} |
| |
| /// \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); |
| |
| /// Build a type-checked reference to the given value. |
| Expr *buildCheckedRefExpr(VarDecl *D, DeclContext *UseDC, |
| DeclNameLoc nameLoc, bool Implicit); |
| |
| /// 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); |
| |
| /// Build implicit autoclosure expression wrapping a given expression. |
| /// Given expression represents computed result of the closure. |
| Expr *buildAutoClosureExpr(DeclContext *DC, Expr *expr, |
| FunctionType *closureType); |
| /// @} |
| |
| /// 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); |
| |
| /// 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, |
| Inlinable, |
| AlwaysEmitIntoClient, |
| DefaultArgument, |
| PropertyInitializer |
| }; |
| |
| static bool diagnoseInlinableDeclRef(SourceLoc loc, ConcreteDeclRef declRef, |
| const DeclContext *DC, |
| FragileFunctionKind Kind, |
| bool TreatUsableFromInlineAsPublic); |
| |
| Expr *buildDefaultInitializer(Type type); |
| |
| private: |
| static bool diagnoseInlinableDeclRefAccess(SourceLoc loc, const ValueDecl *D, |
| const DeclContext *DC, |
| FragileFunctionKind Kind, |
| bool TreatUsableFromInlineAsPublic); |
| |
| /// Given that a declaration is used from a particular context which |
| /// exposes it in the interface of the current module, diagnose if it cannot |
| /// reasonably be shared. |
| static bool diagnoseDeclRefExportability(SourceLoc loc, ConcreteDeclRef declRef, |
| const DeclContext *DC, |
| FragileFunctionKind fragileKind); |
| |
| /// Given that a type is used from a particular context which |
| /// exposes it in the interface of the current module, diagnose if its |
| /// generic arguments require the use of conformances that cannot reasonably |
| /// be shared. |
| /// |
| /// This method \e only checks how generic arguments are used; it is assumed |
| /// that the declarations involved have already been checked elsewhere. |
| static void diagnoseGenericTypeExportability(const TypeLoc &TL, |
| const DeclContext *DC); |
| |
| public: |
| /// 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 |
| static 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 |
| /// @{ |
| |
| /// 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. |
| static 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 |
| static 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. |
| static 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. |
| static 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. |
| static 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. |
| static 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. |
| static 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. |
| static void diagnosePotentialUnavailability(const Decl *D, DeclName Name, |
| SourceRange ReferenceRange, |
| const DeclContext *ReferenceDC, |
| const UnavailabilityReason &Reason); |
| |
| static void diagnosePotentialOpaqueTypeUnavailability(SourceRange ReferenceRange, |
| const DeclContext *ReferenceDC, |
| const UnavailabilityReason &Reason); |
| |
| /// Emits a diagnostic for a reference to a storage accessor that is |
| /// potentially unavailable. |
| static void diagnosePotentialAccessorUnavailability( |
| const 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. |
| static 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, Expr *expr); |
| void checkPropertyWrapperErrorHandling(PatternBindingDecl *binding, |
| Expr *expr); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| void checkFunctionBodyCompilerEvaluable(AbstractFunctionDecl *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); |
| |
| /// Calculate edit distance between declaration names. |
| static unsigned getCallEditDistance(DeclName writtenName, |
| DeclName correctedName, |
| unsigned maxEditDistance); |
| |
| enum : unsigned { |
| /// Never consider a candidate that's this distance away or worse. |
| UnreasonableCallEditDistance = 8, |
| |
| /// Don't consider candidates that score worse than the given distance |
| /// from the best candidate. |
| MaxCallEditDistanceFromBestCandidate = 1 |
| }; |
| |
| /// 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); |
| |
| /// SWIFT_ENABLE_TENSORFLOW |
| // Returns the function declaration corresponding to the given function name |
| // and lookup context. If the function declaration cannot be resolved, emits a |
| // diagnostic and returns nullptr. |
| FuncDecl *lookupFuncDecl( |
| DeclName funcName, SourceLoc funcNameLoc, Type baseType, |
| DeclContext *lookupContext, |
| const std::function<bool(FuncDecl *)> &isValidFuncDecl, |
| const std::function<void()> &overloadDiagnostic, |
| const std::function<void()> &ambiguousDiagnostic, |
| const std::function<void()> ¬FunctionDiagnostic, |
| NameLookupOptions lookupOptions = defaultMemberLookupOptions, |
| const Optional<std::function<bool(FuncDecl *)>> &hasValidTypeCtx = None, |
| const Optional<std::function<void()>> &invalidTypeCtxDiagnostic = None); |
| |
| /// SWIFT_ENABLE_TENSORFLOW |
| /// Creates an `IndexSubset` for the given function type, representing |
| /// all inferred differentiation parameters. |
| /// The differentiation parameters are inferred to be: |
| /// - All parameters of the function type that conform to `Differentiable`. |
| /// - If the function type's result is a function type (i.e. it is a curried |
| /// method type), then also all parameters of the function result type that |
| /// conform to `Differentiable`. |
| static IndexSubset * |
| inferDifferentiableParameters(AbstractFunctionDecl *AFD, |
| GenericEnvironment *derivativeGenEnv); |
| }; |
| |
| /// 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, true, true, ~0U)) {} |
| |
| /// The unescaped message to display to the user. |
| const StringRef Message; |
| }; |
| |
| /// Returns true if the given method is an valid implementation of a |
| /// @dynamicCallable attribute requirement. The method is given to be defined |
| /// as one of the following: `dynamicallyCall(withArguments:)` or |
| /// `dynamicallyCall(withKeywordArguments:)`. |
| bool isValidDynamicCallableMethod(FuncDecl *decl, DeclContext *DC, |
| TypeChecker &TC, bool hasKeywordArguments); |
| |
| /// Returns true if the given subscript method is an valid implementation of |
| /// the `subscript(dynamicMember:)` requirement for @dynamicMemberLookup. |
| /// The method is given to be defined as `subscript(dynamicMember:)`. |
| bool isValidDynamicMemberLookupSubscript(SubscriptDecl *decl, DeclContext *DC, |
| TypeChecker &TC, |
| bool ignoreLabel = false); |
| |
| /// Returns true if the given subscript method is an valid implementation of |
| /// the `subscript(dynamicMember:)` requirement for @dynamicMemberLookup. |
| /// The method is given to be defined as `subscript(dynamicMember:)` which |
| /// takes a single non-variadic parameter that conforms to |
| /// `ExpressibleByStringLiteral` protocol. |
| bool isValidStringDynamicMemberLookup(SubscriptDecl *decl, DeclContext *DC, |
| TypeChecker &TC, |
| bool ignoreLabel = false); |
| |
| /// Returns true if the given subscript method is an valid implementation of |
| /// the `subscript(dynamicMember: {Writable}KeyPath<...>)` requirement for |
| /// @dynamicMemberLookup. |
| /// The method is given to be defined as `subscript(dynamicMember:)` which |
| /// takes a single non-variadic parameter of `{Writable}KeyPath<T, U>` type. |
| bool isValidKeyPathDynamicMemberLookup(SubscriptDecl *decl, TypeChecker &TC, |
| bool ignoreLabel = false); |
| |
| /// Compute the wrapped value type for the given property that has attached |
| /// property wrappers, when the backing storage is known to have the given type. |
| /// |
| /// \param var A property that has attached property wrappers. |
| /// \param backingStorageType The type of the backing storage property. |
| /// \param limit How many levels of unwrapping to perform, where 0 means to return the |
| /// \c backingStorageType directly and the maximum is the number of attached property wrappers |
| /// (which will produce the original property type). If not specified, defaults to the maximum. |
| Type computeWrappedValueType(VarDecl *var, Type backingStorageType, |
| Optional<unsigned> limit = None); |
| |
| /// Build a call to the init(wrappedValue:) initializers of the property |
| /// wrappers, filling in the given \c value as the original value. |
| Expr *buildPropertyWrapperInitialValueCall(VarDecl *var, |
| Type backingStorageType, |
| Expr *value, |
| bool ignoreAttributeArgs); |
| |
| /// Whether an overriding declaration requires the 'override' keyword. |
| enum class OverrideRequiresKeyword { |
| /// The keyword is never required. |
| Never, |
| /// The keyword is always required. |
| Always, |
| /// The keyword can be implicit; it is not required. |
| Implicit, |
| }; |
| |
| /// Determine whether overriding the given declaration requires a keyword. |
| OverrideRequiresKeyword 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); |
| |
| /// Complain if @objc or dynamic is used without importing Foundation. |
| void diagnoseAttrsRequiringFoundation(SourceFile &SF); |
| |
| /// Diagnose any Objective-C method overrides that aren't reflected |
| /// as overrides in Swift. |
| bool diagnoseUnintendedObjCMethodOverrides(SourceFile &sf); |
| |
| /// Diagnose all conflicts between members that have the same |
| /// Objective-C selector in the same class. |
| /// |
| /// \param sf The source file for which we are diagnosing conflicts. |
| /// |
| /// \returns true if there were any conflicts diagnosed. |
| bool diagnoseObjCMethodConflicts(SourceFile &sf); |
| |
| /// Diagnose any unsatisfied @objc optional requirements of |
| /// protocols that conflict with methods. |
| bool diagnoseObjCUnsatisfiedOptReqConflicts(SourceFile &sf); |
| |
| /// Retrieve information about the given Objective-C method for |
| /// diagnostic purposes, to be used with OBJC_DIAG_SELECT in |
| /// DiagnosticsSema.def. |
| std::pair<unsigned, DeclName> getObjCMethodDiagInfo( |
| AbstractFunctionDecl *method); |
| |
| bool areGenericRequirementsSatisfied(const DeclContext *DC, |
| GenericSignature sig, |
| SubstitutionMap Substitutions, |
| bool isExtension); |
| |
| bool canSatisfy(Type type1, Type type2, bool openArchetypes, |
| constraints::ConstraintKind kind, DeclContext *dc); |
| |
| bool hasDynamicMemberLookupAttribute(Type type, |
| llvm::DenseMap<CanType, bool> &DynamicMemberLookupCache); |
| } // end namespace swift |
| |
| #endif |