mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This change adds detection for nested type references in KeyPath components and applies the appropriate fix to generate meaningful error messages, following the same pattern already established for method references. The fix ensures that invalid KeyPath references fail gracefully in normal mode and provide helpful diagnostics in diagnostic mode, improving the developer experience when working with KeyPaths. Resolves: https://github.com/swiftlang/swift/issues/83197
3970 lines
140 KiB
C++
3970 lines
140 KiB
C++
//===--- 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 <string>
|
|
|
|
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,
|
|
|
|
/// Reached the limit of @dynamicMemberLookup depth.
|
|
TooManyDynamicMemberLookups,
|
|
|
|
/// 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 <typename Fix>
|
|
const Fix *getAs() const {
|
|
return Fix::classof(this) ? static_cast<const Fix *>(this) : nullptr;
|
|
}
|
|
|
|
template <typename Fix>
|
|
const Fix *castTo() const {
|
|
assert(Fix::classof(this));
|
|
return static_cast<const Fix *>(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<ScoreKind> 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<ConstraintFix *> 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<std::pair<const Solution *, const ConstraintFix *>>;
|
|
|
|
virtual bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const {
|
|
return false;
|
|
}
|
|
|
|
template <typename E>
|
|
bool directlyAt() const {
|
|
return getLocator()->directlyAt<E>();
|
|
}
|
|
|
|
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<RelabelArguments, Identifier> {
|
|
friend TrailingObjects;
|
|
|
|
unsigned NumLabels;
|
|
|
|
RelabelArguments(ConstraintSystem &cs,
|
|
llvm::ArrayRef<Identifier> 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<Identifier> getLabels() const {
|
|
return {getTrailingObjects<Identifier>(), NumLabels};
|
|
}
|
|
|
|
bool diagnose(const Solution &solution, bool asNote = false) const override;
|
|
|
|
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override;
|
|
|
|
static RelabelArguments *create(ConstraintSystem &cs,
|
|
llvm::ArrayRef<Identifier> correctLabels,
|
|
ConstraintLocator *locator);
|
|
|
|
static bool classof(const ConstraintFix *fix) {
|
|
return fix->getKind() == FixKind::RelabelArguments;
|
|
}
|
|
|
|
private:
|
|
MutableArrayRef<Identifier> getLabelsBuffer() {
|
|
return {getTrailingObjects<Identifier>(), 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<ConstraintFix *> 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<PlaceholderType>()) {
|
|
if (isa<ErrorExpr *>(fromPlaceholder->getOriginator())) {
|
|
return true;
|
|
}
|
|
}
|
|
if (auto toPlaceholder = getToType()->getAs<PlaceholderType>()) {
|
|
if (isa<ErrorExpr *>(toPlaceholder->getOriginator())) {
|
|
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<G> {}
|
|
/// let _:F<Int> = F<Bool>()
|
|
/// ```
|
|
class GenericArgumentsMismatch final
|
|
: public ContextualMismatch,
|
|
private llvm::TrailingObjects<GenericArgumentsMismatch, unsigned> {
|
|
friend TrailingObjects;
|
|
|
|
unsigned NumMismatches;
|
|
|
|
protected:
|
|
GenericArgumentsMismatch(ConstraintSystem &cs, Type actual, Type required,
|
|
llvm::ArrayRef<unsigned> mismatches,
|
|
ConstraintLocator *locator)
|
|
: ContextualMismatch(cs, FixKind::GenericArgumentsMismatch, actual,
|
|
required, locator),
|
|
NumMismatches(mismatches.size()) {
|
|
assert(actual->is<BoundGenericType>());
|
|
assert(required->is<BoundGenericType>());
|
|
std::uninitialized_copy(mismatches.begin(), mismatches.end(),
|
|
getMismatchesBuf().begin());
|
|
}
|
|
|
|
public:
|
|
std::string getName() const override {
|
|
return "fix generic argument mismatch";
|
|
}
|
|
|
|
ArrayRef<unsigned> getMismatches() const {
|
|
return {getTrailingObjects<unsigned>(), NumMismatches};
|
|
}
|
|
|
|
bool coalesceAndDiagnose(const Solution &solution,
|
|
ArrayRef<ConstraintFix *> 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<unsigned> mismatches,
|
|
ConstraintLocator *locator);
|
|
|
|
static bool classof(const ConstraintFix *fix) {
|
|
return fix->getKind() == FixKind::GenericArgumentsMismatch;
|
|
}
|
|
|
|
private:
|
|
bool diagnose(const Solution &solution, ArrayRef<unsigned> mismatches,
|
|
bool asNote = false) const;
|
|
|
|
MutableArrayRef<unsigned> getMismatchesBuf() {
|
|
return {getTrailingObjects<unsigned>(), 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<char, 16> 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<char, 16> 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<char, 16> 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<unsigned> Index;
|
|
|
|
AllowTupleTypeMismatch(ConstraintSystem &cs, Type lhs, Type rhs,
|
|
ConstraintLocator *locator,
|
|
std::optional<unsigned> index)
|
|
: ContextualMismatch(cs, FixKind::AllowTupleTypeMismatch, lhs, rhs,
|
|
locator),
|
|
Index(index) {}
|
|
|
|
public:
|
|
static AllowTupleTypeMismatch *
|
|
create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator,
|
|
std::optional<unsigned> 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<ConstraintFix *> 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<ConstraintFix *> 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<SynthesizedArg> 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<SynthesizedArg> getSynthesizedArguments() const {
|
|
return {getTrailingObjects<SynthesizedArg>(), 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<SynthesizedArg> synthesizedArgs,
|
|
ConstraintLocator *locator);
|
|
|
|
static bool classof(const ConstraintFix *fix) {
|
|
return fix->getKind() == FixKind::AddMissingArguments;
|
|
}
|
|
|
|
private:
|
|
MutableArrayRef<SynthesizedArg> getSynthesizedArgumentsBuf() {
|
|
return {getTrailingObjects<SynthesizedArg>(), NumSynthesized};
|
|
}
|
|
};
|
|
|
|
class RemoveExtraneousArguments final
|
|
: public ConstraintFix,
|
|
private llvm::TrailingObjects<
|
|
RemoveExtraneousArguments,
|
|
std::pair<unsigned, AnyFunctionType::Param>> {
|
|
friend TrailingObjects;
|
|
|
|
using IndexedParam = std::pair<unsigned, AnyFunctionType::Param>;
|
|
|
|
FunctionType *ContextualType;
|
|
unsigned NumExtraneous;
|
|
|
|
RemoveExtraneousArguments(ConstraintSystem &cs, FunctionType *contextualType,
|
|
llvm::ArrayRef<IndexedParam> 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<IndexedParam> getExtraArguments() const {
|
|
return {getTrailingObjects<IndexedParam>(), 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<IndexedParam> extraArgs, ConstraintLocator *locator);
|
|
|
|
static bool classof(const ConstraintFix *fix) {
|
|
return fix->getKind() == FixKind::RemoveExtraneousArguments;
|
|
}
|
|
|
|
private:
|
|
MutableArrayRef<IndexedParam> getExtraArgumentsBuf() {
|
|
return {getTrailingObjects<IndexedParam>(), NumExtraneous};
|
|
}
|
|
};
|
|
|
|
class MoveOutOfOrderArgument final : public ConstraintFix {
|
|
using ParamBinding = SmallVector<unsigned, 1>;
|
|
|
|
unsigned ArgIdx;
|
|
unsigned PrevArgIdx;
|
|
|
|
SmallVector<ParamBinding, 4> Bindings;
|
|
|
|
MoveOutOfOrderArgument(ConstraintSystem &cs, unsigned argIdx,
|
|
unsigned prevArgIdx, ArrayRef<ParamBinding> 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<ParamBinding> 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,
|
|
// Allow a reference to a type as a key path component.
|
|
TypeReference,
|
|
} 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";
|
|
case RefKind::TypeReference:
|
|
return "allow reference to a type 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<CollectionElementContextualMismatch,
|
|
Expr *> {
|
|
friend TrailingObjects;
|
|
|
|
unsigned NumElements;
|
|
|
|
CollectionElementContextualMismatch(ConstraintSystem &cs,
|
|
ArrayRef<Expr *> 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<Expr *> getElements() const {
|
|
return {getTrailingObjects<Expr *>(), 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<Expr *> getElementBuffer() {
|
|
return {getTrailingObjects<Expr *>(), 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<ConstraintFix *> 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<Stmt *, Decl *>;
|
|
|
|
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<Param> &args,
|
|
ArrayRef<Param> params,
|
|
SmallVectorImpl<SmallVector<unsigned, 1>> &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<Foo, Int> ) {
|
|
/// 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, Int>) {
|
|
/// 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, B> = \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<T>.{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<RenameConflictingPatternVariables,
|
|
VarDecl *> {
|
|
friend TrailingObjects;
|
|
|
|
Type ExpectedType;
|
|
unsigned NumConflicts;
|
|
|
|
RenameConflictingPatternVariables(ConstraintSystem &cs, Type expectedTy,
|
|
ArrayRef<VarDecl *> conflicts,
|
|
ConstraintLocator *locator)
|
|
: ConstraintFix(cs, FixKind::RenameConflictingPatternVariables, locator),
|
|
ExpectedType(expectedTy), NumConflicts(conflicts.size()) {
|
|
std::uninitialized_copy(conflicts.begin(), conflicts.end(),
|
|
getConflictingBuffer().begin());
|
|
}
|
|
|
|
MutableArrayRef<VarDecl *> getConflictingBuffer() {
|
|
return {getTrailingObjects<VarDecl *>(), NumConflicts};
|
|
}
|
|
|
|
public:
|
|
std::string getName() const override { return "rename pattern variables"; }
|
|
|
|
ArrayRef<VarDecl *> getConflictingVars() const {
|
|
return {getTrailingObjects<VarDecl *>(), 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<VarDecl *> 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<LocatorPathElt::ApplyArgToParam>());
|
|
}
|
|
|
|
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<char, 16> 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 TooManyDynamicMemberLookups : public ConstraintFix {
|
|
DeclNameRef Name;
|
|
|
|
TooManyDynamicMemberLookups(ConstraintSystem &cs, DeclNameRef name,
|
|
ConstraintLocator *locator)
|
|
: ConstraintFix(cs, FixKind::TooManyDynamicMemberLookups, locator),
|
|
Name(name) {}
|
|
|
|
public:
|
|
std::string getName() const override {
|
|
return "too many dynamic member lookups";
|
|
}
|
|
|
|
bool diagnose(const Solution &solution, bool asNote = false) const override;
|
|
|
|
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
|
|
return diagnose(*commonFixes.front().first);
|
|
}
|
|
|
|
static TooManyDynamicMemberLookups *
|
|
create(ConstraintSystem &cs, DeclNameRef name, ConstraintLocator *locator);
|
|
|
|
static bool classof(const ConstraintFix *fix) {
|
|
return fix->getKind() == FixKind::TooManyDynamicMemberLookups;
|
|
}
|
|
};
|
|
|
|
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<swift::constraints::FixKind> {
|
|
using FixKind = swift::constraints::FixKind;
|
|
static inline FixKind getEmptyKey() {
|
|
return static_cast<FixKind>(0);
|
|
}
|
|
static inline FixKind getTombstoneKey() {
|
|
return static_cast<FixKind>(1);
|
|
}
|
|
static unsigned getHashValue(FixKind kind) {
|
|
return static_cast<unsigned>(kind);
|
|
}
|
|
static bool isEqual(FixKind lhs, FixKind rhs) {
|
|
return lhs == rhs;
|
|
}
|
|
};
|
|
}
|
|
|
|
#endif // SWIFT_SEMA_CSFIX_H
|