//===--- 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 "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 Solution; /// Describes the kind of fix to apply to the given constraint before /// visiting it. enum class FixKind : uint8_t { /// Introduce a '!' to force an optional unwrap. ForceOptional, /// 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 @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, /// 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, /// If there are fewer arguments than parameters, let's fix that up /// by adding new arguments to the list represented as type variables. AddMissingArguments, /// 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, }; 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(); FixKind getKind() const { return Kind; } bool isWarning() const { return IsWarning; } virtual std::string getName() const = 0; /// Diagnose a failure associated with this fix given /// root expression and information from constraint system. virtual bool diagnose(Expr *root, bool asNote = false) const = 0; void print(llvm::raw_ostream &Out) const; LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED, "only for use within the debugger"); /// 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; } }; /// Append 'as! T' to force a downcast to the specified type. class ForceDowncast final : public ConstraintFix { Type DowncastTo; ForceDowncast(ConstraintSystem &cs, Type toType, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::ForceDowncast, locator), DowncastTo(toType) { } public: std::string getName() const override; bool diagnose(Expr *root, bool asNote = false) const override; static ForceDowncast *create(ConstraintSystem &cs, Type toType, ConstraintLocator *locator); }; /// Introduce a '!' to force an optional unwrap. class ForceOptional final : public ConstraintFix { Type BaseType; Type UnwrappedType; ForceOptional(ConstraintSystem &cs, Type baseType, Type unwrappedType, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::ForceOptional, locator), BaseType(baseType), UnwrappedType(unwrappedType) { assert(baseType && "Base type must not be null"); assert(unwrappedType && "Unwrapped type must not be null"); } public: std::string getName() const override { return "force optional"; } bool diagnose(Expr *root, bool asNote = false) const override; static ForceOptional *create(ConstraintSystem &cs, Type baseType, Type unwrappedType, ConstraintLocator *locator); }; /// Unwrap an optional base when we have a member access. class UnwrapOptionalBase final : public ConstraintFix { DeclName MemberName; UnwrapOptionalBase(ConstraintSystem &cs, FixKind kind, DeclName 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(Expr *root, bool asNote = false) const override; static UnwrapOptionalBase *create(ConstraintSystem &cs, DeclName member, ConstraintLocator *locator); static UnwrapOptionalBase * createWithOptionalResult(ConstraintSystem &cs, DeclName member, ConstraintLocator *locator); }; /// Introduce a '&' to take the address of an lvalue. class AddAddressOf final : public ConstraintFix { AddAddressOf(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AddressOf, locator) {} public: std::string getName() const override { return "add address-of"; } bool diagnose(Expr *root, bool asNote = false) const override; static AddAddressOf *create(ConstraintSystem &cs, 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(Expr *root, bool asNote = false) const override; static TreatRValueAsLValue *create(ConstraintSystem &cs, ConstraintLocator *locator); }; /// Replace a coercion ('as') with a forced checked cast ('as!'). class CoerceToCheckedCast final : public ConstraintFix { CoerceToCheckedCast(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::CoerceToCheckedCast, locator) {} public: std::string getName() const override { return "as to as!"; } bool diagnose(Expr *root, bool asNote = false) const override; static CoerceToCheckedCast *create(ConstraintSystem &cs, ConstraintLocator *locator); }; /// Mark function type as explicitly '@escaping'. class MarkExplicitlyEscaping final : public ConstraintFix { /// Sometimes function type has to be marked as '@escaping' /// to be converted to some other generic type. Type ConvertTo; MarkExplicitlyEscaping(ConstraintSystem &cs, ConstraintLocator *locator, Type convertingTo = Type()) : ConstraintFix(cs, FixKind::ExplicitlyEscaping, locator), ConvertTo(convertingTo) {} public: std::string getName() const override { return "add @escaping"; } bool diagnose(Expr *root, bool asNote = false) const override; static MarkExplicitlyEscaping *create(ConstraintSystem &cs, ConstraintLocator *locator, Type convertingTo = Type()); }; /// 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(Expr *root, 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(Expr *root, 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(Expr *root, 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(Expr *root, 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) {} public: std::string getName() const override { return "fix contextual mismatch"; } Type getFromType() const { return LHS; } Type getToType() const { return RHS; } bool diagnose(Expr *root, bool asNote = false) const override; static ContextualMismatch *create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator); }; /// 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(Expr *root, bool asNote = false) const override; static AutoClosureForwarding *create(ConstraintSystem &cs, 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(Expr *root, 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(Expr *root, bool asNote = false) const override; static InsertExplicitCall *create(ConstraintSystem &cs, 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(Expr *root, bool asNote = false) const override; static UseSubscriptOperator *create(ConstraintSystem &cs, ConstraintLocator *locator); }; class DefineMemberBasedOnUse final : public ConstraintFix { Type BaseType; DeclName Name; DefineMemberBasedOnUse(ConstraintSystem &cs, Type baseType, DeclName member, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::DefineMemberBasedOnUse, locator), BaseType(baseType), Name(member) {} 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(Expr *root, bool asNote = false) const override; static DefineMemberBasedOnUse *create(ConstraintSystem &cs, Type baseType, DeclName member, ConstraintLocator *locator); }; class AllowTypeOrInstanceMember final : public ConstraintFix { Type BaseType; ValueDecl *Member; DeclName UsedName; public: AllowTypeOrInstanceMember(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclName name, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowTypeOrInstanceMember, locator), BaseType(baseType), Member(member), UsedName(name) { assert(member); } std::string getName() const override { return "allow access to instance member on type or a type member on instance"; } bool diagnose(Expr *root, bool asNote = false) const override; static AllowTypeOrInstanceMember *create(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclName 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(Expr *root, 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(Expr *root, 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 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(Expr *root, 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; FunctionType *Fn; unsigned NumSynthesized; AddMissingArguments(ConstraintSystem &cs, FunctionType *funcType, llvm::ArrayRef synthesizedArgs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AddMissingArguments, locator), Fn(funcType), 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(Expr *root, bool asNote = false) const override; static AddMissingArguments *create(ConstraintSystem &cs, FunctionType *fnType, llvm::ArrayRef synthesizedArgs, ConstraintLocator *locator); private: MutableArrayRef getSynthesizedArgumentsBuf() { return {getTrailingObjects(), NumSynthesized}; } }; 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(Expr *root, bool asNote = false) const override; static MoveOutOfOrderArgument *create(ConstraintSystem &cs, unsigned argIdx, unsigned prevArgIdx, ArrayRef bindings, ConstraintLocator *locator); }; class AllowInaccessibleMember final : public ConstraintFix { ValueDecl *Member; AllowInaccessibleMember(ConstraintSystem &cs, ValueDecl *member, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowInaccessibleMember, locator), Member(member) {} public: std::string getName() const override { return "allow inaccessible member reference"; } bool diagnose(Expr *root, bool asNote = false) const override; static AllowInaccessibleMember *create(ConstraintSystem &cs, ValueDecl *member, 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(Expr *root, 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(Expr *root, 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"; } } bool diagnose(Expr *root, 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 RemoveAddressOf final : public ConstraintFix { RemoveAddressOf(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::RemoveAddressOf, locator) {} public: std::string getName() const override { return "remove extraneous use of `&`"; } bool diagnose(Expr *root, bool asNote = false) const override; static RemoveAddressOf *create(ConstraintSystem &cs, 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(Expr *root, 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(Expr *root, bool asNote = false) const override; static CollectionElementContextualMismatch * create(ConstraintSystem &cs, Type srcType, Type dstType, ConstraintLocator *locator); }; } // end namespace constraints } // end namespace swift #endif // SWIFT_SEMA_CSFIX_H