//===--- 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/ASTNode.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 "swift/Sema/Constraint.h" #include "swift/Sema/ConstraintLocator.h" #include "swift/Sema/FixBehavior.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; enum ScoreKind: unsigned int; class Solution; struct MemberLookupResult; /// 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, /// Mark function type as having a particular global actor. MarkGlobalActorFunction, /// 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 same-shape generic requirement constraint, /// and assume that pack types have the same shape. SkipSameShapeRequirement, /// 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, /// 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, /// Allow a type that is not a property wrapper to be used as a property /// wrapper. AllowInvalidPropertyWrapperType, /// Remove the '$' prefix from an argument label or parameter name. RemoveProjectedValueArgument, /// 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 result builder. SkipUnhandledConstructInResultBuilder, /// 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 representable, accessible /// using `.rawValue` member. UseRawValue, /// 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, /// 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, /// Type of the closure parameter used in the body couldn't be inferred /// and has to be specified explicitly. SpecifyClosureParameterType, /// 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 couldn't be inferred because the module where /// the default type that implements the associated literal protocol /// is declared was not imported. SpecifyObjectLiteralTypeImport, /// Type of the element in generic pack couldn't be inferred and has to be /// specified explicitly. SpecifyPackElementType, /// Allow any type (and not just class or class-constrained type) to /// be convertible to AnyObject. AllowNonClassTypeToConvertToAnyObject, /// Member shadows a top-level name, such a name could only be accessed by /// prefixing it with a module name. AddQualifierToAccessTopLevelName, /// A warning fix that allows a coercion to perform a force-cast. AllowCoercionToForceCast, /// Allow key path root type mismatch when applying a key path that has a /// root type not convertible to the type of the base instance. AllowKeyPathRootTypeMismatch, /// Allow key path to be bound to a function type with more than 1 argument AllowMultiArgFuncKeyPathMismatch, /// Specify key path root type when it cannot be inferred from context. SpecifyKeyPathRootType, /// Unwrap optional base on key path application. UnwrapOptionalBaseKeyPathApplication, /// Explicitly specify a label to match trailing closure to a certain /// parameter in the call. SpecifyLabelToAssociateTrailingClosure, /// Allow key path expressions with no components. AllowKeyPathWithoutComponents, /// Ignore result builder body which fails `pre-check` call. IgnoreInvalidResultBuilderBody, /// Ignore result builder body if it has `return` statements. IgnoreResultBuilderWithReturnStmts, /// Ignore `ErrorExpr` or `ErrorType` during pre-check. IgnoreInvalidASTNode, /// Ignore a named or `_` pattern whose type we couldn't infer. /// This issue should already have been diagnosed elsewhere. IgnoreUnresolvedPatternVar, /// Ignore a nested UnresolvedPatternExpr in an ExprPattern, which is invalid. IgnoreInvalidPatternInExpr, /// Resolve type of `nil` by providing a contextual type. SpecifyContextualTypeForNil, /// Allow expressions to reference invalid declarations by turning /// them into holes. AllowRefToInvalidDecl, /// Treat empty and single-element array literals as if they were incomplete /// dictionary literals when used as such. TreatArrayLiteralAsDictionary, /// Explicitly specify the type to disambiguate between possible member base /// types. SpecifyBaseTypeForOptionalUnresolvedMember, /// Allow a runtime checked cast from an optional type where we statically /// know the result is always succeed. AllowCheckedCastCoercibleOptionalType, /// Warn about runtime checked cast that is statically known to always /// succeed. AllowNoopCheckedCast, /// Warn about special runtime case where statically known /// checked cast from existentials to CFType always succeed. AllowNoopExistentialToCFTypeCheckedCast, /// Allow a runtime checked cast where at compile time the from is /// convertible, but runtime does not support such conversions. e.g. /// function type casts. AllowUnsupportedRuntimeCheckedCast, /// Allow a runtime checked cast where it is known at compile time /// always fails. AllowCheckedCastToUnrelated, /// Allow reference to a static member on a protocol metatype /// even though result type of the reference doesn't conform /// to an expected protocol. AllowInvalidStaticMemberRefOnProtocolMetatype, /// Allow the wrappedValue type of any property wrapper that is a /// part of a composed property wrapper to mismatch the type of /// another property wrapper that is a part of the same composed /// property wrapper. AllowWrappedValueMismatch, /// Ignore an out-of-place placeholder type. IgnoreInvalidPlaceholder, /// Specify a type for an explicitly written placeholder that could not be /// resolved. SpecifyTypeForPlaceholder, /// Allow Swift -> C pointer conversion in an argument position /// of a Swift function. AllowSwiftToCPointerConversion, /// Allow `weak` declarations to be bound to a non-optional type. AllowNonOptionalWeak, /// Fix conversion from non-Sendable to Sendable by adding explicit /// @Sendable attribute to the source function. AddSendableAttribute, /// Fix conversion from throwing to non-throwing by removing explicit /// `throws` attribute from the source function. DropThrowsAttribute, /// Ignore a mismatch in the thrown error type. IgnoreThrownErrorMismatch, /// Fix conversion from async to sync function by removing explicit /// `async` attribute from the source function. DropAsyncAttribute, /// Allow invalid pointer conversions for autoclosure result types as if the /// pointer type is a function parameter rather than an autoclosure result. AllowAutoClosurePointerConversion, /// Ignore externally imposed type. IgnoreContextualType, /// Ignore a type imposed by an assignment destination e.g. `let x: Int = ...` IgnoreAssignmentDestinationType, /// Allow argument-to-parameter subtyping even when parameter type /// is marked as `inout`. AllowConversionThroughInOut, /// Ignore a type mismatch between deduced element type and externally /// imposed one. IgnoreCollectionElementContextualMismatch, /// Produce a warning for a tuple label mismatch. AllowTupleLabelMismatch, /// Allow an associated value mismatch for an enum element pattern. AllowAssociatedValueMismatch, /// Produce an error for not getting a compile-time constant NotCompileTimeLiteral, /// Ignore a type mismatch while trying to infer generic parameter type /// from default expression. IgnoreDefaultExprTypeMismatch, /// Coerce a result type of a call to a particular existential type /// by adding `as any <#Type#>`. AddExplicitExistentialCoercion, /// For example `.a(let x), .b(let x)` where `x` gets bound to different /// types. RenameConflictingPatternVariables, /// Macro without leading #. MacroMissingPound, /// Allow function type actor mismatch e.g. `@MainActor () -> Void` /// vs.`@OtherActor () -> Void` AllowGlobalActorMismatch, /// Allow 'each' applied to a non-pack type. AllowInvalidPackElement, /// Allow pack references outside of pack expansions. AllowInvalidPackReference, /// Allow pack expansion expressions in a context that does not support them. AllowInvalidPackExpansion, /// Ignore `where` clause in a for-in loop with a pack expansion expression. IgnoreWhereClauseInPackIteration, /// Allow a pack expansion parameter of N elements to be matched /// with a single tuple literal argument of the same arity. DestructureTupleToMatchPackExpansionParameter, /// Allow value pack expansion without pack references. AllowValueExpansionWithoutPackReferences, /// Ignore missing 'each' keyword before value pack reference. IgnoreMissingEachKeyword, /// Ignore the fact that member couldn't be referenced within init accessor /// because its name doesn't appear in 'initializes' or 'accesses' attributes. AllowInvalidMemberReferenceInInitAccessor, /// Ignore an attempt to specialize a non-generic type. AllowConcreteTypeSpecialization, /// Ignore an attempt to specialize a (generic) function reference. AllowFunctionSpecialization, /// Ignore an out-of-place \c then statement. IgnoreOutOfPlaceThenStmt, /// Ignore situations when provided number of generic arguments didn't match /// expected number of parameters. IgnoreGenericSpecializationArityMismatch, /// Ignore situations when key path subscript index gets passed an invalid /// type as an argument (something that is not a key path). IgnoreKeyPathSubscriptIndexMismatch, /// Ignore the following situations: /// /// 1. Where we have a function that expects a function typed parameter /// without a sendable parameter but is passed a function type with a sending /// parameter. /// /// 2. Where we have a function that expects a function typed parameter with a /// sending result, but is passed a function typed parameter without a sending /// result. AllowSendingMismatch, /// Ignore when an 'InlineArray' literal has mismatched number of elements to /// the type it's attempting to bind to. AllowInlineArrayLiteralCountMismatch, /// Ignore that a conformance is isolated but is not allowed to be. IgnoreIsolatedConformance, }; class ConstraintFix { ConstraintSystem &CS; FixKind Kind; ConstraintLocator *Locator; public: /// The behavior limit to apply to the diagnostics emitted. const FixBehavior fixBehavior; ConstraintFix(ConstraintSystem &cs, FixKind kind, ConstraintLocator *locator, FixBehavior fixBehavior = FixBehavior::Error) : CS(cs), Kind(kind), Locator(locator), fixBehavior(fixBehavior) {} virtual ~ConstraintFix(); template const Fix *getAs() const { return Fix::classof(this) ? static_cast(this) : nullptr; } template const Fix *castTo() const { assert(Fix::classof(this)); return static_cast(this); } FixKind getKind() const { return Kind; } /// Whether this fix fatal for the constraint solver, meaning that it cannot /// produce a usable type-checked AST. bool isFatal() const { switch (fixBehavior) { case FixBehavior::AlwaysWarning: case FixBehavior::DowngradeToWarning: case FixBehavior::Suppress: return false; case FixBehavior::Error: return true; } } /// Determine the impact of this fix on the solution score, if any. std::optional impact() const; 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(const Solution &solution, ArrayRef secondaryFixes, bool asNote = false) const { return diagnose(solution, asNote); } /// Diagnose a failure associated with this fix. virtual bool diagnose(const Solution &solution, bool asNote = false) const = 0; using CommonFixesArray = ArrayRef>; virtual bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const { return false; } 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 simplification attempts. ASTNode 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; Type MemberBaseType; UnwrapOptionalBase(ConstraintSystem &cs, FixKind kind, DeclNameRef member, Type memberBaseType, ConstraintLocator *locator) : ConstraintFix(cs, kind, locator), MemberName(member), MemberBaseType(memberBaseType) { assert(kind == FixKind::UnwrapOptionalBase || kind == FixKind::UnwrapOptionalBaseWithOptionalResult); } public: std::string getName() const override { return "unwrap optional base of member lookup"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static UnwrapOptionalBase *create(ConstraintSystem &cs, DeclNameRef member, Type memberBaseType, ConstraintLocator *locator); static UnwrapOptionalBase * createWithOptionalResult(ConstraintSystem &cs, DeclNameRef member, Type memberBaseType, 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(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } /// Assess the impact this fix is going to have at the given location. static unsigned assessImpact(ConstraintSystem &cs, ConstraintLocator *atLoc); static TreatRValueAsLValue *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::TreatRValueAsLValue; } }; /// 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(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override; static RelabelArguments *create(ConstraintSystem &cs, llvm::ArrayRef correctLabels, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::RelabelArguments; } private: MutableArrayRef getLabelsBuffer() { return {getTrailingObjects(), NumLabels}; } }; class RequirementFix : public ConstraintFix { protected: Type LHS; Type RHS; RequirementFix(ConstraintSystem &cs, FixKind kind, Type lhs, Type rhs, ConstraintLocator *locator) : ConstraintFix(cs, kind, locator), LHS(lhs), RHS(rhs) {} public: std::string getName() const override = 0; Type lhsType() const { return LHS; } Type rhsType() const { return RHS; } bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override; bool diagnose(const Solution &solution, bool asNote = false) const override = 0; }; /// Add a new conformance to the type to satisfy a requirement. class MissingConformance final : public RequirementFix { // Determines whether given protocol type comes from the context e.g. // assignment destination or argument comparison. bool IsContextual; MissingConformance(ConstraintSystem &cs, bool isContextual, Type type, Type protocolType, ConstraintLocator *locator) : RequirementFix(cs, FixKind::AddConformance, type, protocolType, locator), IsContextual(isContextual) {} public: std::string getName() const override { return "add missing protocol conformance"; } bool diagnose(const Solution &solution, 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() const { return LHS; } Type getProtocolType() const { return RHS; } bool isEqual(const ConstraintFix *other) const; static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AddConformance; } }; /// Skip same-type generic requirement constraint, /// and assume that types are equal. class SkipSameTypeRequirement final : public RequirementFix { SkipSameTypeRequirement(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) : RequirementFix(cs, FixKind::SkipSameTypeRequirement, lhs, rhs, locator) {} public: std::string getName() const override { return "skip same-type generic requirement"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static SkipSameTypeRequirement *create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::SkipSameTypeRequirement; } }; /// Skip a same-shape requirement between two type packs. /// /// A same shape requirement can be inferred from a generic requirement, /// or from a pack expansion expression. class SkipSameShapeRequirement final : public RequirementFix { SkipSameShapeRequirement(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) : RequirementFix(cs, FixKind::SkipSameShapeRequirement, lhs, rhs, locator) {} public: std::string getName() const override { return "skip same-shape requirement"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static SkipSameShapeRequirement *create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::SkipSameTypeRequirement; } }; /// Skip 'superclass' generic requirement constraint, /// and assume that types are equal. class SkipSuperclassRequirement final : public RequirementFix { SkipSuperclassRequirement(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) : RequirementFix(cs, FixKind::SkipSuperclassRequirement, lhs, rhs, locator) {} public: std::string getName() const override { return "skip superclass generic requirement"; } bool diagnose(const Solution &solution, bool asNote = false) const override; Type subclassType() { return LHS; } Type superclassType() { return RHS; } static SkipSuperclassRequirement * create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::SkipSuperclassRequirement; } }; /// 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; ContextualMismatch(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator, FixBehavior fixBehavior) : ConstraintFix(cs, FixKind::ContextualMismatch, locator, fixBehavior), LHS(lhs), RHS(rhs) {} protected: ContextualMismatch(ConstraintSystem &cs, FixKind kind, Type lhs, Type rhs, ConstraintLocator *locator, FixBehavior fixBehavior = FixBehavior::Error) : ConstraintFix(cs, kind, locator, fixBehavior), 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(const Solution &solution, bool asNote = false) const override; bool coalesceAndDiagnose(const Solution &solution, ArrayRef secondaryFixes, bool asNote = false) const override { // If the from type or to type is a placeholder type that corresponds to an // ErrorExpr, the issue has already been diagnosed. There's no need to // produce another diagnostic for the contextual mismatch complaining that // a type is not convertible to a placeholder type. if (auto fromPlaceholder = getFromType()->getAs()) { if (fromPlaceholder->getOriginator().is()) { return true; } } if (auto toPlaceholder = getToType()->getAs()) { if (toPlaceholder->getOriginator().is()) { return true; } } return ConstraintFix::coalesceAndDiagnose(solution, secondaryFixes, asNote); } bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override; static ContextualMismatch *create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::ContextualMismatch; } }; class TreatArrayLiteralAsDictionary final : public ContextualMismatch { TreatArrayLiteralAsDictionary(ConstraintSystem &cs, Type dictionaryTy, Type arrayTy, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::TreatArrayLiteralAsDictionary, dictionaryTy, arrayTy, locator) { } public: std::string getName() const override { return "treat array literal as dictionary"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static TreatArrayLiteralAsDictionary *attempt(ConstraintSystem &cs, Type dictionaryTy, Type arrayTy, ConstraintLocator *loc); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::TreatArrayLiteralAsDictionary; } }; class AllowWrappedValueMismatch : public ContextualMismatch { AllowWrappedValueMismatch(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::AllowWrappedValueMismatch, lhs, rhs, locator) {} public: std::string getName() const override { return "fix wrapped value type mismatch"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowWrappedValueMismatch *create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowWrappedValueMismatch; } }; /// 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(const Solution &solution, bool asNote = false) const override; static MarkExplicitlyEscaping *create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::ExplicitlyEscaping; } }; /// Mark function type as being part of a global actor. class MarkGlobalActorFunction final : public ContextualMismatch { MarkGlobalActorFunction(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator, FixBehavior fixBehavior) : ContextualMismatch(cs, FixKind::MarkGlobalActorFunction, lhs, rhs, locator, fixBehavior) { } public: std::string getName() const override { return "add global actor"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static MarkGlobalActorFunction *create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator, FixBehavior fixBehavior); /// Try to apply this fix to the given types. /// /// \returns \c true if the fix cannot be applied and the solver must fail, /// or \c false if the fix has been applied and the solver can continue. static bool attempt(ConstraintSystem &cs, ConstraintKind constraintKind, FunctionType *fromType, FunctionType *toType, ConstraintLocatorBuilder locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::MarkGlobalActorFunction; } }; /// 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(const Solution &solution, bool asNote = false) const override; static ForceOptional *create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::ForceOptional; } }; /// This is a contextual mismatch between @Sendable and non-@Sendable /// function types, repair it by adding @Sendable attribute. class AddSendableAttribute final : public ContextualMismatch { AddSendableAttribute(ConstraintSystem &cs, FunctionType *fromType, FunctionType *toType, ConstraintLocator *locator, FixBehavior fixBehavior) : ContextualMismatch(cs, FixKind::AddSendableAttribute, fromType, toType, locator, fixBehavior) { assert(fromType->isSendable() != toType->isSendable()); } public: std::string getName() const override { return "add '@Sendable' attribute"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AddSendableAttribute *create(ConstraintSystem &cs, FunctionType *fromType, FunctionType *toType, ConstraintLocator *locator, FixBehavior fixBehavior); /// Try to apply this fix to the given types. /// /// \returns \c true if the fix cannot be applied and the solver must fail, /// or \c false if the fix has been applied and the solver can continue. static bool attempt(ConstraintSystem &cs, ConstraintKind constraintKind, FunctionType *fromType, FunctionType *toType, ConstraintLocatorBuilder locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AddSendableAttribute; } }; /// 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, FixKind::DropThrowsAttribute, fromType, toType, locator) { } public: std::string getName() const override { return "drop 'throws' attribute"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static DropThrowsAttribute *create(ConstraintSystem &cs, FunctionType *fromType, FunctionType *toType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::DropThrowsAttribute; } }; /// This is a contextual mismatch between the thrown error types of two /// function types, which could be repaired by fixing one of the types. class IgnoreThrownErrorMismatch final : public ContextualMismatch { IgnoreThrownErrorMismatch(ConstraintSystem &cs, Type fromErrorType, Type toErrorType, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::IgnoreThrownErrorMismatch, fromErrorType, toErrorType, locator) { assert(!fromErrorType->isEqual(toErrorType)); } public: std::string getName() const override { return "drop 'throws' attribute"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static IgnoreThrownErrorMismatch *create(ConstraintSystem &cs, Type fromErrorType, Type toErrorType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::IgnoreThrownErrorMismatch; } }; /// This is a contextual mismatch between async and non-async /// function types, repair it by dropping `async` attribute. class DropAsyncAttribute final : public ContextualMismatch { DropAsyncAttribute(ConstraintSystem &cs, FunctionType *fromType, FunctionType *toType, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::DropAsyncAttribute, fromType, toType, locator) { assert(fromType->isAsync() != toType->isAsync()); } public: std::string getName() const override { return "drop 'async' attribute"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static DropAsyncAttribute *create(ConstraintSystem &cs, FunctionType *fromType, FunctionType *toType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::DropAsyncAttribute; } }; /// 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(const Solution &solution, bool asNote = false) const override; static ForceDowncast *create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::ForceDowncast; } }; /// 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(const Solution &solution, bool asNote = false) const override; static AddAddressOf *create(ConstraintSystem &cs, Type argTy, Type paramTy, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AddressOf; } }; 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(const Solution &solution, bool asNote = false) const override; static RemoveAddressOf *create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::RemoveAddressOf; } }; /// 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 coalesceAndDiagnose(const Solution &solution, ArrayRef secondaryFixes, bool asNote = false) const override; bool diagnose(const Solution &solution, bool asNote = false) const override; static GenericArgumentsMismatch *create(ConstraintSystem &cs, Type actual, Type required, llvm::ArrayRef mismatches, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::GenericArgumentsMismatch; } private: bool diagnose(const Solution &solution, ArrayRef mismatches, bool asNote = false) const; MutableArrayRef getMismatchesBuf() { return {getTrailingObjects(), NumMismatches}; } }; class AllowAutoClosurePointerConversion final : public ContextualMismatch { AllowAutoClosurePointerConversion(ConstraintSystem &cs, Type pointeeType, Type pointerType, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::AllowAutoClosurePointerConversion, pointeeType, pointerType, locator) {} public: std::string getName() const override { return "allow pointer conversion for autoclosure result type"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowAutoClosurePointerConversion *create(ConstraintSystem &cs, Type pointeeType, Type pointerType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowAutoClosurePointerConversion; } }; 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(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static RemoveUnwrap *create(ConstraintSystem &cs, Type baseType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::RemoveUnwrap; } }; 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(const Solution &solution, bool asNote = false) const override; static InsertExplicitCall *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::InsertCall; } }; class UsePropertyWrapper final : public ConstraintFix { VarDecl *Wrapped; bool UsingProjection; Type Base; Type Wrapper; UsePropertyWrapper(ConstraintSystem &cs, VarDecl *wrapped, bool usingProjection, Type base, Type wrapper, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::UsePropertyWrapper, locator), Wrapped(wrapped), UsingProjection(usingProjection), Base(base), Wrapper(wrapper) {} public: std::string getName() const override { return "insert '$' or '_' to use property wrapper type instead of wrapped type"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static UsePropertyWrapper *create(ConstraintSystem &cs, VarDecl *wrapped, bool usingProjection, Type base, Type wrapper, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::UsePropertyWrapper; } }; 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 usingProjection() const { return !PropertyWrapper->getName().hasUnderscoredNaming(); } public: std::string getName() const override { return "remove '$' or _ to use wrapped type instead of wrapper type"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static UseWrappedValue *create(ConstraintSystem &cs, VarDecl *propertyWrapper, Type base, Type wrapper, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::UseWrappedValue; } }; class AllowInvalidPropertyWrapperType final : public ConstraintFix { Type wrapperType; AllowInvalidPropertyWrapperType(ConstraintSystem &cs, Type wrapperType, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowInvalidPropertyWrapperType, locator), wrapperType(wrapperType) {} public: static AllowInvalidPropertyWrapperType *create(ConstraintSystem &cs, Type wrapperType, ConstraintLocator *locator); std::string getName() const override { return "allow invalid property wrapper type"; } bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } bool diagnose(const Solution &solution, bool asNote = false) const override; static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowInvalidPropertyWrapperType; } }; class RemoveProjectedValueArgument final : public ConstraintFix { Type wrapperType; ParamDecl *param; RemoveProjectedValueArgument(ConstraintSystem &cs, Type wrapper, ParamDecl *param, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::RemoveProjectedValueArgument, locator), wrapperType(wrapper), param(param) {} public: static RemoveProjectedValueArgument *create(ConstraintSystem &cs, Type wrapper, ParamDecl *param, ConstraintLocator *locator); std::string getName() const override { return "remove '$' from argument label"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::RemoveProjectedValueArgument; } }; 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(const Solution &solution, bool asNote = false) const override; static UseSubscriptOperator *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::UseSubscriptOperator; } }; 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(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override; static DefineMemberBasedOnUse *create(ConstraintSystem &cs, Type baseType, DeclNameRef member, bool alreadyDiagnosed, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::DefineMemberBasedOnUse; } }; class DefineMemberBasedOnUnintendedGenericParam final : public ConstraintFix { Type BaseType; DeclNameRef Name; Identifier ParamName; DefineMemberBasedOnUnintendedGenericParam(ConstraintSystem &cs, Type baseType, DeclNameRef member, Identifier paramName, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::DefineMemberBasedOnUse, locator), BaseType(baseType), Name(member), ParamName(paramName) {} public: std::string getName() const override { llvm::SmallVector scratch; auto memberName = Name.getString(scratch); return "allow access to invalid member '" + memberName.str() + "' on archetype presumed intended to conform to protocol"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static DefineMemberBasedOnUnintendedGenericParam * create(ConstraintSystem &cs, Type baseType, DeclNameRef member, Identifier paramName, 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; } bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override; }; 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(const Solution &solution, bool asNote = false) const override; static AllowMemberRefOnExistential *create(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef memberName, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowMemberRefOnExistential; } }; 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(const Solution &solution, bool asNote = false) const override; static AllowTypeOrInstanceMember *create(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef usedName, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowTypeOrInstanceMember; } }; class AllowInvalidPartialApplication final : public ConstraintFix { bool isWarning; AllowInvalidPartialApplication(bool isWarning, ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowInvalidPartialApplication, locator, isWarning ? FixBehavior::AlwaysWarning : FixBehavior::Error), isWarning(isWarning) {} public: std::string getName() const override { return "allow partially applied 'mutating' method"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowInvalidPartialApplication *create(bool isWarning, ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowInvalidPartialApplication; } }; 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(const Solution &solution, 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); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowInvalidInitRef; } 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. std::optional Index; AllowTupleTypeMismatch(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator, std::optional index) : ContextualMismatch(cs, FixKind::AllowTupleTypeMismatch, lhs, rhs, locator), Index(index) {} public: static AllowTupleTypeMismatch * create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator, std::optional index = std::nullopt); 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.has_value(); } bool coalesceAndDiagnose(const Solution &solution, ArrayRef secondaryFixes, bool asNote = false) const override; bool diagnose(const Solution &solution, 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(const Solution &solution, ArrayRef secondaryFixes, bool asNote = false) const override; bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) 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(const Solution &solution, bool asNote = false) const override; static AllowMutatingMemberOnRValueBase * create(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef name, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowMutatingMemberOnRValueBase; } }; 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(const Solution &solution, bool asNote = false) const override; static AllowClosureParamDestructuring *create(ConstraintSystem &cs, FunctionType *contextualType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowClosureParameterDestructuring; } }; struct SynthesizedArg { unsigned paramIdx; AnyFunctionType::Param param; }; class AddMissingArguments final : public ConstraintFix, private llvm::TrailingObjects< AddMissingArguments, SynthesizedArg> { friend TrailingObjects; unsigned NumSynthesized; AddMissingArguments(ConstraintSystem &cs, 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(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static AddMissingArguments *create(ConstraintSystem &cs, ArrayRef synthesizedArgs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AddMissingArguments; } 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(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } /// 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); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::RemoveExtraneousArguments; } 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(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override; bool isEqual(const ConstraintFix *other) const; static MoveOutOfOrderArgument *create(ConstraintSystem &cs, unsigned argIdx, unsigned prevArgIdx, ArrayRef bindings, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::MoveOutOfOrderArgument; } }; 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(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static AllowInaccessibleMember *create(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef name, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowInaccessibleMember; } }; 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(const Solution &solution, bool asNote = false) const override; static AllowAnyObjectKeyPathRoot *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowAnyObjectKeyPathRoot; } }; class AllowMultiArgFuncKeyPathMismatch final : public ConstraintFix { Type functionType; AllowMultiArgFuncKeyPathMismatch(ConstraintSystem &cs, Type fnType, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowMultiArgFuncKeyPathMismatch, locator), functionType(fnType) {} public: std::string getName() const override { return "allow conversion of a keypath type to a multi-argument function"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowMultiArgFuncKeyPathMismatch *create(ConstraintSystem &cs, Type fnType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowMultiArgFuncKeyPathMismatch; } }; 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(const Solution &solution, bool asNote = false) const override; static TreatKeyPathSubscriptIndexAsHashable * create(ConstraintSystem &cs, Type type, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::TreatKeyPathSubscriptIndexAsHashable; } }; class AllowInvalidRefInKeyPath final : public ConstraintFix { enum RefKind { // Allow invalid references to static members i.e. on instance of a type. StaticMember, // Allow a reference to a static member as a key path component if it is // declared in a module with built with Swift 6.0 compiler version or older. UnsupportedStaticMember, // Allow a reference to a declaration with mutating getter as // a key path component. MutatingGetter, // Allow a reference to a mutating method. Method, // Allow a reference to a initializer instance as a key path // component. Initializer, // Allow a reference to an enum case as a key path component. MutatingMethod, // Allow a reference to an async or throwing method. AsyncOrThrowsMethod, // Allow a reference to an enum case as a key path component. EnumCase, } Kind; ValueDecl *Member; Type BaseType; AllowInvalidRefInKeyPath(ConstraintSystem &cs, Type baseType, RefKind kind, ValueDecl *member, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowInvalidRefInKeyPath, locator), Kind(kind), Member(member), BaseType(baseType) {} public: std::string getName() const override { switch (Kind) { case RefKind::StaticMember: return "allow reference to a static member on invalid base in key path " "context"; case RefKind::UnsupportedStaticMember: return "allow unsupported static member reference"; 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"; case RefKind::Initializer: return "allow reference to an init method as a key path component"; case RefKind::EnumCase: return "allow reference to an enum case as a key path component"; case RefKind::MutatingMethod: return "allow reference to mutating method as a key path component"; case RefKind::AsyncOrThrowsMethod: return "allow reference to async or throwing method as a key path " "component"; } llvm_unreachable("covered switch"); } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override; /// Determine whether give reference requires a fix and produce one. static AllowInvalidRefInKeyPath *forRef(ConstraintSystem &cs, Type baseType, ValueDecl *member, ConstraintLocator *locator); bool isEqual(const ConstraintFix *other) const; static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowInvalidRefInKeyPath; } private: static AllowInvalidRefInKeyPath *create(ConstraintSystem &cs, Type baseType, RefKind kind, ValueDecl *member, ConstraintLocator *locator); }; class RemoveReturn final : public ContextualMismatch { RemoveReturn(ConstraintSystem &cs, Type resultTy, ConstraintLocator *locator); public: std::string getName() const override { return "remove or omit return type"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static RemoveReturn *create(ConstraintSystem &cs, Type resultTy, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::RemoveReturn; } }; class NotCompileTimeLiteral final : public ContextualMismatch { NotCompileTimeLiteral(ConstraintSystem &cs, Type paramTy, ConstraintLocator *locator); public: std::string getName() const override { return "replace with a literal"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static NotCompileTimeLiteral *create(ConstraintSystem &cs, Type paramTy, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::NotCompileTimeLiteral; } }; /// Describes the reason why the type must be copyable struct NoncopyableMatchFailure { enum Kind { CopyableConstraint, ExistentialCast, }; private: Kind reason; union { Type type; }; NoncopyableMatchFailure(Kind reason, Type type) : reason(reason), type(type) {} public: Kind getKind() const { return reason; } Type getType() const { switch (reason) { case ExistentialCast: return type; case CopyableConstraint: llvm_unreachable("no type payload"); }; } static NoncopyableMatchFailure forCopyableConstraint() { return NoncopyableMatchFailure(CopyableConstraint, Type()); } static NoncopyableMatchFailure forExistentialCast(Type existential) { assert(existential->isAnyExistentialType()); return NoncopyableMatchFailure(ExistentialCast, existential); } }; class AllowInvalidPackElement final : public ConstraintFix { Type packElementType; AllowInvalidPackElement(ConstraintSystem &cs, Type packElementType, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowInvalidPackElement, locator), packElementType(packElementType) {} public: std::string getName() const override { return "allow concrete pack element"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowInvalidPackElement *create(ConstraintSystem &cs, Type packElementType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowInvalidPackElement; } }; class AllowInvalidPackReference final : public ConstraintFix { Type packType; AllowInvalidPackReference(ConstraintSystem &cs, Type packType, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowInvalidPackReference, locator), packType(packType) {} public: std::string getName() const override { return "allow pack outside pack expansion"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowInvalidPackReference *create(ConstraintSystem &cs, Type packType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowInvalidPackReference; } }; class AllowInvalidPackExpansion final : public ConstraintFix { AllowInvalidPackExpansion(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowInvalidPackExpansion, locator) {} public: std::string getName() const override { return "allow invalid pack expansion"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowInvalidPackExpansion *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowInvalidPackExpansion; } }; class IgnoreWhereClauseInPackIteration final : public ConstraintFix { IgnoreWhereClauseInPackIteration(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::IgnoreWhereClauseInPackIteration, locator) {} public: std::string getName() const override { return "ignore where clause in pack iteration"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static IgnoreWhereClauseInPackIteration *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::IgnoreWhereClauseInPackIteration; } }; class CollectionElementContextualMismatch final : public ContextualMismatch, private llvm::TrailingObjects { friend TrailingObjects; unsigned NumElements; CollectionElementContextualMismatch(ConstraintSystem &cs, ArrayRef affectedElements, Type srcType, Type dstType, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::IgnoreCollectionElementContextualMismatch, srcType, dstType, locator), NumElements(affectedElements.size()) { std::uninitialized_copy(affectedElements.begin(), affectedElements.end(), getElementBuffer().begin()); } public: std::string getName() const override { return "fix collection element contextual mismatch"; } ArrayRef getElements() const { return {getTrailingObjects(), NumElements}; } bool diagnose(const Solution &solution, bool asNote = false) const override; static CollectionElementContextualMismatch * create(ConstraintSystem &cs, Type srcType, Type dstType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::IgnoreCollectionElementContextualMismatch; } private: MutableArrayRef getElementBuffer() { return {getTrailingObjects(), NumElements}; } }; 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(const Solution &solution, ArrayRef secondaryFixes, bool asNote = false) const override; bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static DefaultGenericArgument *create(ConstraintSystem &cs, GenericTypeParamType *param, ConstraintLocator *locator); }; class SkipUnhandledConstructInResultBuilder final : public ConstraintFix { public: using UnhandledNode = llvm::PointerUnion; private: UnhandledNode unhandled; NominalTypeDecl *builder; SkipUnhandledConstructInResultBuilder(ConstraintSystem &cs, UnhandledNode unhandled, NominalTypeDecl *builder, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::SkipUnhandledConstructInResultBuilder, locator), unhandled(unhandled), builder(builder) { } public: std::string getName() const override { return "skip unhandled constructs when applying a result builder"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static SkipUnhandledConstructInResultBuilder * create(ConstraintSystem &cs, UnhandledNode unhandledNode, NominalTypeDecl *builder, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::SkipUnhandledConstructInResultBuilder; } }; 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(const Solution &solution, 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); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowTupleSplatForSingleParameter; } }; class IgnoreContextualType : public ContextualMismatch { IgnoreContextualType(ConstraintSystem &cs, Type resultTy, Type specifiedTy, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::IgnoreContextualType, resultTy, specifiedTy, locator) {} public: std::string getName() const override { return "ignore specified contextual type"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static IgnoreContextualType *create(ConstraintSystem &cs, Type resultTy, Type specifiedTy, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::IgnoreContextualType; } }; class IgnoreAssignmentDestinationType final : public ContextualMismatch { IgnoreAssignmentDestinationType(ConstraintSystem &cs, Type sourceTy, Type destTy, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::IgnoreAssignmentDestinationType, sourceTy, destTy, locator) {} public: std::string getName() const override { return "ignore type of the assignment destination"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override; static IgnoreAssignmentDestinationType *create(ConstraintSystem &cs, Type sourceTy, Type destTy, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::IgnoreAssignmentDestinationType; } }; /// 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, FixKind::AllowConversionThroughInOut, argType, paramType, locator) {} public: std::string getName() const override { return "allow conversions between argument/parameter marked as `inout`"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowInOutConversion *create(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowConversionThroughInOut; } }; 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, FixBehavior fixBehavior = FixBehavior::Error) : ContextualMismatch( cs, kind, argType, paramType, locator, fixBehavior) {} public: std::string getName() const override { return "allow argument to parameter type conversion mismatch"; } unsigned getParamIdx() const; bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowArgumentMismatch *create(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowArgumentTypeMismatch; } }; 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(const Solution &solution, bool asNote = false) const override; static ExpandArrayIntoVarargs *attempt(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocatorBuilder locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::ExpandArrayIntoVarargs; } }; class ExplicitlyConstructRawRepresentable final : public ConstraintFix { Type RawReprType; Type ExpectedType; ExplicitlyConstructRawRepresentable(ConstraintSystem &cs, Type rawReprType, Type expectedType, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::ExplicitlyConstructRawRepresentable, locator), RawReprType(rawReprType), ExpectedType(expectedType) {} public: std::string getName() const override { return "explicitly construct a raw representable type"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static ExplicitlyConstructRawRepresentable * create(ConstraintSystem &cs, Type rawTypeRepr, Type expectedType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::ExplicitlyConstructRawRepresentable; } }; class UseRawValue final : public ConstraintFix { Type RawReprType; Type ExpectedType; UseRawValue(ConstraintSystem &cs, Type rawReprType, Type expectedType, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::UseRawValue, locator), RawReprType(rawReprType), ExpectedType(expectedType) {} public: std::string getName() const override { return "use `.rawValue` of a raw representable type"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static UseRawValue *create(ConstraintSystem &cs, Type rawReprType, Type expectedType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::UseRawValue; } }; /// Replace a coercion ('as') with runtime checked cast ('as!' or 'as?'). class CoerceToCheckedCast final : public ContextualMismatch { CoerceToCheckedCast(ConstraintSystem &cs, Type fromType, Type toType, bool useConditionalCast, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::CoerceToCheckedCast, fromType, toType, locator), UseConditionalCast(useConditionalCast) {} bool UseConditionalCast = false; public: std::string getName() const override { return UseConditionalCast ? "as to as?" : "as to as!"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static CoerceToCheckedCast *attempt(ConstraintSystem &cs, Type fromType, Type toType, bool useConditionalCast, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::CoerceToCheckedCast; } }; class RemoveInvalidCall final : public ConstraintFix { RemoveInvalidCall(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::RemoveCall, locator) {} public: std::string getName() const override { return "remove extraneous call from value of non-function type"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static RemoveInvalidCall *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::RemoveCall; } }; class TreatEphemeralAsNonEphemeral final : public AllowArgumentMismatch { ConversionRestrictionKind ConversionKind; TreatEphemeralAsNonEphemeral(ConstraintSystem &cs, ConstraintLocator *locator, Type srcType, Type dstType, ConversionRestrictionKind conversionKind, FixBehavior fixBehavior) : AllowArgumentMismatch(cs, FixKind::TreatEphemeralAsNonEphemeral, srcType, dstType, locator, fixBehavior), ConversionKind(conversionKind) {} public: ConversionRestrictionKind getConversionKind() const { return ConversionKind; } std::string getName() const override; bool diagnose(const Solution &solution, bool asNote = false) const override; static TreatEphemeralAsNonEphemeral * create(ConstraintSystem &cs, ConstraintLocator *locator, Type srcType, Type dstType, ConversionRestrictionKind conversionKind, bool downgradeToWarning); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::TreatEphemeralAsNonEphemeral; } }; /// Error if a user passes let f: (sending T) -> () as a (T) -> (). /// /// This prevents data races since f assumes its parameter if the parameter is /// non-Sendable is safe to transfer onto other situations. The caller though /// that this is being sent to does not enforce that invariants within its body. class AllowSendingMismatch final : public ContextualMismatch { AllowSendingMismatch(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator, FixBehavior fixBehavior) : ContextualMismatch(cs, FixKind::AllowSendingMismatch, argType, paramType, locator, fixBehavior) {} public: std::string getName() const override { return "treat a function argument with sending parameters and results as a " "function " "argument without sending parameters and results"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static AllowSendingMismatch *create(ConstraintSystem &cs, Type srcType, Type dstType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowSendingMismatch; } }; 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 override { const auto baseName = MemberName.getBaseName(); return "specify base type in reference to member '" + baseName.userFacingName().str() + "'"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static SpecifyBaseTypeForContextualMember * create(ConstraintSystem &cs, DeclNameRef member, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::SpecifyBaseTypeForContextualMember; } }; class SpecifyClosureParameterType final : public ConstraintFix { SpecifyClosureParameterType(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::SpecifyClosureParameterType, locator) {} public: std::string getName() const override; bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static SpecifyClosureParameterType *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::SpecifyClosureParameterType; } }; class SpecifyClosureReturnType final : public ConstraintFix { SpecifyClosureReturnType(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::SpecifyClosureReturnType, locator) {} public: std::string getName() const override { return "specify closure return type"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static SpecifyClosureReturnType *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::SpecifyClosureReturnType; } }; class SpecifyObjectLiteralTypeImport final : public ConstraintFix { SpecifyObjectLiteralTypeImport(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::SpecifyObjectLiteralTypeImport, locator) {} public: std::string getName() const override { return "import required module to gain access to a default literal type"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static SpecifyObjectLiteralTypeImport *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::SpecifyObjectLiteralTypeImport; } }; class SpecifyPackElementType final : public ConstraintFix { SpecifyPackElementType(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::SpecifyPackElementType, locator) {} public: std::string getName() const override { return "specify pack element type"; } bool diagnose(const Solution &solution, bool asNote) const override; static SpecifyPackElementType *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::SpecifyPackElementType; } }; class AddQualifierToAccessTopLevelName final : public ConstraintFix { AddQualifierToAccessTopLevelName(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AddQualifierToAccessTopLevelName, locator) {} public: std::string getName() const override { return "qualify reference to access top-level function"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AddQualifierToAccessTopLevelName *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AddQualifierToAccessTopLevelName; } }; class AllowNonClassTypeToConvertToAnyObject final : public ContextualMismatch { AllowNonClassTypeToConvertToAnyObject(ConstraintSystem &cs, Type type, ConstraintLocator *locator); public: std::string getName() const override { return "allow non-class type to convert to 'AnyObject'"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowNonClassTypeToConvertToAnyObject * create(ConstraintSystem &cs, Type type, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowNonClassTypeToConvertToAnyObject; } }; /// A warning fix to maintain compatibility with the following: /// /// \code /// func foo(_ arr: [Any]?) { /// _ = (arr ?? []) as [NSObject] /// } /// \endcode /// /// which performs a force-cast of the array's elements, despite being spelled /// as a coercion. class AllowCoercionToForceCast final : public ContextualMismatch { AllowCoercionToForceCast(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::AllowCoercionToForceCast, fromType, toType, locator, FixBehavior::AlwaysWarning) {} public: std::string getName() const override { return "allow coercion to be treated as a force-cast"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowCoercionToForceCast *create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowCoercionToForceCast; } }; /// Attempt to fix a key path application where the key path type cannot be /// applied to a base instance of another type. /// /// \code /// func f(_ bar: Bar , keyPath: KeyPath ) { /// bar[keyPath: keyPath] /// } /// \endcode class AllowKeyPathRootTypeMismatch final : public ContextualMismatch { protected: AllowKeyPathRootTypeMismatch(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::AllowKeyPathRootTypeMismatch, lhs, rhs, locator) {} public: std::string getName() const override { return "allow key path root type mismatch"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowKeyPathRootTypeMismatch * create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowKeyPathRootTypeMismatch; } }; class SpecifyKeyPathRootType final : public ConstraintFix { SpecifyKeyPathRootType(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::SpecifyKeyPathRootType, locator) {} public: std::string getName() const override { return "specify key path root type"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static SpecifyKeyPathRootType *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::SpecifyKeyPathRootType; } }; /// Diagnose missing unwrap of optional base type on key path application. /// /// \code /// func f(_ bar: Bar? , keyPath: KeyPath) { /// bar[keyPath: keyPath] /// } /// \endcode class UnwrapOptionalBaseKeyPathApplication final : public ContextualMismatch { protected: UnwrapOptionalBaseKeyPathApplication(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::UnwrapOptionalBaseKeyPathApplication, lhs, rhs, locator) {} public: std::string getName() const override { return "force unwrap base on key path application"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static UnwrapOptionalBaseKeyPathApplication * attempt(ConstraintSystem &cs, Type baseTy, Type rootTy, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::UnwrapOptionalBaseKeyPathApplication; } }; /// Diagnose situations when solver used old (backward scan) rule /// to match trailing closure to a parameter. /// /// \code /// func multiple_trailing_with_defaults( /// duration: Int, /// animations: (() -> Void)? = nil, /// completion: (() -> Void)? = nil) {} /// /// multiple_trailing_with_defaults(duration: 42) {} // picks `completion:` /// \endcode class SpecifyLabelToAssociateTrailingClosure final : public ConstraintFix { SpecifyLabelToAssociateTrailingClosure(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::SpecifyLabelToAssociateTrailingClosure, locator, FixBehavior::AlwaysWarning) {} public: std::string getName() const override { return "specify a label to associate trailing closure with parameter"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static SpecifyLabelToAssociateTrailingClosure * create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::SpecifyLabelToAssociateTrailingClosure; } }; /// Diagnose situations where we have a key path with no components. /// /// \code /// let _ : KeyPath = \A /// \endcode class AllowKeyPathWithoutComponents final : public ConstraintFix { AllowKeyPathWithoutComponents(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowKeyPathWithoutComponents, locator) {} public: std::string getName() const override { return "key path missing component"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowKeyPathWithoutComponents *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowKeyPathWithoutComponents; } }; class IgnoreInvalidResultBuilderBody : public ConstraintFix { IgnoreInvalidResultBuilderBody(ConstraintSystem &cs, ConstraintLocator *locator) : IgnoreInvalidResultBuilderBody( cs, FixKind::IgnoreInvalidResultBuilderBody, locator) {} protected: IgnoreInvalidResultBuilderBody(ConstraintSystem &cs, FixKind kind, ConstraintLocator *locator) : ConstraintFix(cs, kind, locator) {} public: std::string getName() const override { return "ignore invalid result builder body"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static IgnoreInvalidResultBuilderBody *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::IgnoreInvalidResultBuilderBody; } }; class IgnoreResultBuilderWithReturnStmts final : public IgnoreInvalidResultBuilderBody { Type BuilderType; IgnoreResultBuilderWithReturnStmts(ConstraintSystem &cs, Type builderTy, ConstraintLocator *locator) : IgnoreInvalidResultBuilderBody( cs, FixKind::IgnoreResultBuilderWithReturnStmts, locator), BuilderType(builderTy) {} public: bool diagnose(const Solution &solution, bool asNote = false) const override; static IgnoreResultBuilderWithReturnStmts * create(ConstraintSystem &cs, Type builderTy, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::IgnoreResultBuilderWithReturnStmts; } }; class IgnoreInvalidASTNode final : public ConstraintFix { IgnoreInvalidASTNode(ConstraintSystem &cs, ConstraintLocator *locator) : IgnoreInvalidASTNode(cs, FixKind::IgnoreInvalidASTNode, locator) {} protected: IgnoreInvalidASTNode(ConstraintSystem &cs, FixKind kind, ConstraintLocator *locator) : ConstraintFix(cs, kind, locator) {} public: std::string getName() const override { return "ignore invalid AST node"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static IgnoreInvalidASTNode *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::IgnoreInvalidASTNode; } }; class IgnoreUnresolvedPatternVar final : public ConstraintFix { IgnoreUnresolvedPatternVar(ConstraintSystem &cs, Pattern *pattern, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::IgnoreUnresolvedPatternVar, locator) {} public: std::string getName() const override { return "specify type for pattern match"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static IgnoreUnresolvedPatternVar * create(ConstraintSystem &cs, Pattern *pattern, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::IgnoreUnresolvedPatternVar; } }; class IgnoreInvalidPatternInExpr final : public ConstraintFix { Pattern *P; IgnoreInvalidPatternInExpr(ConstraintSystem &cs, Pattern *pattern, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::IgnoreInvalidPatternInExpr, locator), P(pattern) {} public: std::string getName() const override { return "ignore invalid Pattern nested in Expr"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static IgnoreInvalidPatternInExpr * create(ConstraintSystem &cs, Pattern *pattern, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::IgnoreInvalidPatternInExpr; } }; class SpecifyContextualTypeForNil final : public ConstraintFix { SpecifyContextualTypeForNil(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::SpecifyContextualTypeForNil, locator) {} public: std::string getName() const override { return "specify contextual type to resolve `nil` literal"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static SpecifyContextualTypeForNil *create(ConstraintSystem & cs, ConstraintLocator * locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::SpecifyContextualTypeForNil; } }; class IgnoreInvalidPlaceholder final : public ConstraintFix { IgnoreInvalidPlaceholder(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::IgnoreInvalidPlaceholder, locator) {} public: std::string getName() const override { return "ignore out-of-place placeholder type"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static IgnoreInvalidPlaceholder *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::IgnoreInvalidPlaceholder; } }; class SpecifyTypeForPlaceholder final : public ConstraintFix { SpecifyTypeForPlaceholder(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::SpecifyTypeForPlaceholder, locator) {} public: std::string getName() const override { return "specify type for placeholder"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static SpecifyTypeForPlaceholder *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::SpecifyTypeForPlaceholder; } }; class AllowRefToInvalidDecl final : public ConstraintFix { AllowRefToInvalidDecl(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowRefToInvalidDecl, locator) {} public: std::string getName() const override { return "ignore invalid declaration reference"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static AllowRefToInvalidDecl *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowRefToInvalidDecl; } }; /// Diagnose if the base type is optional, we're referring to a nominal /// type member via the dot syntax and the member name matches /// Optional.{member} or a .none member inferred as non-optional static /// member e.g. let _ : Foo? = .none where Foo has a static member none. class SpecifyBaseTypeForOptionalUnresolvedMember final : public ConstraintFix { SpecifyBaseTypeForOptionalUnresolvedMember(ConstraintSystem &cs, DeclNameRef memberName, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::SpecifyBaseTypeForOptionalUnresolvedMember, locator, FixBehavior::AlwaysWarning), MemberName(memberName) {} DeclNameRef MemberName; public: std::string getName() const override { const auto name = MemberName.getBaseName(); return "specify unresolved member optional base type explicitly '" + name.userFacingName().str() + "'"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static SpecifyBaseTypeForOptionalUnresolvedMember * attempt(ConstraintSystem &cs, ConstraintKind kind, Type baseTy, DeclNameRef memberName, FunctionRefInfo functionRefInfo, MemberLookupResult result, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::SpecifyBaseTypeForOptionalUnresolvedMember; } }; class CheckedCastContextualMismatchWarning : public ContextualMismatch { protected: CheckedCastContextualMismatchWarning(ConstraintSystem &cs, FixKind fixKind, Type fromType, Type toType, CheckedCastKind kind, ConstraintLocator *locator) : ContextualMismatch(cs, fixKind, fromType, toType, locator, FixBehavior::AlwaysWarning), CastKind(kind) {} CheckedCastKind CastKind; }; class AllowCheckedCastCoercibleOptionalType final : public CheckedCastContextualMismatchWarning { AllowCheckedCastCoercibleOptionalType(ConstraintSystem &cs, Type fromType, Type toType, CheckedCastKind kind, ConstraintLocator *locator) : CheckedCastContextualMismatchWarning( cs, FixKind::AllowCheckedCastCoercibleOptionalType, fromType, toType, kind, locator) {} public: std::string getName() const override { return "checked cast coercible optional"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowCheckedCastCoercibleOptionalType * create(ConstraintSystem &cs, Type fromType, Type toType, CheckedCastKind kind, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowCheckedCastCoercibleOptionalType; } }; class AllowNoopCheckedCast final : public CheckedCastContextualMismatchWarning { AllowNoopCheckedCast(ConstraintSystem &cs, Type fromType, Type toType, CheckedCastKind kind, ConstraintLocator *locator) : CheckedCastContextualMismatchWarning(cs, FixKind::AllowNoopCheckedCast, fromType, toType, kind, locator) {} public: std::string getName() const override { return "checked cast always succeeds"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowNoopCheckedCast *create(ConstraintSystem &cs, Type fromType, Type toType, CheckedCastKind kind, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowNoopCheckedCast; } }; class AllowNoopExistentialToCFTypeCheckedCast final : public CheckedCastContextualMismatchWarning { AllowNoopExistentialToCFTypeCheckedCast(ConstraintSystem &cs, Type fromType, Type toType, CheckedCastKind kind, ConstraintLocator *locator) : CheckedCastContextualMismatchWarning( cs, FixKind::AllowNoopExistentialToCFTypeCheckedCast, fromType, toType, kind, locator) {} public: std::string getName() const override { return "checked cast from existential to CFType always succeeds"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowNoopExistentialToCFTypeCheckedCast * attempt(ConstraintSystem &cs, Type fromType, Type toType, CheckedCastKind kind, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowNoopExistentialToCFTypeCheckedCast; } }; class AllowUnsupportedRuntimeCheckedCast final : public CheckedCastContextualMismatchWarning { AllowUnsupportedRuntimeCheckedCast(ConstraintSystem &cs, Type fromType, Type toType, CheckedCastKind kind, ConstraintLocator *locator) : CheckedCastContextualMismatchWarning( cs, FixKind::AllowUnsupportedRuntimeCheckedCast, fromType, toType, kind, locator) {} public: std::string getName() const override { return "runtime unsupported checked cast"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static bool runtimeSupportedFunctionTypeCast(FunctionType *fnFromType, FunctionType *fnToType); static AllowUnsupportedRuntimeCheckedCast * attempt(ConstraintSystem &cs, Type fromType, Type toType, CheckedCastKind kind, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowUnsupportedRuntimeCheckedCast; } }; class AllowCheckedCastToUnrelated final : public CheckedCastContextualMismatchWarning { AllowCheckedCastToUnrelated(ConstraintSystem &cs, Type fromType, Type toType, CheckedCastKind kind, ConstraintLocator *locator) : CheckedCastContextualMismatchWarning( cs, FixKind::AllowCheckedCastToUnrelated, fromType, toType, kind, locator) {} public: std::string getName() const override { return "checked cast always fails"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowCheckedCastToUnrelated *attempt(ConstraintSystem &cs, Type fromType, Type toType, CheckedCastKind kind, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowCheckedCastToUnrelated; } }; class AllowInvalidStaticMemberRefOnProtocolMetatype final : public ConstraintFix { AllowInvalidStaticMemberRefOnProtocolMetatype(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowInvalidStaticMemberRefOnProtocolMetatype, locator) {} public: std::string getName() const override { return "allow invalid static member reference on a protocol metatype"; } bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowInvalidStaticMemberRefOnProtocolMetatype * create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowInvalidStaticMemberRefOnProtocolMetatype; } }; /// Emit a warning for mismatched tuple labels. class AllowTupleLabelMismatch final : public ContextualMismatch { AllowTupleLabelMismatch(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::AllowTupleLabelMismatch, fromType, toType, locator, FixBehavior::AlwaysWarning) {} public: std::string getName() const override { return "allow tuple label mismatch"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowTupleLabelMismatch *create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowTupleLabelMismatch; } }; class AllowAssociatedValueMismatch final : public ContextualMismatch { AllowAssociatedValueMismatch(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::AllowAssociatedValueMismatch, fromType, toType, locator) {} public: std::string getName() const override { return "allow associated value mismatch"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowAssociatedValueMismatch *create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowAssociatedValueMismatch; } }; class AllowNonOptionalWeak final : public ConstraintFix { AllowNonOptionalWeak(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowNonOptionalWeak, locator) {} public: std::string getName() const override { return "allow `weak` with non-optional type"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowNonOptionalWeak *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowNonOptionalWeak; } }; class AllowSwiftToCPointerConversion final : public ConstraintFix { AllowSwiftToCPointerConversion(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowSwiftToCPointerConversion, locator) {} public: std::string getName() const override { return "allow implicit Swift -> C pointer conversion"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowSwiftToCPointerConversion *create(ConstraintSystem &cs, ConstraintLocator *locator); }; class IgnoreDefaultExprTypeMismatch : public AllowArgumentMismatch { protected: IgnoreDefaultExprTypeMismatch(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator) : AllowArgumentMismatch(cs, FixKind::IgnoreDefaultExprTypeMismatch, argType, paramType, locator) {} public: std::string getName() const override { return "allow default expression conversion mismatch"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static IgnoreDefaultExprTypeMismatch *create(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::IgnoreDefaultExprTypeMismatch; } }; class RenameConflictingPatternVariables final : public ConstraintFix, private llvm::TrailingObjects { friend TrailingObjects; Type ExpectedType; unsigned NumConflicts; RenameConflictingPatternVariables(ConstraintSystem &cs, Type expectedTy, ArrayRef conflicts, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::RenameConflictingPatternVariables, locator), ExpectedType(expectedTy), NumConflicts(conflicts.size()) { std::uninitialized_copy(conflicts.begin(), conflicts.end(), getConflictingBuffer().begin()); } MutableArrayRef getConflictingBuffer() { return {getTrailingObjects(), NumConflicts}; } public: std::string getName() const override { return "rename pattern variables"; } ArrayRef getConflictingVars() const { return {getTrailingObjects(), NumConflicts}; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static RenameConflictingPatternVariables * create(ConstraintSystem &cs, Type expectedTy, ArrayRef conflicts, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::RenameConflictingPatternVariables; } }; class MacroMissingPound final : public ConstraintFix { MacroDecl *macro; MacroMissingPound(ConstraintSystem &cs, MacroDecl *macro, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::MacroMissingPound, locator), macro(macro) { } public: std::string getName() const override { return "macro missing pound"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static MacroMissingPound * create(ConstraintSystem &cs, MacroDecl *macro, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::MacroMissingPound; } }; /// Allow mismatch between function types global actors. /// e.g. `@MainActor () -> Void` vs.`@OtherActor () -> Void` class AllowGlobalActorMismatch final : public ContextualMismatch { AllowGlobalActorMismatch(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::AllowGlobalActorMismatch, fromType, toType, locator) {} public: std::string getName() const override { return "allow function type actor mismatch"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowGlobalActorMismatch *create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowGlobalActorMismatch; } }; /// Passing an argument of tuple type to a value pack expansion parameter /// that expected N distinct elements. class DestructureTupleToMatchPackExpansionParameter final : public ConstraintFix { PackType *ParamShape; DestructureTupleToMatchPackExpansionParameter(ConstraintSystem &cs, PackType *paramShapeTy, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::DestructureTupleToMatchPackExpansionParameter, locator), ParamShape(paramShapeTy) { assert(locator->isLastElement()); } public: std::string getName() const override { return "allow pack expansion to match tuple argument"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static DestructureTupleToMatchPackExpansionParameter * create(ConstraintSystem &cs, PackType *paramShapeTy, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::DestructureTupleToMatchPackExpansionParameter; } }; class AllowValueExpansionWithoutPackReferences final : public ConstraintFix { AllowValueExpansionWithoutPackReferences(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowValueExpansionWithoutPackReferences, locator) {} public: std::string getName() const override { return "allow value pack expansion without pack references"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static AllowValueExpansionWithoutPackReferences * create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowValueExpansionWithoutPackReferences; } }; class IgnoreMissingEachKeyword final : public ConstraintFix { Type ValuePackType; IgnoreMissingEachKeyword(ConstraintSystem &cs, Type valuePackTy, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::IgnoreMissingEachKeyword, locator), ValuePackType(valuePackTy) {} public: std::string getName() const override { return "allow value pack reference without 'each'"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static IgnoreMissingEachKeyword * create(ConstraintSystem &cs, Type valuePackTy, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::IgnoreMissingEachKeyword; } }; class AllowInvalidMemberReferenceInInitAccessor final : public ConstraintFix { DeclNameRef MemberName; AllowInvalidMemberReferenceInInitAccessor(ConstraintSystem &cs, DeclNameRef memberName, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowInvalidMemberReferenceInInitAccessor, locator), MemberName(memberName) {} public: std::string getName() const override { llvm::SmallVector scratch; auto memberName = MemberName.getString(scratch); return "allow reference to member '" + memberName.str() + "' in init accessor"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static AllowInvalidMemberReferenceInInitAccessor * create(ConstraintSystem &cs, DeclNameRef memberName, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowInvalidMemberReferenceInInitAccessor; } }; class AllowConcreteTypeSpecialization final : public ConstraintFix { Type ConcreteType; ValueDecl *Decl; AllowConcreteTypeSpecialization(ConstraintSystem &cs, Type concreteTy, ValueDecl *decl, ConstraintLocator *locator, FixBehavior fixBehavior) : ConstraintFix(cs, FixKind::AllowConcreteTypeSpecialization, locator, fixBehavior), ConcreteType(concreteTy), Decl(decl) {} public: std::string getName() const override { return "allow concrete type specialization"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static AllowConcreteTypeSpecialization * create(ConstraintSystem &cs, Type concreteTy, ValueDecl *decl, ConstraintLocator *locator, FixBehavior fixBehavior); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowConcreteTypeSpecialization; } }; class AllowFunctionSpecialization final : public ConstraintFix { ValueDecl *Decl; AllowFunctionSpecialization(ConstraintSystem &cs, ValueDecl *decl, ConstraintLocator *locator, FixBehavior fixBehavior) : ConstraintFix(cs, FixKind::AllowFunctionSpecialization, locator, fixBehavior), Decl(decl) {} public: std::string getName() const override { return "allow (generic) function specialization"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static AllowFunctionSpecialization * create(ConstraintSystem &cs, ValueDecl *decl, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowFunctionSpecialization; } }; class IgnoreOutOfPlaceThenStmt final : public ConstraintFix { IgnoreOutOfPlaceThenStmt(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::IgnoreOutOfPlaceThenStmt, locator) {} public: std::string getName() const override { return "ignore out-of-place ThenStmt"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static IgnoreOutOfPlaceThenStmt *create(ConstraintSystem &cs, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::IgnoreOutOfPlaceThenStmt; } }; class IgnoreGenericSpecializationArityMismatch final : public ConstraintFix { ValueDecl *D; unsigned NumParams; unsigned NumArgs; bool HasParameterPack; IgnoreGenericSpecializationArityMismatch(ConstraintSystem &cs, ValueDecl *decl, unsigned numParams, unsigned numArgs, bool hasParameterPack, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::IgnoreGenericSpecializationArityMismatch, locator), D(decl), NumParams(numParams), NumArgs(numArgs), HasParameterPack(hasParameterPack) {} public: std::string getName() const override { return "ignore generic specialization mismatch"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static IgnoreGenericSpecializationArityMismatch * create(ConstraintSystem &cs, ValueDecl *decl, unsigned numParams, unsigned numArgs, bool hasParameterPack, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::IgnoreGenericSpecializationArityMismatch; } }; class IgnoreKeyPathSubscriptIndexMismatch final : public ConstraintFix { Type ArgType; IgnoreKeyPathSubscriptIndexMismatch(ConstraintSystem &cs, Type argTy, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::IgnoreKeyPathSubscriptIndexMismatch, locator), ArgType(argTy) {} public: std::string getName() const override { return "ignore invalid key path subscript index"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static IgnoreKeyPathSubscriptIndexMismatch * create(ConstraintSystem &cs, Type argType, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::IgnoreKeyPathSubscriptIndexMismatch; } }; class AllowInlineArrayLiteralCountMismatch final : public ConstraintFix { Type lhsCount, rhsCount; AllowInlineArrayLiteralCountMismatch(ConstraintSystem &cs, Type lhsCount, Type rhsCount, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::AllowInlineArrayLiteralCountMismatch, locator), lhsCount(lhsCount), rhsCount(rhsCount) {} public: std::string getName() const override { return "allow vector literal count mismatch"; } bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowInlineArrayLiteralCountMismatch * create(ConstraintSystem &cs, Type lhsCount, Type rhsCount, ConstraintLocator *locator); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::AllowInlineArrayLiteralCountMismatch; } }; class IgnoreIsolatedConformance : public ConstraintFix { ProtocolConformance *conformance; IgnoreIsolatedConformance(ConstraintSystem &cs, ConstraintLocator *locator, ProtocolConformance *conformance) : ConstraintFix(cs, FixKind::IgnoreIsolatedConformance, locator), conformance(conformance) { } public: std::string getName() const override { return "ignore isolated conformance"; } bool diagnose(const Solution &solution, bool asNote = false) const override; bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { return diagnose(*commonFixes.front().first); } static IgnoreIsolatedConformance *create(ConstraintSystem &cs, ConstraintLocator *locator, ProtocolConformance *conformance); static bool classof(const ConstraintFix *fix) { return fix->getKind() == FixKind::IgnoreIsolatedConformance; } }; } // 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