blob: de707a0b5369dc497d6dd39b03b6148473079b99 [file] [log] [blame]
//===--- CSDiagnostics.h - Constraint Diagnostics -------------------------===//
//
// 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 system diagnostics.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SEMA_CSDIAGNOSTICS_H
#define SWIFT_SEMA_CSDIAGNOSTICS_H
#include "TypeChecker.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTNode.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/OperatorNameLookup.h"
#include "swift/AST/Types.h"
#include "swift/Basic/SourceLoc.h"
#include "swift/Sema/ConstraintSystem.h"
#include "swift/Sema/OverloadChoice.h"
#include "llvm/ADT/ArrayRef.h"
#include <tuple>
namespace swift {
namespace constraints {
class FunctionArgApplyInfo;
/// Base class for all of the possible diagnostics,
/// provides most basic information such as location of
/// the problem, parent expression and some utility methods.
class FailureDiagnostic {
const Solution &S;
ConstraintLocator *Locator;
public:
FailureDiagnostic(const Solution &solution, ConstraintLocator *locator)
: S(solution), Locator(locator) {}
FailureDiagnostic(const Solution &solution, ASTNode anchor)
: FailureDiagnostic(solution, solution.getConstraintLocator(anchor)) {}
virtual ~FailureDiagnostic();
virtual SourceLoc getLoc() const { return constraints::getLoc(getAnchor()); }
virtual SourceRange getSourceRange() const {
return constraints::getSourceRange(getAnchor());
}
/// Try to diagnose a problem given affected expression,
/// failure location, types and declarations deduced by
/// constraint system, and other auxiliary information.
///
/// \param asNote In ambiguity cases it's beneficial to
/// produce diagnostic as a note instead of an error if possible.
///
/// \returns true If the problem has been successfully diagnosed
/// and diagnostic message emitted, false otherwise.
bool diagnose(bool asNote = false);
/// Try to produce an error diagnostic for the problem at hand.
///
/// \returns true If anything was diagnosed, false otherwise.
virtual bool diagnoseAsError() = 0;
/// Instead of producing an error diagnostic, attempt to
/// produce a "note" to complement some other diagnostic
/// e.g. ambiguity error.
virtual bool diagnoseAsNote();
ASTNode getRawAnchor() const { return Locator->getAnchor(); }
virtual ASTNode getAnchor() const;
ConstraintLocator *getLocator() const { return Locator; }
Type getType(ASTNode node, bool wantRValue = true) const;
/// Get type associated with a given ASTNode without resolving it,
/// which means that returned type would have type variables.
Type getRawType(ASTNode node) const;
/// Resolve type variables present in the raw type, if any.
Type resolveType(Type rawType, bool reconstituteSugar = false,
bool wantRValue = true) const {
auto &cs = getConstraintSystem();
if (rawType->hasTypeVariable() || rawType->hasHole()) {
rawType = rawType.transform([&](Type type) {
if (auto *typeVar = type->getAs<TypeVariableType>()) {
auto resolvedType = S.simplifyType(typeVar);
Type GP = typeVar->getImpl().getGenericParameter();
return resolvedType->is<UnresolvedType>() && GP
? GP
: resolvedType;
}
return type->isHole() ? Type(cs.getASTContext().TheUnresolvedType)
: type;
});
}
if (reconstituteSugar)
rawType = rawType->reconstituteSugar(/*recursive*/ true);
return wantRValue ? rawType->getRValueType() : rawType;
}
template <typename... ArgTypes>
InFlightDiagnostic emitDiagnostic(ArgTypes &&... Args) const;
template <typename... ArgTypes>
InFlightDiagnostic emitDiagnosticAt(ArgTypes &&... Args) const;
protected:
const Solution &getSolution() const { return S; }
ConstraintSystem &getConstraintSystem() const {
return S.getConstraintSystem();
}
Type getContextualType(ASTNode anchor) const {
auto &cs = getConstraintSystem();
return cs.getContextualType(anchor);
}
TypeLoc getContextualTypeLoc(ASTNode anchor) const {
auto &cs = getConstraintSystem();
return cs.getContextualTypeLoc(anchor);
}
ContextualTypePurpose getContextualTypePurpose(ASTNode anchor) const {
auto &cs = getConstraintSystem();
return cs.getContextualTypePurpose(anchor);
}
DeclContext *getDC() const {
auto &cs = getConstraintSystem();
return cs.DC;
}
ASTContext &getASTContext() const {
auto &cs = getConstraintSystem();
return cs.getASTContext();
}
/// Retrieve overload choice resolved for a given locator
/// by the constraint solver.
Optional<SelectedOverload>
getOverloadChoiceIfAvailable(ConstraintLocator *locator) const {
return S.getOverloadChoiceIfAvailable(locator);
}
/// Retrieve overload choice resolved for a callee for the anchor
/// of a given locator.
Optional<SelectedOverload>
getCalleeOverloadChoiceIfAvailable(ConstraintLocator *locator) const {
return getOverloadChoiceIfAvailable(S.getCalleeLocator(locator));
}
ConstraintLocator *
getConstraintLocator(ASTNode anchor,
ConstraintLocator::PathElement element) const {
return S.getConstraintLocator(anchor, {element});
}
/// Retrive the constraint locator for the given anchor and
/// path, uniqued and automatically calculate the summary flags
ConstraintLocator *getConstraintLocator(
ASTNode anchor,
ArrayRef<ConstraintLocator::PathElement> path = {}) const {
return S.getConstraintLocator(anchor, path);
}
ConstraintLocator *
getConstraintLocator(ConstraintLocator *baseLocator,
ConstraintLocator::PathElement element) const {
return S.getConstraintLocator(baseLocator, element);
}
Optional<FunctionArgApplyInfo>
getFunctionArgApplyInfo(ConstraintLocator *locator) const {
return S.getFunctionArgApplyInfo(locator);
}
/// \returns A parent expression if sub-expression is contained anywhere
/// in the root expression or `nullptr` otherwise.
Expr *findParentExpr(const Expr *subExpr) const;
/// If given expression is some kind of a member reference e.g.
/// `x.foo` or `x[0]` extract and return its base expression.
Expr *getBaseExprFor(const Expr *anchor) const;
/// For a given locator describing an argument application, or a constraint
/// within an argument application, returns the argument list for that
/// application. If the locator is not for an argument application, or
/// the argument list cannot be found, returns \c nullptr.
Expr *getArgumentListExprFor(ConstraintLocator *locator) const;
/// \returns A new type with all of the type variables associated with
/// generic parameters substituted back into being generic parameter type.
Type restoreGenericParameters(
Type type,
llvm::function_ref<void(GenericTypeParamType *, Type)> substitution =
[](GenericTypeParamType *, Type) {});
bool isArrayType(Type type) const {
auto &cs = getConstraintSystem();
return bool(cs.isArrayType(type));
}
bool conformsToKnownProtocol(Type type, KnownProtocolKind protocol) const;
};
/// Base class for all of the diagnostics related to generic requirement
/// failures, provides common information like failed requirement,
/// declaration where such requirement comes from, etc.
class RequirementFailure : public FailureDiagnostic {
protected:
using PathEltKind = ConstraintLocator::PathElementKind;
using DiagOnDecl = Diag<DescriptiveDeclKind, DeclName, Type, Type>;
using DiagInReference = Diag<DescriptiveDeclKind, DeclName, Type, Type, Type>;
using DiagAsNote = Diag<Type, Type, Type, Type, StringRef>;
/// If this failure associated with one of the conditional requirements,
/// this field would represent conformance where requirement comes from.
const ProtocolConformance *Conformance = nullptr;
/// The source of the requirement, if available. One exception
/// is failure associated with conditional requirement where
/// underlying conformance is specialized.
GenericSignature Signature;
const ValueDecl *AffectedDecl;
/// If possible, find application expression associated
/// with current generic requirement failure, that helps
/// to diagnose failures related to arguments.
const ApplyExpr *Apply = nullptr;
/// Types associated with requirement constraint this
/// failure originates from.
Type LHS, RHS;
public:
RequirementFailure(const Solution &solution, Type lhs, Type rhs,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator),
Conformance(getConformanceForConditionalReq(locator)),
Signature(getSignature(locator)), AffectedDecl(getDeclRef()),
LHS(resolveType(lhs)), RHS(resolveType(rhs)) {
assert(locator);
assert(isConditional() || Signature);
assert(AffectedDecl);
assert(getRequirementDC() &&
"Couldn't find where the requirement came from?");
assert(getGenericContext() &&
"Affected decl not within a generic context?");
if (auto *expr = getAsExpr(getRawAnchor()))
if (auto *parentExpr = findParentExpr(expr))
Apply = dyn_cast<ApplyExpr>(parentExpr);
}
unsigned getRequirementIndex() const {
auto reqElt =
getLocator()->castLastElementTo<LocatorPathElt::AnyRequirement>();
return reqElt.getIndex();
}
/// The generic base type where failing requirement comes from.
Type getOwnerType() const;
/// Generic context associated with the failure.
const GenericContext *getGenericContext() const;
/// Generic requirement associated with the failure.
const Requirement &getRequirement() const;
Type getLHS() const { return LHS; }
Type getRHS() const { return RHS; }
bool diagnoseAsError() override;
bool diagnoseAsNote() override;
protected:
/// Determine whether this is a conditional requirement failure.
bool isConditional() const { return bool(Conformance); }
/// Check whether this requirement comes from the contextual type
/// that root expression is coerced/converted into.
bool isFromContextualType() const;
/// Retrieve declaration contextual where current
/// requirement has been introduced.
const DeclContext *getRequirementDC() const;
virtual DiagOnDecl getDiagnosticOnDecl() const = 0;
virtual DiagInReference getDiagnosticInRereference() const = 0;
virtual DiagAsNote getDiagnosticAsNote() const = 0;
static bool isOperator(const ApplyExpr *apply) {
return isa<PrefixUnaryExpr>(apply) || isa<PostfixUnaryExpr>(apply) ||
isa<BinaryExpr>(apply);
}
/// Determine whether given declaration represents a static
/// or instance property/method, excluding operators.
static bool isStaticOrInstanceMember(const ValueDecl *decl);
private:
/// Retrieve declaration associated with failing generic requirement.
ValueDecl *getDeclRef() const;
/// Retrieve generic signature where this parameter originates from.
GenericSignature getSignature(ConstraintLocator *locator);
void emitRequirementNote(const Decl *anchor, Type lhs, Type rhs) const;
/// If this is a failure in conditional requirement, retrieve
/// conformance information.
ProtocolConformance *
getConformanceForConditionalReq(ConstraintLocator *locator);
};
/// Diagnostics for failed conformance checks originating from
/// generic requirements e.g.
/// ```swift
/// struct S {}
/// func foo<T: Hashable>(_ t: T) {}
/// foo(S())
/// ```
class MissingConformanceFailure final : public RequirementFailure {
public:
MissingConformanceFailure(const Solution &solution,
ConstraintLocator *locator,
std::pair<Type, Type> conformance)
: RequirementFailure(solution, conformance.first, conformance.second,
locator) {
auto reqElt = locator->castLastElementTo<LocatorPathElt::AnyRequirement>();
assert(reqElt.getRequirementKind() == RequirementKind::Conformance ||
reqElt.getRequirementKind() == RequirementKind::Layout);
}
bool diagnoseAsError() override;
protected:
/// Check whether this requirement is associated with one of the
/// operator overloads, in cases like that sometimes it makes more
/// sense to produce a generic diagnostic about operator reference
/// instead of conformance, because it could be something like
/// `true + true`, and it doesn't make much sense to suggest to
/// add a conformance from one library type to another.
bool diagnoseAsAmbiguousOperatorRef();
DiagOnDecl getDiagnosticOnDecl() const override {
return (getRequirement().getKind() == RequirementKind::Layout ?
diag::type_does_not_conform_anyobject_decl_owner :
diag::type_does_not_conform_decl_owner);
}
DiagInReference getDiagnosticInRereference() const override {
return (getRequirement().getKind() == RequirementKind::Layout ?
diag::type_does_not_conform_anyobject_in_decl_ref :
diag::type_does_not_conform_in_decl_ref);
}
DiagAsNote getDiagnosticAsNote() const override {
return diag::candidate_types_conformance_requirement;
}
private:
bool diagnoseTypeCannotConform(Type nonConformingType,
Type protocolType) const;
};
/// Diagnose failures related to same-type generic requirements, e.g.
/// ```swift
/// protocol P {
/// associatedtype T
/// }
///
/// struct S : P {
/// typealias T = String
/// }
///
/// func foo<U: P>(_ t: [U]) where U.T == Int {}
/// foo([S()])
/// ```
///
/// `S.T` is not the same type as `Int`, which is required by `foo`.
class SameTypeRequirementFailure final : public RequirementFailure {
public:
SameTypeRequirementFailure(const Solution &solution, Type lhs, Type rhs,
ConstraintLocator *locator)
: RequirementFailure(solution, lhs, rhs, locator) {
auto reqElt = locator->castLastElementTo<LocatorPathElt::AnyRequirement>();
assert(reqElt.getRequirementKind() == RequirementKind::SameType);
}
protected:
DiagOnDecl getDiagnosticOnDecl() const override {
return diag::types_not_equal_decl;
}
DiagInReference getDiagnosticInRereference() const override {
return diag::types_not_equal_in_decl_ref;
}
DiagAsNote getDiagnosticAsNote() const override {
return diag::candidate_types_equal_requirement;
}
};
/// Diagnose failures related to superclass generic requirements, e.g.
/// ```swift
/// class A {
/// }
///
/// class B {
/// }
///
/// func foo<T>(_ t: [T]) where T: A {}
/// foo([B()])
/// ```
///
/// `A` is not the superclass of `B`, which is required by `foo<T>`.
class SuperclassRequirementFailure final : public RequirementFailure {
public:
SuperclassRequirementFailure(const Solution &solution, Type lhs, Type rhs,
ConstraintLocator *locator)
: RequirementFailure(solution, lhs, rhs, locator) {
auto reqElt = locator->castLastElementTo<LocatorPathElt::AnyRequirement>();
assert(reqElt.getRequirementKind() == RequirementKind::Superclass);
}
protected:
DiagOnDecl getDiagnosticOnDecl() const override {
return diag::types_not_inherited_decl;
}
DiagInReference getDiagnosticInRereference() const override {
return diag::types_not_inherited_in_decl_ref;
}
DiagAsNote getDiagnosticAsNote() const override {
return diag::candidate_types_inheritance_requirement;
}
};
/// Diagnose errors associated with missing, extraneous
/// or incorrect labels supplied by arguments, e.g.
/// ```swift
/// func foo(q: String, _ a: Int) {}
/// foo("ultimate quesiton", a: 42)
/// ```
/// Call to `foo` is going to be diagnosed as missing `q:`
/// and having extraneous `a:` labels, with appropriate fix-its added.
class LabelingFailure final : public FailureDiagnostic {
ArrayRef<Identifier> CorrectLabels;
public:
LabelingFailure(const Solution &solution, ConstraintLocator *locator,
ArrayRef<Identifier> labels)
: FailureDiagnostic(solution, locator), CorrectLabels(labels) {}
bool diagnoseAsError() override;
bool diagnoseAsNote() override;
};
/// Diagnose failures related to attempting member access on optional base
/// type without optional chaining or force-unwrapping it first.
class MemberAccessOnOptionalBaseFailure final : public FailureDiagnostic {
DeclNameRef Member;
Type MemberBaseType;
bool ResultTypeIsOptional;
public:
MemberAccessOnOptionalBaseFailure(const Solution &solution,
ConstraintLocator *locator,
DeclNameRef memberName,
Type memberBaseType,
bool resultOptional)
: FailureDiagnostic(solution, locator), Member(memberName),
MemberBaseType(resolveType(memberBaseType)),
ResultTypeIsOptional(resultOptional) {}
bool diagnoseAsError() override;
Type getMemberBaseType() const {
return MemberBaseType;
}
SourceLoc getLoc() const override {
// The end location points to the dot in the member access.
return getSourceRange().End;
}
SourceRange getSourceRange() const override;
};
/// Diagnose errors associated with rvalues in positions
/// where an lvalue is required, such as inout arguments.
class RValueTreatedAsLValueFailure final : public FailureDiagnostic {
public:
RValueTreatedAsLValueFailure(const Solution &solution,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {}
bool diagnoseAsError() override;
bool diagnoseAsNote() override;
};
class TrailingClosureAmbiguityFailure final : public FailureDiagnostic {
ArrayRef<OverloadChoice> Choices;
public:
TrailingClosureAmbiguityFailure(ArrayRef<Solution> solutions, ASTNode anchor,
ArrayRef<OverloadChoice> choices)
: FailureDiagnostic(solutions.front(), anchor), Choices(choices) {}
bool diagnoseAsError() override { return false; }
bool diagnoseAsNote() override;
};
/// Diagnose errors related to assignment expressions e.g.
/// trying to assign something to immutable value, or trying
/// to access mutating member on immutable base.
class AssignmentFailure final : public FailureDiagnostic {
Expr *DestExpr;
SourceLoc Loc;
Diag<StringRef> DeclDiagnostic;
Diag<Type> TypeDiagnostic;
public:
AssignmentFailure(Expr *destExpr, const Solution &solution,
SourceLoc diagnosticLoc);
AssignmentFailure(Expr *destExpr, const Solution &solution,
SourceLoc diagnosticLoc, Diag<StringRef> declDiag,
Diag<Type> typeDiag)
: FailureDiagnostic(solution, destExpr), DestExpr(destExpr),
Loc(diagnosticLoc), DeclDiagnostic(declDiag), TypeDiagnostic(typeDiag) {
}
bool diagnoseAsError() override;
private:
/// Given an expression that has a non-lvalue type, dig into it until
/// we find the part of the expression that prevents the entire subexpression
/// from being mutable. For example, in a sequence like "x.v.v = 42" we want
/// to complain about "x" being a let property if "v.v" are both mutable.
///
/// \returns The base subexpression that looks immutable (or that can't be
/// analyzed any further) along with an OverloadChoice extracted from it if we
/// could.
std::pair<Expr *, Optional<OverloadChoice>>
resolveImmutableBase(Expr *expr) const;
std::pair<Expr *, Optional<OverloadChoice>>
resolveImmutableBase(const Expr *expr) const {
return resolveImmutableBase(const_cast<Expr *>(expr));
}
static Diag<StringRef> findDeclDiagonstic(ASTContext &ctx,
const Expr *destExpr);
/// Retrive an member reference associated with given member
/// looking through dynamic member lookup on the way.
Optional<OverloadChoice> getMemberRef(ConstraintLocator *locator) const;
};
/// Intended to diagnose any possible contextual failure
/// e.g. argument/parameter, closure result, conversions etc.
class ContextualFailure : public FailureDiagnostic {
ContextualTypePurpose CTP;
Type RawFromType, RawToType;
public:
ContextualFailure(const Solution &solution, Type lhs, Type rhs,
ConstraintLocator *locator)
: ContextualFailure(
solution,
solution.getConstraintSystem().getContextualTypePurpose(
locator->getAnchor()),
lhs, rhs, locator) {}
ContextualFailure(const Solution &solution, ContextualTypePurpose purpose,
Type lhs, Type rhs, ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), CTP(purpose), RawFromType(lhs),
RawToType(rhs) {}
Type getFromType() const { return resolve(RawFromType); }
Type getToType() const { return resolve(RawToType); }
Type getRawFromType() const { return RawFromType; }
Type getRawToType() const { return RawToType; }
bool diagnoseAsError() override;
bool diagnoseAsNote() override;
/// If we're trying to convert something to `nil`.
bool diagnoseConversionToNil() const;
/// Diagnose failed conversion in a `CoerceExpr`.
bool diagnoseCoercionToUnrelatedType() const;
/// If we're trying to convert something of type "() -> T" to T,
/// then we probably meant to call the value.
bool diagnoseMissingFunctionCall() const;
/// Produce a specialized diagnostic if this is an invalid conversion to Bool.
bool diagnoseConversionToBool() const;
/// Produce a specialized diagnostic if this is an attempt to throw
/// something with doesn't conform to `Error`.
bool diagnoseThrowsTypeMismatch() const;
/// Produce a specialized diagnostic if this is an attempt to `yield`
/// something of incorrect type.
bool diagnoseYieldByReferenceMismatch() const;
/// Attempt to attach any relevant fix-its to already produced diagnostic.
void tryFixIts(InFlightDiagnostic &diagnostic) const;
/// Attempts to add fix-its for these two mistakes:
///
/// - Passing an integer with the right type but which is getting wrapped with
/// a different integer type unnecessarily. The fixit removes the cast.
///
/// - Passing an integer but expecting different integer type. The fixit adds
/// a wrapping cast.
///
/// - Return true on the fixit is added, false otherwise.
///
/// This helps migration with SDK changes.
bool tryIntegerCastFixIts(InFlightDiagnostic &diagnostic) const;
protected:
/// Try to add a fix-it when converting between a collection and its slice
/// type, such as String <-> Substring or (eventually) Array <-> ArraySlice
bool trySequenceSubsequenceFixIts(InFlightDiagnostic &diagnostic) const;
/// Try to add a fix-it that suggests to explicitly use `as` or `as!`
/// to coerce one type to another if type-checker can prove that such
/// conversion is possible.
bool tryTypeCoercionFixIt(InFlightDiagnostic &diagnostic) const;
/// Try to add a fix-it to conform the decl context (if it's a type) to the
/// protocol
bool tryProtocolConformanceFixIt(InFlightDiagnostic &diagnostic) const;
private:
Type resolve(Type rawType) const {
return resolveType(rawType)->getWithoutSpecifierType();
}
/// Try to add a fix-it to convert a stored property into a computed
/// property
void tryComputedPropertyFixIts() const;
bool isIntegerType(Type type) const {
return conformsToKnownProtocol(
type, KnownProtocolKind::ExpressibleByIntegerLiteral);
}
/// Return true if the conversion from fromType to toType is
/// an invalid string index operation.
bool isIntegerToStringIndexConversion() const;
protected:
ContextualTypePurpose getContextualTypePurpose() const { return CTP; }
static Optional<Diag<Type, Type>>
getDiagnosticFor(ContextualTypePurpose context, Type contextualType);
};
/// Diagnose errors related to using an array literal where a
/// dictionary is expected.
class ArrayLiteralToDictionaryConversionFailure final : public ContextualFailure {
public:
ArrayLiteralToDictionaryConversionFailure(const Solution &solution,
Type arrayTy, Type dictTy,
ConstraintLocator *locator)
: ContextualFailure(solution, arrayTy, dictTy, locator) {}
bool diagnoseAsError() override;
};
/// Diagnose errors related to converting function type which
/// isn't explicitly '@escaping' to some other type.
class NoEscapeFuncToTypeConversionFailure final : public ContextualFailure {
public:
NoEscapeFuncToTypeConversionFailure(const Solution &solution, Type fromType,
Type toType, ConstraintLocator *locator)
: ContextualFailure(solution, fromType, toType, locator) {}
bool diagnoseAsError() override;
private:
/// Emit tailored diagnostics for no-escape parameter conversions e.g.
/// passing such parameter as an @escaping argument, or trying to
/// assign it to a variable which expects @escaping function.
bool diagnoseParameterUse() const;
};
/// Diagnose failures related to use of the unwrapped optional types,
/// which require some type of force-unwrap e.g. "!" or "try!".
class MissingOptionalUnwrapFailure final : public ContextualFailure {
public:
MissingOptionalUnwrapFailure(const Solution &solution, Type fromType,
Type toType, ConstraintLocator *locator)
: ContextualFailure(solution, fromType, toType, locator) {}
bool diagnoseAsError() override;
private:
Type getBaseType() const {
return resolveType(getFromType(), /*reconstituteSugar=*/true);
}
Type getUnwrappedType() const {
return resolveType(getBaseType()->getOptionalObjectType(),
/*reconstituteSugar=*/true);
}
/// Suggest a default value via `?? <default value>`
void offerDefaultValueUnwrapFixIt(DeclContext *DC, const Expr *expr) const;
/// Suggest a force optional unwrap via `!`
void offerForceUnwrapFixIt(const Expr *expr) const;
};
/// Diagnostics for mismatched generic arguments e.g
/// ```swift
/// struct F<G> {}
/// let _:F<Int> = F<Bool>()
/// ```
class GenericArgumentsMismatchFailure final : public ContextualFailure {
ArrayRef<unsigned> Mismatches;
public:
GenericArgumentsMismatchFailure(const Solution &solution, Type actualType,
Type requiredType,
ArrayRef<unsigned> mismatches,
ConstraintLocator *locator)
: ContextualFailure(solution, actualType, requiredType, locator),
Mismatches(mismatches) {
assert(actualType->is<BoundGenericType>());
assert(requiredType->is<BoundGenericType>());
}
bool diagnoseAsError() override;
private:
void emitNotesForMismatches() {
for (unsigned position : Mismatches) {
emitNoteForMismatch(position);
}
}
void emitNoteForMismatch(int mismatchPosition);
Optional<Diag<Type, Type>> getDiagnosticFor(ContextualTypePurpose context);
/// The actual type being used.
BoundGenericType *getActual() const {
return getFromType()->castTo<BoundGenericType>();
}
/// The type needed by the generic requirement.
BoundGenericType *getRequired() const {
return getToType()->castTo<BoundGenericType>();
}
};
/// Diagnose failures related to conversion between throwing function type
/// and non-throwing one e.g.
///
/// ```swift
/// func foo<T>(_ t: T) throws -> Void {}
/// let _: (Int) -> Void = foo // `foo` can't be implictly converted to
/// // non-throwing type `(Int) -> Void`
/// ```
class ThrowingFunctionConversionFailure final : public ContextualFailure {
public:
ThrowingFunctionConversionFailure(const Solution &solution, Type fromType,
Type toType, ConstraintLocator *locator)
: ContextualFailure(solution, fromType, toType, locator) {
auto fnType1 = fromType->castTo<FunctionType>();
auto fnType2 = toType->castTo<FunctionType>();
assert(fnType1->isThrowing() != fnType2->isThrowing());
}
bool diagnoseAsError() override;
};
/// Diagnose failures related to conversion between 'async' function type
/// and a synchronous one e.g.
///
/// ```swift
/// func foo<T>(_ t: T) async -> Void {}
/// let _: (Int) -> Void = foo // `foo` can't be implictly converted to
/// // synchronous function type `(Int) -> Void`
/// ```
class AsyncFunctionConversionFailure final : public ContextualFailure {
public:
AsyncFunctionConversionFailure(const Solution &solution, Type fromType,
Type toType, ConstraintLocator *locator)
: ContextualFailure(solution, fromType, toType, locator) {
auto fnType1 = fromType->castTo<FunctionType>();
auto fnType2 = toType->castTo<FunctionType>();
assert(fnType1->isAsync() != fnType2->isAsync());
}
bool diagnoseAsError() override;
};
/// Diagnose failures related attempt to implicitly convert types which
/// do not support such implicit converstion.
/// "as" or "as!" has to be specified explicitly in cases like that.
class MissingExplicitConversionFailure final : public ContextualFailure {
public:
MissingExplicitConversionFailure(const Solution &solution, Type fromType,
Type toType, ConstraintLocator *locator)
: ContextualFailure(solution, fromType, toType, locator) {}
ASTNode getAnchor() const override;
bool diagnoseAsError() override;
private:
bool exprNeedsParensBeforeAddingAs(const Expr *expr) {
auto *DC = getDC();
auto asPG = TypeChecker::lookupPrecedenceGroup(
DC, DC->getASTContext().Id_CastingPrecedence, SourceLoc()).getSingle();
if (!asPG)
return true;
return exprNeedsParensInsideFollowingOperator(DC, const_cast<Expr *>(expr),
asPG);
}
bool exprNeedsParensAfterAddingAs(const Expr *expr, const Expr *rootExpr) {
auto *DC = getDC();
auto asPG = TypeChecker::lookupPrecedenceGroup(
DC, DC->getASTContext().Id_CastingPrecedence, SourceLoc()).getSingle();
if (!asPG)
return true;
return exprNeedsParensOutsideFollowingOperator(
DC, const_cast<Expr *>(expr), const_cast<Expr *>(rootExpr), asPG);
}
};
/// Diagnose failures related to passing value of some type
/// to `inout` or pointer parameter, without explicitly specifying `&`.
class MissingAddressOfFailure final : public ContextualFailure {
public:
MissingAddressOfFailure(const Solution &solution, Type argTy, Type paramTy,
ConstraintLocator *locator)
: ContextualFailure(solution, argTy, paramTy, locator) {}
bool diagnoseAsError() override;
};
/// Diagnose extraneous use of address of (`&`) which could only be
/// associated with arguments to inout parameters e.g.
///
/// ```swift
/// struct S {}
///
/// var a: S = ...
/// var b: S = ...
///
/// a = &b
/// ```
class InvalidUseOfAddressOf final : public ContextualFailure {
public:
InvalidUseOfAddressOf(const Solution &solution, Type lhs, Type rhs,
ConstraintLocator *locator)
: ContextualFailure(solution, lhs, rhs, locator) {}
bool diagnoseAsError() override;
protected:
/// Compute location of the failure for diagnostic.
SourceLoc getLoc() const override;
};
/// Diagnose mismatches relating to tuple destructuring.
class TupleContextualFailure final : public ContextualFailure {
/// Indices of the tuple elements whose types do not match.
llvm::SmallVector<unsigned, 4> Indices;
public:
TupleContextualFailure(const Solution &solution,
ContextualTypePurpose purpose, Type lhs, Type rhs,
llvm::ArrayRef<unsigned> indices,
ConstraintLocator *locator)
: ContextualFailure(solution, purpose, lhs, rhs, locator),
Indices(indices.begin(), indices.end()) {
std::sort(Indices.begin(), Indices.end());
assert(getFromType()->is<TupleType>() && getToType()->is<TupleType>());
}
bool diagnoseAsError() override;
bool isNumElementsMismatch() const {
auto lhsTy = getFromType()->castTo<TupleType>();
auto rhsTy = getToType()->castTo<TupleType>();
return lhsTy->getNumElements() != rhsTy->getNumElements();
}
};
class FunctionTypeMismatch final : public ContextualFailure {
/// Indices of the parameters whose types do not match.
llvm::SmallVector<unsigned, 4> Indices;
public:
FunctionTypeMismatch(const Solution &solution, ContextualTypePurpose purpose,
Type lhs, Type rhs, llvm::ArrayRef<unsigned> indices,
ConstraintLocator *locator)
: ContextualFailure(solution, purpose, lhs, rhs, locator),
Indices(indices.begin(), indices.end()) {
std::sort(Indices.begin(), Indices.end());
assert(getFromType()->is<AnyFunctionType>() && getToType()->is<AnyFunctionType>());
}
bool diagnoseAsError() override;
};
/// Diagnose situations when @autoclosure argument is passed to @autoclosure
/// parameter directly without calling it first.
class AutoClosureForwardingFailure final : public FailureDiagnostic {
public:
AutoClosureForwardingFailure(const Solution &solution,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {}
bool diagnoseAsError() override;
};
/// Diagnose invalid pointer conversions for an autoclosure result type.
///
/// \code
/// func foo(_ x: @autoclosure () -> UnsafePointer<Int>) {}
///
/// var i = 0
/// foo(&i) // Invalid conversion to UnsafePointer
/// \endcode
class AutoClosurePointerConversionFailure final : public ContextualFailure {
public:
AutoClosurePointerConversionFailure(const Solution &solution,
Type pointeeType, Type pointerType,
ConstraintLocator *locator)
: ContextualFailure(solution, pointeeType, pointerType, locator) {}
bool diagnoseAsError() override;
};
/// Diagnose situations when there was an attempt to unwrap entity
/// of non-optional type e.g.
///
/// ```swift
/// let i: Int = 0
/// _ = i!
///
/// struct A { func foo() {} }
/// func foo(_ a: A) {
/// a?.foo()
/// }
/// ```
class NonOptionalUnwrapFailure final : public FailureDiagnostic {
Type BaseType;
public:
NonOptionalUnwrapFailure(const Solution &solution, Type baseType,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), BaseType(baseType) {}
bool diagnoseAsError() override;
};
class MissingCallFailure final : public FailureDiagnostic {
public:
MissingCallFailure(const Solution &solution, ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {}
ASTNode getAnchor() const override;
bool diagnoseAsError() override;
};
class PropertyWrapperReferenceFailure : public ContextualFailure {
VarDecl *Property;
bool UsingProjection;
public:
PropertyWrapperReferenceFailure(const Solution &solution, VarDecl *property,
bool usingProjection, Type base,
Type wrapper, ConstraintLocator *locator)
: ContextualFailure(solution, base, wrapper, locator), Property(property),
UsingProjection(usingProjection) {}
VarDecl *getProperty() const { return Property; }
Identifier getPropertyName() const { return Property->getName(); }
bool usingProjection() const { return UsingProjection; }
ValueDecl *getReferencedMember() const {
auto *locator = getLocator();
if (auto overload = getOverloadChoiceIfAvailable(locator))
return overload->choice.getDeclOrNull();
return nullptr;
}
};
class ExtraneousPropertyWrapperUnwrapFailure final
: public PropertyWrapperReferenceFailure {
public:
ExtraneousPropertyWrapperUnwrapFailure(const Solution &solution,
VarDecl *property,
bool usingStorageWrapper, Type base,
Type wrapper,
ConstraintLocator *locator)
: PropertyWrapperReferenceFailure(solution, property, usingStorageWrapper,
base, wrapper, locator) {}
bool diagnoseAsError() override;
};
class MissingPropertyWrapperUnwrapFailure final
: public PropertyWrapperReferenceFailure {
public:
MissingPropertyWrapperUnwrapFailure(const Solution &solution,
VarDecl *property,
bool usingStorageWrapper, Type base,
Type wrapper, ConstraintLocator *locator)
: PropertyWrapperReferenceFailure(solution, property, usingStorageWrapper,
base, wrapper, locator) {}
bool diagnoseAsError() override;
};
class SubscriptMisuseFailure final : public FailureDiagnostic {
public:
SubscriptMisuseFailure(const Solution &solution, ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {}
bool diagnoseAsError() override;
bool diagnoseAsNote() override;
};
class InvalidMemberRefFailure : public FailureDiagnostic {
Type BaseType;
DeclNameRef Name;
public:
InvalidMemberRefFailure(const Solution &solution, Type baseType,
DeclNameRef memberName, ConstraintLocator *locator)
: FailureDiagnostic(solution, locator),
BaseType(baseType->getRValueType()), Name(memberName) {}
protected:
Type getBaseType() const { return BaseType; }
DeclNameRef getName() const { return Name; }
};
/// Diagnose situations when member referenced by name is missing
/// from the associated base type, e.g.
///
/// ```swift
/// struct S {}
/// func foo(_ s: S) {
/// let _: Int = s.foo(1, 2) // expected type is `(Int, Int) -> Int`
/// }
/// ```
class MissingMemberFailure : public InvalidMemberRefFailure {
public:
MissingMemberFailure(const Solution &solution, Type baseType,
DeclNameRef memberName, ConstraintLocator *locator)
: InvalidMemberRefFailure(solution, baseType, memberName, locator) {}
SourceLoc getLoc() const override {
// Diagnostic should point to the member instead of its base expression.
return constraints::getLoc(getRawAnchor());
}
bool diagnoseAsError() override;
private:
/// Tailored diagnostics for missing special `@dynamicCallable` methods
/// e.g. if caller expects `dynamicallyCall(withKeywordArguments:)`
/// overload to be present, but a class marked as `@dynamicCallable`
/// defines only `dynamicallyCall(withArguments:)` variant.
bool diagnoseForDynamicCallable() const;
/// Tailored diagnostics for collection literal with unresolved member expression
/// that defaults the element type. e.g. _ = [.e]
bool diagnoseInLiteralCollectionContext() const;
/// Tailored diagnostics for missing subscript member on a tuple base type.
/// e.g
/// ```swift
/// let tuple: (Int, Int) = (0, 0)
/// _ = tuple[0] // -> tuple.0.
/// ```
bool diagnoseForSubscriptMemberWithTupleBase() const;
static DeclName findCorrectEnumCaseName(Type Ty,
TypoCorrectionResults &corrections,
DeclNameRef memberName);
};
class UnintendedExtraGenericParamMemberFailure final
: public MissingMemberFailure {
Identifier ParamName;
public:
UnintendedExtraGenericParamMemberFailure(const Solution &solution,
Type baseType,
DeclNameRef memberName,
Identifier paramName,
ConstraintLocator *locator)
: MissingMemberFailure(solution, baseType, memberName, locator),
ParamName(paramName) {}
bool diagnoseAsError() override;
};
/// Diagnose cases where a member only accessible on generic constraints
/// requiring conformance to a protocol is used on a value of the
/// existential protocol type e.g.
///
/// ```swift
/// protocol P {
/// var foo: Self { get }
/// }
///
/// func bar<X : P>(p: X) {
/// p.foo
/// }
/// ```
class InvalidMemberRefOnExistential final : public InvalidMemberRefFailure {
public:
InvalidMemberRefOnExistential(const Solution &solution, Type baseType,
DeclNameRef memberName,
ConstraintLocator *locator)
: InvalidMemberRefFailure(solution, baseType, memberName, locator) {}
bool diagnoseAsError() override;
};
/// Diagnose situations when we use an instance member on a type
/// or a type member on an instance
///
/// ```swift
/// class Bar {}
///
/// enum Foo {
///
/// static func f() {
/// g(Bar())
/// }
///
/// func g(_: Bar) {}
///
/// }
/// ```
class AllowTypeOrInstanceMemberFailure final : public FailureDiagnostic {
Type BaseType;
ValueDecl *Member;
DeclNameRef Name;
public:
AllowTypeOrInstanceMemberFailure(const Solution &solution, Type baseType,
ValueDecl *member, DeclNameRef name,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator),
BaseType(baseType->getRValueType()), Member(member), Name(name) {
assert(member);
}
bool diagnoseAsError() override;
};
class PartialApplicationFailure final : public FailureDiagnostic {
enum RefKind : unsigned {
MutatingMethod,
SuperInit,
SelfInit,
SuperMethod,
};
bool CompatibilityWarning;
public:
PartialApplicationFailure(bool warning, const Solution &solution,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), CompatibilityWarning(warning) {}
bool diagnoseAsError() override;
};
class InvalidInitRefFailure : public FailureDiagnostic {
protected:
Type BaseType;
const ConstructorDecl *Init;
SourceRange BaseRange;
ASTNode getAnchor() const override { return getRawAnchor(); }
InvalidInitRefFailure(const Solution &solution, Type baseTy,
const ConstructorDecl *init, SourceRange baseRange,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), BaseType(baseTy), Init(init),
BaseRange(baseRange) {}
public:
bool diagnoseAsError() override = 0;
};
/// Diagnose an attempt to construct an object of class type with a metatype
/// value without using 'required' initializer:
///
/// ```swift
/// class C {
/// init(value: Int) {}
/// }
///
/// func make<T: C>(type: T.Type) -> T {
/// return T.init(value: 42)
/// }
/// ```
class InvalidDynamicInitOnMetatypeFailure final : public InvalidInitRefFailure {
public:
InvalidDynamicInitOnMetatypeFailure(const Solution &solution, Type baseTy,
const ConstructorDecl *init,
SourceRange baseRange,
ConstraintLocator *locator)
: InvalidInitRefFailure(solution, baseTy, init, baseRange, locator) {}
bool diagnoseAsError() override;
};
/// Diagnose an attempt to call initializer on protocol metatype:
///
/// ```swift
/// protocol P {
/// init(value: Int)
/// }
///
/// func make(type: P.Type) -> P {
/// return type.init(value: 42)
/// }
/// ```
class InitOnProtocolMetatypeFailure final : public InvalidInitRefFailure {
bool IsStaticallyDerived;
public:
InitOnProtocolMetatypeFailure(const Solution &solution, Type baseTy,
const ConstructorDecl *init,
bool isStaticallyDerived, SourceRange baseRange,
ConstraintLocator *locator)
: InvalidInitRefFailure(solution, baseTy, init, baseRange, locator),
IsStaticallyDerived(isStaticallyDerived) {}
bool diagnoseAsError() override;
};
/// Diagnose an attempt to construct an instance using non-constant
/// metatype base without explictly specifying `init`:
///
/// ```swift
/// let foo = Int.self
/// foo(0) // should be `foo.init(0)`
/// ```
class ImplicitInitOnNonConstMetatypeFailure final
: public InvalidInitRefFailure {
public:
ImplicitInitOnNonConstMetatypeFailure(const Solution &solution, Type baseTy,
const ConstructorDecl *init,
ConstraintLocator *locator)
: InvalidInitRefFailure(solution, baseTy, init, SourceRange(), locator) {}
SourceLoc getLoc() const override;
bool diagnoseAsError() override;
};
class MissingArgumentsFailure final : public FailureDiagnostic {
SmallVector<SynthesizedArg, 4> SynthesizedArgs;
public:
MissingArgumentsFailure(const Solution &solution,
ArrayRef<SynthesizedArg> synthesizedArgs,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator),
SynthesizedArgs(synthesizedArgs.begin(), synthesizedArgs.end()) {
assert(!SynthesizedArgs.empty() && "No missing arguments?!");
}
ASTNode getAnchor() const override;
bool diagnoseAsError() override;
bool diagnoseAsNote() override;
bool diagnoseSingleMissingArgument() const;
private:
/// If missing arguments come from a closure,
/// let's produce tailored diagnostics.
bool diagnoseClosure(const ClosureExpr *closure);
/// Diagnose cases when instead of multiple distinct arguments
/// call got a single tuple argument with expected arity/types.
bool diagnoseInvalidTupleDestructuring() const;
/// Determine whether missing arguments are associated with
/// an implicit call to a property wrapper initializer e.g.
/// `@Foo(answer: 42) var question = "ultimate question"`
bool isPropertyWrapperInitialization() const;
/// Gather information associated with expression that represents
/// a call - function, arguments, # of arguments and the position of
/// the first trailing closure.
std::tuple<Expr *, Expr *, unsigned, Optional<unsigned>>
getCallInfo(ASTNode anchor) const;
/// Transform given argument into format suitable for a fix-it
/// text e.g. `[<label>:]? <#<type#>`
void forFixIt(llvm::raw_svector_ostream &out,
const AnyFunctionType::Param &argument) const;
public:
/// Due to the fact that `matchCallArgument` can't and
/// doesn't take types into consideration while matching
/// arguments to parameters, for cases where both arguments
/// are un-labeled, it's impossible to say which one is missing:
///
/// func foo(_: Int, _: String) {}
/// foo("")
///
/// In this case first argument is missing, but we end up with
/// two fixes - argument mismatch (for #1) and missing argument
/// (for #2), which is incorrect so it has to be handled specially.
static bool isMisplacedMissingArgument(const Solution &solution,
ConstraintLocator *locator);
};
class ExtraneousArgumentsFailure final : public FailureDiagnostic {
FunctionType *ContextualType;
SmallVector<std::pair<unsigned, AnyFunctionType::Param>, 4> ExtraArgs;
public:
ExtraneousArgumentsFailure(
const Solution &solution, FunctionType *contextualType,
ArrayRef<std::pair<unsigned, AnyFunctionType::Param>> extraArgs,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator),
ContextualType(resolveType(contextualType)->castTo<FunctionType>()),
ExtraArgs(extraArgs.begin(), extraArgs.end()) {}
bool diagnoseAsError() override;
bool diagnoseAsNote() override;
private:
bool diagnoseSingleExtraArgument() const;
unsigned getTotalNumArguments() const {
return ContextualType->getNumParams() + ExtraArgs.size();
}
bool isContextualMismatch() const {
auto *locator = getLocator();
return locator->isLastElement<LocatorPathElt::ContextualType>() ||
locator->isLastElement<LocatorPathElt::ApplyArgToParam>();
}
};
class OutOfOrderArgumentFailure final : public FailureDiagnostic {
using ParamBinding = SmallVector<unsigned, 1>;
unsigned ArgIdx;
unsigned PrevArgIdx;
SmallVector<ParamBinding, 4> Bindings;
public:
OutOfOrderArgumentFailure(const Solution &solution, unsigned argIdx,
unsigned prevArgIdx,
ArrayRef<ParamBinding> bindings,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), ArgIdx(argIdx),
PrevArgIdx(prevArgIdx), Bindings(bindings.begin(), bindings.end()) {}
bool diagnoseAsError() override;
};
/// Diagnose an attempt to destructure a single tuple closure parameter
/// into a multiple (possibly anonymous) arguments e.g.
///
/// ```swift
/// let _: ((Int, Int)) -> Void = { $0 + $1 }
/// ```
class ClosureParamDestructuringFailure final : public FailureDiagnostic {
FunctionType *ContextualType;
public:
ClosureParamDestructuringFailure(const Solution &solution,
FunctionType *contextualType,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), ContextualType(contextualType) {}
SourceLoc getLoc() const override;
SourceRange getSourceRange() const override;
bool diagnoseAsError() override;
private:
Type getParameterType() const {
const auto &param = ContextualType->getParams().front();
return resolveType(param.getPlainType());
}
};
/// Diagnose an attempt to reference inaccessible member e.g.
///
/// ```swift
/// struct S {
/// var foo: String
///
/// private init(_ v: String) {
/// self.foo = v
/// }
/// }
/// _ = S("ultimate question")
/// ```
class InaccessibleMemberFailure final : public FailureDiagnostic {
ValueDecl *Member;
public:
InaccessibleMemberFailure(const Solution &solution, ValueDecl *member,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), Member(member) {}
bool diagnoseAsError() override;
};
/// Diagnose an attempt to reference member marked as `mutating`
/// on immutable base e.g. `let` variable:
///
/// ```swift
/// struct S {
/// mutating func foo(_ i: Int) {}
/// func foo(_ f: Float) {}
/// }
///
/// func bar(_ s: S, _ answer: Int) {
/// s.foo(answer)
/// }
/// ```
class MutatingMemberRefOnImmutableBase final : public FailureDiagnostic {
ValueDecl *Member;
public:
MutatingMemberRefOnImmutableBase(const Solution &solution, ValueDecl *member,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), Member(member) {}
bool diagnoseAsError() override;
};
/// Diagnose an attempt to use AnyObject as the root type of a KeyPath
///
/// ```swift
/// let keyPath = \AnyObject.bar
/// ```
class AnyObjectKeyPathRootFailure final : public FailureDiagnostic {
public:
AnyObjectKeyPathRootFailure(const Solution &solution,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {}
SourceLoc getLoc() const override;
SourceRange getSourceRange() const override;
bool diagnoseAsError() override;
};
/// Diagnose an attempt to reference subscript as a keypath component
/// where at least one of the index arguments doesn't conform to Hashable e.g.
///
/// ```swift
/// protocol P {}
///
/// struct S {
/// subscript<T: P>(x: Int, _ y: T) -> Bool { return true }
/// }
///
/// func foo<T: P>(_ x: Int, _ y: T) {
/// _ = \S.[x, y]
/// }
/// ```
class KeyPathSubscriptIndexHashableFailure final : public FailureDiagnostic {
Type NonConformingType;
public:
KeyPathSubscriptIndexHashableFailure(const Solution &solution, Type type,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), NonConformingType(type) {
assert(locator->isResultOfKeyPathDynamicMemberLookup() ||
locator->isKeyPathSubscriptComponent());
}
SourceLoc getLoc() const override;
bool diagnoseAsError() override;
};
class InvalidMemberRefInKeyPath : public FailureDiagnostic {
ValueDecl *Member;
public:
InvalidMemberRefInKeyPath(const Solution &solution, ValueDecl *member,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), Member(member) {
assert(member->hasName());
assert(locator->isForKeyPathComponent() ||
locator->isForKeyPathDynamicMemberLookup());
}
DescriptiveDeclKind getKind() const { return Member->getDescriptiveKind(); }
DeclName getName() const { return Member->getName(); }
bool diagnoseAsError() override = 0;
protected:
/// Compute location of the failure for diagnostic.
SourceLoc getLoc() const override;
bool isForKeyPathDynamicMemberLookup() const {
return getLocator()->isForKeyPathDynamicMemberLookup();
}
};
/// Diagnose an attempt to reference a static member as a key path component
/// e.g.
///
/// ```swift
/// struct S {
/// static var foo: Int = 42
/// }
///
/// _ = \S.Type.foo
/// ```
class InvalidStaticMemberRefInKeyPath final : public InvalidMemberRefInKeyPath {
public:
InvalidStaticMemberRefInKeyPath(const Solution &solution, ValueDecl *member,
ConstraintLocator *locator)
: InvalidMemberRefInKeyPath(solution, member, locator) {}
bool diagnoseAsError() override;
};
/// Diagnose an attempt to reference an enum case as a key path component
/// e.g.
///
/// ```swift
/// enum E {
/// case foo
/// }
///
/// _ = \E.Type.foo
/// ```
class InvalidEnumCaseRefInKeyPath final : public InvalidMemberRefInKeyPath {
public:
InvalidEnumCaseRefInKeyPath(const Solution &solution, ValueDecl *member,
ConstraintLocator *locator)
: InvalidMemberRefInKeyPath(solution, member, locator) {}
bool diagnoseAsError() override;
};
/// Diagnose an attempt to reference a member which has a mutating getter as a
/// key path component e.g.
///
/// ```swift
/// struct S {
/// var foo: Int {
/// mutating get { return 42 }
/// }
///
/// subscript(_: Int) -> Bool {
/// mutating get { return false }
/// }
/// }
///
/// _ = \S.foo
/// _ = \S.[42]
/// ```
class InvalidMemberWithMutatingGetterInKeyPath final
: public InvalidMemberRefInKeyPath {
public:
InvalidMemberWithMutatingGetterInKeyPath(const Solution &solution,
ValueDecl *member,
ConstraintLocator *locator)
: InvalidMemberRefInKeyPath(solution, member, locator) {}
bool diagnoseAsError() override;
};
/// Diagnose an attempt to reference a method or initializer as a key path component
/// e.g.
///
/// ```swift
/// struct S {
/// init() { }
/// func foo() -> Int { return 42 }
/// static func bar() -> Int { return 0 }
/// }
///
/// _ = \S.foo
/// _ = \S.Type.bar
/// _ = \S.init
/// ```
class InvalidMethodRefInKeyPath final : public InvalidMemberRefInKeyPath {
public:
InvalidMethodRefInKeyPath(const Solution &solution, ValueDecl *method,
ConstraintLocator *locator)
: InvalidMemberRefInKeyPath(solution, method, locator) {
assert(isa<FuncDecl>(method) || isa<ConstructorDecl>(method));
}
bool diagnoseAsError() override;
};
/// Diagnose an attempt return something from a function which
/// doesn't have a return type specified e.g.
///
/// ```swift
/// func foo() { return 42 }
/// ```
class ExtraneousReturnFailure final : public FailureDiagnostic {
public:
ExtraneousReturnFailure(const Solution &solution, ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {}
bool diagnoseAsError() override;
};
/// Diagnose a contextual mismatch between expected collection element type
/// and the one provided (e.g. source of the assignment or argument to a call)
/// e.g.:
///
/// ```swift
/// let _: [Int] = ["hello"]
/// ```
class CollectionElementContextualFailure final : public ContextualFailure {
public:
CollectionElementContextualFailure(const Solution &solution, Type eltType,
Type contextualType,
ConstraintLocator *locator)
: ContextualFailure(solution, eltType, contextualType, locator) {}
bool diagnoseAsError() override;
bool diagnoseMergedLiteralElements();
};
class MissingContextualConformanceFailure final : public ContextualFailure {
ContextualTypePurpose Context;
public:
MissingContextualConformanceFailure(const Solution &solution,
ContextualTypePurpose context, Type type,
Type protocolType,
ConstraintLocator *locator)
: ContextualFailure(solution, type, protocolType, locator),
Context(context) {
assert(protocolType->is<ProtocolType>() ||
protocolType->is<ProtocolCompositionType>());
}
bool diagnoseAsError() override;
};
/// Diagnose a conversion mismatch between object types of `inout`
/// argument/parameter e.g. `'inout S' argument conv 'inout P'`.
///
/// Even if `S` conforms to `P` there is no subtyping rule for
/// argument type of `inout` parameter, they have to be equal.
class InOutConversionFailure final : public ContextualFailure {
public:
InOutConversionFailure(const Solution &solution, Type argType, Type paramType,
ConstraintLocator *locator)
: ContextualFailure(solution, argType, paramType, locator) {}
bool diagnoseAsError() override;
protected:
/// Suggest to change a type of the argument if possible.
void fixItChangeArgumentType() const;
};
/// Diagnose generic argument omission e.g.
///
/// ```swift
/// struct S<T> {}
///
/// _ = S()
/// ```
class MissingGenericArgumentsFailure final : public FailureDiagnostic {
SmallVector<GenericTypeParamType *, 4> Parameters;
public:
MissingGenericArgumentsFailure(const Solution &solution,
ArrayRef<GenericTypeParamType *> missingParams,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {
assert(!missingParams.empty());
Parameters.append(missingParams.begin(), missingParams.end());
}
bool hasLoc(GenericTypeParamType *GP) const;
DeclContext *getDeclContext() const {
auto *GP = Parameters.front();
auto *decl = GP->getDecl();
return decl ? decl->getDeclContext() : nullptr;
}
bool diagnoseAsError() override;
bool diagnoseForAnchor(ASTNode anchor,
ArrayRef<GenericTypeParamType *> params) const;
bool diagnoseParameter(ASTNode anchor, GenericTypeParamType *GP) const;
private:
void emitGenericSignatureNote(ASTNode anchor) const;
/// Retrieve representative locations for associated generic prameters.
///
/// \returns true if all of the parameters have been covered.
bool findArgumentLocations(
llvm::function_ref<void(TypeRepr *, GenericTypeParamType *)> callback);
};
class SkipUnhandledConstructInResultBuilderFailure final
: public FailureDiagnostic {
public:
using UnhandledNode = llvm::PointerUnion<Stmt *, Decl *>;
UnhandledNode unhandled;
NominalTypeDecl *builder;
void diagnosePrimary(bool asNote);
public:
SkipUnhandledConstructInResultBuilderFailure(const Solution &solution,
UnhandledNode unhandled,
NominalTypeDecl *builder,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), unhandled(unhandled),
builder(builder) {}
SourceLoc getLoc() const override;
bool diagnoseAsError() override;
bool diagnoseAsNote() override;
};
/// Diagnose situation when a single "tuple" parameter is given N arguments e.g.
///
/// ```swift
/// func foo<T>(_ x: (T, Bool)) {}
/// foo(1, false) // foo exptects a single argument of tuple type `(1, false)`
/// ```
class InvalidTupleSplatWithSingleParameterFailure final
: public FailureDiagnostic {
Type ParamType;
public:
InvalidTupleSplatWithSingleParameterFailure(const Solution &solution,
Type paramTy,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), ParamType(paramTy) {}
bool diagnoseAsError() override;
};
/// Diagnose situation when an array is passed instead of varargs.
///
/// ```swift
/// func foo(_ x: Int...) {}
/// foo([1,2,3]]) // foo expects varags like foo(1,2,3) instead.
/// ```
class ExpandArrayIntoVarargsFailure final : public ContextualFailure {
public:
ExpandArrayIntoVarargsFailure(const Solution &solution, Type lhs, Type rhs,
ConstraintLocator *locator)
: ContextualFailure(solution, lhs, rhs, locator) {}
bool diagnoseAsError() override;
bool diagnoseAsNote() override;
void tryDropArrayBracketsFixIt(const Expr *anchor) const;
};
/// Diagnose a situation there is a mismatch between argument and parameter
/// types e.g.:
///
/// ```swift
/// func foo(_: String) {}
/// func bar(_ v: Int) { foo(v) } // `Int` is not convertible to `String`
/// ```
class ArgumentMismatchFailure : public ContextualFailure {
FunctionArgApplyInfo Info;
public:
ArgumentMismatchFailure(const Solution &solution, Type argType,
Type paramType, ConstraintLocator *locator)
: ContextualFailure(solution, argType, paramType, locator),
Info(*getFunctionArgApplyInfo(getLocator())) {}
bool diagnoseAsError() override;
bool diagnoseAsNote() override;
/// If both argument and parameter are represented by `ArchetypeType`
/// produce a special diagnostic in case their names match.
bool diagnoseArchetypeMismatch() const;
/// Tailored diagnostic for pattern matching with `~=` operator.
bool diagnosePatternMatchingMismatch() const;
/// Tailored diagnostics for argument mismatches associated with
/// reference equality operators `===` and `!==`.
bool diagnoseUseOfReferenceEqualityOperator() const;
/// Tailored diagnostics for type mismatches associated with
/// property wrapper initialization via implicit `init(wrappedValue:)`
/// or now deprecated `init(initialValue:)`.
bool diagnosePropertyWrapperMismatch() const;
/// Tailored diagnostics for argument mismatches associated with trailing
/// closures being passed to non-closure parameters.
bool diagnoseTrailingClosureMismatch() const;
protected:
/// \returns The position of the argument being diagnosed, starting at 1.
unsigned getArgPosition() const { return Info.getArgPosition(); }
/// \returns The position of the parameter being diagnosed, starting at 1.
unsigned getParamPosition() const { return Info.getParamPosition(); }
/// Returns the argument expression being diagnosed.
///
/// Note this may differ from \c getAnchor(), which will return a smaller
/// sub-expression if the failed constraint is for a sub-expression within
/// an argument. For example, in an argument conversion from (T, U) to (U, U),
/// the conversion from T to U may fail. In this case, \c getArgExpr() will
/// return the (T, U) expression, whereas \c getAnchor() will return the T
/// expression.
Expr *getArgExpr() const { return Info.getArgExpr(); }
/// Returns the argument type for the conversion being diagnosed.
///
/// \param withSpecifier Whether to keep the inout or @lvalue specifier of
/// the argument, if any.
///
/// Note this may differ from \c getFromType(), which will give the source
/// type of a failed constraint for the argument conversion. For example in
/// an argument conversion from T? to U?, the conversion from T to U may fail.
/// In this case, \c getArgType() will return T?, whereas \c getFromType()
/// will return T.
Type getArgType(bool withSpecifier = false) const {
return Info.getArgType(withSpecifier);
}
/// \returns A textual description of the argument suitable for diagnostics.
/// For an argument with an unambiguous label, this will the label. Otherwise
/// it will be its position in the argument list.
StringRef getArgDescription(SmallVectorImpl<char> &scratch) const {
return Info.getArgDescription(scratch);
}
/// \returns The interface type for the function being applied.
Type getFnInterfaceType() const { return Info.getFnInterfaceType(); }
/// \returns The function type being applied, including any generic
/// substitutions.
FunctionType *getFnType() const { return Info.getFnType(); }
/// \returns The callee for the argument conversion, if any.
const ValueDecl *getCallee() const { return Info.getCallee(); }
/// \returns The full name of the callee, or a null decl name if there is no
/// callee.
DeclName getCalleeFullName() const {
return getCallee() ? getCallee()->getName() : DeclName();
}
/// Returns the type of the parameter involved in the mismatch, including any
/// generic substitutions.
///
/// \param lookThroughAutoclosure Whether an @autoclosure () -> T parameter
/// should be treated as being of type T.
///
/// Note this may differ from \c getToType(), see the note on \c getArgType().
Type getParamType(bool lookThroughAutoclosure = true) const {
return Info.getParamType(lookThroughAutoclosure);
}
/// Returns the type of the parameter involved in the mismatch.
///
/// \param lookThroughAutoclosure Whether an @autoclosure () -> T parameter
/// should be treated as being of type T.
///
/// Note this may differ from \c getToType(), see the note on \c getArgType().
Type getParamInterfaceType(bool lookThroughAutoclosure = true) const {
return Info.getParamInterfaceType(lookThroughAutoclosure);
}
/// \returns The flags of the parameter involved in the mismatch.
ParameterTypeFlags getParameterFlags() const {
return Info.getParameterFlags();
}
/// \returns The flags of a parameter at a given index.
ParameterTypeFlags getParameterFlagsAtIndex(unsigned idx) const {
return Info.getParameterFlagsAtIndex(idx);
}
/// Situations like this:
///
/// func foo(_: Int, _: String) {}
/// foo("")
///
/// Are currently impossible to fix correctly,
/// so we have to attend to that in diagnostics.
bool diagnoseMisplacedMissingArgument() const;
};
/// Replace a coercion ('as') with a runtime checked cast ('as!' or 'as?').
class InvalidCoercionFailure final : public ContextualFailure {
bool UseConditionalCast;
public:
InvalidCoercionFailure(const Solution &solution, Type fromType, Type toType,
bool useConditionalCast, ConstraintLocator *locator)
: ContextualFailure(solution, fromType, toType, locator),
UseConditionalCast(useConditionalCast) {}
ASTNode getAnchor() const override;
bool diagnoseAsError() override;
};
class ExtraneousCallFailure final : public FailureDiagnostic {
public:
ExtraneousCallFailure(const Solution &solution, ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {}
bool diagnoseAsError() override;
};
class InvalidUseOfTrailingClosure final : public ArgumentMismatchFailure {
public:
InvalidUseOfTrailingClosure(const Solution &solution, Type argType,
Type paramType, ConstraintLocator *locator)
: ArgumentMismatchFailure(solution, argType, paramType, locator) {}
bool diagnoseAsError() override;
};
/// Diagnose the invalid conversion of a temporary pointer argument generated
/// from an X-to-pointer conversion to an @_nonEphemeral parameter.
///
/// ```swift
/// func foo(@_nonEphemeral _ ptr: UnsafePointer<Int>) {}
///
/// foo([1, 2, 3])
/// ```
class NonEphemeralConversionFailure final : public ArgumentMismatchFailure {
ConversionRestrictionKind ConversionKind;
bool DowngradeToWarning;
public:
NonEphemeralConversionFailure(const Solution &solution,
ConstraintLocator *locator, Type fromType,
Type toType,
ConversionRestrictionKind conversionKind,
bool downgradeToWarning)
: ArgumentMismatchFailure(solution, fromType, toType, locator),
ConversionKind(conversionKind), DowngradeToWarning(downgradeToWarning) {
}
bool diagnoseAsError() override;
bool diagnoseAsNote() override;
private:
/// Attempts to emit a specialized diagnostic for
/// Unsafe[Mutable][Raw]Pointer.init([mutating]:) &
/// Unsafe[Mutable][Raw]BufferPointer.init(start:count:).
bool diagnosePointerInit() const;
/// Emits a note explaining to the user that an ephemeral conversion is only
/// valid for the duration of the call, and suggests an alternative to use.
void emitSuggestionNotes() const;
};
class AssignmentTypeMismatchFailure final : public ContextualFailure {
public:
AssignmentTypeMismatchFailure(const Solution &solution,
ContextualTypePurpose context, Type srcType,
Type dstType, ConstraintLocator *locator)
: ContextualFailure(solution, context, srcType, dstType, locator) {}
bool diagnoseAsError() override;
bool diagnoseAsNote() override;
private:
bool diagnoseMissingConformance() const;
};
class MissingContextualBaseInMemberRefFailure final : public FailureDiagnostic {
DeclNameRef MemberName;
public:
MissingContextualBaseInMemberRefFailure(const Solution &solution,
DeclNameRef member,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), MemberName(member) {}
bool diagnoseAsError() override;
};
class UnableToInferClosureParameterType final : public FailureDiagnostic {
public:
UnableToInferClosureParameterType(const Solution &solution,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {}
bool diagnoseAsError() override;
};
class UnableToInferClosureReturnType final : public FailureDiagnostic {
public:
UnableToInferClosureReturnType(const Solution &solution,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {}
bool diagnoseAsError() override;
};
class UnableToInferProtocolLiteralType final : public FailureDiagnostic {
public:
UnableToInferProtocolLiteralType(const Solution &solution,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {}
SourceLoc getLoc() const override;
bool diagnoseAsError() override;
};
/// Diagnose an attempt to reference a top-level name shadowed by a local
/// member e.g.
///
/// ```swift
/// extension Sequence {
/// func test() -> Int {
/// return max(1, 2)
/// }
/// }
/// ```
///
/// Here `max` refers to a global function `max<T>(_: T, _: T)` in `Swift`
/// module and can only be accessed by adding `Swift.` to it, because `Sequence`
/// has a member named `max` which accepts a single argument.
class MissingQuialifierInMemberRefFailure final : public FailureDiagnostic {
public:
MissingQuialifierInMemberRefFailure(const Solution &solution,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {}
bool diagnoseAsError() override;
};
/// Emits a warning about an attempt to use the 'as' operator as the 'as!'
/// operator.
class CoercionAsForceCastFailure final : public ContextualFailure {
public:
CoercionAsForceCastFailure(const Solution &solution, Type fromType,
Type toType, ConstraintLocator *locator)
: ContextualFailure(solution, fromType, toType, locator) {}
bool diagnoseAsError() override;
};
/// Diagnose a key path root type that cannot be applied to an instance
/// base that has another type.
///
/// \code
/// func f(_ bar: Bar , keyPath: KeyPath<Foo, Int> ) {
/// bar[keyPath: keyPath]
/// }
/// \endcode
class KeyPathRootTypeMismatchFailure final : public ContextualFailure {
public:
KeyPathRootTypeMismatchFailure(const Solution &solution, Type lhs, Type rhs,
ConstraintLocator *locator)
: ContextualFailure(solution, lhs, rhs, locator) {}
bool diagnoseAsError() override;
};
/// Diagnose an attempt to use a KeyPath where a multi-argument function is expected
///
/// ```swift
/// [Item].sorted(\Item.name)
/// ```
class MultiArgFuncKeyPathFailure final : public FailureDiagnostic {
Type functionType;
public:
MultiArgFuncKeyPathFailure(const Solution &solution, Type functionType,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator),
functionType(functionType) {}
bool diagnoseAsError() override;
};
/// Diagnose a failure to infer a KeyPath type by context.
///
/// ```swift
/// _ = \.x
/// let _ : AnyKeyPath = \.x
/// ```
class UnableToInferKeyPathRootFailure final : public FailureDiagnostic {
public:
UnableToInferKeyPathRootFailure(const Solution &solution,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {}
bool diagnoseAsError() override;
};
class AbstractRawRepresentableFailure : public FailureDiagnostic {
protected:
Type RawReprType;
Type ExpectedType;
AbstractRawRepresentableFailure(const Solution &solution, Type rawReprType,
Type expectedType, ConstraintLocator *locator)
: FailureDiagnostic(solution, locator),
RawReprType(resolveType(rawReprType)),
ExpectedType(resolveType(expectedType)) {}
public:
virtual Type getFromType() const = 0;
virtual Type getToType() const = 0;
bool diagnoseAsError() override;
bool diagnoseAsNote() override;
protected:
Optional<Diag<Type, Type>> getDiagnostic() const;
virtual void fixIt(InFlightDiagnostic &diagnostic) const = 0;
};
/// Diagnose an attempt to initialize raw representable type or convert to it
/// a value of some other type that matches its `RawValue` type.
///
/// ```swift
/// enum E : Int {
/// case a, b, c
/// }
///
/// let _: E = 0
/// ```
///
/// `0` has to be wrapped into `E(rawValue: 0)` and either defaulted via `??` or
/// force unwrapped to constitute a valid binding.
class MissingRawRepresentableInitFailure final
: public AbstractRawRepresentableFailure {
public:
MissingRawRepresentableInitFailure(const Solution &solution, Type rawReprType,
Type expectedType,
ConstraintLocator *locator)
: AbstractRawRepresentableFailure(solution, rawReprType, expectedType,
locator) {}
Type getFromType() const override { return ExpectedType; }
Type getToType() const override { return RawReprType; }
protected:
void fixIt(InFlightDiagnostic &diagnostic) const override;
};
/// Diagnose an attempt to pass raw representable type where its raw value
/// is expected instead.
///
/// ```swift
/// enum E : Int {
/// case one = 1
/// }
///
/// let _: Int = E.one
/// ```
///
/// `E.one` has to use `.rawValue` to match `Int` expected by pattern binding.
class MissingRawValueFailure final : public AbstractRawRepresentableFailure {
public:
MissingRawValueFailure(const Solution &solution, Type rawReprType,
Type expectedType, ConstraintLocator *locator)
: AbstractRawRepresentableFailure(solution, rawReprType, expectedType,
locator) {}
Type getFromType() const override { return RawReprType; }
Type getToType() const override { return ExpectedType; }
private:
void fixIt(InFlightDiagnostic &diagnostic) const override;
};
/// Diagnose a key path optional base that should be unwraped in order to
/// apply key path subscript.
///
/// \code
/// func f(_ bar: Bar? , keyPath: KeyPath<Bar, Int>) {
/// bar[keyPath: keyPath]
/// }
/// \endcode
class MissingOptionalUnwrapKeyPathFailure final : public ContextualFailure {
public:
MissingOptionalUnwrapKeyPathFailure(const Solution &solution, Type lhs,
Type rhs, ConstraintLocator *locator)
: ContextualFailure(solution, lhs, rhs, locator) {}
bool diagnoseAsError() override;
SourceLoc getLoc() const override;
};
/// Diagnose situations when trailing closure has been matched to a specific
/// parameter via a deprecated backward scan.
///
/// \code
/// func multiple_trailing_with_defaults(
/// duration: Int,
/// animations: (() -> Void)? = nil,
/// completion: (() -> Void)? = nil) {}
///
/// multiple_trailing_with_defaults(duration: 42) {} // picks `completion:`
/// \endcode
class TrailingClosureRequiresExplicitLabel final : public FailureDiagnostic {
public:
TrailingClosureRequiresExplicitLabel(const Solution &solution,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {}
bool diagnoseAsError() override;
private:
void fixIt(InFlightDiagnostic &diagnostic,
const FunctionArgApplyInfo &info) const;
};
/// Diagnose situations where we have a key path with no components.
///
/// \code
/// let _ : KeyPath<A, B> = \A
/// \endcode
class InvalidEmptyKeyPathFailure final : public FailureDiagnostic {
public:
InvalidEmptyKeyPathFailure(const Solution &solution,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {}
bool diagnoseAsError() override;
};
/// Diagnose situations where there is no context to determine a
/// type of `nil` literal e.g.
///
/// \code
/// let _ = nil
/// let _ = try nil
/// let _ = nil!
/// \endcode
class MissingContextualTypeForNil final : public FailureDiagnostic {
public:
MissingContextualTypeForNil(const Solution &solution,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {}
bool diagnoseAsError() override;
};
/// Diagnostic situations where AST node references an invalid declaration.
///
/// \code
/// let foo = doesntExist // or something invalid
/// foo(42)
/// \endcode
class ReferenceToInvalidDeclaration final : public FailureDiagnostic {
public:
ReferenceToInvalidDeclaration(const Solution &solution,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {}
bool diagnoseAsError() override;
};
/// Diagnose use of `return` statements in a body of a result builder.
///
/// \code
/// struct S : Builder {
/// var foo: some Builder {
/// return EmptyBuilder()
/// }
/// }
/// \endcode
class InvalidReturnInResultBuilderBody final : public FailureDiagnostic {
Type BuilderType;
public:
InvalidReturnInResultBuilderBody(const Solution &solution, Type builderTy,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), BuilderType(builderTy) {}
bool diagnoseAsError() override;
};
/// 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_name} or an unresolved `.none` inferred as a static
/// non-optional member base but could be an Optional<T>.none. So we enforce
/// explicit type annotation to avoid ambiguity.
///
/// \code
/// enum Enum<T> {
/// case bar
/// static var none: Enum<Int> { .bar }
/// }
/// let _: Enum<Int>? = .none // Base inferred as Optional.none, suggest
/// // explicit type.
/// let _: Enum? = .none // Base inferred as static member Enum<Int>.none,
/// // emit warning suggesting explicit type.
/// let _: Enum = .none // Ok
/// \endcode
class MemberMissingExplicitBaseTypeFailure final : public FailureDiagnostic {
DeclNameRef Member;
public:
MemberMissingExplicitBaseTypeFailure(const Solution &solution,
DeclNameRef member,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), Member(member) {}
bool diagnoseAsError() override;
};
} // end namespace constraints
} // end namespace swift
#endif // SWIFT_SEMA_CSDIAGNOSTICS_H