//===--- ConstraintSystem.h - Constraint-based Type Checking ----*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file provides the constraint-based type checker, anchored by the // \c ConstraintSystem class, which provides type checking and type // inference for expressions. // //===----------------------------------------------------------------------===// #ifndef SWIFT_SEMA_CONSTRAINT_SYSTEM_H #define SWIFT_SEMA_CONSTRAINT_SYSTEM_H #include "TypeChecker.h" #include "Constraint.h" #include "ConstraintGraph.h" #include "ConstraintGraphScope.h" #include "ConstraintLocator.h" #include "OverloadChoice.h" #include "swift/Basic/Fixnum.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/Optional.h" #include "swift/Basic/OptionSet.h" #include "swift/AST/ASTContext.h" #include "swift/AST/NameLookup.h" #include "swift/AST/Types.h" #include "swift/AST/TypeCheckerDebugConsumer.h" #include "llvm/ADT/ilist.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include #include namespace swift { class Expr; namespace constraints { class ConstraintGraph; class ConstraintGraphNode; class ConstraintSystem; } // end namespace constraints } // end namespace swift /// \brief Allocate memory within the given constraint system. void *operator new(size_t bytes, swift::constraints::ConstraintSystem& cs, size_t alignment = 8); namespace swift { namespace constraints { /// \brief A handle that holds the saved state of a type variable, which /// can be restored. class SavedTypeVariableBinding { /// \brief The type variable. TypeVariableType *TypeVar; /// \brief The parent or fixed type. llvm::PointerUnion ParentOrFixed; public: explicit SavedTypeVariableBinding(TypeVariableType *typeVar); /// \brief Restore the state of the type variable to the saved state. void restore(); }; /// \brief A set of saved type variable bindings. typedef SmallVector SavedTypeVariableBindings; class ConstraintLocator; /// Describes a conversion restriction or a fix. struct RestrictionOrFix { ConversionRestrictionKind Restriction; Fix TheFix; bool IsRestriction; public: RestrictionOrFix(ConversionRestrictionKind restriction) : Restriction(restriction), IsRestriction(true) { } RestrictionOrFix(Fix fix) : TheFix(fix), IsRestriction(false) { } RestrictionOrFix(FixKind fix) : TheFix(fix), IsRestriction(false) { } Optional getRestriction() const { if (IsRestriction) return Restriction; return Nothing; } Optional getFix() const { if (!IsRestriction) return TheFix; return Nothing; } }; } // end namespace constraints /// Options that describe how a type variable can be used. enum TypeVariableOptions { /// Whether the type variable can be bound to an lvalue type or not. TVO_CanBindToLValue = 0x01, /// Whether a more specific deduction for this type variable implies a /// better solution to the constraint system. TVO_PrefersSubtypeBinding = 0x02 }; /// \brief The implementation object for a type variable used within the /// constraint-solving type checker. /// /// The implementation object for a type variable contains information about /// the type variable, where it was generated, what protocols it must conform /// to, what specific types it might be and, eventually, the fixed type to /// which it is assigned. class TypeVariableType::Implementation { /// Type variable options. unsigned Options : 2; /// \brief The locator that describes where this type variable was generated. constraints::ConstraintLocator *locator; /// \brief Either the parent of this type variable within an equivalence /// class of type variables, or the fixed type to which this type variable /// type is bound. llvm::PointerUnion ParentOrFixed; /// The corresponding node in the constraint graph. constraints::ConstraintGraphNode *GraphNode = nullptr; /// Index into the list of type variables, as used by the /// constraint graph. unsigned GraphIndex; friend class constraints::SavedTypeVariableBinding; public: explicit Implementation(constraints::ConstraintLocator *locator, unsigned options) : Options(options), locator(locator), ParentOrFixed(getTypeVariable()) { } /// \brief Retrieve the unique ID corresponding to this type variable. unsigned getID() const { return getTypeVariable()->getID(); } /// Whether this type variable can bind to an lvalue type. bool canBindToLValue() const { return Options & TVO_CanBindToLValue; } /// Whether this type variable prefers a subtype binding over a supertype /// binding. bool prefersSubtypeBinding() const { return Options & TVO_PrefersSubtypeBinding; } /// \brief Retrieve the type variable associated with this implementation. TypeVariableType *getTypeVariable() { return reinterpret_cast(this) - 1; } /// \brief Retrieve the type variable associated with this implementation. const TypeVariableType *getTypeVariable() const { return reinterpret_cast(this) - 1; } /// Retrieve the corresponding node in the constraint graph. constraints::ConstraintGraphNode *getGraphNode() const { return GraphNode; } /// Set the corresponding node in the constraint graph. void setGraphNode(constraints::ConstraintGraphNode *newNode) { GraphNode = newNode; } /// Retrieve the index into the constraint graph's list of type variables. unsigned getGraphIndex() const { assert(GraphNode && "Graph node isn't set"); return GraphIndex; } /// Set the index into the constraint graph's list of type variables. void setGraphIndex(unsigned newIndex) { GraphIndex = newIndex; } /// \brief Check whether this type variable either has a representative that /// is not itself or has a fixed type binding. bool hasRepresentativeOrFixed() const { // If we have a fixed type, we're done. if (!ParentOrFixed.is()) return true; // Check whether the representatative is different from our own type // variable. return ParentOrFixed.get() != getTypeVariable(); } /// \brief Record the current type-variable binding. void recordBinding(constraints::SavedTypeVariableBindings &record) { record.push_back(constraints::SavedTypeVariableBinding(getTypeVariable())); } /// \brief Retrieve the locator describing where this type variable was /// created. constraints::ConstraintLocator *getLocator() const { return locator; } /// \brief Retrieve the archetype opened by this type variable. ArchetypeType *getArchetype() const; /// \brief Retrieve the representative of the equivalence class to which this /// type variable belongs. /// /// \param record The record of changes made by retrieving the representative, /// which can happen due to path compression. If null, path compression is /// not performed. TypeVariableType * getRepresentative(constraints::SavedTypeVariableBindings *record) { // Find the representative type variable. auto result = getTypeVariable(); Implementation *impl = this; while (impl->ParentOrFixed.is()) { // Extract the representative. auto nextTV = impl->ParentOrFixed.get(); if (nextTV == result) break; result = nextTV; impl = &nextTV->getImpl(); } if (impl == this || !record) return result; // Perform path compression. impl = this; while (impl->ParentOrFixed.is()) { // Extract the representative. auto nextTV = impl->ParentOrFixed.get(); if (nextTV == result) break; // Record the state change. impl->recordBinding(*record); impl->ParentOrFixed = result; impl = &nextTV->getImpl(); } return result; } /// \brief Merge the equivalence class of this type variable with the /// equivalence class of another type variable. /// /// \param other The type variable to merge with. /// /// \param record The record of state changes. void mergeEquivalenceClasses(TypeVariableType *other, constraints::SavedTypeVariableBindings *record) { // Merge the equivalence classes corresponding to these two type // variables. Always merge 'up' the constraint stack, because it is simpler. if (getID() < other->getImpl().getID()) { auto rep = other->getImpl().getRepresentative(record); if (record) rep->getImpl().recordBinding(*record); rep->getImpl().ParentOrFixed = getTypeVariable(); assert(rep->getImpl().canBindToLValue() == canBindToLValue()); } else { auto rep = getRepresentative(record); if (record) rep->getImpl().recordBinding(*record); rep->getImpl().ParentOrFixed = other; assert(rep->getImpl().canBindToLValue() == other->getImpl().canBindToLValue()); } } /// \brief Retrieve the fixed type that corresponds to this type variable, /// if there is one. /// /// \returns the fixed type associated with this type variable, or a null /// type if there is no fixed type. /// /// \param record The record of changes made by retrieving the representative, /// which can happen due to path compression. If null, path compression is /// not performed. Type getFixedType(constraints::SavedTypeVariableBindings *record) { // Find the representative type variable. auto rep = getRepresentative(record); Implementation &repImpl = rep->getImpl(); // Check whether it has a fixed type. if (auto type = repImpl.ParentOrFixed.dyn_cast()) return type; return Type(); } /// \brief Assign a fixed type to this equivalence class. void assignFixedType(Type type, constraints::SavedTypeVariableBindings *record) { assert((!getFixedType(0) || getFixedType(0)->isEqual(type)) && "Already has a fixed type!"); auto rep = getRepresentative(record); if (record) rep->getImpl().recordBinding(*record); rep->getImpl().ParentOrFixed = type.getPointer(); } /// \brief Print the type variable to the given output stream. void print(llvm::raw_ostream &OS); }; namespace constraints { struct ResolvedOverloadSetListItem; /// \brief Describes a failure. class Failure : public llvm::FoldingSetNode { public: /// \brief The various kinds of failures that can occur enum FailureKind { /// \brief Tuple types with different numbers of elements. TupleSizeMismatch, /// \brief Tuple element names mismatch when they need to match. TupleNameMismatch, /// \brief Tuple element name matched, but at a different position. TupleNamePositionMismatch, /// \brief One tuple type is variadic, the other is not. TupleVariadicMismatch, /// \brief Unused element in tuple. TupleUnused, /// \brief Autoclosure function type mismatch. FunctionAutoclosureMismatch, /// \brief Noreturn attribute function type mismatch. FunctionNoReturnMismatch, /// \brief Types are not the same. TypesNotEqual, /// \brief Types are not subtypes. TypesNotSubtypes, /// \brief Types are not convertible. TypesNotConvertible, /// \brief Types are not constructible. TypesNotConstructible, /// \brief Function types mismatch. FunctionTypesMismatch, /// \brief The first type doesn't conform to a protocol in the second /// type. DoesNotConformToProtocol, /// \brief The first type does not have a member with the given name. DoesNotHaveMember, /// \brief The first type does not have a non mutating member with the given /// name. DoesNotHaveNonMutatingMember, /// \brief The type is not an archetype. IsNotArchetype, /// \brief The type is not a class. IsNotClass, /// \brief The type is not a dynamic lookup value. IsNotDynamicLookup, /// \brief The type is not allowed to be an l-value. IsForbiddenLValue, /// \brief The type is not a metatype. IsNotMetatype, /// Out-of-order arguments. OutOfOrderArgument, /// Missing argument in a call. MissingArgument, /// Extra argument in a call. ExtraArgument, }; private: /// \brief The kind of failure this describes. FailureKind kind : 8; /// \brief A value, if used. unsigned value; /// \brief Another value, if used. unsigned value2; /// Describes the location of this failure. ConstraintLocator *locator; /// The resolved overload sets that led to this failure. ResolvedOverloadSetListItem *resolvedOverloadSets; /// \brief The first type. Type first; /// \brief The second value, which may be one of several things (type, /// member name, etc.). union { TypeBase *type; void *name; } second; public: /// \brief Retrieve the failure kind. FailureKind getKind() const { return kind; } /// \brief Retrieve the failure locator. ConstraintLocator *getLocator() const { return locator; } /// Retrieve the resolved overload sets active when this failure occurred. ResolvedOverloadSetListItem *getResolvedOverloadSets() const { return resolvedOverloadSets; } /// \brief Retrieve the first type. Type getFirstType() const { return first; } /// \brief Retrieve the second type. Type getSecondType() const { return second.type; } /// \brief Retrieve the name. DeclName getName() const { return DeclName::getFromOpaqueValue(second.name); } /// \brief Retrieve the value. unsigned getValue() const { return value; } /// \brief Retrieve the value. unsigned getSecondValue() const { return value2; } /// \brief Profile the given failure. void Profile(llvm::FoldingSetNodeID &id) { switch (kind) { case FunctionTypesMismatch: case FunctionAutoclosureMismatch: case FunctionNoReturnMismatch: case TupleNameMismatch: case TupleNamePositionMismatch: case TupleSizeMismatch: case TupleUnused: case TupleVariadicMismatch: case TypesNotConstructible: case TypesNotConvertible: case TypesNotEqual: case TypesNotSubtypes: case DoesNotConformToProtocol: case IsForbiddenLValue: case IsNotMetatype: return Profile(id, locator, kind, resolvedOverloadSets, getFirstType(), getSecondType()); case DoesNotHaveMember: case DoesNotHaveNonMutatingMember: return Profile(id, locator, kind, resolvedOverloadSets, getFirstType(), getName()); case IsNotArchetype: case IsNotClass: case IsNotDynamicLookup: case MissingArgument: return Profile(id, locator, kind, resolvedOverloadSets, getFirstType(), value); case OutOfOrderArgument: return Profile(id, locator, kind, resolvedOverloadSets, value, value2); case ExtraArgument: return Profile(id, locator, kind, resolvedOverloadSets, value, value2); } } /// \brief Dump a debug representation of this failure. LLVM_ATTRIBUTE_DEPRECATED( void dump(SourceManager *SM) const LLVM_ATTRIBUTE_USED, "only for use within the debugger"); void dump(SourceManager *SM, raw_ostream &OS) const; private: friend class ConstraintSystem; /// \brief Construct a failure involving one type. Failure(ConstraintLocator *locator, FailureKind kind, ResolvedOverloadSetListItem *resolvedOverloadSets, Type type, unsigned value = 0) : kind(kind), value(value), value2(0), locator(locator), resolvedOverloadSets(resolvedOverloadSets), first(type) { second.type = nullptr; } /// \brief Construct a failure involving two types and an optional value. Failure(ConstraintLocator *locator, FailureKind kind, ResolvedOverloadSetListItem *resolvedOverloadSets, Type type1, Type type2, unsigned value = 0) : kind(kind), value(value), value2(0), locator(locator), resolvedOverloadSets(resolvedOverloadSets), first(type1) { second.type = type2.getPointer(); } /// \brief Construct a failure involving a type and a name. Failure(ConstraintLocator *locator, FailureKind kind, ResolvedOverloadSetListItem *resolvedOverloadSets, Type type, DeclName name) : kind(kind), value(0), value2(0), locator(locator), resolvedOverloadSets(resolvedOverloadSets), first(type) { second.name = name.getOpaqueValue(); } /// \brief Construct a failure involving two values. Failure(ConstraintLocator *locator, FailureKind kind, ResolvedOverloadSetListItem *resolvedOverloadSets, unsigned value, unsigned value2 = 0) : kind(kind), value(value), value2(value2), locator(locator), resolvedOverloadSets(resolvedOverloadSets) { second.type = nullptr; } /// \brief Profile a failure involving one type. static void Profile(llvm::FoldingSetNodeID &id, ConstraintLocator *locator, FailureKind kind, ResolvedOverloadSetListItem *resolvedOverloadSets, Type type, unsigned value = 0) { id.AddPointer(locator); id.AddInteger(kind); id.AddPointer(resolvedOverloadSets); id.AddPointer(type.getPointer()); id.AddInteger(value); } /// \brief Profile a failure involving two types. static void Profile(llvm::FoldingSetNodeID &id, ConstraintLocator *locator, FailureKind kind, ResolvedOverloadSetListItem *resolvedOverloadSets, Type type1, Type type2) { id.AddPointer(locator); id.AddInteger(kind); id.AddPointer(resolvedOverloadSets); id.AddPointer(type1.getPointer()); id.AddPointer(type2.getPointer()); } /// \brief Profile a failure involving two types and a value. static void Profile(llvm::FoldingSetNodeID &id, ConstraintLocator *locator, FailureKind kind, ResolvedOverloadSetListItem *resolvedOverloadSets, Type type1, Type type2, unsigned value) { id.AddPointer(locator); id.AddInteger(kind); id.AddPointer(resolvedOverloadSets); id.AddPointer(type1.getPointer()); id.AddPointer(type2.getPointer()); id.AddInteger(value); } /// \brief Profile a failure involving a type and a name. static void Profile(llvm::FoldingSetNodeID &id, ConstraintLocator *locator, FailureKind kind, ResolvedOverloadSetListItem *resolvedOverloadSets, Type type, DeclName name) { id.AddPointer(locator); id.AddInteger(kind); id.AddPointer(resolvedOverloadSets); id.AddPointer(type.getPointer()); id.AddPointer(name.getOpaqueValue()); } /// \brief Profile a failure involving two values. static void Profile(llvm::FoldingSetNodeID &id, ConstraintLocator *locator, FailureKind kind, ResolvedOverloadSetListItem *resolvedOverloadSets, unsigned value, unsigned value2 = 0) { id.AddPointer(locator); id.AddInteger(kind); id.AddPointer(resolvedOverloadSets); id.AddInteger(value); id.AddInteger(value2); } /// \brief Create a new Failure object with the given arguments, allocated /// from the given bump pointer allocator. template static Failure *create(llvm::BumpPtrAllocator &allocator, ConstraintLocator *locator, FailureKind kind, Args &&...args) { void *mem = allocator.Allocate(sizeof(Failure), alignof(Failure)); return new (mem) Failure(locator, kind, args...); } }; /// \brief The kind of type matching to perform in matchTypes(). enum class TypeMatchKind : char { /// \brief Bind the types together directly. BindType, /// \brief Require the types to match exactly, but strips lvalueness from /// a type when binding to a type variable. SameType, /// \brief Require the first type to be a subtype of the second type /// (or be an exact match or trivial subtype). Subtype, /// \brief Requires the first type to be convertible to the second type, /// which includes exact matches and both forms of subtyping. Conversion, /// Requires the first type to be an argument type (tuple) that can be /// converted to the second type, which represents the parameter type (tuple). ArgumentTupleConversion, /// \brief Requires the first type to be convertible to the second type, /// which includes exact matches, both forms of subtyping, and inserting /// address-of to convert implicit lvalues to inout arguments. This is /// used by assignment operators. OperatorArgumentConversion, /// Like \c ArgumentTupleConversion, but for operators. OperatorArgumentTupleConversion, }; /// \brief The result of comparing two constraint systems that are a solutions /// to the given set of constraints. enum class SolutionCompareResult { /// \brief The two solutions are incomparable, because, e.g., because one /// solution has some better decisions and some worse decisions than the /// other. Incomparable, /// \brief The two solutions are identical. Identical, /// \brief The first solution is better than the second. Better, /// \brief The second solution is better than the first. Worse }; /// An overload that has been selected in a particular solution. /// /// A selected overload captures the specific overload choice (e.g., a /// particular declaration) as well as the type to which the reference to the /// declaration was opened, which may involve type variables. struct SelectedOverload { /// The overload choice. OverloadChoice choice; /// The opened type of the base of the reference to this overload, if /// we're referencing a member. Type openedFullType; /// The opened type produced by referring to this overload. Type openedType; }; /// Describes an aspect of a solution that affects is overall score, i.e., a /// user-defined conversions. enum ScoreKind { // These values are used as indices into a Score value. /// A fix needs to be applied to the source. SK_Fix, /// An implicit force of an implicitly unwrapped optional value. SK_ForceUnchecked, /// A user-defined conversion. SK_UserConversion, /// A non-trivial function conversion. SK_FunctionConversion, /// A literal expression bound to a non-default literal type. SK_NonDefaultLiteral, /// An implicit upcast conversion between array types. SK_ArrayUpcastConversion, /// An implicit bridged conversion between array types. SK_ArrayBridgedConversion, }; /// The number of score kinds. const unsigned NumScoreKinds = 7; /// Describes the fixed score of a solution to the constraint system. struct Score { unsigned Data[NumScoreKinds] = {}; friend Score &operator+=(Score &x, const Score &y) { for (unsigned i = 0; i != NumScoreKinds; ++i) { x.Data[i] += y.Data[i]; } return x; } friend Score operator+(const Score &x, const Score &y) { Score result; for (unsigned i = 0; i != NumScoreKinds; ++i) { result.Data[i] = x.Data[i] + y.Data[i]; } return result; } friend Score operator-(const Score &x, const Score &y) { Score result; for (unsigned i = 0; i != NumScoreKinds; ++i) { result.Data[i] = x.Data[i] - y.Data[i]; } return result; } friend Score &operator-=(Score &x, const Score &y) { for (unsigned i = 0; i != NumScoreKinds; ++i) { x.Data[i] -= y.Data[i]; } return x; } friend bool operator==(const Score &x, const Score &y) { for (unsigned i = 0; i != NumScoreKinds; ++i) { if (x.Data[i] != y.Data[i]) return false; } return true; } friend bool operator!=(const Score &x, const Score &y) { return !(x == y); } friend bool operator<(const Score &x, const Score &y) { for (unsigned i = 0; i != NumScoreKinds; ++i) { if (x.Data[i] < y.Data[i]) return true; if (x.Data[i] > y.Data[i]) return false; } return false; } friend bool operator<=(const Score &x, const Score &y) { return !(y < x); } friend bool operator>(const Score &x, const Score &y) { return y < x; } friend bool operator>=(const Score &x, const Score &y) { return !(x < y); } }; /// Display a score. llvm::raw_ostream &operator<<(llvm::raw_ostream &out, const Score &score); /// \brief A complete solution to a constraint system. /// /// A solution to a constraint system consists of type variable bindings to /// concrete types for every type variable that is used in the constraint /// system along with a set of mappings from each constraint locator /// involving an overload set to the selected overload. class Solution { /// \brief The constraint system this solution solves. ConstraintSystem *constraintSystem; /// \brief The fixed score for this solution. Score FixedScore; public: /// \brief Create a solution for the given constraint system. Solution(ConstraintSystem &cs, const Score &score) : constraintSystem(&cs), FixedScore(score) {} // Solution is a non-copyable type for performance reasons. Solution(const Solution &other) = delete; Solution &operator=(const Solution &other) = delete; Solution(Solution &&other) = default; Solution &operator=(Solution &&other) = default; /// \brief Retrieve the constraint system that this solution solves. ConstraintSystem &getConstraintSystem() const { return *constraintSystem; } /// \brief The set of type bindings. llvm::SmallDenseMap typeBindings; /// \brief The set of overload choices along with their types. llvm::SmallDenseMap overloadChoices; /// The set of constraint restrictions used to arrive at this restriction, /// which informs constraint application. llvm::SmallDenseMap, ConversionRestrictionKind> ConstraintRestrictions; /// The list of fixes that need to be applied to the initial expression /// to make the solution work. llvm::SmallVector, 4> Fixes; /// The set of disjunction choices used to arrive at this solution, /// which informs constraint application. llvm::SmallDenseMap DisjunctionChoices; /// \brief Simplify the given type by substituting all occurrences of /// type variables for their fixed types. Type simplifyType(TypeChecker &tc, Type type) const; /// \brief Coerce the given expression to the given type. /// /// This operation cannot fail. /// /// \param expr The expression to coerce. /// \param toType The type to coerce the expression to. /// \param locator Locator used to describe the location of this expression. /// /// \returns the coerced expression, which will have type \c ToType. Expr *coerceToType(Expr *expr, Type toType, ConstraintLocator *locator) const; /// \brief Convert the given expression to a logic value. /// /// This operation cannot fail. /// /// \param expr The expression to coerce. The type of this expression /// must conform to the LogicValue protocol. /// /// \param locator Locator used to describe the location of this expression. /// /// \returns the expression converted to a logic value (Builtin i1). Expr *convertToLogicValue(Expr *expr, ConstraintLocator *locator) const; /// \brief Convert the given expression to an array bound. /// /// This operation cannot fail. /// /// \param expr The expression to coerce. The type of this expression /// must conform to the ArrayBound protocol. /// /// \param locator Locator used to describe the location of this expression. /// /// \returns the expression converted to an array bound (Builtin integral /// type). Expr *convertToArrayBound(Expr *expr, ConstraintLocator *locator) const; /// Compute the set of substitutions required to map the given type /// to the provided "opened" type. /// /// Either the generic type (\c origType) must either be a /// \c GenericFunctionType, in which case it's generic requirements will be /// used to compute the required substitutions, or \c dc must be a generic /// context, in which case it's generic requirements will be used. /// /// \param origType The generic type. /// /// \param openedType The type to which this reference to the given /// generic function type was opened. /// /// \param dc The declaration context that owns the generic type /// /// \param substitutions Will be populated with the set of substitutions /// to be applied to the generic function type. /// /// \returns The opened type after applying the computed substitutions. Type computeSubstitutions(Type origType, DeclContext *dc, Type openedType, SmallVectorImpl &substitutions) const; /// Return the disjunction choice for the given constraint location. unsigned getDisjunctionChoice(ConstraintLocator *locator) const { assert(DisjunctionChoices.count(locator)); return DisjunctionChoices.find(locator)->second; } /// \brief Retrieve the fixed score of this solution const Score &getFixedScore() const { return FixedScore; } /// \brief Retrieve the fixed score of this solution Score &getFixedScore() { return FixedScore; } /// \brief Retrieve the fixed type for the given type variable. Type getFixedType(TypeVariableType *typeVar) const; LLVM_ATTRIBUTE_DEPRECATED( void dump(SourceManager *SM) const LLVM_ATTRIBUTE_USED, "only for use within the debugger"); /// \brief Dump this solution. void dump(SourceManager *SM, raw_ostream &OS) const LLVM_ATTRIBUTE_USED; }; /// \brief Describes the differences between several solutions to the same /// constraint system. class SolutionDiff { public: /// \brief A difference between two overloads. struct OverloadDiff { /// \brief The locator that describes where the overload comes from. ConstraintLocator *locator; /// \brief The choices that each solution made. SmallVector choices; }; /// \brief A difference between two type variable bindings. struct TypeBindingDiff { /// \brief The type variable. TypeVariableType *typeVar; /// \brief The bindings that each solution made. SmallVector bindings; }; /// \brief The differences between the overload choices between the /// solutions. SmallVector overloads; /// \brief The differences between the type variable bindings of the /// solutions. SmallVector typeBindings; /// \brief Compute the differences between the given set of solutions. /// /// \param solutions The set of solutions. explicit SolutionDiff(ArrayRef solutions); }; /// Describes one resolved overload set within the list of overload sets /// resolved by the solver. struct ResolvedOverloadSetListItem { /// The previously resolved overload set in the list. ResolvedOverloadSetListItem *Previous; /// The type that this overload binds. Type BoundType; /// The overload choice. OverloadChoice Choice; /// The locator for this choice. ConstraintLocator *Locator; /// The type of the fully-opened base, if any. Type OpenedFullType; /// The type of the referenced choice. Type ImpliedType; // Make vanilla new/delete illegal for overload set items. void *operator new(size_t Bytes) = delete; void operator delete(void *Data) = delete; // Only allow allocation of list items using the allocator in the // constraint system. void *operator new(size_t bytes, ConstraintSystem &cs, unsigned alignment = alignof(ResolvedOverloadSetListItem)); }; /// Identifies a specific conversion from struct SpecificConstraint { CanType First; CanType Second; ConstraintKind Kind; }; /// Abstract class implemented by clients that want to be involved in /// the process of opening dependent types to type variables. class DependentTypeOpener { public: virtual ~DependentTypeOpener() { } /// Invoked when a generic type parameter is opened to a type variable. /// /// \param param The generic type parameter. /// /// \param typeVar The type variable to which the generic parameter was /// opened. /// /// \param replacementType If the caller sets this to a non-null type, the /// type variable will be bound directly to this type. virtual void openedGenericParameter(GenericTypeParamType *param, TypeVariableType *typeVar, Type &replacementType) { } /// Invoked when an associated type reference is opened to a type /// variable to determine how the associated type should be resolved. /// /// \param baseType The type of the base of the reference. /// /// \param baseTypeVar The type variable to which the base type was /// opened. /// /// \param assocType The associated type being opened. /// /// \param memberTypeVar The type variable representing the /// dependent member type. /// /// \param replacementType If the caller sets this to a non-null type, the /// member type variable will be bound directly to this type. /// /// \returns true if the constraint system should introduce a /// constraint that specifies that the member type is in fact a the /// named member of the base's type variable. virtual bool shouldBindAssociatedType(Type baseType, TypeVariableType *baseTypeVar, AssociatedTypeDecl *assocType, TypeVariableType *memberTypeVar, Type &replacementType) { return true; } }; /// An intrusive, doubly-linked list of constraints. typedef llvm::ilist ConstraintList; enum class ConstraintSystemFlags { /// Whether we allow the solver to attempt fixes to the system. AllowFixes = 0x01 }; /// Options that affect the constraint system as a whole. typedef OptionSet ConstraintSystemOptions; /// \brief Describes a system of constraints on type variables, the /// solution of which assigns concrete types to each of the type variables. /// Constraint systems are typically generated given an (untyped) expression. class ConstraintSystem { public: TypeChecker &TC; DeclContext *DC; ConstraintSystemOptions Options; friend class Fix; class SolverScope; private: Constraint *failedConstraint = nullptr; /// \brief Allocator used for all of the related constraint systems. llvm::BumpPtrAllocator Allocator; /// \brief Arena used for memory management of constraint-checker-related /// allocations. ConstraintCheckerArenaRAII Arena; /// \brief Counter for type variables introduced. unsigned TypeCounter = 0; /// \brief Cached member lookups. llvm::DenseMap, Optional> MemberLookups; /// Cached sets of "alternative" literal types. Optional> AlternativeLiteralTypes[8]; /// \brief Folding set containing all of the locators used in this /// constraint system. llvm::FoldingSet ConstraintLocators; /// \brief Folding set containing all of the failures that have occurred /// while building and initially simplifying this constraint system. /// /// These failures are unavoidable, in the sense that they occur before /// we have made any (potentially incorrect) assumptions at all. TinyPtrVector unavoidableFailures; /// \brief Failures that occured while solving. /// /// FIXME: We really need to track overload sets and type variable bindings /// to make any sense of this data. Also, it probably belongs within /// SolverState. llvm::FoldingSet failures; /// \brief The overload sets that have been resolved along the current path. ResolvedOverloadSetListItem *resolvedOverloadSets = nullptr; /// The current fixed score for this constraint system and the (partial) /// solution it represents. Score CurrentScore; SmallVector TypeVariables; llvm::DenseMap PossibleDynamicLookupCalls; /// \brief The set of constraint restrictions used to reach the /// current constraint system. /// /// Constraint restrictions help describe which path the solver took when /// there are multiple ways in which one type could convert to another, e.g., /// given class types A and B, the solver might choose either a superclass /// conversion or a user-defined conversion. SmallVector, 32> ConstraintRestrictions; /// The set of fixes applied to make the solution work. /// /// Each fix is paired with a locator that describes where the fix occurs. SmallVector, 4> Fixes; /// The names used in relabel-tuple fixes. std::vector> RelabelTupleNames; /// \brief The set of remembered disjunction choices used to reach /// the current constraint system. SmallVector, 32> DisjunctionChoices; /// The worklist of "active" constraints that should be revisited /// due to a change. ConstraintList ActiveConstraints; /// The list of "inactive" constraints that still need to be solved, /// but will not be revisited until one of their inputs changes. ConstraintList InactiveConstraints; /// The constraint graph. ConstraintGraph &CG; /// \brief Describes the current solver state. struct SolverState { SolverState(ConstraintSystem &cs); ~SolverState(); /// The constraint system. ConstraintSystem &CS; /// Old value of DebugConstraintSolver. /// FIXME: Move the "debug constraint solver" bit into the constraint /// system itself. bool OldDebugConstraintSolver; /// \brief Depth of the solution stack. unsigned depth = 0; /// \brief Whether to record failures or not. bool recordFailures = false; /// The list of constraints that have been retired along the /// current path. ConstraintList retiredConstraints; /// The current set of generated constraints. SmallVector generatedConstraints; /// \brief The set of type variable bindings that have changed while /// processing this constraint system. SavedTypeVariableBindings savedBindings; /// The best solution computed so far. Optional BestScore; /// The number of the solution attempt we're looking at. unsigned SolutionAttempt; /// Refers to the innermost partial solution scope. SolverScope *PartialSolutionScope = nullptr; // Statistics #define CS_STATISTIC(Name, Description) unsigned Name = 0; #include "ConstraintSolverStats.def" }; public: /// \brief The current solver state. /// /// This will be non-null when we're actively solving the constraint /// system, and carries temporary state related to the current path /// we're exploring. SolverState *solverState = nullptr; private: unsigned assignTypeVariableID() { return TypeCounter++; } public: /// \brief Introduces a new solver scope, which any changes to the /// solver state or constraint system are temporary and will be undone when /// this object is destroyed. /// /// class SolverScope { ConstraintSystem &cs; /// \brief The current resolved overload set list. ResolvedOverloadSetListItem *resolvedOverloadSets; /// \brief The length of \c TypeVariables. unsigned numTypeVariables; /// \brief The length of \c SavedBindings. unsigned numSavedBindings; /// The length of generatedConstraints. unsigned numGeneratedConstraints; /// \brief The last retired constraint in the list. ConstraintList::iterator firstRetired; /// \brief The length of \c ConstraintRestrictions. unsigned numConstraintRestrictions; /// \brief The length of \c Fixes. unsigned numFixes; /// \brief The length of \c DisjunctionChoices. unsigned numDisjunctionChoices; /// The previous score. Score PreviousScore; /// Constraint graph scope associated with this solver scope. ConstraintGraphScope CGScope; SolverScope(const SolverScope &) = delete; SolverScope &operator=(const SolverScope &) = delete; friend class ConstraintSystem; public: explicit SolverScope(ConstraintSystem &cs); ~SolverScope(); }; ConstraintSystem(TypeChecker &tc, DeclContext *dc, ConstraintSystemOptions options); ~ConstraintSystem(); /// Retrieve the type checker associated with this constraint system. TypeChecker &getTypeChecker() const { return TC; } /// Retrieve the constraint graph associated with this constraint system. ConstraintGraph &getConstraintGraph() const { return CG; } /// \brief Retrieve the AST context. ASTContext &getASTContext() const { return TC.Context; } private: /// \brief Determine whether this constraint system has any free type /// variables. bool hasFreeTypeVariables(); /// \brief Finalize this constraint system; we're done attempting to solve /// it. /// /// \returns the solution. Solution finalize(FreeTypeVariableBinding allowFreeTypeVariables); /// \brief Apply the given solution to the current constraint system. /// /// This operation is used to take a solution computed based on some /// subset of the constraints and then apply it back to the /// constraint system for further exploration. void applySolution(const Solution &solution); /// \brief Restore the type variable bindings to what they were before /// we attempted to solve this constraint system. /// /// \param numBindings The number of bindings to restore, from the end of /// the saved-binding stack. void restoreTypeVariableBindings(unsigned numBindings); /// \brief Retrieve the set of saved type variable bindings, if available. /// /// \returns null when we aren't currently solving the system. SavedTypeVariableBindings *getSavedBindings() const { return solverState? &solverState->savedBindings : nullptr; } /// Add a new type variable that was already created. void addTypeVariable(TypeVariableType *typeVar); public: /// \brief Lookup for a member with the given name in the given base type. /// /// This routine caches the results of member lookups in the top constraint /// system, to avoid. /// /// FIXME: This caching should almost certainly be performed at the /// module level, since type checking occurs after name binding, /// and no new names are introduced after name binding. /// /// \returns A reference to the member-lookup result. LookupResult &lookupMember(Type base, DeclName name); /// Retrieve the set of "alternative" literal types that we'll explore /// for a given literal protocol kind. ArrayRef getAlternativeLiteralTypes(KnownProtocolKind kind); /// \brief Create a new type variable. TypeVariableType *createTypeVariable(ConstraintLocator *locator, unsigned options) { auto tv = TypeVariableType::getNew(TC.Context, assignTypeVariableID(), locator, options); addTypeVariable(tv); return tv; } /// Retrieve the set of active type variables. ArrayRef getTypeVariables() const { return TypeVariables; } /// \brief Retrieve the constraint locator for the given anchor and /// path, uniqued. ConstraintLocator * getConstraintLocator(Expr *anchor, ArrayRef path, unsigned summaryFlags); /// \brief Retrieve the constraint locator for the given anchor and /// an empty path, uniqued. ConstraintLocator *getConstraintLocator(Expr *anchor) { return getConstraintLocator(anchor, {}, 0); } /// \brief Retrieve the constraint locator for the given anchor and /// path element. ConstraintLocator * getConstraintLocator(Expr *anchor, ConstraintLocator::PathElement pathElt) { return getConstraintLocator(anchor, llvm::makeArrayRef(pathElt), pathElt.getNewSummaryFlags()); } /// \brief Extend the given constraint locator with a path element. ConstraintLocator * getConstraintLocator(ConstraintLocator *locator, ConstraintLocator::PathElement pathElt) { return getConstraintLocator(ConstraintLocatorBuilder(locator) .withPathElement(pathElt)); } /// \brief Retrieve the constraint locator described by the given /// builder. ConstraintLocator * getConstraintLocator(const ConstraintLocatorBuilder &builder); private: /// \brief Record failure with already-simplified arguments. template void recordFailureSimplified(ConstraintLocator *locator, Failure::FailureKind kind, Args &&...args) { // If there is no solver state, this failure is unavoidable. if (!solverState) { auto failure = Failure::create(getAllocator(), locator, kind, resolvedOverloadSets, std::forward(args)...); // Debug output. if (getASTContext().LangOpts.DebugConstraintSolver) { auto &log = getASTContext().TypeCheckerDebug->getStream(); log.indent(2); failure->dump(&TC.Context.SourceMgr, log); } unavoidableFailures.push_back(failure); return; } // Check whether we've recorded this failure already. llvm::FoldingSetNodeID id; Failure::Profile(id, locator, kind, resolvedOverloadSets, args...); void *insertPos = nullptr; auto failure = failures.FindNodeOrInsertPos(id, insertPos); if (!failure) { // Allocate a new failure and record it. failure = Failure::create(getAllocator(), locator, kind, resolvedOverloadSets, args...); failures.InsertNode(failure, insertPos); } // Debug output. if (getASTContext().LangOpts.DebugConstraintSolver) { auto &log = getASTContext().TypeCheckerDebug->getStream(); log.indent(solverState->depth * 2 + 2); failure->dump(&TC.Context.SourceMgr, log); } return; } /// \brief Simplifies an argument to the failure by simplifying the type. Type simplifyFailureArg(Type type) { // FIXME: Should also map type variables back to their corresponding // archetypes here. return simplifyType(type); } /// \brief Simplifies an argument to the failure by simplifying the type. Type simplifyFailureArg(TypeBase *type) { return simplifyType(type); } /// \brief Simplifies an argument to the failure (a no-op). unsigned simplifyFailureArg(unsigned arg) { return arg; } /// \brief Simplifies an argument to the failure (a no-op). DeclName simplifyFailureArg(DeclName arg) { return arg; } /// \brief Determine if the type in question is an Array. bool isArrayType(Type t); public: /// \brief Whether we should be recording failures. bool shouldRecordFailures() { // FIXME: It still makes sense to record failures when there are fixes // present, but they shold be less desirable. if (!Fixes.empty()) return false; return !solverState || solverState->recordFailures || TC.Context.LangOpts.DebugConstraintSolver; } /// \brief Whether we should attempt to fix problems. bool shouldAttemptFixes() { if (!(Options & ConstraintSystemFlags::AllowFixes)) return false; return !solverState || solverState->recordFailures; } /// \brief Record a failure at the given location with the given kind, /// along with any additional arguments to be passed to the failure /// constructor. template void recordFailure(ConstraintLocator *locator, Failure::FailureKind kind, Args &&...args) { // If we don't want to record failures, don't. if (!shouldRecordFailures() || (locator && locator->shouldDiscardFailures())) return; recordFailureSimplified(locator, kind, simplifyFailureArg(std::forward(args))...); } /// \brief Try to salvage the constraint system by applying (speculative) /// fixes to the underlying expression. /// /// \param viable the set of viable solutions produced by the initial /// solution attempt. /// /// \param expr the expression we're trying to salvage. /// /// \param onlyFailures Whether we only want to salvage a diagnostic based off /// of unavoidable failures in the system. /// /// \returns false if we were able to salvage the system, in which case /// \c viable[0] contains the resulting solution. Otherwise, emits a /// diagnostic and returns true. bool salvage(SmallVectorImpl &viable, Expr *expr, bool onlyFailures = false); /// \brief Mine the active and inactive constraints in the constraint /// system to generate a plausible diagnosis of why the system could not be /// solved. /// /// \param expr The expression whose constraints we're investigating for a /// better diagnostic. /// /// \return true if we were able to create a diagnostic from expr's /// constraints. bool diagnoseFailureFromConstraints(Expr *expr); /// \brief Add a newly-allocated constraint after attempting to simplify /// it. /// /// \param isExternallySolved Whether this constraint is being solved /// as an eager simplification, outside of the simplify() loop. /// /// \param simplifyExisting Whether we're simplifying an existing /// constraint rather than introducing a new constraint. /// /// \returns true if this constraint was solved. bool addConstraint(Constraint *constraint, bool isExternallySolved = false, bool simplifyExisting = false); /// \brief Add a constraint to the constraint system. void addConstraint(ConstraintKind kind, Type first, Type second, ConstraintLocator *locator = nullptr) { assert(first && "Missing first type"); assert(second && "Missing second type"); addConstraint(Constraint::create(*this, kind, first, second, DeclName(), locator)); } /// Add a constraint that binds an overload set to a specific choice. void addBindOverloadConstraint(Type boundTy, OverloadChoice choice, ConstraintLocator *locator) { addConstraint(Constraint::createBindOverload(*this, boundTy, choice, locator)); } /// \brief Add a value member constraint to the constraint system. void addValueMemberConstraint(Type baseTy, DeclName name, Type memberTy, ConstraintLocator *locator = nullptr) { assert(baseTy); assert(memberTy); assert(name); addConstraint(Constraint::create(*this, ConstraintKind::ValueMember, baseTy, memberTy, name, locator)); } /// \brief Add an archetype constraint. void addArchetypeConstraint(Type baseTy, ConstraintLocator *locator = nullptr) { assert(baseTy); addConstraint(Constraint::create(*this, ConstraintKind::Archetype, baseTy, Type(), DeclName(), locator)); } /// \brief Remove an inactive constraint from the current constraint graph. void removeInactiveConstraint(Constraint *constraint) { CG.removeConstraint(constraint); InactiveConstraints.erase(constraint); } void recordPossibleDynamicCall(UnresolvedDotExpr *UDE, ApplyExpr *AE) { PossibleDynamicLookupCalls[UDE] = AE; } /// Retrieve the type that corresponds to the given member of the /// given base type, which may be a newly-created type variable. /// /// \param baseTypeVar The base type variable whose member is being queried. /// /// \param assocType The associated type we're referencing. /// /// \param locator The location used to describe this member access. /// /// \param options Options to be supplied to type variable creation if /// a new type is created. /// /// \returns the type variable representing the member type. TypeVariableType *getMemberType(TypeVariableType *baseTypeVar, AssociatedTypeDecl *assocType, ConstraintLocatorBuilder locator, unsigned options); /// Retrieve the list of inactive constraints. ConstraintList &getConstraints() { return InactiveConstraints; } /// \brief Retrieve the representative of the equivalence class containing /// this type variable. TypeVariableType *getRepresentative(TypeVariableType *typeVar) { return typeVar->getImpl().getRepresentative(getSavedBindings()); } /// \brief Merge the equivalence sets of the two type variables. /// /// Note that both \c typeVar1 and \c typeVar2 must be the /// representatives of their equivalence classes, and must be /// distinct. void mergeEquivalenceClasses(TypeVariableType *typeVar1, TypeVariableType *typeVar2); /// \brief Retrieve the fixed type corresponding to the given type variable, /// or a null type if there is no fixed type. Type getFixedType(TypeVariableType *typeVar) { return typeVar->getImpl().getFixedType(getSavedBindings()); } /// Retrieve the fixed type corresponding to a given type variable, /// recursively, until we hit something that isn't a type variable /// or a type variable that doesn't have a fixed type. /// /// \param type The type to simplify. /// /// \param typeVar Will receive the type variable at which simplification /// stopped, which has no fixed type. /// /// \param wantRValue Whether this routine should look through /// lvalues at each step. /// /// param retainParens Whether to retain parentheses. Type getFixedTypeRecursive(Type type, TypeVariableType *&typeVar, bool wantRValue, bool retainParens = false); /// \brief Assign a fixed type to the given type variable. /// /// \param typeVar The type variable to bind. /// /// \param type The fixed type to which the type variable will be bound. /// /// \param updateState Whether to update the state based on this binding. /// False when we're only assigning a type as part of reconstructing /// a complete solution from partial solutions. void assignFixedType(TypeVariableType *typeVar, Type type, bool updateState = true); private: /// Introduce the constraints associated with the given type variable /// into the worklist. void addTypeVariableConstraintsToWorkList(TypeVariableType *typeVar); public: /// \brief "Open" the given type by replacing any occurrences of generic /// parameter types and dependent member types with fresh type variables. /// /// \param type The type to open. /// /// \param dc The declaration context in which the type occurs. /// /// \param skipProtocolSelfConstraint Whether to skip the constraint on a /// protocol's 'Self' type. /// /// \returns The opened type. Type openType(Type type, DeclContext *dc = nullptr, bool skipProtocolSelfConstraint = false, DependentTypeOpener *opener = nullptr) { llvm::DenseMap replacements; return openType(type, replacements, dc, skipProtocolSelfConstraint, opener); } /// \brief "Open" the given type by replacing any occurrences of generic /// parameter types and dependent member types with fresh type variables. /// /// \param type The type to open. /// /// \param replacements The mapping from opened types to the type /// variables to which they were opened. /// /// \param dc The declaration context in which the type occurs. /// /// \param skipProtocolSelfConstraint Whether to skip the constraint on a /// protocol's 'Self' type. /// /// \param opener Abstract class that assists in opening dependent /// types. /// /// \returns The opened type, or \c type if there are no archetypes in it. Type openType(Type type, llvm::DenseMap &replacements, DeclContext *dc = nullptr, bool skipProtocolSelfConstraint = false, DependentTypeOpener *opener = nullptr); /// \brief "Open" the given binding type by replacing any occurrences of /// archetypes (including those implicit in unbound generic types) with /// fresh type variables. /// /// This variant of \c openType() tweaks the result from \c openType() to /// prefer arrays to slices. /// FIXME: This is a bit of a hack. /// /// \param type The type to open. /// \returns The opened type, or \c type if there are no archetypes in it. Type openBindingType(Type type, DeclContext *dc = nullptr); /// Open the generic parameter list and its requirements, creating /// type variables for each of the type parameters. void openGeneric(DeclContext *dc, ArrayRef params, ArrayRef requirements, bool skipProtocolSelfConstraint, DependentTypeOpener *opener, llvm::DenseMap &replacements); /// \brief Retrieve the type of a reference to the given value declaration. /// /// For references to polymorphic function types, this routine "opens up" /// the type by replacing each instance of an archetype with a fresh type /// variable. /// /// \param decl The declarations whose type is being computed. /// /// \param isTypeReference Whether it's a reference to this declaration /// as a type. /// /// \param isSpecialized Whether this declaration is immediately specialized. /// /// \returns a pair containing the full opened type (if applicable) and /// opened type of a reference to declaration. std::pair getTypeOfReference( ValueDecl *decl, bool isTypeReference, bool isSpecialized, DependentTypeOpener *opener = nullptr); /// \brief Retrieve the type of a reference to the given value declaration, /// as a member with a base of the given type. /// /// For references to generic function types or members of generic types, /// this routine "opens up" the type by replacing each instance of a generic /// parameter with a fresh type variable. /// /// \param isTypeReference Indicates that we want to refer to the declared /// type of the type declaration rather than referring to it as a value. /// /// \param isDynamicResult Indicates that this declaration was found via /// dynamic lookup. /// /// \returns a pair containing the full opened type (which includes the opened /// base) and opened type of a reference to this member. std::pair getTypeOfMemberReference( Type baseTy, ValueDecl *decl, bool isTypeReference, bool isDynamicResult, DependentTypeOpener *opener = nullptr); /// \brief Add a new overload set to the list of unresolved overload /// sets. void addOverloadSet(Type boundType, ArrayRef choices, ConstraintLocator *locator); /// If the given type is ImplicitlyUnwrappedOptional, and we're in a context /// that should transparently look through ImplicitlyUnwrappedOptional types, /// return T. Type lookThroughImplicitlyUnwrappedOptionalType(Type type); /// \brief Retrieve the allocator used by this constraint system. llvm::BumpPtrAllocator &getAllocator() { return Allocator; } template ArrayRef::value_type> allocateCopy(It start, It end) { typedef typename std::iterator_traits::value_type T; T *result = (T*)getAllocator().Allocate(sizeof(T)*(end-start), __alignof__(T)); unsigned i; for (i = 0; start != end; ++start, ++i) new (result+i) T(*start); return ArrayRef(result, i); } template ArrayRef allocateCopy(ArrayRef array) { return allocateCopy(array.begin(), array.end()); } template ArrayRef allocateCopy(SmallVectorImpl &vec) { return allocateCopy(vec.begin(), vec.end()); } /// \brief Generate constraints for the given (unchecked) expression. /// /// \returns a possibly-sanitized expression, or null if an error occurred. Expr *generateConstraints(Expr *E); /// \brief Generate constraints for the given top-level expression, /// assuming that its children are already type-checked. /// /// \returns a possibly-sanitized expression, or null if an error occurred. Expr *generateConstraintsShallow(Expr *E); /// \brief Generate constraints for binding the given pattern to the /// value of the given expression. /// /// \returns a possibly-sanitized initializer, or null if an error occurred. Type generateConstraints(Pattern *P, ConstraintLocatorBuilder locator); /// \brief The result of attempting to resolve a constraint or set of /// constraints. enum class SolutionKind : char { /// \brief The constraint has been solved completely, and provides no /// more information. Solved, /// \brief The constraint could not be solved at this point. Unsolved, /// \brief The constraint uncovers an inconsistency in the system. Error }; /// \brief Compute the rvalue type of the given expression, which is the /// destination of an assignment statement. Type computeAssignDestType(Expr *dest, SourceLoc equalLoc); public: /// \brief Flags that direct type matching. enum TypeMatchFlags { TMF_None = 0, /// \brief Indicates that we are in a context where we should be /// generating constraints for any unsolvable problems. /// /// This flag is automatically introduced when type matching destructures /// a type constructor (tuple, function type, etc.), solving that /// constraint while potentially generating others. TMF_GenerateConstraints = 0x01, /// Indicates that we are applying a fix. TMF_ApplyingFix = 0x02, }; private: /// \brief Subroutine of \c matchTypes(), which matches up two tuple types. /// /// \returns the result of performing the tuple-to-tuple conversion. SolutionKind matchTupleTypes(TupleType *tuple1, TupleType *tuple2, TypeMatchKind kind, unsigned flags, ConstraintLocatorBuilder locator); /// \brief Subroutine of \c matchTypes(), which matches a scalar type to /// a tuple type. /// /// \returns the result of performing the scalar-to-tuple conversion. SolutionKind matchScalarToTupleTypes(Type type1, TupleType *tuple2, TypeMatchKind kind, unsigned flags, ConstraintLocatorBuilder locator); /// \brief Subroutine of \c matchTypes(), which extracts a scalar value from /// a single-element tuple type. /// /// \returns the result of performing the tuple-to-scalar conversion. SolutionKind matchTupleToScalarTypes(TupleType *tuple1, Type type2, TypeMatchKind kind, unsigned flags, ConstraintLocatorBuilder locator); /// \brief Subroutine of \c matchTypes(), which matches up two function /// types. SolutionKind matchFunctionTypes(FunctionType *func1, FunctionType *func2, TypeMatchKind kind, unsigned flags, ConstraintLocatorBuilder locator); /// \brief Subroutine of \c matchTypes(), which matches up a value to a /// superclass. SolutionKind matchSuperclassTypes(Type type1, Type type2, TypeMatchKind kind, unsigned flags, ConstraintLocatorBuilder locator); /// \brief Subroutine of \c matchTypes(), which matches up two types that /// refer to the same declaration via their generic arguments. SolutionKind matchDeepEqualityTypes(Type type1, Type type2, ConstraintLocatorBuilder locator); /// \brief Subroutine of \c matchTypes(), which matches up a value to an /// existential type. SolutionKind matchExistentialTypes(Type type1, Type type2, TypeMatchKind kind, unsigned flags, ConstraintLocatorBuilder locator); public: // FIXME: public due to statics in CSSimplify.cpp /// \brief Attempt to match up types \c type1 and \c type2, which in effect /// is solving the given type constraint between these two types. /// /// \param type1 The first type, which is on the left of the type relation. /// /// \param type2 The second type, which is on the right of the type relation. /// /// \param kind The kind of type match being performed, e.g., exact match, /// trivial subtyping, subtyping, or conversion. /// /// \param flags A set of flags composed from the TMF_* constants, which /// indicates how /// /// \param locator The locator that will be used to track the location of /// the specific types being matched. /// /// \returns the result of attempting to solve this constraint. SolutionKind matchTypes(Type type1, Type type2, TypeMatchKind kind, unsigned flags, ConstraintLocatorBuilder locator); public: /// \brief Resolve the given overload set to the given choice. void resolveOverload(ConstraintLocator *locator, Type boundType, OverloadChoice choice); /// \brief Simplify a type, by replacing type variables with either their /// fixed types (if available) or their representatives. /// /// The resulting types can be compared canonically, so long as additional /// type equivalence requirements aren't introduced between comparisons. Type simplifyType(Type type){ llvm::SmallPtrSet substituting; return simplifyType(type, substituting); } private: /// \brief Simplify a type, by replacing type variables with either their /// fixed types (if available) or their representatives. /// /// \param type the type to be simplified. /// /// \param substituting the set of type variables that we're already /// substituting for. These type variables will not be substituted again, /// to avoid infinite recursion. /// /// The resulting types can be compared canonically, so long as additional /// type equivalence requirements aren't introduced between comparisons. Type simplifyType(Type type, llvm::SmallPtrSet &substituting); /// \brief Attempt to simplify the given construction constraint. /// /// \param valueType The type being constructed. /// /// \param argType The type of the argument, used to call \c /// valueType's constructor. /// /// \param flags Flags that indicate how the constraint should be /// simplified. /// /// \param locator Locator describing where this construction /// occurred. SolutionKind simplifyConstructionConstraint(Type valueType, Type argType, unsigned flags, ConstraintLocator *locator); /// \brief Attempt to simplify the given conformance constraint. /// /// \param type The type being testing. /// \param protocol The protocol to which the type should conform. /// \param locator Locator describing where this constraint occurred. /// /// \param allowNonConformingExistential Allow an existential type that /// contains the protocol but does not conform to it (i.e., due to associated /// types). SolutionKind simplifyConformsToConstraint(Type type, ProtocolDecl *protocol, ConstraintLocatorBuilder locator, bool allowNonConformingExistential); /// Attempt to simplify a checked-cast constraint. SolutionKind simplifyCheckedCastConstraint(Type fromType, Type toType, ConstraintLocatorBuilder locator); /// \brief Attempt to simplify the given member constraint. SolutionKind simplifyMemberConstraint(const Constraint &constraint); /// \brief Attempt to simplify the ApplicableFunction constraint. SolutionKind simplifyApplicableFnConstraint(const Constraint &constraint); /// \brief Attempt to simplify the given DynamicTypeOf constraint. SolutionKind simplifyDynamicTypeOfConstraint(const Constraint &constraint); /// \brief Attempt to simplify the given archetype constraint. SolutionKind simplifyArchetypeConstraint(const Constraint &constraint); /// \brief Attempt to simplify the given class constraint. SolutionKind simplifyClassConstraint(const Constraint &constraint); /// \brief Attempt to simplify the given dynamic lookup constraint. SolutionKind simplifyDynamicLookupConstraint(const Constraint &constraint); /// \brief Simplify the given constaint. SolutionKind simplifyConstraint(const Constraint &constraint); /// \brief Simplify a conversion constraint by applying the given /// reduction rule, which is known to apply at the outermost level. SolutionKind simplifyRestrictedConstraint(ConversionRestrictionKind restriction, Type type1, Type type2, TypeMatchKind matchKind, unsigned flags, ConstraintLocatorBuilder locator); public: // FIXME: Public for use by static functions. /// \brief Simplify a conversion constraint with a fix applied to it. SolutionKind simplifyFixConstraint(Fix fix, Type type1, Type type2, TypeMatchKind matchKind, unsigned flags, ConstraintLocatorBuilder locator); public: /// \brief Simplify the system of constraints, by breaking down complex /// constraints into simpler constraints. /// /// The result of simplification is a constraint system that consisting of /// only simple constraints relating type variables to each other or /// directly to fixed types. There are no constraints that involve /// type constructors on both sides. the simplified constraint system may, /// of course, include type variables for which we have constraints but /// no fixed type. Such type variables are left to the solver to bind. /// /// \returns true if an error occurred, false otherwise. bool simplify(); private: /// \brief Solve the system of constraints after it has already been /// simplified. /// /// \param solutions The set of solutions to this system of constraints. /// /// \param allowFreeTypeVariables How to bind free type variables in /// the solution. /// /// \returns true if an error occurred, false otherwise. bool solveSimplified(SmallVectorImpl &solutions, FreeTypeVariableBinding allowFreeTypeVariables); public: /// \brief Solve the system of constraints. /// /// \param solutions The set of solutions to this system of constraints. /// /// \param allowFreeTypeVariables How to bind free type variables in /// the solution. /// /// \returns true if an error occurred, false otherwise. bool solve(SmallVectorImpl &solutions, FreeTypeVariableBinding allowFreeTypeVariables = FreeTypeVariableBinding::Disallow); private: // \brief Compare two solutions to the same set of constraints. /// /// \param cs The constraint system. /// \param solutions All of the solutions to the system. /// \param diff The differences among the solutions. /// \param idx1 The index of the first solution. /// \param idx2 The index of the second solution. static SolutionCompareResult compareSolutions(ConstraintSystem &cs, ArrayRef solutions, const SolutionDiff &diff, unsigned idx1, unsigned idx2); public: /// Increase the score of the given kind for the current (partial) solution /// along the. void increaseScore(ScoreKind kind); /// Determine whether this solution is guaranteed to be worse than the best /// solution found so far. bool worseThanBestSolution() const; /// \brief Given a set of viable solutions, find the best /// solution. /// /// \param solutions The set of viable solutions to consider. /// /// \param minimize If true, then in the case where there is no single /// best solution, minimize the set of solutions by removing any solutions /// that are identical to or worse than some other solution. This operation /// is quadratic. /// /// \returns The index of the best solution, or nothing if there was no /// best solution. Optional findBestSolution(SmallVectorImpl &solutions, bool minimize); /// \brief Apply a given solution to the expression, producing a fully /// type-checked expression. Expr *applySolution(Solution &solution, Expr *expr); /// \brief Apply a given solution to the expression to the top-level /// expression, producing a fully type-checked expression. Expr *applySolutionShallow(const Solution &solution, Expr *expr); /// \brief Obtain the specializations computed for a type variable. This is /// useful when emitting diagnostics for computed type variables. void getComputedBindings(TypeVariableType *tvt, SmallVectorImpl &bindings); /// Extract the base type from an array or slice type. /// \param type The array type to inspect. /// \returns the base type of the array. Type getBaseTypeForArrayType(TypeBase *type); LLVM_ATTRIBUTE_DEPRECATED( void dump() LLVM_ATTRIBUTE_USED, "only for use within the debugger"); void dump(raw_ostream &out); }; /// \brief Compute the shuffle required to map from a given tuple type to /// another tuple type. /// /// \param fromTuple The tuple type we're converting from. /// /// \param toTuple The tuple type we're converting to. /// /// \param sources Will be populated with information about the source of each /// of the elements for the result tuple. The indices into this array are the /// indices of the tuple type we're converting to, while the values are /// either one of the \c TupleShuffleExpr constants or are an index into the /// source tuple. /// /// \param variadicArgs Will be populated with all of the variadic arguments /// that will be placed into the variadic tuple element (i.e., at the index /// \c where \c consumed[i] is \c TupleShuffleExpr::FirstVariadic). The values /// are indices into the source tuple. /// /// \param sourceLabelsAreMandatory True if labels in the source type are /// mandatory to match; false means to make an effort to match them, but /// they can also be dropped. /// /// \returns true if no tuple conversion is possible, false otherwise. bool computeTupleShuffle(TupleType *fromTuple, TupleType *toTuple, SmallVectorImpl &sources, SmallVectorImpl &variadicArgs, bool sourceLabelsAreMandatory); /// Given that an expression has tuple type, are labels in that type /// mandatory or advistory? Mandatory labels must be matched in the /// destination type; optional labels can be matched with unlabeled /// elements. bool hasMandatoryTupleLabels(Expr *expr); /// Compute an argument or parameter type into an array of tuple type elements. /// /// \param type The type to decompose. /// \param scalar A \c TupleTypeElt to be used for scratch space for scalars. ArrayRef decomposeArgParamType(Type type, TupleTypeElt &scalar); /// Describes the arguments to which a parameter binds. /// FIXME: This is an awful data structure. We want the equivalent of a /// TinyPtrVector for unsigned values. typedef SmallVector ParamBinding; /// Class used as the base for listeners to the \c matchCallArguments process. /// /// By default, none of the callbacks do anything. class MatchCallArgumentListener { public: virtual ~MatchCallArgumentListener(); /// Indicates that the argument at the given index does not match any /// parameter. /// /// \param argIdx The index of the extra argument. virtual void extraArgument(unsigned argIdx); /// Indicates that no argument was provided for the parameter at the given /// indices. /// /// \param paramIdx The index of the parameter that is missing an argument. virtual void missingArgument(unsigned paramIdx); /// Indicates that an argument is out-of-order with respect to a previously- /// seen argument. /// /// \param argIdx The argument that came too late in the argument list. /// \param prevArgIdx The argument that the \c argIdx should have preceded. virtual void outOfOrderArgument(unsigned argIdx, unsigned prevArgIdx); /// Indicates that the arguments need to be relabed to match the parameters. /// /// \returns true to indicate that this should cause a failure, false /// otherwise. virtual bool relabelArguments(ArrayRef newNames); }; /// Match the call arguments (as described by the given argument type) to /// the parameters (as described by the given parameter type). /// /// \param argTuple The elements in the argument tuple. /// \param paramTuple The elements in the parameter tuple. /// \param allowFixes Whether to allow fixes when matching arguments. /// /// \param listener Listener that will be notified when certain problems occur, /// e.g., to produce a diagnostic. /// /// \param parameterBindings Will be populated with the arguments that are /// bound to each of the parameters. /// \returns true if the call arguments could not be matched to the parameters. bool matchCallArguments(ArrayRef argTuple, ArrayRef paramTuple, bool allowFixes, MatchCallArgumentListener &listener, SmallVectorImpl ¶meterBindings); /// Simplify the given locator by zeroing in on the most specific /// subexpression described by the locator. /// /// This routine can also find the corresponding "target" locator, which /// typically provides the other end of a relational constraint. For example, /// if the primary locator refers to a function argument, the target locator /// will be set to refer to the corresponding function parameter. /// /// \param cs The constraint system in which the locator will be simplified. /// /// \param locator The locator to simplify. /// /// \param range1 Will be populated with an "interesting" range. /// /// \param range2 Will be populated with a second "interesting" range. /// /// \param targetLocator If non-null, will be set to a locator that describes /// the target of the input locator. /// /// \return the simplified locator. ConstraintLocator *simplifyLocator(ConstraintSystem &cs, ConstraintLocator *locator, SourceRange &range1, SourceRange &range2, ConstraintLocator **targetLocator = nullptr); void simplifyLocator(Expr *&anchor, ArrayRef &path, Expr *&targetAnchor, SmallVectorImpl &targetPath, SourceRange &range1, SourceRange &range2); /// Describes the kind of entity to which a locator was resolved. enum class ResolvedLocatorKind : uint8_t { /// The locator could not be resolved. Unresolved, /// The locator refers to a function. Function, /// The locator refers to a constructor. Constructor, /// The locator refers to a parameter of a function. Parameter }; /// The entity to which a locator resolved. class ResolvedLocator { ResolvedLocatorKind kind; ValueDecl *decl; public: ResolvedLocator() : kind(ResolvedLocatorKind::Unresolved) { } ResolvedLocator(FuncDecl *func) : kind(ResolvedLocatorKind::Function), decl(func) { } ResolvedLocator(ConstructorDecl *constructor) : kind(ResolvedLocatorKind::Constructor), decl(constructor) { } ResolvedLocator(VarDecl *param) : kind(ResolvedLocatorKind::Parameter), decl(param) { } /// Determine the kind of entity to which the locator resolved. ResolvedLocatorKind getKind() const { return kind; } /// Retrieve the declaration to which the locator resolved. ValueDecl *getDecl() const { return decl; } explicit operator bool() const { return getKind() != ResolvedLocatorKind::Unresolved; } }; /// Resolve a locator to the specific declaration it references, if possible. /// /// \param cs The constraint system in which the locator will be resolved. /// /// \param locator The locator to resolve. /// /// \param findOvlChoice A function that searches for the overload choice /// associated with the given locator, or an empty optional if there is no such /// overload. /// /// \returns the entity to which the locator resolved. /// /// FIXME: It would be more natural to express the result as a locator. ResolvedLocator resolveLocatorToDecl( ConstraintSystem &cs, ConstraintLocator *locator, std::function(ConstraintLocator *)> findOvlChoice); } // end namespace constraints template TypeVariableType *TypeVariableType::getNew(const ASTContext &C, unsigned ID, Args &&...args) { // Allocate memory void *mem = C.Allocate(sizeof(TypeVariableType) + sizeof(Implementation), alignof(TypeVariableType), AllocationArena::ConstraintSolver); // Construct the type variable. auto *result = ::new (mem) TypeVariableType(C, ID); // Construct the implementation object. new (result+1) TypeVariableType::Implementation(std::forward(args)...); return result; } } // end namespace swift #endif // LLVM_SWIFT_SEMA_CONSTRAINT_SYSTEM_H