//===--- CSFix.h - Constraint Fixes ---------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file provides necessary abstractions for constraint fixes. // //===----------------------------------------------------------------------===// #ifndef SWIFT_SEMA_CSFIX_H #define SWIFT_SEMA_CSFIX_H #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" #include "swift/AST/Identifier.h" #include "swift/AST/Type.h" #include "swift/AST/Types.h" #include "swift/Basic/Debug.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/TrailingObjects.h" #include namespace llvm { class raw_ostream; } namespace swift { class SourceManager; namespace constraints { class OverloadChoice; class ConstraintSystem; class ConstraintLocator; class ConstraintLocatorBuilder; enum class ConversionRestrictionKind; class Solution; /// Describes the kind of fix to apply to the given constraint before /// visiting it. /// /// Note: values 0 and 1 are reserved for empty and tombstone kinds. enum class FixKind : uint8_t { /// Introduce a '!' to force an optional unwrap. ForceOptional = 2, /// Unwrap an optional base when we have a member access. UnwrapOptionalBase, UnwrapOptionalBaseWithOptionalResult, /// Append 'as! T' to force a downcast to the specified type. ForceDowncast, /// Introduce a '&' to take the address of an lvalue. AddressOf, /// Remove extraneous use of `&`. RemoveAddressOf, /// Replace a coercion ('as') with a forced checked cast ('as!'). CoerceToCheckedCast, /// Mark function type as explicitly '@escaping'. ExplicitlyEscaping, /// Arguments have labeling failures - missing/extraneous or incorrect /// labels attached to the, fix it by suggesting proper labels. RelabelArguments, /// Treat rvalue as lvalue TreatRValueAsLValue, /// Add a new conformance to the type to satisfy a requirement. AddConformance, /// Skip same-type generic requirement constraint, /// and assume that types are equal. SkipSameTypeRequirement, /// Skip superclass generic requirement constraint, /// and assume that types are related. SkipSuperclassRequirement, /// Fix up one of the sides of conversion to make it seem /// like the types are aligned. ContextualMismatch, /// Fix up the generic arguments of two types so they match each other. GenericArgumentsMismatch, /// Fix up @autoclosure argument to the @autoclosure parameter, /// to for a call to be able to foward it properly, since /// @autoclosure conversions are unsupported starting from /// Swift version 5. AutoClosureForwarding, /// Remove `!` or `?` because base is not an optional type. RemoveUnwrap, /// Add explicit `()` at the end of function or member to call it. InsertCall, /// Add '$' or '_' to refer to the property wrapper or storage instead /// of the wrapped property type. UsePropertyWrapper, /// Remove '$' or '_' to refer to the wrapped property type instead of /// the storage or property wrapper. UseWrappedValue, /// Instead of spelling out `subscript` directly, use subscript operator. UseSubscriptOperator, /// Requested name is not associated with a give base type, /// fix this issue by pretending that member exists and matches /// given arguments/result types exactly. DefineMemberBasedOnUse, /// Allow access to type member on instance or instance member on type AllowTypeOrInstanceMember, /// Allow expressions where 'mutating' method is only partially applied, /// which means either not applied at all e.g. `Foo.bar` or only `Self` /// is applied e.g. `foo.bar` or `Foo.bar(&foo)`. /// /// Allow expressions where initializer call (either `self.init` or /// `super.init`) is only partially applied. AllowInvalidPartialApplication, /// Non-required constructors may not be not inherited. Therefore when /// constructing a class object, either the metatype must be statically /// derived (rather than an arbitrary value of metatype type) or the /// referenced constructor must be required. AllowInvalidInitRef, /// Allow a tuple to be destructured with mismatched arity, or mismatched /// types. AllowTupleTypeMismatch, /// Allow a function type to be destructured with mismatched parameter types /// or return type. AllowFunctionTypeMismatch, /// Allow an invalid member access on a value of protocol type as if /// that protocol type were a generic constraint requiring conformance /// to that protocol. AllowMemberRefOnExistential, /// If there are fewer arguments than parameters, let's fix that up /// by adding new arguments to the list represented as type variables. AddMissingArguments, /// If there are more arguments than parameters, let's fix that up /// by removing extraneous arguments. RemoveExtraneousArguments, /// Allow single tuple closure parameter destructuring into N arguments. AllowClosureParameterDestructuring, /// If there is out-of-order argument, let's fix that by re-ordering. MoveOutOfOrderArgument, /// If there is a matching inaccessible member - allow it as if there /// no access control. AllowInaccessibleMember, /// Allow KeyPaths to use AnyObject as root type AllowAnyObjectKeyPathRoot, /// Using subscript references in the keypath requires that each /// of the index arguments to be Hashable. TreatKeyPathSubscriptIndexAsHashable, /// Allow an invalid reference to a member declaration as part /// of a key path component. AllowInvalidRefInKeyPath, /// Remove `return` or default last expression of single expression /// function to `Void` to conform to expected result type. RemoveReturn, /// Default ambiguous generic arguments to \c Any DefaultGenericArgument, /// Skip any unhandled constructs that occur within a closure argument that /// matches up with a /// parameter that has a function builder. SkipUnhandledConstructInFunctionBuilder, /// Allow invalid reference to a member declared as `mutating` /// when base is an r-value type. AllowMutatingMemberOnRValueBase, /// Allow a single tuple parameter to be matched with N arguments /// by forming all of the given arguments into a single tuple. AllowTupleSplatForSingleParameter, /// Allow a single argument type mismatch. This is the most generic /// failure related to argument-to-parameter conversions. AllowArgumentTypeMismatch, /// Explicitly construct type conforming to `RawRepresentable` protocol /// via forming `Foo(rawValue:)` instead of using its `RawValue` directly. ExplicitlyConstructRawRepresentable, /// Use raw value type associated with raw representative accessible /// using `.rawValue` member. UseValueTypeOfRawRepresentative, /// If an array was passed to a variadic argument, give a specific diagnostic /// and offer to drop the brackets if it's a literal. ExpandArrayIntoVarargs, /// Remove extraneous call to something which can't be invoked e.g. /// a variable, a property etc. RemoveCall, AllowInvalidUseOfTrailingClosure, /// Allow an ephemeral argument conversion for a parameter marked as being /// non-ephemeral. TreatEphemeralAsNonEphemeral, /// Base type in reference to the contextual member e.g. `.foo` couldn't be /// inferred and has to be specified explicitly. SpecifyBaseTypeForContextualMember, /// Closure return type has to be explicitly specified because it can't be /// inferred in current context e.g. because it's a multi-statement closure. SpecifyClosureReturnType, /// Object literal type coudn't be infered because the module where /// the default type that implements the associated literal protocol /// is declared was not imported. SpecifyObjectLiteralTypeImport, }; class ConstraintFix { ConstraintSystem &CS; FixKind Kind; ConstraintLocator *Locator; /// Determines whether this fix is simplify a warning which doesn't /// require immediate source changes. bool IsWarning; public: ConstraintFix(ConstraintSystem &cs, FixKind kind, ConstraintLocator *locator, bool warning = false) : CS(cs), Kind(kind), Locator(locator), IsWarning(warning) {} virtual ~ConstraintFix(); template const Fix *getAs() const { return Fix::classof(this) ? static_cast(this) : nullptr; } FixKind getKind() const { return Kind; } bool isWarning() const { return IsWarning; } virtual std::string getName() const = 0; /// Coalesce this fix with the given secondary fixes and diagnose the failure. /// /// The default implementation ignores \c secondaryFixes and calls /// \c diagnose. virtual bool coalesceAndDiagnose(ArrayRef secondaryFixes, bool asNote = false) const { return diagnose(asNote); } /// Diagnose a failure associated with this fix. virtual bool diagnose(bool asNote = false) const = 0; void print(llvm::raw_ostream &Out) const; SWIFT_DEBUG_DUMP; /// Retrieve anchor expression associated with this fix. /// NOTE: such anchor comes directly from locator without /// any simplication attempts. Expr *getAnchor() const; ConstraintLocator *getLocator() const { return Locator; } protected: ConstraintSystem &getConstraintSystem() const { return CS; } }; /// Unwrap an optional base when we have a member access. class UnwrapOptionalBase final : public ConstraintFix { DeclNameRef MemberName; UnwrapOptionalBase(ConstraintSystem &cs, FixKind kind, DeclNameRef member, ConstraintLocator *locator) : ConstraintFix(cs, kind, locator), MemberName(member) { assert(kind == FixKind::UnwrapOptionalBase || kind == FixKind::UnwrapOptionalBaseWithOptionalResult); } public: std::string getName() const override { return "unwrap optional base of member lookup"; } bool diagnose(bool asNote = false) const override; static UnwrapOptionalBase *create(ConstraintSystem &cs, DeclNameRef member, ConstraintLocator *locator); static UnwrapOptionalBase * createWithOptionalResult(ConstraintSystem &cs, DeclNameRef member, ConstraintLocator *locator); }; // Treat rvalue as if it was an lvalue class TreatRValueAsLValue final : public ConstraintFix { TreatRValueAsLValue(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::TreatRValueAsLValue, locator) {} public: std::string getName() const override { return "treat rvalue as lvalue"; } bool diagnose(bool asNote = false) const override; static TreatRValueAsLValue *create(ConstraintSystem &cs, ConstraintLocator *locator); }; /// Arguments have labeling failures - missing/extraneous or incorrect /// labels attached to the, fix it by suggesting proper labels. class RelabelArguments final : public ConstraintFix, private llvm::TrailingObjects { friend TrailingObjects; unsigned NumLabels; RelabelArguments(ConstraintSystem &cs, llvm::ArrayRef correctLabels, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::RelabelArguments, locator), NumLabels(correctLabels.size()) { std::uninitialized_copy(correctLabels.begin(), correctLabels.end(), getLabelsBuffer().begin()); } public: std::string getName() const override { return "re-label argument(s)"; } ArrayRef getLabels() const { return {getTrailingObjects(), NumLabels}; } bool diagnose(bool asNote = false) const override; static RelabelArguments *create(ConstraintSystem &cs, llvm::ArrayRef correctLabels, ConstraintLocator *locator); private: MutableArrayRef getLabelsBuffer() { return {getTrailingObjects(), NumLabels}; } }; /// Add a new conformance to the type to satisfy a requirement. class MissingConformance final : public ConstraintFix { // Determines whether given protocol type comes from the context e.g. // assignment destination or argument comparison. bool IsContextual; Type NonConformingType; // This could either be a protocol or protocol composition. Type ProtocolType; MissingConformance(ConstraintSystem &cs, bool isContextual, Type type, Type protocolType, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AddConformance, locator), IsContextual(isContextual), NonConformingType(type), ProtocolType(protocolType) {} public: std::string getName() const override { return "add missing protocol conformance"; } bool diagnose(bool asNote = false) const override; static MissingConformance *forRequirement(ConstraintSystem &cs, Type type, Type protocolType, ConstraintLocator *locator); static MissingConformance *forContextual(ConstraintSystem &cs, Type type, Type protocolType, ConstraintLocator *locator); Type getNonConformingType() { return NonConformingType; } Type getProtocolType() { return ProtocolType; } }; /// Skip same-type generic requirement constraint, /// and assume that types are equal. class SkipSameTypeRequirement final : public ConstraintFix { Type LHS, RHS; SkipSameTypeRequirement(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::SkipSameTypeRequirement, locator), LHS(lhs), RHS(rhs) {} public: std::string getName() const override { return "skip same-type generic requirement"; } bool diagnose(bool asNote = false) const override; Type lhsType() { return LHS; } Type rhsType() { return RHS; } static SkipSameTypeRequirement *create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator); }; /// Skip 'superclass' generic requirement constraint, /// and assume that types are equal. class SkipSuperclassRequirement final : public ConstraintFix { Type LHS, RHS; SkipSuperclassRequirement(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::SkipSuperclassRequirement, locator), LHS(lhs), RHS(rhs) {} public: std::string getName() const override { return "skip superclass generic requirement"; } bool diagnose(bool asNote = false) const override; Type subclassType() { return LHS; } Type superclassType() { return RHS; } static SkipSuperclassRequirement * create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator); }; /// For example: Sometimes type returned from the body of the /// closure doesn't match expected contextual type: /// /// func foo(_: () -> Int) {} /// foo { "ultimate question" } /// /// Body of the closure produces `String` type when `Int` is expected /// by the context. class ContextualMismatch : public ConstraintFix { Type LHS, RHS; protected: ContextualMismatch(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::ContextualMismatch, locator), LHS(lhs), RHS(rhs) {} ContextualMismatch(ConstraintSystem &cs, FixKind kind, Type lhs, Type rhs, ConstraintLocator *locator, bool warning = false) : ConstraintFix(cs, kind, locator, warning), LHS(lhs), RHS(rhs) {} public: std::string getName() const override { return "fix contextual mismatch"; } Type getFromType() const { return LHS; } Type getToType() const { return RHS; } bool diagnose(bool asNote = false) const override; static ContextualMismatch *create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator); }; /// Mark function type as explicitly '@escaping'. class MarkExplicitlyEscaping final : public ContextualMismatch { MarkExplicitlyEscaping(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::ExplicitlyEscaping, lhs, rhs, locator) { } public: std::string getName() const override { return "add @escaping"; } bool diagnose(bool asNote = false) const override; static MarkExplicitlyEscaping *create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator); }; /// Introduce a '!' to force an optional unwrap. class ForceOptional final : public ContextualMismatch { ForceOptional(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::ForceOptional, fromType, toType, locator) { assert(fromType && "Base type must not be null"); assert(fromType->getOptionalObjectType() && "Unwrapped type must not be null"); } public: std::string getName() const override { return "force optional"; } bool diagnose(bool asNote = false) const override; static ForceOptional *create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator); }; /// This is a contextual mismatch between throwing and non-throwing /// function types, repair it by dropping `throws` attribute. class DropThrowsAttribute final : public ContextualMismatch { DropThrowsAttribute(ConstraintSystem &cs, FunctionType *fromType, FunctionType *toType, ConstraintLocator *locator) : ContextualMismatch(cs, fromType, toType, locator) { assert(fromType->throws() != toType->throws()); } public: std::string getName() const override { return "drop 'throws' attribute"; } bool diagnose(bool asNote = false) const override; static DropThrowsAttribute *create(ConstraintSystem &cs, FunctionType *fromType, FunctionType *toType, ConstraintLocator *locator); }; /// Append 'as! T' to force a downcast to the specified type. class ForceDowncast final : public ContextualMismatch { ForceDowncast(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::ForceDowncast, fromType, toType, locator) {} public: std::string getName() const override; bool diagnose(bool asNote = false) const override; static ForceDowncast *create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator); }; /// Introduce a '&' to take the address of an lvalue. class AddAddressOf final : public ContextualMismatch { AddAddressOf(ConstraintSystem &cs, Type argTy, Type paramTy, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::AddressOf, argTy, paramTy, locator) {} public: std::string getName() const override { return "add address-of"; } bool diagnose(bool asNote = false) const override; static AddAddressOf *create(ConstraintSystem &cs, Type argTy, Type paramTy, ConstraintLocator *locator); }; class RemoveAddressOf final : public ContextualMismatch { RemoveAddressOf(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::RemoveAddressOf, lhs, rhs, locator) {} public: std::string getName() const override { return "remove extraneous use of `&`"; } bool diagnose(bool asNote = false) const override; static RemoveAddressOf *create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator); }; /// Detect situations where two type's generic arguments must /// match but are not convertible e.g. /// /// ```swift /// struct F {} /// let _:F = F() /// ``` class GenericArgumentsMismatch final : public ContextualMismatch, private llvm::TrailingObjects { friend TrailingObjects; unsigned NumMismatches; protected: GenericArgumentsMismatch(ConstraintSystem &cs, Type actual, Type required, llvm::ArrayRef mismatches, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::GenericArgumentsMismatch, actual, required, locator), NumMismatches(mismatches.size()) { assert(actual->is()); assert(required->is()); std::uninitialized_copy(mismatches.begin(), mismatches.end(), getMismatchesBuf().begin()); } public: std::string getName() const override { return "fix generic argument mismatch"; } ArrayRef getMismatches() const { return {getTrailingObjects(), NumMismatches}; } bool diagnose(bool asNote = false) const override; static GenericArgumentsMismatch *create(ConstraintSystem &cs, Type actual, Type required, llvm::ArrayRef mismatches, ConstraintLocator *locator); private: MutableArrayRef getMismatchesBuf() { return {getTrailingObjects(), NumMismatches}; } }; /// Detect situations where key path doesn't have capability required /// by the context e.g. read-only vs. writable, or either root or value /// types are incorrect e.g. /// /// ```swift /// struct S { let foo: Int } /// let _: WritableKeyPath = \.foo /// ``` /// /// Here context requires a writable key path but `foo` property is /// read-only. class KeyPathContextualMismatch final : public ContextualMismatch { KeyPathContextualMismatch(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) : ContextualMismatch(cs, lhs, rhs, locator) {} public: std::string getName() const override { return "fix key path contextual mismatch"; } static KeyPathContextualMismatch * create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator); }; /// Detect situations when argument of the @autoclosure parameter is itself /// marked as @autoclosure and is not applied. Form a fix which suggests a /// proper way to forward such arguments, e.g.: /// /// ```swift /// func foo(_ fn: @autoclosure () -> Int) {} /// func bar(_ fn: @autoclosure () -> Int) { /// foo(fn) // error - fn should be called /// } /// ``` class AutoClosureForwarding final : public ConstraintFix { AutoClosureForwarding(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AutoClosureForwarding, locator) {} public: std::string getName() const override { return "fix @autoclosure forwarding"; } bool diagnose(bool asNote = false) const override; static AutoClosureForwarding *create(ConstraintSystem &cs, ConstraintLocator *locator); }; /// Allow invalid pointer conversions for autoclosure result types as if the /// pointer type is a function parameter rather than an autoclosure result. class AllowAutoClosurePointerConversion final : public ContextualMismatch { AllowAutoClosurePointerConversion(ConstraintSystem &cs, Type pointeeType, Type pointerType, ConstraintLocator *locator) : ContextualMismatch(cs, pointeeType, pointerType, locator) {} public: std::string getName() const override { return "allow pointer conversion for autoclosure result type"; } bool diagnose(bool asNote = false) const override; static AllowAutoClosurePointerConversion *create(ConstraintSystem &cs, Type pointeeType, Type pointerType, ConstraintLocator *locator); }; class RemoveUnwrap final : public ConstraintFix { Type BaseType; RemoveUnwrap(ConstraintSystem &cs, Type baseType, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::RemoveUnwrap, locator), BaseType(baseType) {} public: std::string getName() const override { return "remove unwrap operator `!` or `?`"; } bool diagnose(bool asNote = false) const override; static RemoveUnwrap *create(ConstraintSystem &cs, Type baseType, ConstraintLocator *locator); }; class InsertExplicitCall final : public ConstraintFix { InsertExplicitCall(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::InsertCall, locator) {} public: std::string getName() const override { return "insert explicit `()` to make a call"; } bool diagnose(bool asNote = false) const override; static InsertExplicitCall *create(ConstraintSystem &cs, ConstraintLocator *locator); }; class UsePropertyWrapper final : public ConstraintFix { VarDecl *Wrapped; bool UsingStorageWrapper; Type Base; Type Wrapper; UsePropertyWrapper(ConstraintSystem &cs, VarDecl *wrapped, bool usingStorageWrapper, Type base, Type wrapper, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::UsePropertyWrapper, locator), Wrapped(wrapped), UsingStorageWrapper(usingStorageWrapper), Base(base), Wrapper(wrapper) {} public: std::string getName() const override { return "insert '$' or '_' to use property wrapper type instead of wrapped type"; } bool diagnose(bool asNote = false) const override; static UsePropertyWrapper *create(ConstraintSystem &cs, VarDecl *wrapped, bool usingStorageWrapper, Type base, Type wrapper, ConstraintLocator *locator); }; class UseWrappedValue final : public ConstraintFix { VarDecl *PropertyWrapper; Type Base; Type Wrapper; UseWrappedValue(ConstraintSystem &cs, VarDecl *propertyWrapper, Type base, Type wrapper, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::UseWrappedValue, locator), PropertyWrapper(propertyWrapper), Base(base), Wrapper(wrapper) {} bool usingStorageWrapper() const { auto nameStr = PropertyWrapper->getName().str(); return !nameStr.startswith("_"); } public: std::string getName() const override { return "remove '$' or _ to use wrapped type instead of wrapper type"; } bool diagnose(bool asNote = false) const override; static UseWrappedValue *create(ConstraintSystem &cs, VarDecl *propertyWrapper, Type base, Type wrapper, ConstraintLocator *locator); }; class UseSubscriptOperator final : public ConstraintFix { UseSubscriptOperator(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::UseSubscriptOperator, locator) {} public: std::string getName() const override { return "replace '.subscript(...)' with subscript operator"; } bool diagnose(bool asNote = false) const override; static UseSubscriptOperator *create(ConstraintSystem &cs, ConstraintLocator *locator); }; class DefineMemberBasedOnUse final : public ConstraintFix { Type BaseType; DeclNameRef Name; /// Whether or not the member error is already diagnosed. This can happen /// when referencing an erroneous member, and the error is diagnosed at the /// member declaration. /// /// We still want to define erroneous members based on use in order to find /// a solution through the new diagnostic infrastructure, but we don't /// want to report a second error message. bool AlreadyDiagnosed; DefineMemberBasedOnUse(ConstraintSystem &cs, Type baseType, DeclNameRef member, bool alreadyDiagnosed, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::DefineMemberBasedOnUse, locator), BaseType(baseType), Name(member), AlreadyDiagnosed(alreadyDiagnosed) {} public: std::string getName() const override { llvm::SmallVector scratch; auto memberName = Name.getString(scratch); return "define missing member named '" + memberName.str() + "' based on its use"; } bool diagnose(bool asNote = false) const override; static DefineMemberBasedOnUse *create(ConstraintSystem &cs, Type baseType, DeclNameRef member, bool alreadyDiagnosed, ConstraintLocator *locator); }; class AllowInvalidMemberRef : public ConstraintFix { Type BaseType; ValueDecl *Member; DeclNameRef Name; protected: AllowInvalidMemberRef(ConstraintSystem &cs, FixKind kind, Type baseType, ValueDecl *member, DeclNameRef name, ConstraintLocator *locator) : ConstraintFix(cs, kind, locator), BaseType(baseType), Member(member), Name(name) {} public: Type getBaseType() const { return BaseType; } ValueDecl *getMember() const { return Member; } DeclNameRef getMemberName() const { return Name; } }; class AllowMemberRefOnExistential final : public AllowInvalidMemberRef { AllowMemberRefOnExistential(ConstraintSystem &cs, Type baseType, DeclNameRef memberName, ValueDecl *member, ConstraintLocator *locator) : AllowInvalidMemberRef(cs, FixKind::AllowMemberRefOnExistential, baseType, member, memberName, locator) {} public: std::string getName() const override { llvm::SmallVector scratch; auto memberName = getMemberName().getString(scratch); return "allow access to invalid member '" + memberName.str() + "' on value of protocol type"; } bool diagnose(bool asNote = false) const override; static AllowMemberRefOnExistential *create(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef memberName, ConstraintLocator *locator); }; class AllowTypeOrInstanceMember final : public AllowInvalidMemberRef { AllowTypeOrInstanceMember(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef name, ConstraintLocator *locator) : AllowInvalidMemberRef(cs, FixKind::AllowTypeOrInstanceMember, baseType, member, name, locator) { assert(member); } public: std::string getName() const override { return "allow access to instance member on type or a type member on instance"; } bool diagnose(bool asNote = false) const override; static AllowTypeOrInstanceMember *create(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef usedName, ConstraintLocator *locator); }; class AllowInvalidPartialApplication final : public ConstraintFix { AllowInvalidPartialApplication(bool isWarning, ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowInvalidPartialApplication, locator, isWarning) {} public: std::string getName() const override { return "allow partially applied 'mutating' method"; } bool diagnose(bool asNote = false) const override; static AllowInvalidPartialApplication *create(bool isWarning, ConstraintSystem &cs, ConstraintLocator *locator); }; class AllowInvalidInitRef final : public ConstraintFix { enum class RefKind { DynamicOnMetatype, ProtocolMetatype, NonConstMetatype, } Kind; Type BaseType; const ConstructorDecl *Init; bool IsStaticallyDerived; SourceRange BaseRange; AllowInvalidInitRef(ConstraintSystem &cs, RefKind kind, Type baseTy, ConstructorDecl *init, bool isStaticallyDerived, SourceRange baseRange, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowInvalidInitRef, locator), Kind(kind), BaseType(baseTy), Init(init), IsStaticallyDerived(isStaticallyDerived), BaseRange(baseRange) {} public: std::string getName() const override { return "allow invalid initializer reference"; } bool diagnose(bool asNote = false) const override; static AllowInvalidInitRef * dynamicOnMetatype(ConstraintSystem &cs, Type baseTy, ConstructorDecl *init, SourceRange baseRange, ConstraintLocator *locator); static AllowInvalidInitRef * onProtocolMetatype(ConstraintSystem &cs, Type baseTy, ConstructorDecl *init, bool isStaticallyDerived, SourceRange baseRange, ConstraintLocator *locator); static AllowInvalidInitRef *onNonConstMetatype(ConstraintSystem &cs, Type baseTy, ConstructorDecl *init, ConstraintLocator *locator); private: static AllowInvalidInitRef *create(RefKind kind, ConstraintSystem &cs, Type baseTy, ConstructorDecl *init, bool isStaticallyDerived, SourceRange baseRange, ConstraintLocator *locator); }; class AllowTupleTypeMismatch final : public ContextualMismatch { /// If this is an element mismatch, \c Index is the element index where the /// type mismatch occurred. If this is an arity or label mismatch, \c Index /// will be \c None. Optional Index; AllowTupleTypeMismatch(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator, Optional index) : ContextualMismatch(cs, FixKind::AllowTupleTypeMismatch, lhs, rhs, locator), Index(index) {} public: static AllowTupleTypeMismatch *create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator, Optional index = None); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowTupleTypeMismatch; } std::string getName() const override { return "fix tuple mismatches in type and arity"; } bool isElementMismatch() const { return Index.hasValue(); } bool coalesceAndDiagnose(ArrayRef secondaryFixes, bool asNote = false) const override; bool diagnose(bool asNote = false) const override; }; class AllowFunctionTypeMismatch final : public ContextualMismatch { /// The index of the parameter where the type mismatch occurred. unsigned ParamIndex; AllowFunctionTypeMismatch(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator, unsigned index) : ContextualMismatch(cs, FixKind::AllowFunctionTypeMismatch, lhs, rhs, locator), ParamIndex(index) {} public: static AllowFunctionTypeMismatch *create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator, unsigned index); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowFunctionTypeMismatch; } std::string getName() const override { return "allow function type mismatch"; } bool coalesceAndDiagnose(ArrayRef secondaryFixes, bool asNote = false) const override; bool diagnose(bool asNote = false) const override; }; class AllowMutatingMemberOnRValueBase final : public AllowInvalidMemberRef { AllowMutatingMemberOnRValueBase(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef name, ConstraintLocator *locator) : AllowInvalidMemberRef(cs, FixKind::AllowMutatingMemberOnRValueBase, baseType, member, name, locator) {} public: std::string getName() const override { return "allow `mutating` method on r-value base"; } bool diagnose(bool asNote = false) const override; static AllowMutatingMemberOnRValueBase * create(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef name, ConstraintLocator *locator); }; class AllowClosureParamDestructuring final : public ConstraintFix { FunctionType *ContextualType; AllowClosureParamDestructuring(ConstraintSystem &cs, FunctionType *contextualType, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowClosureParameterDestructuring, locator), ContextualType(contextualType) {} public: std::string getName() const override { return "allow closure parameter destructuring"; } bool diagnose(bool asNote = false) const override; static AllowClosureParamDestructuring *create(ConstraintSystem &cs, FunctionType *contextualType, ConstraintLocator *locator); }; class AddMissingArguments final : public ConstraintFix, private llvm::TrailingObjects { friend TrailingObjects; using Param = AnyFunctionType::Param; unsigned NumSynthesized; AddMissingArguments(ConstraintSystem &cs, llvm::ArrayRef synthesizedArgs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AddMissingArguments, locator), NumSynthesized(synthesizedArgs.size()) { std::uninitialized_copy(synthesizedArgs.begin(), synthesizedArgs.end(), getSynthesizedArgumentsBuf().begin()); } public: std::string getName() const override { return "synthesize missing argument(s)"; } ArrayRef getSynthesizedArguments() const { return {getTrailingObjects(), NumSynthesized}; } bool diagnose(bool asNote = false) const override; static AddMissingArguments *create(ConstraintSystem &cs, llvm::ArrayRef synthesizedArgs, ConstraintLocator *locator); private: MutableArrayRef getSynthesizedArgumentsBuf() { return {getTrailingObjects(), NumSynthesized}; } }; class RemoveExtraneousArguments final : public ConstraintFix, private llvm::TrailingObjects< RemoveExtraneousArguments, std::pair> { friend TrailingObjects; using IndexedParam = std::pair; FunctionType *ContextualType; unsigned NumExtraneous; RemoveExtraneousArguments(ConstraintSystem &cs, FunctionType *contextualType, llvm::ArrayRef extraArgs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::RemoveExtraneousArguments, locator), ContextualType(contextualType), NumExtraneous(extraArgs.size()) { std::uninitialized_copy(extraArgs.begin(), extraArgs.end(), getExtraArgumentsBuf().begin()); } public: std::string getName() const override { return "remove extraneous argument(s)"; } ArrayRef getExtraArguments() const { return {getTrailingObjects(), NumExtraneous}; } bool diagnose(bool asNote = false) const override; /// FIXME(diagnostics): Once `resolveDeclRefExpr` is gone this /// logic would be obsolete. /// /// Determine whether presence of extraneous arguments indicates /// potential name shadowing problem with local `min`/`max` shadowing /// global definitions with different number of arguments. static bool isMinMaxNameShadowing(ConstraintSystem &cs, ConstraintLocatorBuilder locator); static RemoveExtraneousArguments * create(ConstraintSystem &cs, FunctionType *contextualType, llvm::ArrayRef extraArgs, ConstraintLocator *locator); private: MutableArrayRef getExtraArgumentsBuf() { return {getTrailingObjects(), NumExtraneous}; } }; class MoveOutOfOrderArgument final : public ConstraintFix { using ParamBinding = SmallVector; unsigned ArgIdx; unsigned PrevArgIdx; SmallVector Bindings; MoveOutOfOrderArgument(ConstraintSystem &cs, unsigned argIdx, unsigned prevArgIdx, ArrayRef bindings, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::MoveOutOfOrderArgument, locator), ArgIdx(argIdx), PrevArgIdx(prevArgIdx), Bindings(bindings.begin(), bindings.end()) {} public: std::string getName() const override { return "move out-of-order argument to correct position"; } bool diagnose(bool asNote = false) const override; static MoveOutOfOrderArgument *create(ConstraintSystem &cs, unsigned argIdx, unsigned prevArgIdx, ArrayRef bindings, ConstraintLocator *locator); }; class AllowInaccessibleMember final : public AllowInvalidMemberRef { AllowInaccessibleMember(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef name, ConstraintLocator *locator) : AllowInvalidMemberRef(cs, FixKind::AllowInaccessibleMember, baseType, member, name, locator) {} public: std::string getName() const override { return "allow inaccessible member reference"; } bool diagnose(bool asNote = false) const override; static AllowInaccessibleMember *create(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef name, ConstraintLocator *locator); }; class AllowAnyObjectKeyPathRoot final : public ConstraintFix { AllowAnyObjectKeyPathRoot(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowAnyObjectKeyPathRoot, locator) {} public: std::string getName() const override { return "allow anyobject as root type for a keypath"; } bool diagnose(bool asNote = false) const override; static AllowAnyObjectKeyPathRoot *create(ConstraintSystem &cs, ConstraintLocator *locator); }; class TreatKeyPathSubscriptIndexAsHashable final : public ConstraintFix { Type NonConformingType; TreatKeyPathSubscriptIndexAsHashable(ConstraintSystem &cs, Type type, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::TreatKeyPathSubscriptIndexAsHashable, locator), NonConformingType(type) {} public: std::string getName() const override { return "treat keypath subscript index as conforming to Hashable"; } bool diagnose(bool asNote = false) const override; static TreatKeyPathSubscriptIndexAsHashable * create(ConstraintSystem &cs, Type type, ConstraintLocator *locator); }; class AllowInvalidRefInKeyPath final : public ConstraintFix { enum RefKind { // Allow a reference to a static member as a key path component. StaticMember, // Allow a reference to a declaration with mutating getter as // a key path component. MutatingGetter, // Allow a reference to a method (instance or static) as // a key path component. Method, } Kind; ValueDecl *Member; AllowInvalidRefInKeyPath(ConstraintSystem &cs, RefKind kind, ValueDecl *member, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowInvalidRefInKeyPath, locator), Kind(kind), Member(member) {} public: std::string getName() const override { switch (Kind) { case RefKind::StaticMember: return "allow reference to a static member as a key path component"; case RefKind::MutatingGetter: return "allow reference to a member with mutating getter as a key " "path component"; case RefKind::Method: return "allow reference to a method as a key path component"; } llvm_unreachable("covered switch"); } bool diagnose(bool asNote = false) const override; /// Determine whether give reference requires a fix and produce one. static AllowInvalidRefInKeyPath * forRef(ConstraintSystem &cs, ValueDecl *member, ConstraintLocator *locator); private: static AllowInvalidRefInKeyPath *create(ConstraintSystem &cs, RefKind kind, ValueDecl *member, ConstraintLocator *locator); }; class RemoveReturn final : public ConstraintFix { RemoveReturn(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::RemoveReturn, locator) {} public: std::string getName() const override { return "remove or omit return type"; } bool diagnose(bool asNote = false) const override; static RemoveReturn *create(ConstraintSystem &cs, ConstraintLocator *locator); }; class CollectionElementContextualMismatch final : public ContextualMismatch { CollectionElementContextualMismatch(ConstraintSystem &cs, Type srcType, Type dstType, ConstraintLocator *locator) : ContextualMismatch(cs, srcType, dstType, locator) {} public: std::string getName() const override { return "fix collection element contextual mismatch"; } bool diagnose(bool asNote = false) const override; static CollectionElementContextualMismatch * create(ConstraintSystem &cs, Type srcType, Type dstType, ConstraintLocator *locator); }; class DefaultGenericArgument final : public ConstraintFix { GenericTypeParamType *Param; DefaultGenericArgument(ConstraintSystem &cs, GenericTypeParamType *param, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::DefaultGenericArgument, locator), Param(param) {} public: static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::DefaultGenericArgument; } std::string getName() const override { auto paramName = Param->getString(); return "default generic argument '" + paramName + "' to 'Any'"; } bool coalesceAndDiagnose(ArrayRef secondaryFixes, bool asNote = false) const override; bool diagnose(bool asNote = false) const override; static DefaultGenericArgument *create(ConstraintSystem &cs, GenericTypeParamType *param, ConstraintLocator *locator); }; class SkipUnhandledConstructInFunctionBuilder final : public ConstraintFix { public: using UnhandledNode = llvm::PointerUnion; private: UnhandledNode unhandled; NominalTypeDecl *builder; SkipUnhandledConstructInFunctionBuilder(ConstraintSystem &cs, UnhandledNode unhandled, NominalTypeDecl *builder, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::SkipUnhandledConstructInFunctionBuilder, locator), unhandled(unhandled), builder(builder) { } public: std::string getName() const override { return "skip unhandled constructs when applying a function builder"; } bool diagnose(bool asNote = false) const override; static SkipUnhandledConstructInFunctionBuilder * create(ConstraintSystem &cs, UnhandledNode unhandledNode, NominalTypeDecl *builder, ConstraintLocator *locator); }; class AllowTupleSplatForSingleParameter final : public ConstraintFix { using Param = AnyFunctionType::Param; Type ParamType; AllowTupleSplatForSingleParameter(ConstraintSystem &cs, Type paramTy, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowTupleSplatForSingleParameter, locator), ParamType(paramTy) {} public: std::string getName() const override { return "allow single parameter tuple splat"; } bool diagnose(bool asNote = false) const override; /// Apply this fix to given arguments/parameters and return `true` /// this fix is not applicable and solver can't continue, `false` /// otherwise. static bool attempt(ConstraintSystem &cs, SmallVectorImpl &args, ArrayRef params, SmallVectorImpl> &bindings, ConstraintLocatorBuilder locator); }; class IgnoreContextualType : public ContextualMismatch { IgnoreContextualType(ConstraintSystem &cs, Type resultTy, Type specifiedTy, ConstraintLocator *locator) : ContextualMismatch(cs, resultTy, specifiedTy, locator) {} public: std::string getName() const override { return "ignore specified contextual type"; } bool diagnose(bool asNote = false) const override; static IgnoreContextualType *create(ConstraintSystem &cs, Type resultTy, Type specifiedTy, ConstraintLocator *locator); }; class IgnoreAssignmentDestinationType final : public ContextualMismatch { IgnoreAssignmentDestinationType(ConstraintSystem &cs, Type sourceTy, Type destTy, ConstraintLocator *locator) : ContextualMismatch(cs, sourceTy, destTy, locator) {} public: std::string getName() const override { return "ignore type of the assignment destination"; } bool diagnose(bool asNote = false) const override; static IgnoreAssignmentDestinationType *create(ConstraintSystem &cs, Type sourceTy, Type destTy, ConstraintLocator *locator); }; /// If this is an argument-to-parameter conversion which is associated with /// `inout` parameter, subtyping is not permitted, types have to /// be identical. class AllowInOutConversion final : public ContextualMismatch { AllowInOutConversion(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator) : ContextualMismatch(cs, argType, paramType, locator) {} public: std::string getName() const override { return "allow conversions between argument/parameter marked as `inout`"; } bool diagnose(bool asNote = false) const override; static AllowInOutConversion *create(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator); }; class AllowArgumentMismatch : public ContextualMismatch { protected: AllowArgumentMismatch(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator) : AllowArgumentMismatch(cs, FixKind::AllowArgumentTypeMismatch, argType, paramType, locator) {} AllowArgumentMismatch(ConstraintSystem &cs, FixKind kind, Type argType, Type paramType, ConstraintLocator *locator, bool warning = false) : ContextualMismatch(cs, kind, argType, paramType, locator, warning) {} public: std::string getName() const override { return "allow argument to parameter type conversion mismatch"; } bool diagnose(bool asNote = false) const override; static AllowArgumentMismatch *create(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator); }; class ExpandArrayIntoVarargs final : public AllowArgumentMismatch { ExpandArrayIntoVarargs(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator) : AllowArgumentMismatch(cs, FixKind::ExpandArrayIntoVarargs, argType, paramType, locator) {} public: std::string getName() const override { return "cannot pass Array elements as variadic arguments"; } bool diagnose(bool asNote = false) const override; static ExpandArrayIntoVarargs *attempt(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocatorBuilder locator); }; class ExplicitlyConstructRawRepresentable final : public AllowArgumentMismatch { ExplicitlyConstructRawRepresentable(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator) : AllowArgumentMismatch(cs, FixKind::ExplicitlyConstructRawRepresentable, argType, paramType, locator) {} public: std::string getName() const override { return "explicitly construct a raw representable type"; } static ExplicitlyConstructRawRepresentable * attempt(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocatorBuilder locator); }; class UseValueTypeOfRawRepresentative final : public AllowArgumentMismatch { UseValueTypeOfRawRepresentative(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator) : AllowArgumentMismatch(cs, FixKind::UseValueTypeOfRawRepresentative, argType, paramType, locator) {} public: std::string getName() const override { return "use `.rawValue` of a raw representable type"; } static UseValueTypeOfRawRepresentative * attempt(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocatorBuilder locator); }; /// Replace a coercion ('as') with a forced checked cast ('as!'). class CoerceToCheckedCast final : public ContextualMismatch { CoerceToCheckedCast(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::CoerceToCheckedCast, fromType, toType, locator) {} public: std::string getName() const { return "as to as!"; } bool diagnose(bool asNote = false) const; static CoerceToCheckedCast *attempt(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator); }; class RemoveInvalidCall final : public ConstraintFix { RemoveInvalidCall(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::RemoveCall, locator) {} public: std::string getName() const { return "remove extraneous call from value of non-function type"; } bool diagnose(bool asNote = false) const; static RemoveInvalidCall *create(ConstraintSystem &cs, ConstraintLocator *locator); }; class AllowInvalidUseOfTrailingClosure final : public AllowArgumentMismatch { AllowInvalidUseOfTrailingClosure(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator) : AllowArgumentMismatch(cs, FixKind::AllowInvalidUseOfTrailingClosure, argType, paramType, locator) {} public: std::string getName() const { return "allow invalid use of trailing closure"; } bool diagnose(bool asNote = false) const; static AllowInvalidUseOfTrailingClosure *create(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator); }; class TreatEphemeralAsNonEphemeral final : public AllowArgumentMismatch { ConversionRestrictionKind ConversionKind; TreatEphemeralAsNonEphemeral(ConstraintSystem &cs, ConstraintLocator *locator, Type srcType, Type dstType, ConversionRestrictionKind conversionKind, bool downgradeToWarning) : AllowArgumentMismatch(cs, FixKind::TreatEphemeralAsNonEphemeral, srcType, dstType, locator, downgradeToWarning), ConversionKind(conversionKind) {} public: ConversionRestrictionKind getConversionKind() const { return ConversionKind; } std::string getName() const override; bool diagnose(bool asNote = false) const override; static TreatEphemeralAsNonEphemeral * create(ConstraintSystem &cs, ConstraintLocator *locator, Type srcType, Type dstType, ConversionRestrictionKind conversionKind, bool downgradeToWarning); }; class SpecifyBaseTypeForContextualMember final : public ConstraintFix { DeclNameRef MemberName; SpecifyBaseTypeForContextualMember(ConstraintSystem &cs, DeclNameRef member, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::SpecifyBaseTypeForContextualMember, locator), MemberName(member) {} public: std::string getName() const { const auto baseName = MemberName.getBaseName(); return "specify base type in reference to member '" + baseName.userFacingName().str() + "'"; } bool diagnose(bool asNote = false) const; static SpecifyBaseTypeForContextualMember * create(ConstraintSystem &cs, DeclNameRef member, ConstraintLocator *locator); }; class SpecifyClosureReturnType final : public ConstraintFix { SpecifyClosureReturnType(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::SpecifyClosureReturnType, locator) {} public: std::string getName() const { return "specify closure return type"; } bool diagnose(bool asNote = false) const; static SpecifyClosureReturnType *create(ConstraintSystem &cs, ConstraintLocator *locator); }; class SpecifyObjectLiteralTypeImport final : public ConstraintFix { SpecifyObjectLiteralTypeImport(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::SpecifyObjectLiteralTypeImport, locator) {} public: std::string getName() const { return "import required module to gain access to a default literal type"; } bool diagnose(bool asNote = false) const; static SpecifyObjectLiteralTypeImport *create(ConstraintSystem &cs, ConstraintLocator *locator); }; } // end namespace constraints } // end namespace swift namespace llvm { template <> struct DenseMapInfo { using FixKind = swift::constraints::FixKind; static inline FixKind getEmptyKey() { return static_cast(0); } static inline FixKind getTombstoneKey() { return static_cast(1); } static unsigned getHashValue(FixKind kind) { return static_cast(kind); } static bool isEqual(FixKind lhs, FixKind rhs) { return lhs == rhs; } }; } #endif // SWIFT_SEMA_CSFIX_H