//===--- CSFix.cpp - 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 implements the \c ConstraintFix class and its related types, // which is used by constraint solver to attempt to fix constraints to be // able to produce a solution which is easily diagnosable. // //===----------------------------------------------------------------------===// #include "CSDiagnostics.h" #include "TypeCheckConcurrency.h" #include "swift/AST/ConformanceLookup.h" #include "swift/AST/Expr.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Type.h" #include "swift/AST/Types.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/RequirementSignature.h" #include "swift/Basic/Assertions.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/Version.h" #include "swift/Sema/ConstraintLocator.h" #include "swift/Sema/ConstraintSystem.h" #include "swift/Sema/CSFix.h" #include "swift/Sema/OverloadChoice.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" #include using namespace swift; using namespace constraints; ConstraintFix::~ConstraintFix() {} std::optional ConstraintFix::impact() const { switch (fixBehavior) { case FixBehavior::AlwaysWarning: return std::nullopt; case FixBehavior::Error: return SK_Fix; case FixBehavior::DowngradeToWarning: return SK_DisfavoredOverload; case FixBehavior::Suppress: return std::nullopt; } } ASTNode ConstraintFix::getAnchor() const { return getLocator()->getAnchor(); } void ConstraintFix::print(llvm::raw_ostream &Out) const { Out << "[fix: "; Out << getName(); Out << ']'; Out << " @ "; getLocator()->dump(&CS.getASTContext().SourceMgr, Out); } void ConstraintFix::dump() const {print(llvm::errs()); } std::string ForceDowncast::getName() const { llvm::SmallString<16> name; name += "force downcast ("; name += getFromType()->getString(); name += " as! "; name += getToType()->getString(); name += ")"; return name.c_str(); } bool ForceDowncast::diagnose(const Solution &solution, bool asNote) const { MissingExplicitConversionFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } ForceDowncast *ForceDowncast::create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator) { return new (cs.getAllocator()) ForceDowncast(cs, fromType, toType, locator); } bool ForceOptional::diagnose(const Solution &solution, bool asNote) const { MissingOptionalUnwrapFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } ForceOptional *ForceOptional::create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator) { return new (cs.getAllocator()) ForceOptional(cs, fromType, toType, locator); } bool UnwrapOptionalBase::diagnose(const Solution &solution, bool asNote) const { bool resultIsOptional = getKind() == FixKind::UnwrapOptionalBaseWithOptionalResult; MemberAccessOnOptionalBaseFailure failure(solution, getLocator(), MemberName, MemberBaseType, resultIsOptional); return failure.diagnose(asNote); } UnwrapOptionalBase *UnwrapOptionalBase::create(ConstraintSystem &cs, DeclNameRef member, Type memberBaseType, ConstraintLocator *locator) { return new (cs.getAllocator()) UnwrapOptionalBase( cs, FixKind::UnwrapOptionalBase, member, memberBaseType, locator); } UnwrapOptionalBase *UnwrapOptionalBase::createWithOptionalResult( ConstraintSystem &cs, DeclNameRef member, Type memberBaseType, ConstraintLocator *locator) { return new (cs.getAllocator()) UnwrapOptionalBase(cs, FixKind::UnwrapOptionalBaseWithOptionalResult, member, memberBaseType, locator); } bool AddAddressOf::diagnose(const Solution &solution, bool asNote) const { MissingAddressOfFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } AddAddressOf *AddAddressOf::create(ConstraintSystem &cs, Type argTy, Type paramTy, ConstraintLocator *locator) { return new (cs.getAllocator()) AddAddressOf(cs, argTy, paramTy, locator); } bool TreatRValueAsLValue::diagnose(const Solution &solution, bool asNote) const { RValueTreatedAsLValueFailure failure(solution, getLocator()); return failure.diagnose(asNote); } unsigned TreatRValueAsLValue::assessImpact(ConstraintSystem &cs, ConstraintLocator *atLoc) { // Results of calls can never be l-value. unsigned impact = isExpr(atLoc->getAnchor()) ? 2 : 1; // An overload choice that isn't settable is least interesting for // diagnosis. auto *calleeLoc = cs.getCalleeLocator(atLoc, /*lookThroughApply=*/false); if (auto overload = cs.findSelectedOverloadFor(calleeLoc)) { if (auto *var = dyn_cast_or_null( overload->choice.getDeclOrNull())) { impact += !var->isSettableInSwift(cs.DC) ? 1 : 0; } else { impact += 1; } } // This is extra impactful if location has other issues. if (cs.hasFixFor(atLoc) || cs.hasFixFor(calleeLoc)) impact += 2; return impact; } TreatRValueAsLValue *TreatRValueAsLValue::create(ConstraintSystem &cs, ConstraintLocator *locator) { if (locator->isLastElement()) locator = cs.getConstraintLocator( locator, LocatorPathElt::ArgumentAttribute::forInOut()); return new (cs.getAllocator()) TreatRValueAsLValue(cs, locator); } bool CoerceToCheckedCast::diagnose(const Solution &solution, bool asNote) const { InvalidCoercionFailure failure(solution, getFromType(), getToType(), UseConditionalCast, getLocator()); return failure.diagnose(asNote); } CoerceToCheckedCast *CoerceToCheckedCast::attempt(ConstraintSystem &cs, Type fromType, Type toType, bool useConditionalCast, ConstraintLocator *locator) { // If any of the types have type variables or placeholders, don't add the fix. // `typeCheckCheckedCast` doesn't support checking such types. if (fromType->hasTypeVariableOrPlaceholder() || toType->hasTypeVariableOrPlaceholder()) { return nullptr; } auto anchor = locator->getAnchor(); if (auto *assignExpr = getAsExpr(anchor)) anchor = assignExpr->getSrc(); auto *coerceExpr = getAsExpr(anchor); if (!coerceExpr) return nullptr; const auto castKind = TypeChecker::typeCheckCheckedCast( fromType, toType, CheckedCastContextKind::Coercion, cs.DC); // Invalid cast. if (castKind == CheckedCastKind::Unresolved) return nullptr; return new (cs.getAllocator()) CoerceToCheckedCast(cs, fromType, toType, useConditionalCast, locator); } bool TreatArrayLiteralAsDictionary::diagnose(const Solution &solution, bool asNote) const { ArrayLiteralToDictionaryConversionFailure failure(solution, getToType(), getFromType(), getLocator()); return failure.diagnose(asNote); } TreatArrayLiteralAsDictionary * TreatArrayLiteralAsDictionary::attempt(ConstraintSystem &cs, Type dictionaryTy, Type arrayTy, ConstraintLocator *locator) { if (!arrayTy->isArray()) return nullptr; // Determine the ArrayExpr from the locator. auto *expr = getAsExpr(simplifyLocatorToAnchor(locator)); if (!expr) return nullptr; if (auto *AE = dyn_cast(expr)) expr = AE->getSrc(); auto *arrayExpr = dyn_cast(expr); if (!arrayExpr) return nullptr; // This fix only applies if the array is used as a dictionary. auto unwrappedDict = dictionaryTy->lookThroughAllOptionalTypes(); if (unwrappedDict->isTypeVariableOrMember()) return nullptr; auto &ctx = cs.getASTContext(); if (auto *proto = ctx.getProtocol(KnownProtocolKind::ExpressibleByDictionaryLiteral)) if (!lookupConformance(unwrappedDict, proto)) return nullptr; auto arrayLoc = cs.getConstraintLocator(arrayExpr); return new (cs.getAllocator()) TreatArrayLiteralAsDictionary(cs, dictionaryTy, arrayTy, arrayLoc); } bool MarkExplicitlyEscaping::diagnose(const Solution &solution, bool asNote) const { AttributedFuncToTypeConversionFailure failure( solution, getFromType(), getToType(), getLocator(), AttributedFuncToTypeConversionFailure::Escaping); return failure.diagnose(asNote); } MarkExplicitlyEscaping * MarkExplicitlyEscaping::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) { if (locator->isLastElement()) locator = cs.getConstraintLocator( locator, LocatorPathElt::ArgumentAttribute::forEscaping()); return new (cs.getAllocator()) MarkExplicitlyEscaping(cs, lhs, rhs, locator); } bool MarkGlobalActorFunction::diagnose(const Solution &solution, bool asNote) const { DroppedGlobalActorFunctionAttr failure( solution, getFromType(), getToType(), getLocator(), fixBehavior); return failure.diagnose(asNote); } /// The fix behavior to apply to a concurrency-related diagnostic. static std::optional getConcurrencyFixBehavior(ConstraintSystem &cs, ConstraintKind constraintKind, ConstraintLocatorBuilder locator, bool forSendable) { // We can only handle the downgrade for conversions. switch (constraintKind) { case ConstraintKind::Conversion: case ConstraintKind::Subtype: break; case ConstraintKind::ArgumentConversion: { if (!forSendable) break; // Passing a static member reference as an argument needs to be downgraded // to a warning until future major mode to maintain source compatibility for // code with non-Sendable metatypes. if (!cs.getASTContext().LangOpts.isSwiftVersionAtLeast(7)) { auto *argLoc = cs.getConstraintLocator(locator); if (auto *argument = getAsExpr(simplifyLocatorToAnchor(argLoc))) { if (auto overload = cs.findSelectedOverloadFor( argument->getSemanticsProvidingExpr())) { auto *decl = overload->choice.getDeclOrNull(); if (decl && decl->isStatic()) return FixBehavior::DowngradeToWarning; } } } break; } default: if (!cs.shouldAttemptFixes()) return std::nullopt; return FixBehavior::Error; } // For a @preconcurrency callee outside of a strict concurrency // context, ignore. if (cs.hasPreconcurrencyCallee(locator)) { // Preconcurrency failures are always downgraded to warnings, even in // Swift 6 mode. if (contextRequiresStrictConcurrencyChecking( cs.DC, GetClosureType{cs}, ClosureIsolatedByPreconcurrency{cs})) { return FixBehavior::DowngradeToWarning; } return FixBehavior::Suppress; } // Otherwise, warn until Swift 6. if (!cs.getASTContext().LangOpts.isSwiftVersionAtLeast(6)) return FixBehavior::DowngradeToWarning; return FixBehavior::Error; } MarkGlobalActorFunction * MarkGlobalActorFunction::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator, FixBehavior fixBehavior) { if (locator->isLastElement()) locator = cs.getConstraintLocator( locator, LocatorPathElt::ArgumentAttribute::forGlobalActor()); return new (cs.getAllocator()) MarkGlobalActorFunction( cs, lhs, rhs, locator, fixBehavior); } bool MarkGlobalActorFunction::attempt(ConstraintSystem &cs, ConstraintKind constraintKind, FunctionType *fromType, FunctionType *toType, ConstraintLocatorBuilder locator) { auto fixBehavior = getConcurrencyFixBehavior( cs, constraintKind, locator, /*forSendable=*/false); if (!fixBehavior) return true; auto *fix = MarkGlobalActorFunction::create( cs, fromType, toType, cs.getConstraintLocator(locator), *fixBehavior); return cs.recordFix(fix); } bool AddSendableAttribute::diagnose(const Solution &solution, bool asNote) const { AttributedFuncToTypeConversionFailure failure( solution, getFromType(), getToType(), getLocator(), AttributedFuncToTypeConversionFailure::Concurrent, fixBehavior); return failure.diagnose(asNote); } AddSendableAttribute * AddSendableAttribute::create(ConstraintSystem &cs, FunctionType *fromType, FunctionType *toType, ConstraintLocator *locator, FixBehavior fixBehavior) { if (locator->isLastElement()) locator = cs.getConstraintLocator( locator, LocatorPathElt::ArgumentAttribute::forConcurrent()); return new (cs.getAllocator()) AddSendableAttribute( cs, fromType, toType, locator, fixBehavior); } bool AddSendableAttribute::attempt(ConstraintSystem &cs, ConstraintKind constraintKind, FunctionType *fromType, FunctionType *toType, ConstraintLocatorBuilder locator) { auto fixBehavior = getConcurrencyFixBehavior( cs, constraintKind, locator, /*forSendable=*/true); if (!fixBehavior) return true; auto *fix = AddSendableAttribute::create( cs, fromType, toType, cs.getConstraintLocator(locator), *fixBehavior); return cs.recordFix(fix); } bool RelabelArguments::diagnose(const Solution &solution, bool asNote) const { LabelingFailure failure(solution, getLocator(), getLabels()); return failure.diagnose(asNote); } bool RelabelArguments::diagnoseForAmbiguity( CommonFixesArray commonFixes) const { SmallPtrSet overloadChoices; // First, let's find overload choice associated with each // re-labeling fix. for (const auto &fix : commonFixes) { auto &solution = *fix.first; auto calleeLocator = solution.getCalleeLocator(getLocator()); if (!calleeLocator) return false; auto overloadChoice = solution.getOverloadChoiceIfAvailable(calleeLocator); if (!overloadChoice) return false; auto *decl = overloadChoice->choice.getDeclOrNull(); if (!decl) return false; (void)overloadChoices.insert(decl); } // If all of the fixes point to the same overload choice then it's // exactly the same issue since the call site is static. if (overloadChoices.size() == 1) return diagnose(*commonFixes.front().first); return false; } RelabelArguments * RelabelArguments::create(ConstraintSystem &cs, llvm::ArrayRef correctLabels, ConstraintLocator *locator) { unsigned size = totalSizeToAlloc(correctLabels.size()); void *mem = cs.getAllocator().Allocate(size, alignof(RelabelArguments)); return new (mem) RelabelArguments(cs, correctLabels, locator); } bool MissingConformance::diagnose(const Solution &solution, bool asNote) const { auto *locator = getLocator(); if (IsContextual) { auto &cs = solution.getConstraintSystem(); auto context = cs.getContextualTypePurpose(locator->getAnchor()); MissingContextualConformanceFailure failure( solution, context, getNonConformingType(), getProtocolType(), locator); return failure.diagnose(asNote); } MissingConformanceFailure failure( solution, locator, std::make_pair(getNonConformingType(), getProtocolType())); return failure.diagnose(asNote); } bool RequirementFix::diagnoseForAmbiguity( CommonFixesArray commonFixes) const { auto *primaryFix = commonFixes.front().second; assert(primaryFix); if (llvm::all_of( commonFixes, [&primaryFix]( const std::pair &entry) { return primaryFix->getLocator() == entry.second->getLocator(); })) return diagnose(*commonFixes.front().first); // If the location is the same but there are different requirements // involved let's not attempt to diagnose that as an ambiguity. return false; } bool MissingConformance::isEqual(const ConstraintFix *other) const { auto *conformanceFix = other->getAs(); if (!conformanceFix) return false; return IsContextual == conformanceFix->IsContextual && getNonConformingType()->isEqual( conformanceFix->getNonConformingType()) && getProtocolType()->isEqual(conformanceFix->getProtocolType()); } MissingConformance * MissingConformance::forContextual(ConstraintSystem &cs, Type type, Type protocolType, ConstraintLocator *locator) { return new (cs.getAllocator()) MissingConformance( cs, /*isContextual=*/true, type, protocolType, locator); } MissingConformance * MissingConformance::forRequirement(ConstraintSystem &cs, Type type, Type protocolType, ConstraintLocator *locator) { return new (cs.getAllocator()) MissingConformance( cs, /*isContextual=*/false, type, protocolType, locator); } bool SkipSameTypeRequirement::diagnose(const Solution &solution, bool asNote) const { SameTypeRequirementFailure failure(solution, LHS, RHS, getLocator()); return failure.diagnose(asNote); } SkipSameTypeRequirement * SkipSameTypeRequirement::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) { return new (cs.getAllocator()) SkipSameTypeRequirement(cs, lhs, rhs, locator); } bool SkipSameShapeRequirement::diagnose(const Solution &solution, bool asNote) const { if (getLocator()->isLastElement()) { SameShapeExpansionFailure failure(solution, LHS, RHS, getLocator()); return failure.diagnose(asNote); } SameShapeRequirementFailure failure(solution, LHS, RHS, getLocator()); return failure.diagnose(asNote); } SkipSameShapeRequirement * SkipSameShapeRequirement::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) { return new (cs.getAllocator()) SkipSameShapeRequirement(cs, lhs, rhs, locator); } bool SkipSuperclassRequirement::diagnose(const Solution &solution, bool asNote) const { SuperclassRequirementFailure failure(solution, LHS, RHS, getLocator()); return failure.diagnose(asNote); } SkipSuperclassRequirement * SkipSuperclassRequirement::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) { return new (cs.getAllocator()) SkipSuperclassRequirement(cs, lhs, rhs, locator); } bool ContextualMismatch::diagnose(const Solution &solution, bool asNote) const { ContextualFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } bool ContextualMismatch::diagnoseForAmbiguity( CommonFixesArray commonFixes) const { auto getTypes = [&](const std::pair &entry) -> std::pair { auto &solution = *entry.first; auto *fix = static_cast(entry.second); return {solution.simplifyType(fix->getFromType()), solution.simplifyType(fix->getToType())}; }; auto etalonTypes = getTypes(commonFixes.front()); if (llvm::all_of( commonFixes, [&](const std::pair &entry) { auto types = getTypes(entry); return etalonTypes.first->isEqual(types.first) && etalonTypes.second->isEqual(types.second); })) { const auto &primary = commonFixes.front(); return primary.second->diagnose(*primary.first, /*asNote=*/false); } return false; } ContextualMismatch *ContextualMismatch::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) { return new (cs.getAllocator()) ContextualMismatch( cs, lhs, rhs, locator, FixBehavior::Error); } bool AllowWrappedValueMismatch::diagnose(const Solution &solution, bool asError) const { WrappedValueMismatch failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnoseAsError(); } AllowWrappedValueMismatch *AllowWrappedValueMismatch::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowWrappedValueMismatch(cs, lhs, rhs, locator); } /// Computes the contextual type information for a type mismatch of a /// component in a structural type (tuple or function type). /// /// \returns A tuple containing the contextual type purpose, the source type, /// and the contextual type. static std::optional> getStructuralTypeContext(const Solution &solution, ConstraintLocator *locator) { if (auto contextualTypeElt = locator->findLast()) { assert(locator->isLastElement() || locator->isLastElement()); auto anchor = locator->getAnchor(); auto contextualInfo = solution.getContextualTypeInfo(anchor); // For some patterns the type could be empty and the entry is // there to indicate the purpose only. if (!contextualInfo || !contextualInfo->getType()) return std::nullopt; auto exprType = solution.getType(anchor); return std::make_tuple(contextualInfo->purpose, exprType, contextualInfo->getType()); } else if (auto argApplyInfo = solution.getFunctionArgApplyInfo(locator)) { Type fromType = argApplyInfo->getArgType(); Type toType = argApplyInfo->getParamType(); // In case locator points to the function result we want the // argument and param function types result. if (locator->isLastElement()) { auto fromFnType = fromType->getAs(); auto toFnType = toType->getAs(); if (fromFnType && toFnType) { return std::make_tuple( solution.getContextualTypePurpose(locator->getAnchor()), fromFnType->getResult(), toFnType->getResult()); } } return std::make_tuple(CTP_CallArgument, fromType, toType); } else if (auto *coerceExpr = getAsExpr(locator->getAnchor())) { return std::make_tuple(CTP_CoerceOperand, solution.getType(coerceExpr->getSubExpr()), solution.getType(coerceExpr)); } else if (auto *assignExpr = getAsExpr(locator->getAnchor())) { auto CTP = isa(assignExpr->getDest()) ? CTP_SubscriptAssignSource : CTP_AssignSource; return std::make_tuple(CTP, solution.getType(assignExpr->getSrc()), solution.getType(assignExpr->getDest())->getRValueType()); } return std::nullopt; } bool AllowTupleTypeMismatch::coalesceAndDiagnose( const Solution &solution, ArrayRef fixes, bool asNote) const { llvm::SmallVector indices; if (isElementMismatch()) indices.push_back(*Index); for (auto fix : fixes) { auto *tupleFix = fix->getAs(); if (!tupleFix || !tupleFix->isElementMismatch()) continue; indices.push_back(*tupleFix->Index); } auto *locator = getLocator(); ContextualTypePurpose purpose; if (isExpr(locator->getAnchor())) { purpose = CTP_CoerceOperand; } else if (auto *assignExpr = getAsExpr(locator->getAnchor())) { purpose = isa(assignExpr->getDest()) ? CTP_SubscriptAssignSource : CTP_AssignSource; } else { auto &cs = getConstraintSystem(); purpose = cs.getContextualTypePurpose(locator->getAnchor()); } if (!getFromType()->is() || !getToType()->is()) { return false; } TupleContextualFailure failure(solution, purpose, getFromType(), getToType(), indices, locator); return failure.diagnose(asNote); } bool AllowTupleTypeMismatch::diagnose(const Solution &solution, bool asNote) const { return coalesceAndDiagnose(solution, {}, asNote); } AllowTupleTypeMismatch * AllowTupleTypeMismatch::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator, std::optional index) { return new (cs.getAllocator()) AllowTupleTypeMismatch(cs, lhs, rhs, locator, index); } bool AllowFunctionTypeMismatch::coalesceAndDiagnose( const Solution &solution, ArrayRef fixes, bool asNote) const { llvm::SmallVector indices{ParamIndex}; for (auto fix : fixes) { if (auto *fnFix = fix->getAs()) indices.push_back(fnFix->ParamIndex); } auto *locator = getLocator(); ContextualTypePurpose purpose; Type fromType; Type toType; auto contextualTypeInfo = getStructuralTypeContext(solution, locator); if (!contextualTypeInfo) return false; std::tie(purpose, fromType, toType) = *contextualTypeInfo; FunctionTypeMismatch failure(solution, purpose, fromType, toType, indices, locator); return failure.diagnose(asNote); } bool AllowFunctionTypeMismatch::diagnose(const Solution &solution, bool asNote) const { return coalesceAndDiagnose(solution, {}, asNote); } bool AllowFunctionTypeMismatch::diagnoseForAmbiguity( CommonFixesArray commonFixes) const { if (ContextualMismatch::diagnoseForAmbiguity(commonFixes)) return true; auto *locator = getLocator(); // If this is a mismatch between two function types at argument // position, there is a tailored diagnostic for that. if (auto argConv = locator->getLastElementAs()) { auto &cs = getConstraintSystem(); auto &DE = cs.getASTContext().Diags; auto &solution = *commonFixes[0].first; auto info = getStructuralTypeContext(solution, locator); if (!info) return false; auto *argLoc = cs.getConstraintLocator(simplifyLocatorToAnchor(locator)); auto overload = solution.getOverloadChoiceIfAvailable( solution.getCalleeLocator(argLoc)); if (!overload) return false; auto name = overload->choice.getName().getBaseName(); DE.diagnose(getLoc(getAnchor()), diag::no_candidates_match_argument_type, name.userFacingName(), std::get<2>(*info), argConv->getParamIdx()); for (auto &entry : commonFixes) { auto &solution = *entry.first; auto overload = solution.getOverloadChoiceIfAvailable( solution.getCalleeLocator(argLoc)); if (!(overload && overload->choice.isDecl())) continue; auto *decl = overload->choice.getDecl(); if (decl->getLoc().isValid()) { DE.diagnose(decl, diag::found_candidate_type, solution.simplifyType(overload->adjustedOpenedType)); } } return true; } return false; } AllowFunctionTypeMismatch * AllowFunctionTypeMismatch::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator, unsigned index) { return new (cs.getAllocator()) AllowFunctionTypeMismatch(cs, lhs, rhs, locator, index); } bool GenericArgumentsMismatch::coalesceAndDiagnose( const Solution &solution, ArrayRef secondaryFixes, bool asNote) const { std::set scratch(getMismatches().begin(), getMismatches().end()); for (auto *fix : secondaryFixes) { auto *genericArgsFix = fix->castTo(); for (auto mismatchIdx : genericArgsFix->getMismatches()) scratch.insert(mismatchIdx); } SmallVector mismatches(scratch.begin(), scratch.end()); return diagnose(solution, mismatches, asNote); } bool GenericArgumentsMismatch::diagnose(const Solution &solution, bool asNote) const { return diagnose(solution, getMismatches(), asNote); } bool GenericArgumentsMismatch::diagnose(const Solution &solution, ArrayRef mismatches, bool asNote) const { GenericArgumentsMismatchFailure failure(solution, getFromType(), getToType(), mismatches, getLocator()); return failure.diagnose(asNote); } GenericArgumentsMismatch *GenericArgumentsMismatch::create( ConstraintSystem &cs, Type actual, Type required, llvm::ArrayRef mismatches, ConstraintLocator *locator) { unsigned size = totalSizeToAlloc(mismatches.size()); void *mem = cs.getAllocator().Allocate(size, alignof(GenericArgumentsMismatch)); return new (mem) GenericArgumentsMismatch(cs, actual, required, mismatches, locator); } bool AllowAutoClosurePointerConversion::diagnose(const Solution &solution, bool asNote) const { AutoClosurePointerConversionFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } AllowAutoClosurePointerConversion * AllowAutoClosurePointerConversion::create(ConstraintSystem &cs, Type pointeeType, Type pointerType, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowAutoClosurePointerConversion(cs, pointeeType, pointerType, locator); } bool RemoveUnwrap::diagnose(const Solution &solution, bool asNote) const { NonOptionalUnwrapFailure failure(solution, BaseType, getLocator()); return failure.diagnose(asNote); } RemoveUnwrap *RemoveUnwrap::create(ConstraintSystem &cs, Type baseType, ConstraintLocator *locator) { return new (cs.getAllocator()) RemoveUnwrap(cs, baseType, locator); } bool InsertExplicitCall::diagnose(const Solution &solution, bool asNote) const { MissingCallFailure failure(solution, getLocator()); return failure.diagnose(asNote); } InsertExplicitCall *InsertExplicitCall::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) InsertExplicitCall(cs, locator); } bool UsePropertyWrapper::diagnose(const Solution &solution, bool asNote) const { ExtraneousPropertyWrapperUnwrapFailure failure( solution, Wrapped, UsingProjection, Base, Wrapper, getLocator()); return failure.diagnose(asNote); } UsePropertyWrapper *UsePropertyWrapper::create(ConstraintSystem &cs, VarDecl *wrapped, bool usingProjection, Type base, Type wrapper, ConstraintLocator *locator) { return new (cs.getAllocator()) UsePropertyWrapper( cs, wrapped, usingProjection, base, wrapper, locator); } bool UseWrappedValue::diagnose(const Solution &solution, bool asNote) const { MissingPropertyWrapperUnwrapFailure failure(solution, PropertyWrapper, usingProjection(), Base, Wrapper, getLocator()); return failure.diagnose(asNote); } UseWrappedValue *UseWrappedValue::create(ConstraintSystem &cs, VarDecl *propertyWrapper, Type base, Type wrapper, ConstraintLocator *locator) { return new (cs.getAllocator()) UseWrappedValue(cs, propertyWrapper, base, wrapper, locator); } bool AllowInvalidPropertyWrapperType::diagnose(const Solution &solution, bool asNote) const { InvalidPropertyWrapperType failure(solution, wrapperType, getLocator()); return failure.diagnose(asNote); } AllowInvalidPropertyWrapperType * AllowInvalidPropertyWrapperType::create(ConstraintSystem &cs, Type wrapperType, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInvalidPropertyWrapperType(cs, wrapperType, locator); } bool RemoveProjectedValueArgument::diagnose(const Solution &solution, bool asNote) const { InvalidProjectedValueArgument failure(solution, wrapperType, param, getLocator()); return failure.diagnose(asNote); } RemoveProjectedValueArgument * RemoveProjectedValueArgument::create(ConstraintSystem &cs, Type wrapperType, ParamDecl *param, ConstraintLocator *locator) { return new (cs.getAllocator()) RemoveProjectedValueArgument(cs, wrapperType, param, locator); } bool UseSubscriptOperator::diagnose(const Solution &solution, bool asNote) const { SubscriptMisuseFailure failure(solution, getLocator()); return failure.diagnose(asNote); } UseSubscriptOperator *UseSubscriptOperator::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) UseSubscriptOperator(cs, locator); } bool DefineMemberBasedOnUse::diagnose(const Solution &solution, bool asNote) const { MissingMemberFailure failure(solution, BaseType, Name, getLocator()); return AlreadyDiagnosed || failure.diagnose(asNote); } bool DefineMemberBasedOnUse::diagnoseForAmbiguity(CommonFixesArray commonFixes) const { Type concreteBaseType; for (const auto &solutionAndFix : commonFixes) { const auto *solution = solutionAndFix.first; const auto *fix = solutionAndFix.second->getAs(); auto baseType = solution->simplifyType(fix->BaseType); if (!concreteBaseType) concreteBaseType = baseType; if (concreteBaseType->getCanonicalType() != baseType->getCanonicalType()) { auto &DE = getConstraintSystem().getASTContext().Diags; DE.diagnose(getLoc(getAnchor()), diag::unresolved_member_no_inference, Name); return true; } } return diagnose(*commonFixes.front().first); } DefineMemberBasedOnUse * DefineMemberBasedOnUse::create(ConstraintSystem &cs, Type baseType, DeclNameRef member, bool alreadyDiagnosed, ConstraintLocator *locator) { return new (cs.getAllocator()) DefineMemberBasedOnUse(cs, baseType, member, alreadyDiagnosed, locator); } bool DefineMemberBasedOnUnintendedGenericParam::diagnose( const Solution &solution, bool asNote) const { UnintendedExtraGenericParamMemberFailure failure(solution, BaseType, Name, ParamName, getLocator()); return failure.diagnose(asNote); } DefineMemberBasedOnUnintendedGenericParam * DefineMemberBasedOnUnintendedGenericParam::create(ConstraintSystem &cs, Type baseType, DeclNameRef member, Identifier paramName, ConstraintLocator *locator) { return new (cs.getAllocator()) DefineMemberBasedOnUnintendedGenericParam( cs, baseType, member, paramName, locator); } AllowMemberRefOnExistential * AllowMemberRefOnExistential::create(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef memberName, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowMemberRefOnExistential(cs, baseType, memberName, member, locator); } bool AllowMemberRefOnExistential::diagnose(const Solution &solution, bool asNote) const { InvalidMemberRefOnExistential failure(solution, getBaseType(), getMemberName(), getLocator()); return failure.diagnose(asNote); } bool AllowInvalidMemberRef::diagnoseForAmbiguity( CommonFixesArray commonFixes) const { auto *primaryFix = static_cast(commonFixes.front().second); Type baseTy = primaryFix->getBaseType(); for (const auto &entry : commonFixes) { auto *memberFix = static_cast(entry.second); if (!baseTy->isEqual(memberFix->getBaseType())) return false; } return diagnose(*commonFixes.front().first); } bool AllowTypeOrInstanceMember::diagnose(const Solution &solution, bool asNote) const { AllowTypeOrInstanceMemberFailure failure(solution, getBaseType(), getMember(), getMemberName(), getLocator()); return failure.diagnose(asNote); } AllowTypeOrInstanceMember * AllowTypeOrInstanceMember::create(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef usedName, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowTypeOrInstanceMember(cs, baseType, member, usedName, locator); } bool AllowInvalidPartialApplication::diagnose(const Solution &solution, bool asNote) const { PartialApplicationFailure failure(isWarning, solution, getLocator()); return failure.diagnose(asNote); } AllowInvalidPartialApplication * AllowInvalidPartialApplication::create(bool isWarning, ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInvalidPartialApplication(isWarning, cs, locator); } bool AllowInvalidInitRef::diagnose(const Solution &solution, bool asNote) const { switch (Kind) { case RefKind::DynamicOnMetatype: { InvalidDynamicInitOnMetatypeFailure failure(solution, BaseType, Init, BaseRange, getLocator()); return failure.diagnose(asNote); } case RefKind::ProtocolMetatype: { InitOnProtocolMetatypeFailure failure( solution, BaseType, Init, IsStaticallyDerived, BaseRange, getLocator()); return failure.diagnose(asNote); } case RefKind::NonConstMetatype: { ImplicitInitOnNonConstMetatypeFailure failure(solution, BaseType, Init, getLocator()); return failure.diagnose(asNote); } } llvm_unreachable("covered switch"); } AllowInvalidInitRef *AllowInvalidInitRef::dynamicOnMetatype( ConstraintSystem &cs, Type baseTy, ConstructorDecl *init, SourceRange baseRange, ConstraintLocator *locator) { return create(RefKind::DynamicOnMetatype, cs, baseTy, init, /*isStaticallyDerived=*/false, baseRange, locator); } AllowInvalidInitRef *AllowInvalidInitRef::onProtocolMetatype( ConstraintSystem &cs, Type baseTy, ConstructorDecl *init, bool isStaticallyDerived, SourceRange baseRange, ConstraintLocator *locator) { return create(RefKind::ProtocolMetatype, cs, baseTy, init, isStaticallyDerived, baseRange, locator); } AllowInvalidInitRef * AllowInvalidInitRef::onNonConstMetatype(ConstraintSystem &cs, Type baseTy, ConstructorDecl *init, ConstraintLocator *locator) { return create(RefKind::NonConstMetatype, cs, baseTy, init, /*isStaticallyDerived=*/false, SourceRange(), locator); } AllowInvalidInitRef * AllowInvalidInitRef::create(RefKind kind, ConstraintSystem &cs, Type baseTy, ConstructorDecl *init, bool isStaticallyDerived, SourceRange baseRange, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInvalidInitRef( cs, kind, baseTy, init, isStaticallyDerived, baseRange, locator); } bool AllowClosureParamDestructuring::diagnose(const Solution &solution, bool asNote) const { ClosureParamDestructuringFailure failure(solution, ContextualType, getLocator()); return failure.diagnose(asNote); } AllowClosureParamDestructuring * AllowClosureParamDestructuring::create(ConstraintSystem &cs, FunctionType *contextualType, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowClosureParamDestructuring(cs, contextualType, locator); } bool AddMissingArguments::diagnose(const Solution &solution, bool asNote) const { MissingArgumentsFailure failure(solution, getSynthesizedArguments(), getLocator()); return failure.diagnose(asNote); } AddMissingArguments * AddMissingArguments::create(ConstraintSystem &cs, ArrayRef synthesizedArgs, ConstraintLocator *locator) { unsigned size = totalSizeToAlloc(synthesizedArgs.size()); void *mem = cs.getAllocator().Allocate(size, alignof(AddMissingArguments)); return new (mem) AddMissingArguments(cs, synthesizedArgs, locator); } bool RemoveExtraneousArguments::diagnose(const Solution &solution, bool asNote) const { ExtraneousArgumentsFailure failure(solution, ContextualType, getExtraArguments(), getLocator()); return failure.diagnose(asNote); } bool RemoveExtraneousArguments::isMinMaxNameShadowing( ConstraintSystem &cs, ConstraintLocatorBuilder locator) { auto *anchor = getAsExpr(locator.getAnchor()); if (!anchor) return false; if (auto *UDE = dyn_cast(anchor->getFn())) { if (auto *baseExpr = dyn_cast(UDE->getBase())) { auto *decl = baseExpr->getDecl(); if (baseExpr->isImplicit() && decl && decl->getName() == cs.getASTContext().Id_self) { auto memberName = UDE->getName(); return memberName.isSimpleName("min") || memberName.isSimpleName("max"); } } } return false; } RemoveExtraneousArguments *RemoveExtraneousArguments::create( ConstraintSystem &cs, FunctionType *contextualType, llvm::ArrayRef extraArgs, ConstraintLocator *locator) { unsigned size = totalSizeToAlloc(extraArgs.size()); void *mem = cs.getAllocator().Allocate(size, alignof(RemoveExtraneousArguments)); return new (mem) RemoveExtraneousArguments(cs, contextualType, extraArgs, locator); } bool MoveOutOfOrderArgument::diagnose(const Solution &solution, bool asNote) const { OutOfOrderArgumentFailure failure(solution, ArgIdx, PrevArgIdx, Bindings, getLocator()); return failure.diagnose(asNote); } bool MoveOutOfOrderArgument::diagnoseForAmbiguity( CommonFixesArray commonFixes) const { auto *primaryFix = commonFixes.front().second->getAs(); assert(primaryFix); if (llvm::all_of( commonFixes, [&primaryFix]( const std::pair &entry) { return primaryFix->isEqual(entry.second); })) return diagnose(*commonFixes.front().first); return false; } bool MoveOutOfOrderArgument::isEqual(const ConstraintFix *other) const { auto OoOFix = other->getAs(); return OoOFix ? ArgIdx == OoOFix->ArgIdx && PrevArgIdx == OoOFix->PrevArgIdx : false; } MoveOutOfOrderArgument *MoveOutOfOrderArgument::create( ConstraintSystem &cs, unsigned argIdx, unsigned prevArgIdx, ArrayRef bindings, ConstraintLocator *locator) { return new (cs.getAllocator()) MoveOutOfOrderArgument(cs, argIdx, prevArgIdx, bindings, locator); } bool AllowInaccessibleMember::diagnose(const Solution &solution, bool asNote) const { InaccessibleMemberFailure failure(solution, getMember(), getLocator()); return failure.diagnose(asNote); } AllowInaccessibleMember * AllowInaccessibleMember::create(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef name, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInaccessibleMember(cs, baseType, member, name, locator); } bool AllowAnyObjectKeyPathRoot::diagnose(const Solution &solution, bool asNote) const { AnyObjectKeyPathRootFailure failure(solution, getLocator()); return failure.diagnose(asNote); } AllowAnyObjectKeyPathRoot * AllowAnyObjectKeyPathRoot::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowAnyObjectKeyPathRoot(cs, locator); } bool AllowMultiArgFuncKeyPathMismatch::diagnose(const Solution &solution, bool asNote) const { MultiArgFuncKeyPathFailure failure(solution, functionType, getLocator()); return failure.diagnose(asNote); } AllowMultiArgFuncKeyPathMismatch * AllowMultiArgFuncKeyPathMismatch::create(ConstraintSystem &cs, Type fnType, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowMultiArgFuncKeyPathMismatch(cs, fnType, locator); } bool TreatKeyPathSubscriptIndexAsHashable::diagnose(const Solution &solution, bool asNote) const { KeyPathSubscriptIndexHashableFailure failure(solution, NonConformingType, getLocator()); return failure.diagnose(asNote); } TreatKeyPathSubscriptIndexAsHashable * TreatKeyPathSubscriptIndexAsHashable::create(ConstraintSystem &cs, Type type, ConstraintLocator *locator) { return new (cs.getAllocator()) TreatKeyPathSubscriptIndexAsHashable(cs, type, locator); } bool AllowInvalidRefInKeyPath::diagnose(const Solution &solution, bool asNote) const { switch (Kind) { case RefKind::StaticMember: { InvalidStaticMemberRefInKeyPath failure(solution, BaseType, Member, getLocator()); return failure.diagnose(asNote); } case RefKind::UnsupportedStaticMember: { UnsupportedStaticMemberRefInKeyPath failure(solution, BaseType, Member, getLocator()); return failure.diagnose(asNote); } case RefKind::EnumCase: { InvalidEnumCaseRefInKeyPath failure(solution, Member, getLocator()); return failure.diagnose(asNote); } case RefKind::MutatingGetter: { InvalidMemberWithMutatingGetterInKeyPath failure(solution, Member, getLocator()); return failure.diagnose(asNote); } case RefKind::Method: case RefKind::Initializer: { UnsupportedMethodRefInKeyPath failure(solution, Member, getLocator()); return failure.diagnose(asNote); } case RefKind::MutatingMethod: { InvalidMutatingMethodRefInKeyPath failure(solution, Member, getLocator()); return failure.diagnose(asNote); } case RefKind::AsyncOrThrowsMethod: { InvalidAsyncOrThrowsMethodRefInKeyPath failure(solution, Member, getLocator()); return failure.diagnose(asNote); } case RefKind::TypeReference: { InvalidTypeRefInKeyPath failure(solution, Member, getLocator()); return failure.diagnose(asNote); } } llvm_unreachable("covered switch"); } bool AllowInvalidRefInKeyPath::diagnoseForAmbiguity( CommonFixesArray commonFixes) const { auto *primaryFix = commonFixes.front().second->getAs(); assert(primaryFix); if (llvm::all_of( commonFixes, [&primaryFix]( const std::pair &entry) { return primaryFix->isEqual(entry.second); })) { return diagnose(*commonFixes.front().first); } return false; } bool AllowInvalidRefInKeyPath::isEqual(const ConstraintFix *other) const { auto *refFix = other->getAs(); return refFix ? Kind == refFix->Kind && Member == refFix->Member : false; } AllowInvalidRefInKeyPath * AllowInvalidRefInKeyPath::forRef(ConstraintSystem &cs, Type baseType, ValueDecl *member, ConstraintLocator *locator) { if (member->isStatic() && !isa(member)) { // References to static members are supported only for modules that // are built with 6.1+ compilers, libraries produced by earlier // compilers don't have required symbols. if (auto *module = member->getDeclContext()->getParentModule()) { if (module->isBuiltFromInterface()) { auto compilerVersion = module->getSwiftInterfaceCompilerVersion(); if (!compilerVersion.isVersionAtLeast(6, 1)) return AllowInvalidRefInKeyPath::create( cs, baseType, RefKind::UnsupportedStaticMember, member, locator); } } if (!baseType->getRValueType()->is()) return AllowInvalidRefInKeyPath::create( cs, baseType, RefKind::StaticMember, member, locator); } // Referencing enum cases in key path is not currently allowed. if (isa(member)) { return AllowInvalidRefInKeyPath::create(cs, baseType, RefKind::EnumCase, member, locator); } if (auto *storage = dyn_cast(member)) { // Referencing members with mutating getters in key path is not // currently allowed. if (storage->isGetterMutating()) return AllowInvalidRefInKeyPath::create( cs, baseType, RefKind::MutatingGetter, member, locator); } if (cs.getASTContext().LangOpts.hasFeature( Feature::KeyPathWithMethodMembers)) { // Referencing mutating, throws or async method members is not currently // allowed. if (auto method = dyn_cast(member)) { if (method->isAsyncContext()) return AllowInvalidRefInKeyPath::create( cs, baseType, RefKind::AsyncOrThrowsMethod, member, locator); if (auto methodType = method->getInterfaceType()->getAs()) { if (methodType->getResult()->getAs()->isThrowing()) return AllowInvalidRefInKeyPath::create( cs, baseType, RefKind::AsyncOrThrowsMethod, member, locator); } if (method->isMutating()) return AllowInvalidRefInKeyPath::create( cs, baseType, RefKind::MutatingMethod, member, locator); return nullptr; } if (isa(member)) return nullptr; } // Referencing (instance or static) methods in key path is // not currently allowed. if (isa(member)) return AllowInvalidRefInKeyPath::create(cs, baseType, RefKind::Method, member, locator); // Referencing initializers in key path is not currently allowed. if (isa(member)) return AllowInvalidRefInKeyPath::create(cs, baseType, RefKind::Initializer, member, locator); // Referencing types in key path is not currently allowed. if (isa(member)) return AllowInvalidRefInKeyPath::create(cs, baseType, RefKind::TypeReference, member, locator); return nullptr; } AllowInvalidRefInKeyPath * AllowInvalidRefInKeyPath::create(ConstraintSystem &cs, Type baseType, RefKind kind, ValueDecl *member, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInvalidRefInKeyPath(cs, baseType, kind, member, locator); } bool RemoveAddressOf::diagnose(const Solution &solution, bool asNote) const { InvalidUseOfAddressOf failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } RemoveAddressOf *RemoveAddressOf::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) { return new (cs.getAllocator()) RemoveAddressOf(cs, lhs, rhs, locator); } RemoveReturn::RemoveReturn(ConstraintSystem &cs, Type resultTy, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::RemoveReturn, resultTy, cs.getASTContext().TheEmptyTupleType, locator) {} bool RemoveReturn::diagnose(const Solution &solution, bool asNote) const { ExtraneousReturnFailure failure(solution, getLocator()); return failure.diagnose(asNote); } RemoveReturn *RemoveReturn::create(ConstraintSystem &cs, Type resultTy, ConstraintLocator *locator) { return new (cs.getAllocator()) RemoveReturn(cs, resultTy, locator); } NotCompileTimeLiteral::NotCompileTimeLiteral(ConstraintSystem &cs, Type paramTy, ConstraintLocator *locator): ContextualMismatch(cs, FixKind::NotCompileTimeLiteral, paramTy, cs.getASTContext().TheEmptyTupleType, locator, FixBehavior::AlwaysWarning) {} NotCompileTimeLiteral * NotCompileTimeLiteral::create(ConstraintSystem &cs, Type paramTy, ConstraintLocator *locator) { return new (cs.getAllocator()) NotCompileTimeLiteral(cs, paramTy, locator); } bool NotCompileTimeLiteral::diagnose(const Solution &solution, bool asNote) const { auto *locator = getLocator(); if (auto *E = getAsExpr(locator->getAnchor())) { auto isAccepted = E->isSemanticallyConstExpr([&](Expr *E) { if (auto *UMC = dyn_cast(E)) { E = UMC->getSubExpr(); } auto locator = solution.getConstraintSystem().getConstraintLocator(E); // Referencing an enum element directly is considered a compile-time literal. if (auto *d = solution.resolveLocatorToDecl(locator).getDecl()) { if (isa(d)) { if (!d->hasParameterList()) { return true; } } } return false; }); if (isAccepted) return true; } NotCompileTimeLiteralFailure failure(solution, locator); return failure.diagnose(asNote); } bool AllowInvalidPackElement::diagnose(const Solution &solution, bool asNote) const { InvalidPackElement failure(solution, packElementType, getLocator()); return failure.diagnose(asNote); } AllowInvalidPackElement * AllowInvalidPackElement::create(ConstraintSystem &cs, Type packElementType, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInvalidPackElement(cs, packElementType, locator); } bool AllowInvalidPackReference::diagnose(const Solution &solution, bool asNote) const { InvalidPackReference failure(solution, packType, getLocator()); return failure.diagnose(asNote); } AllowInvalidPackReference * AllowInvalidPackReference::create(ConstraintSystem &cs, Type packType, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInvalidPackReference(cs, packType, locator); } bool AllowInvalidPackExpansion::diagnose(const Solution &solution, bool asNote) const { InvalidPackExpansion failure(solution, getLocator()); return failure.diagnose(asNote); } AllowInvalidPackExpansion * AllowInvalidPackExpansion::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInvalidPackExpansion(cs, locator); } bool IgnoreWhereClauseInPackIteration::diagnose(const Solution &solution, bool asNote) const { InvalidWhereClauseInPackIteration failure(solution, getLocator()); return failure.diagnose(asNote); } IgnoreWhereClauseInPackIteration * IgnoreWhereClauseInPackIteration::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreWhereClauseInPackIteration(cs, locator); } bool CollectionElementContextualMismatch::diagnose(const Solution &solution, bool asNote) const { CollectionElementContextualFailure failure( solution, getElements(), getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } CollectionElementContextualMismatch * CollectionElementContextualMismatch::create(ConstraintSystem &cs, Type srcType, Type dstType, ConstraintLocator *locator) { // It's common for a single literal element to represent types of other // literal elements of the same kind, let's check whether that is the case // here and record all of the affected positions. SmallVector affected; { if (auto *elementLoc = getAsExpr(simplifyLocatorToAnchor(locator))) { auto *typeVar = cs.getType(elementLoc)->getAs(); if (typeVar && typeVar->getImpl().getAtomicLiteralKind()) { const auto *node = cs.getRepresentative(typeVar)->getImpl().getGraphNode(); for (auto *typeVar : node->getEquivalenceClass()) { auto *locator = typeVar->getImpl().getLocator(); if (auto *eltLoc = getAsExpr(simplifyLocatorToAnchor(locator))) affected.push_back(eltLoc); } } } } unsigned size = totalSizeToAlloc(affected.size()); void *mem = cs.getAllocator().Allocate( size, alignof(CollectionElementContextualMismatch)); return new (mem) CollectionElementContextualMismatch(cs, affected, srcType, dstType, locator); } bool DefaultGenericArgument::coalesceAndDiagnose( const Solution &solution, ArrayRef fixes, bool asNote) const { llvm::SmallVector missingParams{Param}; for (auto *otherFix : fixes) { if (auto *fix = otherFix->getAs()) missingParams.push_back(fix->Param); } MissingGenericArgumentsFailure failure(solution, missingParams, getLocator()); return failure.diagnose(asNote); } bool DefaultGenericArgument::diagnose(const Solution &solution, bool asNote) const { return coalesceAndDiagnose(solution, {}, asNote); } DefaultGenericArgument * DefaultGenericArgument::create(ConstraintSystem &cs, GenericTypeParamType *param, ConstraintLocator *locator) { return new (cs.getAllocator()) DefaultGenericArgument(cs, param, locator); } SkipUnhandledConstructInResultBuilder * SkipUnhandledConstructInResultBuilder::create(ConstraintSystem &cs, UnhandledNode unhandled, NominalTypeDecl *builder, ConstraintLocator *locator) { return new (cs.getAllocator()) SkipUnhandledConstructInResultBuilder(cs, unhandled, builder, locator); } bool SkipUnhandledConstructInResultBuilder::diagnose(const Solution &solution, bool asNote) const { SkipUnhandledConstructInResultBuilderFailure failure(solution, unhandled, builder, getLocator()); return failure.diagnose(asNote); } bool AllowMutatingMemberOnRValueBase::diagnose(const Solution &solution, bool asNote) const { MutatingMemberRefOnImmutableBase failure(solution, getMember(), getLocator()); return failure.diagnose(asNote); } AllowMutatingMemberOnRValueBase * AllowMutatingMemberOnRValueBase::create(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef name, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowMutatingMemberOnRValueBase(cs, baseType, member, name, locator); } bool AllowTupleSplatForSingleParameter::diagnose(const Solution &solution, bool asNote) const { InvalidTupleSplatWithSingleParameterFailure failure(solution, ParamType, getLocator()); return failure.diagnose(asNote); } bool AllowTupleSplatForSingleParameter::attempt( ConstraintSystem &cs, SmallVectorImpl &args, ArrayRef params, SmallVectorImpl> &bindings, ConstraintLocatorBuilder locator) { if (params.size() != 1 || args.size() <= 1) return true; const auto ¶m = params.front(); if (param.isInOut() || param.isVariadic() || param.isAutoClosure()) return true; auto paramTy = param.getOldType(); // Parameter type has to be either a tuple (with the same arity as // argument list), or a type variable. if (!(paramTy->is() && paramTy->castTo()->getNumElements() == args.size())) return true; SmallVector argElts; for (unsigned index : indices(args)) { const auto &arg = args[index]; auto label = arg.getLabel(); auto flags = arg.getParameterFlags(); // In situations where there is a single labeled parameter // we need to form a tuple which omits the label e.g. // // func foo(x: (T, T)) {} // foo(x: 0, 1) // // We'd want to suggest argument list to be `x: (0, 1)` instead // of `(x: 0, 1)` which would be incorrect. if (param.hasLabel() && label == param.getLabel()) { if (index == 0) { label = Identifier(); } else { // If label match anything other than first argument, // this can't be a tuple splat. return true; } } // Tuple can't have `inout` elements. if (flags.isInOut()) return true; argElts.push_back({arg.getPlainType(), label}); } bindings[0].clear(); bindings[0].push_back(0); auto newArgType = TupleType::get(argElts, cs.getASTContext()); args.clear(); args.push_back(AnyFunctionType::Param(newArgType, param.getLabel())); auto *fix = new (cs.getAllocator()) AllowTupleSplatForSingleParameter( cs, paramTy, cs.getConstraintLocator(locator)); return cs.recordFix(fix); } bool DropThrowsAttribute::diagnose(const Solution &solution, bool asNote) const { ThrowingFunctionConversionFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } DropThrowsAttribute *DropThrowsAttribute::create(ConstraintSystem &cs, FunctionType *fromType, FunctionType *toType, ConstraintLocator *locator) { return new (cs.getAllocator()) DropThrowsAttribute(cs, fromType, toType, locator); } bool IgnoreThrownErrorMismatch::diagnose(const Solution &solution, bool asNote) const { ThrownErrorTypeConversionFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } IgnoreThrownErrorMismatch *IgnoreThrownErrorMismatch::create(ConstraintSystem &cs, Type fromErrorType, Type toErrorType, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreThrownErrorMismatch(cs, fromErrorType, toErrorType, locator); } bool DropAsyncAttribute::diagnose(const Solution &solution, bool asNote) const { AsyncFunctionConversionFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } DropAsyncAttribute *DropAsyncAttribute::create(ConstraintSystem &cs, FunctionType *fromType, FunctionType *toType, ConstraintLocator *locator) { return new (cs.getAllocator()) DropAsyncAttribute(cs, fromType, toType, locator); } bool IgnoreContextualType::diagnose(const Solution &solution, bool asNote) const { ContextualFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } IgnoreContextualType *IgnoreContextualType::create(ConstraintSystem &cs, Type resultTy, Type specifiedTy, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreContextualType(cs, resultTy, specifiedTy, locator); } bool IgnoreAssignmentDestinationType::diagnose(const Solution &solution, bool asNote) const { auto &cs = getConstraintSystem(); auto *AE = getAsExpr(getAnchor()); assert(AE); // Let's check whether this is a situation of chained assignment where // one of the steps in the chain is an assignment to self e.g. // `let _ = { $0 = $0 = 42 }`. Assignment chaining results in // type mismatch between result of the previous assignment and the next. { llvm::SaveAndRestore anchor(AE); do { if (TypeChecker::diagnoseSelfAssignment(AE)) return true; } while ((AE = dyn_cast_or_null(cs.getParentExpr(AE)))); } auto CTP = isa(AE->getDest()) ? CTP_SubscriptAssignSource : CTP_AssignSource; AssignmentTypeMismatchFailure failure( solution, CTP, getFromType(), getToType(), cs.getConstraintLocator(AE->getSrc(), LocatorPathElt::ContextualType(CTP))); return failure.diagnose(asNote); } bool IgnoreAssignmentDestinationType::diagnoseForAmbiguity( CommonFixesArray commonFixes) const { auto &cs = getConstraintSystem(); // If all of the types are the same let's try to diagnose // this as if there is no ambiguity. if (ContextualMismatch::diagnoseForAmbiguity(commonFixes)) return true; auto *commonLocator = getLocator(); auto *assignment = castToExpr(commonLocator->getAnchor()); auto &solution = *commonFixes.front().first; auto *calleeLocator = solution.getCalleeLocator( solution.getConstraintLocator(assignment->getSrc())); auto overload = solution.getOverloadChoiceIfAvailable(calleeLocator); if (!overload) return false; auto declName = overload->choice.getName(); if (!declName) return false; auto destType = solution.getType(assignment->getDest()); auto &DE = cs.getASTContext().Diags; // TODO(diagnostics): It might be good to add a tailored diagnostic // for cases like this instead of using "contextual" one. DE.diagnose(assignment->getSrc()->getLoc(), diag::no_candidates_match_result_type, declName.getBaseName().userFacingName(), solution.simplifyType(destType)->getRValueType()); for (auto &entry : commonFixes) { entry.second->diagnose(*entry.first, /*asNote=*/true); } return true; } IgnoreAssignmentDestinationType * IgnoreAssignmentDestinationType::create(ConstraintSystem &cs, Type sourceTy, Type destTy, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreAssignmentDestinationType(cs, sourceTy, destTy, locator); } IgnoreNonMetatypeDynamicType * IgnoreNonMetatypeDynamicType::create(ConstraintSystem &cs, Type instanceTy, Type metatypeTy, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreNonMetatypeDynamicType(cs, instanceTy, metatypeTy, locator); } bool IgnoreNonMetatypeDynamicType::diagnose(const Solution &solution, bool asNote) const { NonMetatypeDynamicTypeFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } bool AllowInOutConversion::diagnose(const Solution &solution, bool asNote) const { InOutConversionFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } AllowInOutConversion *AllowInOutConversion::create(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInOutConversion(cs, argType, paramType, locator); } ExpandArrayIntoVarargs * ExpandArrayIntoVarargs::attempt(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocatorBuilder builder) { auto *locator = cs.getConstraintLocator(builder); auto argLoc = locator->getLastElementAs(); if (!(argLoc && argLoc->getParameterFlags().isVariadic())) return nullptr; auto elementType = argType->getArrayElementType(); if (!elementType) return nullptr; ConstraintSystem::TypeMatchOptions options; options |= ConstraintSystem::TypeMatchFlags::TMF_ApplyingFix; options |= ConstraintSystem::TypeMatchFlags::TMF_GenerateConstraints; auto result = cs.matchTypes(elementType, paramType, ConstraintKind::Subtype, options, builder); if (result.isFailure()) return nullptr; return new (cs.getAllocator()) ExpandArrayIntoVarargs(cs, argType, paramType, locator); } bool ExpandArrayIntoVarargs::diagnose(const Solution &solution, bool asNote) const { ExpandArrayIntoVarargsFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } bool ExplicitlyConstructRawRepresentable::diagnose(const Solution &solution, bool asNote) const { MissingRawRepresentableInitFailure failure(solution, RawReprType, ExpectedType, getLocator()); return failure.diagnose(asNote); } ExplicitlyConstructRawRepresentable * ExplicitlyConstructRawRepresentable::create(ConstraintSystem &cs, Type rawReprType, Type expectedType, ConstraintLocator *locator) { return new (cs.getAllocator()) ExplicitlyConstructRawRepresentable( cs, rawReprType, expectedType, locator); } bool UseRawValue::diagnose(const Solution &solution, bool asNote) const { MissingRawValueFailure failure(solution, RawReprType, ExpectedType, getLocator()); return failure.diagnose(asNote); } UseRawValue *UseRawValue::create(ConstraintSystem &cs, Type rawReprType, Type expectedType, ConstraintLocator *locator) { return new (cs.getAllocator()) UseRawValue(cs, rawReprType, expectedType, locator); } unsigned AllowArgumentMismatch::getParamIdx() const { const auto *locator = getLocator(); auto elt = locator->castLastElementTo(); return elt.getParamIdx(); } bool AllowArgumentMismatch::diagnose(const Solution &solution, bool asNote) const { ArgumentMismatchFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } AllowArgumentMismatch * AllowArgumentMismatch::create(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowArgumentMismatch(cs, argType, paramType, locator); } bool RemoveInvalidCall::diagnose(const Solution &solution, bool asNote) const { ExtraneousCallFailure failure(solution, getLocator()); return failure.diagnose(asNote); } RemoveInvalidCall *RemoveInvalidCall::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) RemoveInvalidCall(cs, locator); } bool TreatEphemeralAsNonEphemeral::diagnose(const Solution &solution, bool asNote) const { NonEphemeralConversionFailure failure(solution, getLocator(), getFromType(), getToType(), ConversionKind, fixBehavior); return failure.diagnose(asNote); } TreatEphemeralAsNonEphemeral *TreatEphemeralAsNonEphemeral::create( ConstraintSystem &cs, ConstraintLocator *locator, Type srcType, Type dstType, ConversionRestrictionKind conversionKind, bool downgradeToWarning) { return new (cs.getAllocator()) TreatEphemeralAsNonEphemeral( cs, locator, srcType, dstType, conversionKind, downgradeToWarning ? FixBehavior::DowngradeToWarning : FixBehavior::Error); } std::string TreatEphemeralAsNonEphemeral::getName() const { std::string name; name += "treat ephemeral as non-ephemeral for "; name += ::getName(ConversionKind); return name; } bool AllowSendingMismatch::diagnose(const Solution &solution, bool asNote) const { SendingMismatchFailure failure(solution, getFromType(), getToType(), getLocator(), fixBehavior); return failure.diagnose(asNote); } AllowSendingMismatch *AllowSendingMismatch::create(ConstraintSystem &cs, Type srcType, Type dstType, ConstraintLocator *locator) { auto fixBehavior = cs.getASTContext().LangOpts.isSwiftVersionAtLeast(6) ? FixBehavior::Error : FixBehavior::DowngradeToWarning; return new (cs.getAllocator()) AllowSendingMismatch(cs, srcType, dstType, locator, fixBehavior); } bool SpecifyBaseTypeForContextualMember::diagnose(const Solution &solution, bool asNote) const { MissingContextualBaseInMemberRefFailure failure(solution, MemberName, getLocator()); return failure.diagnose(asNote); } SpecifyBaseTypeForContextualMember *SpecifyBaseTypeForContextualMember::create( ConstraintSystem &cs, DeclNameRef member, ConstraintLocator *locator) { return new (cs.getAllocator()) SpecifyBaseTypeForContextualMember(cs, member, locator); } std::string SpecifyClosureParameterType::getName() const { std::string name; llvm::raw_string_ostream OS(name); auto *closure = castToExpr(getAnchor()); auto paramLoc = getLocator()->castLastElementTo(); auto *PD = closure->getParameters()->get(paramLoc.getIndex()); OS << "specify type for parameter "; OS << "'" << PD->getParameterName() << "'"; return OS.str(); } bool SpecifyClosureParameterType::diagnose(const Solution &solution, bool asNote) const { UnableToInferClosureParameterType failure(solution, getLocator()); return failure.diagnose(asNote); } SpecifyClosureParameterType * SpecifyClosureParameterType::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) SpecifyClosureParameterType(cs, locator); } bool SpecifyClosureReturnType::diagnose(const Solution &solution, bool asNote) const { UnableToInferClosureReturnType failure(solution, getLocator()); return failure.diagnose(asNote); } SpecifyClosureReturnType * SpecifyClosureReturnType::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) SpecifyClosureReturnType(cs, locator); } bool SpecifyObjectLiteralTypeImport::diagnose(const Solution &solution, bool asNote) const { UnableToInferProtocolLiteralType failure(solution, getLocator()); return failure.diagnose(asNote); } SpecifyObjectLiteralTypeImport * SpecifyObjectLiteralTypeImport::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) SpecifyObjectLiteralTypeImport(cs, locator); } AllowNonClassTypeToConvertToAnyObject::AllowNonClassTypeToConvertToAnyObject( ConstraintSystem &cs, Type type, ConstraintLocator *locator) : ContextualMismatch(cs, FixKind::AllowNonClassTypeToConvertToAnyObject, type, cs.getASTContext().getAnyObjectType(), locator) { } bool AllowNonClassTypeToConvertToAnyObject::diagnose(const Solution &solution, bool asNote) const { auto *locator = getLocator(); NonClassTypeToAnyObjectConversionFailure failure(solution, getFromType(), getToType(), locator); return failure.diagnose(asNote); } AllowNonClassTypeToConvertToAnyObject * AllowNonClassTypeToConvertToAnyObject::create(ConstraintSystem &cs, Type type, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowNonClassTypeToConvertToAnyObject(cs, type, locator); } bool SpecifyPackElementType::diagnose(const Solution &solution, bool asNote) const { UnableToInferGenericPackElementType failure(solution, getLocator()); return failure.diagnose(asNote); } SpecifyPackElementType * SpecifyPackElementType::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) SpecifyPackElementType(cs, locator); } bool AddQualifierToAccessTopLevelName::diagnose(const Solution &solution, bool asNote) const { MissingQualifierInMemberRefFailure failure(solution, getLocator()); return failure.diagnose(asNote); } AddQualifierToAccessTopLevelName * AddQualifierToAccessTopLevelName::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) AddQualifierToAccessTopLevelName(cs, locator); } bool AllowCoercionToForceCast::diagnose(const Solution &solution, bool asNote) const { CoercionAsForceCastFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } AllowCoercionToForceCast * AllowCoercionToForceCast::create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowCoercionToForceCast(cs, fromType, toType, locator); } bool AllowKeyPathRootTypeMismatch::diagnose(const Solution &solution, bool asNote) const { KeyPathRootTypeMismatchFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } AllowKeyPathRootTypeMismatch * AllowKeyPathRootTypeMismatch::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowKeyPathRootTypeMismatch(cs, lhs, rhs, locator); } SpecifyKeyPathRootType * SpecifyKeyPathRootType::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) SpecifyKeyPathRootType(cs, locator); } bool SpecifyKeyPathRootType::diagnose(const Solution &solution, bool asNote) const { UnableToInferKeyPathRootFailure failure(solution, getLocator()); return failure.diagnose(asNote); } bool UnwrapOptionalBaseKeyPathApplication::diagnose(const Solution &solution, bool asNote) const { MissingOptionalUnwrapKeyPathFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } UnwrapOptionalBaseKeyPathApplication * UnwrapOptionalBaseKeyPathApplication::attempt(ConstraintSystem &cs, Type baseTy, Type rootTy, ConstraintLocator *locator) { if(baseTy->hasTypeVariable() || rootTy->hasTypeVariable()) return nullptr; if (!isExpr(locator->getAnchor())) return nullptr; // Only diagnose this if base is an optional type and we only have a // single level of optionality so we can safely suggest unwrapping. auto nonOptionalTy = baseTy->getOptionalObjectType(); if (!nonOptionalTy || nonOptionalTy->getOptionalObjectType()) return nullptr; auto result = cs.matchTypes(nonOptionalTy, rootTy, ConstraintKind::Subtype, ConstraintSystem::TypeMatchFlags::TMF_ApplyingFix, locator); if (result.isFailure()) return nullptr; return new (cs.getAllocator()) UnwrapOptionalBaseKeyPathApplication(cs, baseTy, rootTy, locator); } bool SpecifyLabelToAssociateTrailingClosure::diagnose(const Solution &solution, bool asNote) const { TrailingClosureRequiresExplicitLabel failure(solution, getLocator()); return failure.diagnose(asNote); } SpecifyLabelToAssociateTrailingClosure * SpecifyLabelToAssociateTrailingClosure::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) SpecifyLabelToAssociateTrailingClosure(cs, locator); } bool AllowKeyPathWithoutComponents::diagnose(const Solution &solution, bool asNote) const { InvalidEmptyKeyPathFailure failure(solution, getLocator()); return failure.diagnose(asNote); } AllowKeyPathWithoutComponents * AllowKeyPathWithoutComponents::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowKeyPathWithoutComponents(cs, locator); } bool IgnoreInvalidResultBuilderBody::diagnose(const Solution &solution, bool asNote) const { // This should already be diagnosed by `matchResultBuilder`, emit a fallback // diagnostic if not. FallbackDiagnostic diag(solution, getLocator()); return diag.diagnose(asNote); } IgnoreInvalidResultBuilderBody * IgnoreInvalidResultBuilderBody::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreInvalidResultBuilderBody(cs, locator); } bool IgnoreInvalidASTNode::diagnose(const Solution &solution, bool asNote) const { // This should already be diagnosed by the producer of ErrorExpr or ErrorType, // emit a fallback diagnostic if not. FallbackDiagnostic diag(solution, getLocator()); return diag.diagnose(asNote); } IgnoreInvalidASTNode *IgnoreInvalidASTNode::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreInvalidASTNode(cs, locator); } bool IgnoreInvalidPatternInExpr::diagnose(const Solution &solution, bool asNote) const { InvalidPatternInExprFailure failure(solution, P, getLocator()); return failure.diagnose(asNote); } IgnoreInvalidPatternInExpr * IgnoreInvalidPatternInExpr::create(ConstraintSystem &cs, Pattern *pattern, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreInvalidPatternInExpr(cs, pattern, locator); } bool SpecifyContextualTypeForNil::diagnose(const Solution &solution, bool asNote) const { MissingContextualTypeForNil failure(solution, getLocator()); return failure.diagnose(asNote); } SpecifyContextualTypeForNil * SpecifyContextualTypeForNil::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) SpecifyContextualTypeForNil(cs, locator); } bool IgnoreInvalidPlaceholder::diagnose(const Solution &solution, bool asNote) const { InvalidPlaceholderFailure failure(solution, getLocator()); return failure.diagnose(asNote); } IgnoreInvalidPlaceholder * IgnoreInvalidPlaceholder::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreInvalidPlaceholder(cs, locator); } bool SpecifyTypeForPlaceholder::diagnose(const Solution &solution, bool asNote) const { CouldNotInferPlaceholderType failure(solution, getLocator()); return failure.diagnose(asNote); } SpecifyTypeForPlaceholder * SpecifyTypeForPlaceholder::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) SpecifyTypeForPlaceholder(cs, locator); } bool AllowRefToInvalidDecl::diagnose(const Solution &solution, bool asNote) const { ReferenceToInvalidDeclaration failure(solution, getLocator()); return failure.diagnose(asNote); } AllowRefToInvalidDecl * AllowRefToInvalidDecl::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowRefToInvalidDecl(cs, locator); } bool IgnoreResultBuilderWithReturnStmts::diagnose(const Solution &solution, bool asNote) const { InvalidReturnInResultBuilderBody failure(solution, BuilderType, getLocator()); return failure.diagnose(asNote); } IgnoreResultBuilderWithReturnStmts * IgnoreResultBuilderWithReturnStmts::create(ConstraintSystem &cs, Type builderTy, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreResultBuilderWithReturnStmts(cs, builderTy, locator); } bool IgnoreUnresolvedPatternVar::diagnose(const Solution &solution, bool asNote) const { // An unresolved AnyPatternDecl means there was some issue in the match // that means we couldn't infer the pattern. We don't have a diagnostic to // emit here, the failure should be diagnosed by the fix for expression. return false; } IgnoreUnresolvedPatternVar * IgnoreUnresolvedPatternVar::create(ConstraintSystem &cs, Pattern *pattern, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreUnresolvedPatternVar(cs, pattern, locator); } bool SpecifyBaseTypeForOptionalUnresolvedMember::diagnose( const Solution &solution, bool asNote) const { MemberMissingExplicitBaseTypeFailure failure(solution, MemberName, getLocator()); return failure.diagnose(asNote); } SpecifyBaseTypeForOptionalUnresolvedMember * SpecifyBaseTypeForOptionalUnresolvedMember::attempt( ConstraintSystem &cs, ConstraintKind kind, Type baseTy, DeclNameRef memberName, FunctionRefInfo functionRefInfo, MemberLookupResult result, ConstraintLocator *locator) { if (kind != ConstraintKind::UnresolvedValueMember) return nullptr; // Only diagnose for UnresolvedMemberExprs. // TODO: We ought to support diagnosing EnumElementPatterns too. if (!isExpr(locator->getAnchor())) return nullptr; // None or only one viable candidate, there is no ambiguity. if (result.ViableCandidates.size() <= 1) return nullptr; // Only diagnose those situations for static members. if (!baseTy->is()) return nullptr; // Don't diagnose for function members e.g. Foo? = .none(0). if (!functionRefInfo.isUnappliedBaseName()) return nullptr; Type underlyingBaseType = baseTy->getMetatypeInstanceType(); if (!underlyingBaseType->getNominalOrBoundGenericNominal()) return nullptr; if (!underlyingBaseType->getOptionalObjectType()) return nullptr; auto unwrappedType = underlyingBaseType->lookThroughAllOptionalTypes(); bool allOptionalBaseCandidates = true; auto filterViableCandidates = [&](SmallVector &candidates, SmallVector &viableCandidates, bool &allOptionalBase) { for (OverloadChoice choice : candidates) { if (!choice.isDecl()) continue; auto memberDecl = choice.getDecl(); if (isa(memberDecl)) continue; if (memberDecl->isInstanceMember()) continue; // Disable this warning for ambiguities related to a // static member lookup in generic context because it's // possible to declare a member with the same name on // a concrete type and in an extension of a protocol // that type conforms to e.g.: // // struct S : P { static var test: S { ... } // // extension P where Self == S { static var test: { ... } } // // And use that in an optional context e.g. passing `.test` // to a parameter of expecting `S?`. if (auto *extension = dyn_cast(memberDecl->getDeclContext())) { if (extension->getSelfProtocolDecl()) { allOptionalBase = false; break; } } allOptionalBase &= bool(choice.getBaseType() ->getMetatypeInstanceType() ->getOptionalObjectType()); if (auto EED = dyn_cast(memberDecl)) { if (!EED->hasAssociatedValues()) viableCandidates.push_back(choice); } else if (auto VD = dyn_cast(memberDecl)) { if (unwrappedType->hasTypeVariable() || VD->getInterfaceType()->isEqual(unwrappedType)) viableCandidates.push_back(choice); } } }; SmallVector viableCandidates; filterViableCandidates(result.ViableCandidates, viableCandidates, allOptionalBaseCandidates); // Also none or only one viable candidate after filtering candidates, there is // no ambiguity. if (viableCandidates.size() <= 1) return nullptr; // Right now, name lookup only unwraps a single layer of optionality, which // for cases where base type is a multi-optional type e.g. Foo?? it only // finds optional base candidates. To produce the correct warning we perform // an extra lookup on unwrapped type. if (!allOptionalBaseCandidates) return new (cs.getAllocator()) SpecifyBaseTypeForOptionalUnresolvedMember(cs, memberName, locator); MemberLookupResult unwrappedResult = cs.performMemberLookup(kind, memberName, MetatypeType::get(unwrappedType), functionRefInfo, locator, /*includeInaccessibleMembers*/ false); SmallVector unwrappedViableCandidates; filterViableCandidates(unwrappedResult.ViableCandidates, unwrappedViableCandidates, allOptionalBaseCandidates); if (unwrappedViableCandidates.empty()) return nullptr; return new (cs.getAllocator()) SpecifyBaseTypeForOptionalUnresolvedMember(cs, memberName, locator); } AllowCheckedCastCoercibleOptionalType * AllowCheckedCastCoercibleOptionalType::create(ConstraintSystem &cs, Type fromType, Type toType, CheckedCastKind kind, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowCheckedCastCoercibleOptionalType( cs, fromType, toType, kind, locator); } bool AllowCheckedCastCoercibleOptionalType::diagnose(const Solution &solution, bool asNote) const { CoercibleOptionalCheckedCastFailure failure( solution, getFromType(), getToType(), CastKind, getLocator()); return failure.diagnose(asNote); } AllowNoopCheckedCast *AllowNoopCheckedCast::create(ConstraintSystem &cs, Type fromType, Type toType, CheckedCastKind kind, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowNoopCheckedCast(cs, fromType, toType, kind, locator); } bool AllowNoopCheckedCast::diagnose(const Solution &solution, bool asNote) const { NoopCheckedCast warning(solution, getFromType(), getToType(), CastKind, getLocator()); return warning.diagnose(asNote); } AllowNoopExistentialToCFTypeCheckedCast * AllowNoopExistentialToCFTypeCheckedCast::attempt(ConstraintSystem &cs, Type fromType, Type toType, CheckedCastKind kind, ConstraintLocator *locator) { if (!isExpr(locator->getAnchor())) return nullptr; if (!fromType->isExistentialType()) return nullptr; const auto *cls = toType->getAs(); if (!(cls && cls->getDecl()->getForeignClassKind() == ClassDecl::ForeignKind::CFType)) return nullptr; return new (cs.getAllocator()) AllowNoopExistentialToCFTypeCheckedCast( cs, fromType, toType, kind, locator); } bool AllowNoopExistentialToCFTypeCheckedCast::diagnose(const Solution &solution, bool asNote) const { NoopExistentialToCFTypeCheckedCast warning( solution, getFromType(), getToType(), CastKind, getLocator()); return warning.diagnose(asNote); } // Although function types maybe compile-time convertible because // compiler can emit thunks at SIL to handle the conversion when // required, only conversions that are supported by the runtime are // when types are trivially equal or non-throwing from type is equal // to throwing to type without throwing clause conversions are not // possible at runtime. bool AllowUnsupportedRuntimeCheckedCast::runtimeSupportedFunctionTypeCast( FunctionType *fnFromType, FunctionType *fnToType) { if (fnFromType->isEqual(fnToType)) { return true; } else if (!fnFromType->isThrowing() && fnToType->isThrowing()) { return fnFromType->isEqual( fnToType->getWithoutThrowing()->castTo()); } // Runtime cannot perform such conversion. return false; } AllowUnsupportedRuntimeCheckedCast * AllowUnsupportedRuntimeCheckedCast::attempt(ConstraintSystem &cs, Type fromType, Type toType, CheckedCastKind kind, ConstraintLocator *locator) { auto fnFromType = fromType->getAs(); auto fnToType = toType->getAs(); if (!(fnFromType && fnToType)) return nullptr; if (runtimeSupportedFunctionTypeCast(fnFromType, fnToType)) return nullptr; return new (cs.getAllocator()) AllowUnsupportedRuntimeCheckedCast(cs, fromType, toType, kind, locator); } bool AllowUnsupportedRuntimeCheckedCast::diagnose(const Solution &solution, bool asNote) const { UnsupportedRuntimeCheckedCastFailure failure( solution, getFromType(), getToType(), CastKind, getLocator()); return failure.diagnose(asNote); } AllowCheckedCastToUnrelated * AllowCheckedCastToUnrelated::attempt(ConstraintSystem &cs, Type fromType, Type toType, CheckedCastKind kind, ConstraintLocator *locator) { // Explicit optional-to-optional casts always succeed because a nil // value of any optional type can be cast to any other optional type. if (fromType->getOptionalObjectType() && toType->getOptionalObjectType()) { return nullptr; } return new (cs.getAllocator()) AllowCheckedCastToUnrelated(cs, fromType, toType, kind, locator); } bool AllowCheckedCastToUnrelated::diagnose(const Solution &solution, bool asNote) const { CheckedCastToUnrelatedFailure warning(solution, getFromType(), getToType(), CastKind, getLocator()); return warning.diagnose(asNote); } bool AllowInvalidStaticMemberRefOnProtocolMetatype::diagnose( const Solution &solution, bool asNote) const { InvalidMemberRefOnProtocolMetatype failure(solution, getLocator()); return failure.diagnose(asNote); } AllowInvalidStaticMemberRefOnProtocolMetatype * AllowInvalidStaticMemberRefOnProtocolMetatype::create( ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInvalidStaticMemberRefOnProtocolMetatype(cs, locator); } bool AllowNonOptionalWeak::diagnose(const Solution &solution, bool asNote) const { InvalidWeakAttributeUse failure(solution, getLocator()); return failure.diagnose(asNote); } AllowNonOptionalWeak *AllowNonOptionalWeak::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowNonOptionalWeak(cs, locator); } AllowTupleLabelMismatch * AllowTupleLabelMismatch::create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowTupleLabelMismatch(cs, fromType, toType, locator); } bool AllowTupleLabelMismatch::diagnose(const Solution &solution, bool asNote) const { TupleLabelMismatchWarning warning(solution, getFromType(), getToType(), getLocator()); return warning.diagnose(asNote); } AllowAssociatedValueMismatch * AllowAssociatedValueMismatch::create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowAssociatedValueMismatch(cs, fromType, toType, locator); } bool AllowAssociatedValueMismatch::diagnose(const Solution &solution, bool asNote) const { AssociatedValueMismatchFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } bool AllowSwiftToCPointerConversion::diagnose(const Solution &solution, bool asNote) const { SwiftToCPointerConversionInInvalidContext failure(solution, getLocator()); return failure.diagnose(asNote); } AllowSwiftToCPointerConversion * AllowSwiftToCPointerConversion::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowSwiftToCPointerConversion(cs, locator); } bool IgnoreDefaultExprTypeMismatch::diagnose(const Solution &solution, bool asNote) const { DefaultExprTypeMismatch failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } IgnoreDefaultExprTypeMismatch * IgnoreDefaultExprTypeMismatch::create(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreDefaultExprTypeMismatch(cs, argType, paramType, locator); } bool RenameConflictingPatternVariables::diagnose(const Solution &solution, bool asNote) const { ConflictingPatternVariables failure(solution, ExpectedType, getConflictingVars(), getLocator()); return failure.diagnose(asNote); } RenameConflictingPatternVariables * RenameConflictingPatternVariables::create(ConstraintSystem &cs, Type expectedTy, ArrayRef conflicts, ConstraintLocator *locator) { unsigned size = totalSizeToAlloc(conflicts.size()); void *mem = cs.getAllocator().Allocate( size, alignof(RenameConflictingPatternVariables)); return new (mem) RenameConflictingPatternVariables(cs, expectedTy, conflicts, locator); } bool MacroMissingPound::diagnose(const Solution &solution, bool asNote) const { AddMissingMacroPound failure(solution, macro, getLocator()); return failure.diagnose(asNote); } MacroMissingPound * MacroMissingPound::create(ConstraintSystem &cs, MacroDecl *macro, ConstraintLocator *locator) { return new (cs.getAllocator()) MacroMissingPound(cs, macro, locator); } bool AllowGlobalActorMismatch::diagnose(const Solution &solution, bool asNote) const { GlobalActorFunctionMismatchFailure failure(solution, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } AllowGlobalActorMismatch * AllowGlobalActorMismatch::create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowGlobalActorMismatch(cs, fromType, toType, locator); } bool DestructureTupleToMatchPackExpansionParameter::diagnose( const Solution &solution, bool asNote) const { DestructureTupleToUseWithPackExpansionParameter failure(solution, ParamShape, getLocator()); return failure.diagnose(asNote); } DestructureTupleToMatchPackExpansionParameter * DestructureTupleToMatchPackExpansionParameter::create( ConstraintSystem &cs, PackType *paramShapeTy, ConstraintLocator *locator) { return new (cs.getAllocator()) DestructureTupleToMatchPackExpansionParameter(cs, paramShapeTy, locator); } bool AllowValueExpansionWithoutPackReferences::diagnose( const Solution &solution, bool asNote) const { ValuePackExpansionWithoutPackReferences failure(solution, getLocator()); return failure.diagnose(asNote); } AllowValueExpansionWithoutPackReferences * AllowValueExpansionWithoutPackReferences::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowValueExpansionWithoutPackReferences(cs, locator); } bool IgnoreMissingEachKeyword::diagnose(const Solution &solution, bool asNote) const { MissingEachForValuePackReference failure(solution, ValuePackType, getLocator()); return failure.diagnose(asNote); } IgnoreMissingEachKeyword * IgnoreMissingEachKeyword::create(ConstraintSystem &cs, Type valuePackTy, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreMissingEachKeyword(cs, valuePackTy, locator); } bool AllowInvalidMemberReferenceInInitAccessor::diagnose( const Solution &solution, bool asNote) const { InvalidMemberReferenceWithinInitAccessor failure(solution, MemberName, getLocator()); return failure.diagnose(asNote); } AllowInvalidMemberReferenceInInitAccessor * AllowInvalidMemberReferenceInInitAccessor::create(ConstraintSystem &cs, DeclNameRef memberName, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInvalidMemberReferenceInInitAccessor(cs, memberName, locator); } bool AllowConcreteTypeSpecialization::diagnose(const Solution &solution, bool asNote) const { ConcreteTypeSpecialization failure(solution, ConcreteType, Decl, getLocator(), fixBehavior); return failure.diagnose(asNote); } AllowConcreteTypeSpecialization *AllowConcreteTypeSpecialization::create( ConstraintSystem &cs, Type concreteTy, ValueDecl *decl, ConstraintLocator *locator, FixBehavior fixBehavior) { return new (cs.getAllocator()) AllowConcreteTypeSpecialization( cs, concreteTy, decl, locator, fixBehavior); } bool AllowFunctionSpecialization::diagnose(const Solution &solution, bool asNote) const { InvalidFunctionSpecialization failure(solution, Decl, getLocator(), fixBehavior); return failure.diagnose(asNote); } AllowFunctionSpecialization * AllowFunctionSpecialization::create(ConstraintSystem &cs, ValueDecl *decl, ConstraintLocator *locator) { auto fixBehavior = cs.getASTContext().isSwiftVersionAtLeast(6) ? FixBehavior::Error : FixBehavior::DowngradeToWarning; return new (cs.getAllocator()) AllowFunctionSpecialization(cs, decl, locator, fixBehavior); } bool IgnoreOutOfPlaceThenStmt::diagnose(const Solution &solution, bool asNote) const { OutOfPlaceThenStmtFailure failure(solution, getLocator()); return failure.diagnose(asNote); } IgnoreOutOfPlaceThenStmt * IgnoreOutOfPlaceThenStmt::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreOutOfPlaceThenStmt(cs, locator); } bool IgnoreGenericSpecializationArityMismatch::diagnose( const Solution &solution, bool asNote) const { InvalidTypeSpecializationArity failure(solution, D, NumParams, NumArgs, HasParameterPack, getLocator()); return failure.diagnose(asNote); } IgnoreGenericSpecializationArityMismatch * IgnoreGenericSpecializationArityMismatch::create(ConstraintSystem &cs, ValueDecl *decl, unsigned numParams, unsigned numArgs, bool hasParameterPack, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreGenericSpecializationArityMismatch( cs, decl, numParams, numArgs, hasParameterPack, locator); } bool IgnoreKeyPathSubscriptIndexMismatch::diagnose(const Solution &solution, bool asNote) const { InvalidTypeAsKeyPathSubscriptIndex failure(solution, ArgType, getLocator()); return failure.diagnose(asNote); } IgnoreKeyPathSubscriptIndexMismatch * IgnoreKeyPathSubscriptIndexMismatch::create(ConstraintSystem &cs, Type argType, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreKeyPathSubscriptIndexMismatch(cs, argType, locator); } AllowInlineArrayLiteralCountMismatch * AllowInlineArrayLiteralCountMismatch::create(ConstraintSystem &cs, Type lhsCount, Type rhsCount, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInlineArrayLiteralCountMismatch(cs, lhsCount, rhsCount, locator); } bool AllowInlineArrayLiteralCountMismatch::diagnose(const Solution &solution, bool asNote) const { IncorrectInlineArrayLiteralCount failure(solution, lhsCount, rhsCount, getLocator()); return failure.diagnose(asNote); } TooManyDynamicMemberLookups * TooManyDynamicMemberLookups::create(ConstraintSystem &cs, DeclNameRef name, ConstraintLocator *locator) { return new (cs.getAllocator()) TooManyDynamicMemberLookups(cs, name, locator); } bool TooManyDynamicMemberLookups::diagnose(const Solution &solution, bool asNote) const { TooManyDynamicMemberLookupsFailure failure(solution, Name, getLocator()); return failure.diagnose(asNote); } IgnoreIsolatedConformance * IgnoreIsolatedConformance::create(ConstraintSystem &cs, ConstraintLocator *locator, ProtocolConformance *conformance) { return new (cs.getAllocator()) IgnoreIsolatedConformance(cs, locator, conformance); } bool IgnoreIsolatedConformance::diagnose(const Solution &solution, bool asNote) const { DisallowedIsolatedConformance failure(solution, conformance, getLocator()); return failure.diagnose(asNote); }