//===--- CSDiag.cpp - 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 implements diagnostics for the type checker. // //===----------------------------------------------------------------------===// #include "CSDiag.h" #include "CSDiagnostics.h" #include "CalleeCandidateInfo.h" #include "ConstraintSystem.h" #include "MiscDiagnostics.h" #include "TypeCheckAvailability.h" #include "TypoCorrection.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Initializer.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/TypeMatcher.h" #include "swift/AST/TypeWalker.h" #include "swift/Basic/Defer.h" #include "swift/Basic/StringExtras.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SetVector.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/SaveAndRestore.h" using namespace swift; using namespace constraints; namespace swift { std::string getTypeListString(Type type) { std::string result; // Always make sure to have at least one set of parens bool forceParens = !type->is() && !type->hasParenSugar(); if (forceParens) result.push_back('('); llvm::raw_string_ostream OS(result); type->print(OS); OS.flush(); if (forceParens) result.push_back(')'); return result; } Type replaceTypeParametersWithUnresolved(Type ty) { if (!ty) return ty; if (!ty->hasTypeParameter() && !ty->hasArchetype()) return ty; auto &ctx = ty->getASTContext(); return ty.transform([&](Type type) -> Type { if (type->is() || type->isTypeParameter()) return ctx.TheUnresolvedType; return type; }); } Type replaceTypeVariablesWithUnresolved(Type ty) { if (!ty) return ty; if (!ty->hasTypeVariable()) return ty; auto &ctx = ty->getASTContext(); return ty.transform([&](Type type) -> Type { if (type->isTypeVariableOrMember()) return ctx.TheUnresolvedType; return type; }); } }; static bool isUnresolvedOrTypeVarType(Type ty) { return ty->isTypeVariableOrMember() || ty->is(); } /// Given a subpath of an old locator, compute its summary flags. static unsigned recomputeSummaryFlags(ConstraintLocator *oldLocator, ArrayRef path) { if (oldLocator->getSummaryFlags() != 0) return ConstraintLocator::getSummaryFlagsForPath(path); return 0; } ConstraintLocator * constraints::simplifyLocator(ConstraintSystem &cs, ConstraintLocator *locator, SourceRange &range, ConstraintLocator **targetLocator) { // Clear out the target locator result. if (targetLocator) *targetLocator = nullptr; // The path to be tacked on to the target locator to identify the specific // target. Expr *targetAnchor; SmallVector targetPath; auto path = locator->getPath(); auto anchor = locator->getAnchor(); simplifyLocator(anchor, path, targetAnchor, targetPath, range); // If we have a target anchor, build and simplify the target locator. if (targetLocator && targetAnchor) { SourceRange targetRange; unsigned targetFlags = recomputeSummaryFlags(locator, targetPath); auto loc = cs.getConstraintLocator(targetAnchor, targetPath, targetFlags); *targetLocator = simplifyLocator(cs, loc, targetRange); } // If we didn't simplify anything, just return the input. if (anchor == locator->getAnchor() && path.size() == locator->getPath().size()) { return locator; } // Recompute the summary flags if we had any to begin with. This is // necessary because we might remove e.g. tuple elements from the path. unsigned summaryFlags = recomputeSummaryFlags(locator, path); return cs.getConstraintLocator(anchor, path, summaryFlags); } void constraints::simplifyLocator(Expr *&anchor, ArrayRef &path, Expr *&targetAnchor, SmallVectorImpl &targetPath, SourceRange &range) { range = SourceRange(); targetAnchor = nullptr; while (!path.empty()) { switch (path[0].getKind()) { case ConstraintLocator::ApplyArgument: { // Extract application argument. if (auto applyExpr = dyn_cast(anchor)) { // The target anchor is the function being called. targetAnchor = applyExpr->getFn(); targetPath.push_back(path[0]); anchor = applyExpr->getArg(); path = path.slice(1); continue; } if (auto objectLiteralExpr = dyn_cast(anchor)) { targetAnchor = nullptr; targetPath.clear(); anchor = objectLiteralExpr->getArg(); path = path.slice(1); continue; } if (auto *UME = dyn_cast(anchor)) { // The target anchor is the method being called, // no additional information could be retrieved // about this call. targetAnchor = nullptr; targetPath.clear(); anchor = UME->getArgument(); path = path.slice(1); continue; } break; } case ConstraintLocator::ApplyFunction: // Extract application function. if (auto applyExpr = dyn_cast(anchor)) { // No additional target locator information. targetAnchor = nullptr; targetPath.clear(); anchor = applyExpr->getFn(); path = path.slice(1); continue; } // The unresolved member itself is the function. if (auto unresolvedMember = dyn_cast(anchor)) { if (unresolvedMember->getArgument()) { // No additional target locator information. targetAnchor = nullptr; targetPath.clear(); anchor = unresolvedMember; path = path.slice(1); continue; } } break; case ConstraintLocator::AutoclosureResult: case ConstraintLocator::LValueConversion: case ConstraintLocator::RValueAdjustment: case ConstraintLocator::UnresolvedMember: // Arguments in autoclosure positions, lvalue and rvalue adjustments, and // scalar-to-tuple conversions, and unresolved members are // implicit. path = path.slice(1); continue; case ConstraintLocator::NamedTupleElement: case ConstraintLocator::TupleElement: // Extract tuple element. if (auto tupleExpr = dyn_cast(anchor)) { unsigned index = path[0].getValue(); if (index < tupleExpr->getNumElements()) { // Append this extraction to the target locator path. if (targetAnchor) { targetPath.push_back(path[0]); } anchor = tupleExpr->getElement(index); path = path.slice(1); continue; } } break; case ConstraintLocator::ApplyArgToParam: // Extract tuple element. if (auto tupleExpr = dyn_cast(anchor)) { unsigned index = path[0].getValue(); if (index < tupleExpr->getNumElements()) { // Append this extraction to the target locator path. if (targetAnchor) { targetPath.push_back(path[0]); } anchor = tupleExpr->getElement(index); path = path.slice(1); continue; } } // Extract subexpression in parentheses. if (auto parenExpr = dyn_cast(anchor)) { assert(path[0].getValue() == 0); // Append this extraction to the target locator path. if (targetAnchor) { targetPath.push_back(path[0]); } anchor = parenExpr->getSubExpr(); path = path.slice(1); continue; } break; case ConstraintLocator::ConstructorMember: if (auto typeExpr = dyn_cast(anchor)) { // This is really an implicit 'init' MemberRef, so point at the base, // i.e. the TypeExpr. targetAnchor = nullptr; targetPath.clear(); range = SourceRange(); anchor = typeExpr; path = path.slice(1); continue; } LLVM_FALLTHROUGH; case ConstraintLocator::Member: case ConstraintLocator::MemberRefBase: if (auto UDE = dyn_cast(anchor)) { // No additional target locator information. targetAnchor = nullptr; targetPath.clear(); range = UDE->getNameLoc().getSourceRange(); anchor = UDE->getBase(); path = path.slice(1); continue; } break; case ConstraintLocator::SubscriptMember: if (isa(anchor)) { targetAnchor = nullptr; targetPath.clear(); path = path.slice(1); continue; } break; case ConstraintLocator::ClosureResult: if (auto CE = dyn_cast(anchor)) { if (CE->hasSingleExpressionBody()) { targetAnchor = nullptr; targetPath.clear(); anchor = CE->getSingleExpressionBody(); path = path.slice(1); continue; } } break; case ConstraintLocator::ContextualType: // This was just for identifying purposes, strip it off. path = path.slice(1); continue; default: // FIXME: Lots of other cases to handle. break; } // If we get here, we couldn't simplify the path further. break; } } /// Flags that can be used to control name lookup. enum TCCFlags { /// Allow the result of the subexpression to be an lvalue. If this is not /// specified, any lvalue will be forced to be loaded into an rvalue. TCC_AllowLValue = 0x01, /// Re-type-check the given subexpression even if the expression has already /// been checked already. The client is asserting that infinite recursion is /// not possible because it has relaxed a constraint on the system. TCC_ForceRecheck = 0x02, /// tell typeCheckExpression that it is ok to produce an ambiguous result, /// it can just fill in holes with UnresolvedType and we'll deal with it. TCC_AllowUnresolvedTypeVariables = 0x04 }; using TCCOptions = OptionSet; inline TCCOptions operator|(TCCFlags flag1, TCCFlags flag2) { return TCCOptions(flag1) | flag2; } namespace { /// If a constraint system fails to converge on a solution for a given /// expression, this class can produce a reasonable diagnostic for the failure /// by analyzing the remnants of the failed constraint system. (Specifically, /// left-over inactive, active and failed constraints.) /// This class does not tune its diagnostics for a specific expression kind, /// for that, you'll want to use an instance of the FailureDiagnosis class. class FailureDiagnosis :public ASTVisitor{ friend class ASTVisitor; Expr *expr = nullptr; ConstraintSystem &CS; public: FailureDiagnosis(Expr *expr, ConstraintSystem &cs) : expr(expr), CS(cs) { assert(expr); } template InFlightDiagnostic diagnose(ArgTypes &&...Args) { return CS.TC.diagnose(std::forward(Args)...); } /// Attempt to diagnose a failure without taking into account the specific /// kind of expression that could not be type checked. bool diagnoseConstraintFailure(); /// Unless we've already done this, retypecheck the specified child of the /// current expression on its own, without including any contextual /// constraints or the parent expr nodes. This is more likely to succeed than /// type checking the original expression. /// /// This mention may only be used on immediate children of the current expr /// node, because ClosureExpr parameters need to be treated specially. /// /// This can return a new expression (for e.g. when a UnresolvedDeclRef gets /// resolved) and returns null when the subexpression fails to typecheck. /// Expr *typeCheckChildIndependently( Expr *subExpr, Type convertType = Type(), ContextualTypePurpose convertTypePurpose = CTP_Unused, TCCOptions options = TCCOptions(), ExprTypeCheckListener *listener = nullptr, bool allowFreeTypeVariables = true); Expr *typeCheckChildIndependently(Expr *subExpr, TCCOptions options, bool allowFreeTypeVariables = true) { return typeCheckChildIndependently(subExpr, Type(), CTP_Unused, options, nullptr, allowFreeTypeVariables); } Type getTypeOfTypeCheckedChildIndependently(Expr *subExpr, TCCOptions options = TCCOptions()) { auto e = typeCheckChildIndependently(subExpr, options); return e ? CS.getType(e) : Type(); } /// This is the same as typeCheckChildIndependently, but works on an arbitrary /// subexpression of the current node because it handles ClosureExpr parents /// of the specified node. Expr *typeCheckArbitrarySubExprIndependently(Expr *subExpr, TCCOptions options = TCCOptions()); /// Special magic to handle inout exprs and tuples in argument lists. Expr *typeCheckArgumentChildIndependently(Expr *argExpr, Type argType, const CalleeCandidateInfo &candidates, TCCOptions options = TCCOptions()); void getPossibleTypesOfExpressionWithoutApplying( Expr *&expr, DeclContext *dc, SmallPtrSetImpl &types, FreeTypeVariableBinding allowFreeTypeVariables = FreeTypeVariableBinding::Disallow, ExprTypeCheckListener *listener = nullptr) { CS.TC.getPossibleTypesOfExpressionWithoutApplying( expr, dc, types, allowFreeTypeVariables, listener); CS.cacheExprTypes(expr); } Type getTypeOfExpressionWithoutApplying( Expr *&expr, DeclContext *dc, ConcreteDeclRef &referencedDecl, FreeTypeVariableBinding allowFreeTypeVariables = FreeTypeVariableBinding::Disallow, ExprTypeCheckListener *listener = nullptr) { auto type = CS.TC.getTypeOfExpressionWithoutApplying(expr, dc, referencedDecl, allowFreeTypeVariables, listener); CS.cacheExprTypes(expr); return type; } /// Diagnose common failures due to applications of an argument list to an /// ApplyExpr or SubscriptExpr. bool diagnoseParameterErrors(CalleeCandidateInfo &CCI, Expr *fnExpr, Expr *argExpr, ArrayRef argLabels); /// Attempt to diagnose a specific failure from the info we've collected from /// the failed constraint system. bool diagnoseExprFailure(); /// Emit an ambiguity diagnostic about the specified expression. void diagnoseAmbiguity(Expr *E); /// Attempt to produce a diagnostic for a mismatch between an expression's /// type and its assumed contextual type. bool diagnoseContextualConversionError(Expr *expr, Type contextualType, ContextualTypePurpose CTP, Type suggestedType = Type()); /// For an expression being type checked with a CTP_CalleeResult contextual /// type, try to diagnose a problem. bool diagnoseCalleeResultContextualConversionError(); /// Attempt to produce a diagnostic for a mismatch between a call's /// type and its assumed contextual type. bool diagnoseCallContextualConversionErrors(ApplyExpr *callEpxr, Type contextualType, ContextualTypePurpose CTP); bool diagnoseImplicitSelfErrors(Expr *fnExpr, Expr *argExpr, CalleeCandidateInfo &CCI, ArrayRef argLabels); private: /// Validate potential contextual type for type-checking one of the /// sub-expressions, usually correct/valid types are the ones which /// either don't have type variables or are not generic, because /// generic types with left-over type variables or unresolved types /// degrade quality of diagnostics if allowed to be used as contextual. /// /// \param contextualType The candidate contextual type. /// \param CTP The contextual purpose attached to the given candidate. /// /// \returns Pair of validated type and it's purpose, potentially nullified /// if it wasn't an appropriate type to be used. std::pair validateContextualType(Type contextualType, ContextualTypePurpose CTP); /// Check the specified closure to see if it is a multi-statement closure with /// an uninferred type. If so, diagnose the problem with an error and return /// true. bool diagnoseAmbiguousMultiStatementClosure(ClosureExpr *closure); /// Check the associated constraint system to see if it has any opened generic /// parameters that were not bound to a fixed type. If so, diagnose the /// problem with an error and return true. bool diagnoseAmbiguousGenericParameters(); /// Emit an error message about an unbound generic parameter, and emit notes /// referring to the target of a diagnostic, e.g., the function or parameter /// being used. void diagnoseAmbiguousGenericParameter(GenericTypeParamType *paramTy, Expr *anchor); /// Produce a diagnostic for a general member-lookup failure (irrespective of /// the exact expression kind). bool diagnoseGeneralMemberFailure(Constraint *constraint); /// Given a result of name lookup that had no viable results, diagnose the /// unviable ones. void diagnoseUnviableLookupResults(MemberLookupResult &lookupResults, Expr *expr, Type baseObjTy, Expr *baseExpr, DeclName memberName, DeclNameLoc nameLoc, SourceLoc loc); /// Produce a diagnostic for a general overload resolution failure /// (irrespective of the exact expression kind). bool diagnoseGeneralOverloadFailure(Constraint *constraint); /// Produce a diagnostic for a general conversion failure (irrespective of the /// exact expression kind). bool diagnoseGeneralConversionFailure(Constraint *constraint); /// Produce a specialized diagnostic if this is an invalid conversion to Bool. bool diagnoseConversionToBool(Expr *expr, Type exprType); /// Produce a diagnostic for binary comparisons of the nil literal /// to other values. bool diagnoseNilLiteralComparison(Expr *lhsExpr, Expr *rhsExpr, CalleeCandidateInfo &calleeInfo, SourceLoc applyLoc); /// Produce diagnostic for failures related to attributes associated with /// candidate functions/methods e.g. mutability. bool diagnoseMethodAttributeFailures(ApplyExpr *expr, ArrayRef argLabels, bool hasTrailingClosure, CalleeCandidateInfo &candidates); /// Produce diagnostic for failures related to unfulfilled requirements /// of the generic parameters used as arguments. bool diagnoseArgumentGenericRequirements(TypeChecker &TC, Expr *callExpr, Expr *fnExpr, Expr *argExpr, CalleeCandidateInfo &candidates, ArrayRef argLabels); bool diagnoseMemberFailures( Expr *E, Expr *baseEpxr, ConstraintKind lookupKind, DeclName memberName, FunctionRefKind funcRefKind, ConstraintLocator *locator, Optional)>> callback = None, bool includeInaccessibleMembers = true); bool diagnoseTrailingClosureErrors(ApplyExpr *expr); bool diagnoseClosureExpr(ClosureExpr *closureExpr, Type contextualType, llvm::function_ref resultTypeProcessor); bool diagnoseSubscriptErrors(SubscriptExpr *SE, bool performingSet); /// Try to diagnose common errors involving implicitly non-escaping parameters /// of function type, giving more specific and simpler diagnostics, attaching /// notes on the parameter, and offering fixits to insert @escaping. Returns /// true if it detects and issues an error, false if it does nothing. bool diagnoseNonEscapingParameterToEscaping(Expr *expr, Type srcType, Type dstType, ContextualTypePurpose dstPurpose); bool visitExpr(Expr *E); bool visitIdentityExpr(IdentityExpr *E); bool visitTryExpr(TryExpr *E); bool visitTupleExpr(TupleExpr *E); bool visitUnresolvedMemberExpr(UnresolvedMemberExpr *E); bool visitUnresolvedDotExpr(UnresolvedDotExpr *UDE); bool visitArrayExpr(ArrayExpr *E); bool visitDictionaryExpr(DictionaryExpr *E); bool visitObjectLiteralExpr(ObjectLiteralExpr *E); bool visitForceValueExpr(ForceValueExpr *FVE); bool visitBindOptionalExpr(BindOptionalExpr *BOE); bool visitSubscriptExpr(SubscriptExpr *SE); bool visitApplyExpr(ApplyExpr *AE); bool visitAssignExpr(AssignExpr *AE); bool visitInOutExpr(InOutExpr *IOE); bool visitCoerceExpr(CoerceExpr *CE); bool visitIfExpr(IfExpr *IE); bool visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E); bool visitCaptureListExpr(CaptureListExpr *CLE); bool visitClosureExpr(ClosureExpr *CE); bool visitKeyPathExpr(KeyPathExpr *KPE); }; } // end anonymous namespace static bool isMemberConstraint(Constraint *C) { return C->getClassification() == ConstraintClassification::Member; } static bool isOverloadConstraint(Constraint *C) { if (C->getKind() == ConstraintKind::BindOverload) return true; if (C->getKind() != ConstraintKind::Disjunction) return false; return C->getNestedConstraints().front()->getKind() == ConstraintKind::BindOverload; } /// Return true if this constraint is a conversion or requirement between two /// types. static bool isConversionConstraint(const Constraint *C) { return C->getClassification() == ConstraintClassification::Relational; } /// Attempt to diagnose a failure without taking into account the specific /// kind of expression that could not be type checked. bool FailureDiagnosis::diagnoseConstraintFailure() { // This is the priority order in which we handle constraints. Things earlier // in the list are considered to have higher specificity (and thus, higher // priority) than things lower in the list. enum ConstraintRanking { CR_MemberConstraint, CR_ConversionConstraint, CR_OverloadConstraint, CR_OtherConstraint }; // Start out by classifying all the constraints. using RCElt = std::pair; std::vector rankedConstraints; // This is a predicate that classifies constraints according to our // priorities. std::function classifyConstraint = [&](Constraint *C) { if (isMemberConstraint(C)) return rankedConstraints.push_back({C, CR_MemberConstraint}); if (isOverloadConstraint(C)) return rankedConstraints.push_back({C, CR_OverloadConstraint}); if (isConversionConstraint(C)) return rankedConstraints.push_back({C, CR_ConversionConstraint}); // We occasionally end up with disjunction constraints containing an // original constraint along with one considered with a fix. If we find // this situation, add the original one to our list for diagnosis. if (C->getKind() == ConstraintKind::Disjunction) { Constraint *Orig = nullptr; bool AllOthersHaveFixes = true; for (auto DC : C->getNestedConstraints()) { // If this is a constraint inside of the disjunction with a fix, ignore // it. if (DC->getFix()) continue; // If we already found a candidate without a fix, we can't do this. if (Orig) { AllOthersHaveFixes = false; break; } // Remember this as the exemplar to use. Orig = DC; } if (Orig && AllOthersHaveFixes) return classifyConstraint(Orig); // If we got all the way down to a truly ambiguous disjunction constraint // with a conversion in it, the problem could be that none of the options // in the disjunction worked. // // We don't have a lot of great options here, so (if all else fails), // we'll attempt to diagnose the issue as though the first option was the // problem. rankedConstraints.push_back({ C->getNestedConstraints()[0], CR_OtherConstraint }); return; } return rankedConstraints.push_back({C, CR_OtherConstraint}); }; // Look at the failed constraint and the general constraint list. Processing // the failed constraint first slightly biases it in the ranking ahead of // other failed constraints at the same level. if (CS.failedConstraint) classifyConstraint(CS.failedConstraint); for (auto &C : CS.getConstraints()) classifyConstraint(&C); // Okay, now that we've classified all the constraints, sort them by their // priority and privilege the favored constraints. std::stable_sort(rankedConstraints.begin(), rankedConstraints.end(), [&] (RCElt LHS, RCElt RHS) { // Rank things by their kind as the highest priority. if (LHS.second < RHS.second) return true; if (LHS.second > RHS.second) return false; // Next priority is favored constraints. if (LHS.first->isFavored() != RHS.first->isFavored()) return LHS.first->isFavored(); return false; }); // Now that we have a sorted precedence of constraints to diagnose, charge // through them. for (auto elt : rankedConstraints) { auto C = elt.first; if (isMemberConstraint(C) && diagnoseGeneralMemberFailure(C)) return true; if (isConversionConstraint(C) && diagnoseGeneralConversionFailure(C)) return true; if (isOverloadConstraint(C) && diagnoseGeneralOverloadFailure(C)) return true; // TODO: There can be constraints that aren't handled here! When this // happens, we end up diagnosing them as ambiguities that don't make sense. // This isn't as bad as it seems though, because most of these will be // diagnosed by expr diagnostics. } // Otherwise, all the constraints look ok, diagnose this as an ambiguous // expression. return false; } bool FailureDiagnosis::diagnoseGeneralMemberFailure(Constraint *constraint) { assert(isMemberConstraint(constraint)); // Get the referenced base expression from the failed constraint, along with // the SourceRange for the member ref. In "x.y", this returns the expr for x // and the source range for y. auto anchor = expr; SourceRange memberRange = anchor->getSourceRange(); auto locator = constraint->getLocator(); if (locator) { locator = simplifyLocator(CS, locator, memberRange); if (locator->getAnchor()) anchor = locator->getAnchor(); } // Check to see if this is a locator referring to something we cannot or do // here: in this case, we ignore paths that end on archetypes witnesses, or // associated types of the expression. if (locator && !locator->getPath().empty()) { // TODO: This should only ignore *unresolved* archetypes. For resolved // archetypes return false; } return diagnoseMemberFailures(expr, anchor, constraint->getKind(), constraint->getMember(), constraint->getFunctionRefKind(), locator); } /// Given a result of name lookup that had no viable results, diagnose the /// unviable ones. void FailureDiagnosis::diagnoseUnviableLookupResults( MemberLookupResult &result, Expr *E, Type baseObjTy, Expr *baseExpr, DeclName memberName, DeclNameLoc nameLoc, SourceLoc loc) { SourceRange baseRange = baseExpr ? baseExpr->getSourceRange() : SourceRange(); // If we found no results at all, mention that fact. if (result.UnviableCandidates.empty()) { MissingMemberFailure failure(nullptr, CS, baseObjTy, memberName, CS.getConstraintLocator(E)); auto diagnosed = failure.diagnoseAsError(); assert(diagnosed && "Failed to produce missing member diagnostic"); (void)diagnosed; return; } // Otherwise, we have at least one (and potentially many) viable candidates // sort them out. If all of the candidates have the same problem (commonly // because there is exactly one candidate!) diagnose this. bool sameProblem = true; auto firstProblem = result.UnviableCandidates[0].second; ValueDecl *member = nullptr; for (auto cand : result.UnviableCandidates) { if (member == nullptr) member = cand.first.getDecl(); sameProblem &= cand.second == firstProblem; } auto instanceTy = baseObjTy; if (auto *MTT = instanceTy->getAs()) instanceTy = MTT->getInstanceType(); if (sameProblem) { switch (firstProblem) { case MemberLookupResult::UR_LabelMismatch: break; case MemberLookupResult::UR_UnavailableInExistential: diagnose(loc, diag::could_not_use_member_on_existential, instanceTy, memberName) .highlight(baseRange).highlight(nameLoc.getSourceRange()); return; case MemberLookupResult::UR_InstanceMemberOnType: case MemberLookupResult::UR_TypeMemberOnInstance: { auto locatorKind = isa(E) ? ConstraintLocator::SubscriptMember : ConstraintLocator::Member; AllowTypeOrInstanceMemberFailure failure( nullptr, CS, baseObjTy, memberName, CS.getConstraintLocator(E, locatorKind)); auto diagnosed = failure.diagnoseAsError(); assert(diagnosed && "Failed to produce missing or extraneous metatype diagnostic"); (void)diagnosed; return; } case MemberLookupResult::UR_MutatingMemberOnRValue: case MemberLookupResult::UR_MutatingGetterOnRValue: { auto diagIDsubelt = diag::cannot_pass_rvalue_mutating_subelement; auto diagIDmember = diag::cannot_pass_rvalue_mutating; if (firstProblem == MemberLookupResult::UR_MutatingGetterOnRValue) { diagIDsubelt = diag::cannot_pass_rvalue_mutating_getter_subelement; diagIDmember = diag::cannot_pass_rvalue_mutating_getter; } assert(baseExpr && "Cannot have a mutation failure without a base"); AssignmentFailure failure(baseExpr, CS, loc, diagIDsubelt, diagIDmember); (void)failure.diagnose(); return; } case MemberLookupResult::UR_Inaccessible: { auto decl = result.UnviableCandidates[0].first.getDecl(); // FIXME: What if the unviable candidates have different levels of access? // // If we found an inaccessible member of a protocol extension, it might // be declared 'public'. This can only happen if the protocol is not // visible to us, but the conforming type is. In this case, we need to // clamp the formal access for diagnostics purposes to the formal access // of the protocol itself. diagnose(nameLoc, diag::candidate_inaccessible, decl->getBaseName(), decl->getFormalAccessScope().accessLevelForDiagnostics()); for (auto cand : result.UnviableCandidates) diagnose(cand.first.getDecl(), diag::decl_declared_here, memberName); return; } } } // Otherwise, we don't have a specific issue to diagnose. Just say the vague // 'cannot use' diagnostic. if (!baseObjTy->isEqual(instanceTy)) diagnose(loc, diag::could_not_use_type_member, instanceTy, memberName) .highlight(baseRange).highlight(nameLoc.getSourceRange()); else diagnose(loc, diag::could_not_use_value_member, baseObjTy, memberName) .highlight(baseRange).highlight(nameLoc.getSourceRange()); return; } // In the absence of a better conversion constraint failure, point out the // inability to find an appropriate overload. bool FailureDiagnosis::diagnoseGeneralOverloadFailure(Constraint *constraint) { Constraint *bindOverload = constraint; if (constraint->getKind() == ConstraintKind::Disjunction) bindOverload = constraint->getNestedConstraints().front(); auto overloadChoice = bindOverload->getOverloadChoice(); auto overloadName = overloadChoice.getName(); // Get the referenced expression from the failed constraint. auto anchor = expr; if (auto locator = bindOverload->getLocator()) { anchor = simplifyLocatorToAnchor(CS, locator); if (!anchor) return false; } // The anchor for the constraint is almost always an OverloadedDeclRefExpr or // UnresolvedDotExpr. Look at the parent node in the AST to find the Apply to // give a better diagnostic. Expr *call = expr->getParentMap()[anchor]; // We look through some simple things that get in between the overload set // and the apply. while (call && (isa(call) || isa(call) || isa(call))) { call = expr->getParentMap()[call]; } // FIXME: This is only needed because binops don't respect contextual types. if (call && isa(call)) return false; // This happens, for example, with ambiguous OverloadedDeclRefExprs. We should // just implement visitOverloadedDeclRefExprs and nuke this. // If we couldn't resolve an argument, then produce a generic "ambiguity" // diagnostic. diagnose(anchor->getLoc(), diag::ambiguous_member_overload_set, overloadName) .highlight(anchor->getSourceRange()); if (constraint->getKind() == ConstraintKind::Disjunction) { for (auto elt : constraint->getNestedConstraints()) { if (elt->getKind() != ConstraintKind::BindOverload) continue; if (!elt->getOverloadChoice().isDecl()) continue; auto candidate = elt->getOverloadChoice().getDecl(); diagnose(candidate, diag::found_candidate); } } return true; } /// Produce a specialized diagnostic if this is an invalid conversion to Bool. bool FailureDiagnosis::diagnoseConversionToBool(Expr *expr, Type exprType) { // Check for "=" converting to Bool. The user probably meant ==. if (auto *AE = dyn_cast(expr->getValueProvidingExpr())) { diagnose(AE->getEqualLoc(), diag::use_of_equal_instead_of_equality) .fixItReplace(AE->getEqualLoc(), "==") .highlight(AE->getDest()->getLoc()) .highlight(AE->getSrc()->getLoc()); return true; } // If we're trying to convert something from optional type to Bool, then a // comparison against nil was probably expected. // TODO: It would be nice to handle "!x" --> x == false, but we have no way // to get to the parent expr at present. if (exprType->getOptionalObjectType()) { StringRef prefix = "(("; StringRef suffix = ") != nil)"; // Check if we need the inner parentheses. // Technically we only need them if there's something in 'expr' with // lower precedence than '!=', but the code actually comes out nicer // in most cases with parens on anything non-trivial. if (expr->canAppendPostfixExpression()) { prefix = prefix.drop_back(); suffix = suffix.drop_front(); } // FIXME: The outer parentheses may be superfluous too. diagnose(expr->getLoc(), diag::optional_used_as_boolean, exprType) .fixItInsert(expr->getStartLoc(), prefix) .fixItInsertAfter(expr->getEndLoc(), suffix); return true; } return false; } static bool diagnoseUnresolvedDotExprTypeRequirementFailure(ConstraintSystem &cs, Constraint *constraint) { auto &TC = cs.TC; auto *locator = constraint->getLocator(); if (!locator) return false; auto path = locator->getPath(); if (path.empty()) return false; auto &last = path.back(); if (last.getKind() != ConstraintLocator::TypeParameterRequirement) return false; auto *anchor = locator->getAnchor(); if (!anchor) return false; auto *UDE = dyn_cast(anchor); if (!UDE) return false; auto ownerType = cs.getType(UDE->getBase()); if (!ownerType) return false; ownerType = cs.simplifyType(ownerType)->getWithoutSpecifierType(); if (ownerType->hasTypeVariable() || ownerType->hasUnresolvedType()) return false; // If we actually resolved the member to use, use it. auto loc = cs.getConstraintLocator(UDE, ConstraintLocator::Member); auto *member = cs.findResolvedMemberRef(loc); // If the problem is contextual it's diagnosed elsewhere. if (!member || !member->getAsGenericContext()) return false; auto req = member->getAsGenericContext() ->getGenericSignature() ->getRequirements()[last.getValue()]; Diag note; switch (req.getKind()) { case RequirementKind::Conformance: case RequirementKind::Layout: return false; case RequirementKind::Superclass: note = diag::candidate_types_inheritance_requirement; break; case RequirementKind::SameType: note = diag::candidate_types_equal_requirement; break; } TC.diagnose(UDE->getLoc(), diag::could_not_find_value_member, ownerType, UDE->getName()); auto first = cs.simplifyType(constraint->getFirstType()); auto second = cs.simplifyType(constraint->getSecondType()); auto rawFirstType = req.getFirstType(); auto rawSecondType = req.getSecondType(); TC.diagnose(member, note, first, second, rawFirstType, rawSecondType, ""); return true; } /// Diagnose problems related to failures in constraints /// generated by `openGeneric` which represent different /// kinds of type parameter requirements. static bool diagnoseTypeRequirementFailure(ConstraintSystem &cs, Constraint *constraint) { auto &TC = cs.TC; auto *locator = constraint->getLocator(); if (!locator) return false; auto path = locator->getPath(); if (path.empty()) return false; auto &last = path.back(); if (last.getKind() != ConstraintLocator::TypeParameterRequirement) return false; auto *anchor = locator->getAnchor(); if (!anchor) return false; auto ownerType = cs.getType(anchor); if (isa(anchor)) ownerType = cs.getContextualType(); else if (auto *UDE = dyn_cast(anchor)) ownerType = cs.getType(UDE->getBase()); if (!ownerType) return false; ownerType = cs.simplifyType(ownerType)->getWithoutSpecifierType(); if (ownerType->hasTypeVariable() || ownerType->hasUnresolvedType()) return false; if (diagnoseUnresolvedDotExprTypeRequirementFailure(cs, constraint)) return true; auto lhs = cs.simplifyType(constraint->getFirstType()); auto rhs = cs.simplifyType(constraint->getSecondType()); switch (constraint->getKind()) { case ConstraintKind::ConformsTo: TC.diagnose(anchor->getLoc(), diag::type_does_not_conform_owner, ownerType, lhs, rhs); return true; case ConstraintKind::Subtype: // superclass TC.diagnose(anchor->getLoc(), diag::type_does_not_inherit, ownerType, lhs, rhs); return true; case ConstraintKind::Bind: { // same type TC.diagnose(anchor->getLoc(), diag::types_not_equal, ownerType, lhs, rhs); return true; } default: break; } return false; } bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){ auto anchor = expr; bool resolvedAnchorToExpr = false; if (auto locator = constraint->getLocator()) { anchor = simplifyLocatorToAnchor(CS, locator); if (anchor) resolvedAnchorToExpr = true; else anchor = locator->getAnchor(); } Type fromType = CS.simplifyType(constraint->getFirstType()); if (fromType->hasTypeVariable() && resolvedAnchorToExpr) { TCCOptions options; // If we know we're removing a contextual constraint, then we can force a // type check of the subexpr because we know we're eliminating that // constraint. if (CS.getContextualTypePurpose() != CTP_Unused) options |= TCC_ForceRecheck; auto sub = typeCheckArbitrarySubExprIndependently(anchor, options); if (!sub) return true; fromType = CS.getType(sub); } // Bail on constraints that don't relate two types. if (constraint->getKind() == ConstraintKind::Disjunction || constraint->getKind() == ConstraintKind::BindOverload) return false; fromType = fromType->getRValueType(); auto toType = CS.simplifyType(constraint->getSecondType()); // Try to simplify irrelevant details of function types. For example, if // someone passes a "() -> Float" function to a "() throws -> Int" // parameter, then uttering the "throws" may confuse them into thinking that // that is the problem, even though there is a clear subtype relation. if (auto srcFT = fromType->getAs()) if (auto destFT = toType->getAs()) { auto destExtInfo = destFT->getExtInfo(); if (!srcFT->isNoEscape()) destExtInfo = destExtInfo.withNoEscape(false); if (!srcFT->throws()) destExtInfo = destExtInfo.withThrows(false); if (destExtInfo != destFT->getExtInfo()) toType = FunctionType::get(destFT->getParams(), destFT->getResult(), destExtInfo); // If this is a function conversion that discards throwability or // noescape, emit a specific diagnostic about that. if (srcFT->throws() && !destFT->throws()) { diagnose(expr->getLoc(), diag::throws_functiontype_mismatch, fromType, toType) .highlight(expr->getSourceRange()); return true; } auto destPurpose = CTP_Unused; if (constraint->getKind() == ConstraintKind::ArgumentConversion || constraint->getKind() == ConstraintKind::OperatorArgumentConversion) destPurpose = CTP_CallArgument; if (diagnoseNonEscapingParameterToEscaping(anchor, fromType, toType, destPurpose)) return true; } // If this is a callee that mismatches an expected return type, we can emit a // very nice and specific error. In this case, what we'll generally see is // a failed conversion constraint of "A -> B" to "_ -> C", where the error is // that B isn't convertible to C. if (CS.getContextualTypePurpose() == CTP_CalleeResult) { auto destFT = toType->getAs(); auto srcFT = fromType->getAs(); if (destFT && srcFT && !isUnresolvedOrTypeVarType(srcFT->getResult())) { // Otherwise, the error is that the result types mismatch. diagnose(expr->getLoc(), diag::invalid_callee_result_type, srcFT->getResult(), destFT->getResult()) .highlight(expr->getSourceRange()); return true; } } // If simplification has turned this into the same types, then this isn't the // broken constraint that we're looking for. if (fromType->isEqual(toType) && constraint->getKind() != ConstraintKind::ConformsTo && constraint->getKind() != ConstraintKind::LiteralConformsTo) return false; // If we have two tuples with mismatching types, produce a tailored // diagnostic. if (auto fromTT = fromType->getAs()) if (auto toTT = toType->getAs()) { if (fromTT->getNumElements() != toTT->getNumElements()) { diagnose(anchor->getLoc(), diag::tuple_types_not_convertible_nelts, fromTT, toTT) .highlight(anchor->getSourceRange()); return true; } SmallVector FromElts; auto voidTy = CS.getASTContext().TheUnresolvedType; for (unsigned i = 0, e = fromTT->getNumElements(); i != e; ++i) FromElts.push_back({ voidTy, fromTT->getElement(i).getName() }); auto TEType = TupleType::get(FromElts, CS.getASTContext()); SmallVector sources; // If the shuffle conversion is invalid (e.g. incorrect element labels), // then we have a type error. if (computeTupleShuffle(TEType->castTo()->getElements(), toTT->getElements(), sources)) { diagnose(anchor->getLoc(), diag::tuple_types_not_convertible, fromTT, toTT) .highlight(anchor->getSourceRange()); return true; } } // If the second type is a type variable, the expression itself is // ambiguous. Bail out so the general ambiguity diagnosing logic can handle // it. if (fromType->hasUnresolvedType() || fromType->hasTypeVariable() || toType->hasUnresolvedType() || toType->hasTypeVariable() || // FIXME: Why reject unbound generic types here? fromType->is()) return false; // Check for various issues converting to Bool. if (toType->isBool() && diagnoseConversionToBool(anchor, fromType)) return true; if (auto PT = toType->getAs()) { if (isa(expr->getValueProvidingExpr())) { diagnose(expr->getLoc(), diag::cannot_use_nil_with_this_type, toType) .highlight(expr->getSourceRange()); return true; } // Emit a conformance error through conformsToProtocol. if (auto conformance = CS.TC.conformsToProtocol( fromType, PT->getDecl(), CS.DC, ConformanceCheckFlags::InExpression, expr->getLoc())) { if (conformance->isAbstract() || !conformance->getConcrete()->isInvalid()) return false; } return true; } // Due to migration reasons, types used to conform to BooleanType, which // contain a member var 'boolValue', now does not convert to Bool. This block // tries to add a specific diagnosis/fixit to explicitly invoke 'boolValue'. if (toType->isBool() && fromType->mayHaveMembers()) { auto LookupResult = CS.TC.lookupMember( CS.DC, fromType, DeclName(CS.TC.Context.getIdentifier("boolValue"))); if (!LookupResult.empty()) { if (isa(LookupResult.begin()->getValueDecl())) { if (anchor->canAppendPostfixExpression()) diagnose(anchor->getLoc(), diag::types_not_convertible_use_bool_value, fromType, toType).fixItInsertAfter(anchor->getEndLoc(), ".boolValue"); else diagnose(anchor->getLoc(), diag::types_not_convertible_use_bool_value, fromType, toType).fixItInsert(anchor->getStartLoc(), "("). fixItInsertAfter(anchor->getEndLoc(), ").boolValue"); return true; } } } if (diagnoseTypeRequirementFailure(CS, constraint)) return true; diagnose(anchor->getLoc(), diag::types_not_convertible, constraint->getKind() == ConstraintKind::Subtype, fromType, toType) .highlight(anchor->getSourceRange()); // Check to see if this constraint came from a cast instruction. If so, // and if this conversion constraint is different than the types being cast, // produce a note that talks about the overall expression. // // TODO: Using parentMap would be more general, rather than requiring the // issue to be related to the root of the expr under study. if (auto ECE = dyn_cast(expr)) if (constraint->getLocator() && constraint->getLocator()->getAnchor() == ECE->getSubExpr()) { if (!toType->isEqual(ECE->getCastTypeLoc().getType())) diagnose(expr->getLoc(), diag::in_cast_expr_types, CS.getType(ECE->getSubExpr())->getRValueType(), ECE->getCastTypeLoc().getType()->getRValueType()) .highlight(ECE->getSubExpr()->getSourceRange()) .highlight(ECE->getCastTypeLoc().getSourceRange()); } return true; } namespace { class ExprTypeSaverAndEraser { llvm::DenseMap ExprTypes; llvm::DenseMap TypeLocTypes; llvm::DenseMap PatternTypes; llvm::DenseMap ParamDeclTypes; llvm::DenseMap ParamDeclInterfaceTypes; llvm::DenseMap CollectionSemanticExprs; llvm::DenseSet PossiblyInvalidDecls; ExprTypeSaverAndEraser(const ExprTypeSaverAndEraser&) = delete; void operator=(const ExprTypeSaverAndEraser&) = delete; public: ExprTypeSaverAndEraser(Expr *E) { struct TypeSaver : public ASTWalker { ExprTypeSaverAndEraser *TS; TypeSaver(ExprTypeSaverAndEraser *TS) : TS(TS) {} std::pair walkToExprPre(Expr *expr) override { TS->ExprTypes[expr] = expr->getType(); SWIFT_DEFER { assert((!expr->getType() || !expr->getType()->hasTypeVariable() // FIXME: We shouldn't allow these, either. || isa(expr)) && "Type variable didn't get erased!"); }; // Preserve module expr type data to prevent further lookups. if (auto *declRef = dyn_cast(expr)) if (isa(declRef->getDecl())) return { false, expr }; // Don't strip type info off OtherConstructorDeclRefExpr, because // CSGen doesn't know how to reconstruct it. if (isa(expr)) return { false, expr }; // If a literal has a Builtin.Int or Builtin.FP type on it already, // then sema has already expanded out a call to // Init.init() // and we don't want it to make // Init.init(Init.init()) // preserve the type info to prevent this from happening. if (isa(expr) && !isa(expr) && !(expr->getType() && expr->getType()->hasError())) return { false, expr }; // If a ClosureExpr's parameter list has types on the decls, then // remove them so that they'll get regenerated from the // associated TypeLocs or resynthesized as fresh typevars. if (auto *CE = dyn_cast(expr)) for (auto P : *CE->getParameters()) { if (P->hasType()) { TS->ParamDeclTypes[P] = P->getType(); P->setType(Type()); } if (P->hasInterfaceType()) { TS->ParamDeclInterfaceTypes[P] = P->getInterfaceType(); P->setInterfaceType(Type()); } TS->PossiblyInvalidDecls.insert(P); if (P->isInvalid()) P->setInvalid(false); } // If we have a CollectionExpr with a type checked SemanticExpr, // remove it so we can recalculate a new semantic form. if (auto *CE = dyn_cast(expr)) { if (auto SE = CE->getSemanticExpr()) { TS->CollectionSemanticExprs[CE] = SE; CE->setSemanticExpr(nullptr); } } expr->setType(nullptr); return { true, expr }; } // If we find a TypeLoc (e.g. in an as? expr), save and erase it. bool walkToTypeLocPre(TypeLoc &TL) override { if (TL.getTypeRepr() && TL.getType()) { TS->TypeLocTypes[&TL] = TL.getType(); TL.setType(Type()); } return true; } std::pair walkToPatternPre(Pattern *P) override { if (P->hasType()) { TS->PatternTypes[P] = P->getType(); P->setType(Type()); } return { true, P }; } // Don't walk into statements. This handles the BraceStmt in // non-single-expr closures, so we don't walk into their body. std::pair walkToStmtPre(Stmt *S) override { return { false, S }; } }; E->walk(TypeSaver(this)); } void restore() { for (auto exprElt : ExprTypes) exprElt.first->setType(exprElt.second); for (auto typelocElt : TypeLocTypes) typelocElt.first->setType(typelocElt.second); for (auto patternElt : PatternTypes) patternElt.first->setType(patternElt.second); for (auto paramDeclElt : ParamDeclTypes) { assert(!paramDeclElt.first->isImmutable() || !paramDeclElt.second->is()); paramDeclElt.first->setType(paramDeclElt.second->getInOutObjectType()); } for (auto paramDeclIfaceElt : ParamDeclInterfaceTypes) { assert(!paramDeclIfaceElt.first->isImmutable() || !paramDeclIfaceElt.second->is()); paramDeclIfaceElt.first->setInterfaceType(paramDeclIfaceElt.second->getInOutObjectType()); } for (auto CSE : CollectionSemanticExprs) CSE.first->setSemanticExpr(CSE.second); if (!PossiblyInvalidDecls.empty()) for (auto D : PossiblyInvalidDecls) if (D->hasInterfaceType()) D->setInvalid(D->getInterfaceType()->hasError()); // Done, don't do redundant work on destruction. ExprTypes.clear(); TypeLocTypes.clear(); PatternTypes.clear(); PossiblyInvalidDecls.clear(); } // On destruction, if a type got wiped out, reset it from null to its // original type. This is helpful because type checking a subexpression // can lead to replacing the nodes in that subexpression. However, the // failed ConstraintSystem still has locators pointing to the old nodes, // and if expr-specific diagnostics fail to turn up anything useful to say, // we go digging through failed constraints, and expect their locators to // still be meaningful. ~ExprTypeSaverAndEraser() { for (auto CSE : CollectionSemanticExprs) if (!CSE.first->getType()) CSE.first->setSemanticExpr(CSE.second); for (auto exprElt : ExprTypes) if (!exprElt.first->getType()) exprElt.first->setType(exprElt.second); for (auto typelocElt : TypeLocTypes) if (!typelocElt.first->getType()) typelocElt.first->setType(typelocElt.second); for (auto patternElt : PatternTypes) if (!patternElt.first->hasType()) patternElt.first->setType(patternElt.second); for (auto paramDeclElt : ParamDeclTypes) if (!paramDeclElt.first->hasType()) { paramDeclElt.first->setType(getParamBaseType(paramDeclElt)); } for (auto paramDeclIfaceElt : ParamDeclInterfaceTypes) if (!paramDeclIfaceElt.first->hasInterfaceType()) { paramDeclIfaceElt.first->setInterfaceType( getParamBaseType(paramDeclIfaceElt)); } if (!PossiblyInvalidDecls.empty()) for (auto D : PossiblyInvalidDecls) if (D->hasInterfaceType()) D->setInvalid(D->getInterfaceType()->hasError()); } private: static Type getParamBaseType(std::pair &storedParam) { ParamDecl *param; Type storedType; std::tie(param, storedType) = storedParam; // FIXME: We are currently in process of removing `InOutType` // so `VarDecl::get{Interface}Type` is going to wrap base // type into `InOutType` if its flag indicates that it's // an `inout` parameter declaration. But such type can't // be restored directly using `VarDecl::set{Interface}Type` // caller needs additional logic to extract base type. if (auto *IOT = storedType->getAs()) { assert(param->isInOut()); return IOT->getObjectType(); } return storedType; } }; } // end anonymous namespace /// Unless we've already done this, retypecheck the specified subexpression on /// its own, without including any contextual constraints or parent expr /// nodes. This is more likely to succeed than type checking the original /// expression. /// /// This can return a new expression (for e.g. when a UnresolvedDeclRef gets /// resolved) and returns null when the subexpression fails to typecheck. Expr *FailureDiagnosis::typeCheckChildIndependently( Expr *subExpr, Type convertType, ContextualTypePurpose convertTypePurpose, TCCOptions options, ExprTypeCheckListener *listener, bool allowFreeTypeVariables) { // If this sub-expression is currently being diagnosed, refuse to recheck the // expression (which may lead to infinite recursion). If the client is // telling us that it knows what it is doing, then believe it. if (!options.contains(TCC_ForceRecheck)) { if (CS.TC.isExprBeingDiagnosed(subExpr)) { auto *savedExpr = CS.TC.getExprBeingDiagnosed(subExpr); if (subExpr == savedExpr) return subExpr; CS.cacheExprTypes(savedExpr); return savedExpr; } } // Mark current expression as about to be diagnosed. CS.TC.addExprForDiagnosis(subExpr, subExpr); // Validate contextual type before trying to use it. std::tie(convertType, convertTypePurpose) = validateContextualType(convertType, convertTypePurpose); // If we have no contextual type information and the subexpr is obviously a // overload set, don't recursively simplify this. The recursive solver will // sometimes pick one based on arbitrary ranking behavior (e.g. like // which is the most specialized) even then all the constraints are being // fulfilled by UnresolvedType, which doesn't tell us anything. if (convertTypePurpose == CTP_Unused && (isa(subExpr->getValueProvidingExpr()))) { return subExpr; } // Save any existing type data of the subexpr tree, and reset it to null in // prep for re-type-checking the tree. If things fail, we can revert the // types back to their original state. ExprTypeSaverAndEraser SavedTypeData(subExpr); // Store off the sub-expression, in case a new one is provided via the // type check operation. Expr *preCheckedExpr = subExpr; // Disable structural checks, because we know that the overall expression // has type constraint problems, and we don't want to know about any // syntactic issues in a well-typed subexpression (which might be because // the context is missing). TypeCheckExprOptions TCEOptions = TypeCheckExprFlags::DisableStructuralChecks; // Make sure that typechecker knows that this is an attempt // to diagnose a problem. TCEOptions |= TypeCheckExprFlags::SubExpressionDiagnostics; // Don't walk into non-single expression closure bodies, because // ExprTypeSaver and TypeNullifier skip them too. TCEOptions |= TypeCheckExprFlags::SkipMultiStmtClosures; // Claim that the result is discarded to preserve the lvalue type of // the expression. if (options.contains(TCC_AllowLValue)) TCEOptions |= TypeCheckExprFlags::IsDiscarded; // If there is no contextual type available, tell typeCheckExpression that it // is ok to produce an ambiguous result, it can just fill in holes with // UnresolvedType and we'll deal with it. if ((!convertType || options.contains(TCC_AllowUnresolvedTypeVariables)) && allowFreeTypeVariables) TCEOptions |= TypeCheckExprFlags::AllowUnresolvedTypeVariables; auto resultTy = CS.TC.typeCheckExpression( subExpr, CS.DC, TypeLoc::withoutLoc(convertType), convertTypePurpose, TCEOptions, listener, &CS); CS.cacheExprTypes(subExpr); // This is a terrible hack to get around the fact that typeCheckExpression() // might change subExpr to point to a new OpenExistentialExpr. In that case, // since the caller passed subExpr by value here, they would be left // holding on to an expression containing open existential types but // no OpenExistentialExpr, which breaks invariants enforced by the // ASTChecker. // Another reason why we need to do this is because diagnostics might pick // constraint anchor for re-typechecking which would only have opaque value // expression and not enclosing open existential, which is going to trip up // sanitizer. eraseOpenedExistentials(CS, subExpr); // If recursive type checking failed, then an error was emitted. Return // null to indicate this to the caller. if (!resultTy) return nullptr; // If we type checked the result but failed to get a usable output from it, // just pretend as though nothing happened. if (resultTy->is()) { subExpr = preCheckedExpr; if (subExpr->getType()) CS.cacheType(subExpr); SavedTypeData.restore(); } if (preCheckedExpr != subExpr) CS.TC.addExprForDiagnosis(preCheckedExpr, subExpr); return subExpr; } /// This is the same as typeCheckChildIndependently, but works on an arbitrary /// subexpression of the current node because it handles ClosureExpr parents /// of the specified node. Expr *FailureDiagnosis:: typeCheckArbitrarySubExprIndependently(Expr *subExpr, TCCOptions options) { if (subExpr == expr) return typeCheckChildIndependently(subExpr, options); // Construct a parent map for the expr tree we're investigating. auto parentMap = expr->getParentMap(); ClosureExpr *NearestClosure = nullptr; // Walk the parents of the specified expression, handling any ClosureExprs. for (Expr *node = parentMap[subExpr]; node; node = parentMap[node]) { auto *CE = dyn_cast(node); if (!CE) continue; // Keep track of the innermost closure we see that we're jumping into. if (!NearestClosure) NearestClosure = CE; // If we have a ClosureExpr parent of the specified node, check to make sure // none of its arguments are type variables. If so, these type variables // would be accessible to name lookup of the subexpression and may thus leak // in. Reset them to UnresolvedTypes for safe measures. for (auto *param : *CE->getParameters()) { if (param->hasValidSignature()) { auto type = param->getType(); assert(!type->hasTypeVariable() && !type->hasError()); (void)type; } } } // When we're type checking a single-expression closure, we need to reset the // DeclContext to this closure for the recursive type checking. Otherwise, // if there is a closure in the subexpression, we can violate invariants. auto newDC = NearestClosure ? NearestClosure : CS.DC; llvm::SaveAndRestore SavedDC(CS.DC, newDC); // Otherwise, we're ok to type check the subexpr. return typeCheckChildIndependently(subExpr, options); } /// For an expression being type checked with a CTP_CalleeResult contextual /// type, try to diagnose a problem. bool FailureDiagnosis::diagnoseCalleeResultContextualConversionError() { // Try to dig out the conversion constraint in question to find the contextual // result type being specified. Type contextualResultType; for (auto &c : CS.getConstraints()) { if (!isConversionConstraint(&c) || !c.getLocator() || c.getLocator()->getAnchor() != expr) continue; // If we found our contextual type, then we know we have a conversion to // some function type, and that the result type is concrete. If not, // ignore it. auto toType = CS.simplifyType(c.getSecondType()); if (auto *FT = toType->getAs()) if (!isUnresolvedOrTypeVarType(FT->getResult())) { contextualResultType = FT->getResult(); break; } } if (!contextualResultType) return false; // Retypecheck the callee expression without a contextual type to resolve // whatever we can in it. auto callee = typeCheckChildIndependently(expr, TCC_ForceRecheck); if (!callee) return true; // Based on that, compute an overload set. CalleeCandidateInfo calleeInfo(callee, /*hasTrailingClosure*/false, CS); switch (calleeInfo.size()) { case 0: // If we found no overloads, then there is something else going on here. return false; case 1: // If the callee isn't of function type, then something else has gone wrong. if (!calleeInfo[0].getResultType()) return false; diagnose(expr->getLoc(), diag::candidates_no_match_result_type, calleeInfo.declName, calleeInfo[0].getResultType(), contextualResultType); return true; default: // Check to see if all of the viable candidates produce the same result, // this happens for things like "==" and "&&" operators. if (auto resultTy = calleeInfo[0].getResultType()) { for (unsigned i = 1, e = calleeInfo.size(); i != e; ++i) if (auto ty = calleeInfo[i].getResultType()) if (!resultTy->isEqual(ty)) { resultTy = Type(); break; } if (resultTy) { diagnose(expr->getLoc(), diag::candidates_no_match_result_type, calleeInfo.declName, calleeInfo[0].getResultType(), contextualResultType); return true; } } // Otherwise, produce a candidate set. diagnose(expr->getLoc(), diag::no_candidates_match_result_type, calleeInfo.declName, contextualResultType); calleeInfo.suggestPotentialOverloads(expr->getLoc(), /*isResult*/true); return true; } } /// Return true if the given type conforms to a known protocol type. static bool conformsToKnownProtocol(Type fromType, KnownProtocolKind kind, const ConstraintSystem &CS) { auto proto = CS.TC.getProtocol(SourceLoc(), kind); if (!proto) return false; if (CS.TC.conformsToProtocol(fromType, proto, CS.DC, ConformanceCheckFlags::InExpression)) { return true; } return false; } static bool isIntegerType(Type fromType, const ConstraintSystem &CS) { return conformsToKnownProtocol(fromType, KnownProtocolKind::ExpressibleByIntegerLiteral, CS); } /// Return true if the given type conforms to RawRepresentable. static Type isRawRepresentable(Type fromType, const ConstraintSystem &CS) { auto rawReprType = CS.TC.getProtocol(SourceLoc(), KnownProtocolKind::RawRepresentable); if (!rawReprType) return Type(); auto conformance = CS.TC.conformsToProtocol( fromType, rawReprType, CS.DC, ConformanceCheckFlags::InExpression); if (!conformance) return Type(); Type rawTy = ProtocolConformanceRef::getTypeWitnessByName( fromType, *conformance, CS.getASTContext().Id_RawValue, &CS.TC); return rawTy; } /// Return true if the given type conforms to RawRepresentable, with an /// underlying type conforming to the given known protocol. static Type isRawRepresentable(Type fromType, KnownProtocolKind kind, const ConstraintSystem &CS) { Type rawTy = isRawRepresentable(fromType, CS); if (!rawTy || !conformsToKnownProtocol(rawTy, kind, CS)) return Type(); return rawTy; } /// Return true if the conversion from fromType to toType is an invalid string /// index operation. static bool isIntegerToStringIndexConversion(Type fromType, Type toType, ConstraintSystem &CS) { auto kind = KnownProtocolKind::ExpressibleByIntegerLiteral; return (conformsToKnownProtocol(fromType, kind, CS) && toType->getCanonicalType().getString() == "String.CharacterView.Index"); } static bool isOptionSetType(Type fromType, const ConstraintSystem &CS) { return conformsToKnownProtocol(fromType, KnownProtocolKind::OptionSet, CS); } /// Attempts to add fix-its for these two mistakes: /// /// - Passing an integer where a type conforming to RawRepresentable is /// expected, by wrapping the expression in a call to the contextual /// type's initializer /// /// - Passing a type conforming to RawRepresentable where an integer is /// expected, by wrapping the expression in a call to the rawValue /// accessor /// /// - Return true on the fixit is added, false otherwise. /// /// This helps migration with SDK changes. static bool tryRawRepresentableFixIts(InFlightDiagnostic &diag, const ConstraintSystem &CS, Type fromType, Type toType, KnownProtocolKind kind, const Expr *expr) { // The following fixes apply for optional destination types as well. bool toTypeIsOptional = !toType->getOptionalObjectType().isNull(); toType = toType->lookThroughAllOptionalTypes(); Type fromTypeUnwrapped = fromType->getOptionalObjectType(); bool fromTypeIsOptional = !fromTypeUnwrapped.isNull(); if (fromTypeIsOptional) fromType = fromTypeUnwrapped; auto fixIt = [&](StringRef convWrapBefore, StringRef convWrapAfter) { SourceRange exprRange = expr->getSourceRange(); if (fromTypeIsOptional && toTypeIsOptional) { // Use optional's map function to convert conditionally, like so: // expr.map{ T(rawValue: $0) } bool needsParens = !expr->canAppendPostfixExpression(); std::string mapCodeFix; if (needsParens) { diag.fixItInsert(exprRange.Start, "("); mapCodeFix += ")"; } mapCodeFix += ".map { "; mapCodeFix += convWrapBefore; mapCodeFix += "$0"; mapCodeFix += convWrapAfter; mapCodeFix += " }"; diag.fixItInsertAfter(exprRange.End, mapCodeFix); } else if (!fromTypeIsOptional) { diag.fixItInsert(exprRange.Start, convWrapBefore); diag.fixItInsertAfter(exprRange.End, convWrapAfter); } else { SmallString<16> fixItBefore(convWrapBefore); SmallString<16> fixItAfter; if (!expr->canAppendPostfixExpression(true)) { fixItBefore += "("; fixItAfter = ")"; } fixItAfter += "!" + convWrapAfter.str(); diag.flush(); CS.TC .diagnose(expr->getLoc(), diag::construct_raw_representable_from_unwrapped_value, toType, fromType) .highlight(exprRange) .fixItInsert(exprRange.Start, fixItBefore) .fixItInsertAfter(exprRange.End, fixItAfter); } }; if (conformsToKnownProtocol(fromType, kind, CS)) { if (isOptionSetType(toType, CS) && isa(expr) && cast(expr)->getDigitsText() == "0") { diag.fixItReplace(expr->getSourceRange(), "[]"); return true; } if (auto rawTy = isRawRepresentable(toType, kind, CS)) { // Produce before/after strings like 'Result(rawValue: RawType())' // or just 'Result(rawValue: )'. std::string convWrapBefore = toType.getString(); convWrapBefore += "(rawValue: "; std::string convWrapAfter = ")"; if (!isa(expr) && !CS.TC.isConvertibleTo(fromType, rawTy, CS.DC)) { // Only try to insert a converting construction if the protocol is a // literal protocol and not some other known protocol. switch (kind) { #define EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME(name, _, __, ___) \ case KnownProtocolKind::name: \ break; #define PROTOCOL_WITH_NAME(name, _) \ case KnownProtocolKind::name: return false; #include "swift/AST/KnownProtocols.def" } convWrapBefore += rawTy->getString(); convWrapBefore += "("; convWrapAfter += ")"; } fixIt(convWrapBefore, convWrapAfter); return true; } } if (auto rawTy = isRawRepresentable(fromType, kind, CS)) { if (conformsToKnownProtocol(toType, kind, CS)) { std::string convWrapBefore; std::string convWrapAfter = ".rawValue"; if (!CS.TC.isConvertibleTo(rawTy, toType, CS.DC)) { // Only try to insert a converting construction if the protocol is a // literal protocol and not some other known protocol. switch (kind) { #define EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME(name, _, __, ___) \ case KnownProtocolKind::name: \ break; #define PROTOCOL_WITH_NAME(name, _) \ case KnownProtocolKind::name: return false; #include "swift/AST/KnownProtocols.def" } convWrapBefore += toType->getString(); convWrapBefore += "("; convWrapAfter += ")"; } fixIt(convWrapBefore, convWrapAfter); return true; } } return false; } /// 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. static bool tryIntegerCastFixIts(InFlightDiagnostic &diag, ConstraintSystem &CS, Type fromType, Type toType, Expr *expr) { if (!isIntegerType(fromType, CS) || !isIntegerType(toType, CS)) return false; auto getInnerCastedExpr = [&]() -> Expr * { if (auto *CE = dyn_cast(expr)) return CE->getSubExpr(); auto *CE = dyn_cast(expr); if (!CE) return nullptr; if (!isa(CE->getFn())) return nullptr; auto *parenE = dyn_cast(CE->getArg()); if (!parenE) return nullptr; return parenE->getSubExpr(); }; if (Expr *innerE = getInnerCastedExpr()) { Type innerTy = CS.getType(innerE); if (CS.TC.isConvertibleTo(innerTy, toType, CS.DC)) { // Remove the unnecessary cast. diag.fixItRemoveChars(expr->getLoc(), innerE->getStartLoc()) .fixItRemove(expr->getEndLoc()); return true; } } // Add a wrapping integer cast. std::string convWrapBefore = toType.getString(); convWrapBefore += "("; std::string convWrapAfter = ")"; SourceRange exprRange = expr->getSourceRange(); diag.fixItInsert(exprRange.Start, convWrapBefore); diag.fixItInsertAfter(exprRange.End, convWrapAfter); return true; } static bool addTypeCoerceFixit(InFlightDiagnostic &diag, ConstraintSystem &CS, Type fromType, Type toType, Expr *expr) { // Look through optional types; casts can add them, but can't remove extra // ones. bool bothOptional = fromType->getOptionalObjectType() && toType->getOptionalObjectType(); if (bothOptional) fromType = fromType->getOptionalObjectType(); toType = toType->lookThroughAllOptionalTypes(); CheckedCastKind Kind = CS.getTypeChecker().typeCheckCheckedCast( fromType, toType, CheckedCastContextKind::None, CS.DC, SourceLoc(), nullptr, SourceRange()); if (Kind != CheckedCastKind::Unresolved) { SmallString<32> buffer; llvm::raw_svector_ostream OS(buffer); bool canUseAs = Kind == CheckedCastKind::Coercion || Kind == CheckedCastKind::BridgingCoercion; if (bothOptional && canUseAs) toType = OptionalType::get(toType); toType->print(OS); diag.fixItInsert( Lexer::getLocForEndOfToken(CS.DC->getASTContext().SourceMgr, expr->getEndLoc()), (llvm::Twine(canUseAs ? " as " : " as! ") + OS.str()).str()); return true; } return false; } /// Try to diagnose common errors involving implicitly non-escaping parameters /// of function type, giving more specific and simpler diagnostics, attaching /// notes on the parameter, and offering fixits to insert @escaping. Returns /// true if it detects and issues an error, false if it does nothing. bool FailureDiagnosis::diagnoseNonEscapingParameterToEscaping( Expr *expr, Type srcType, Type dstType, ContextualTypePurpose dstPurpose) { assert(expr); // Need to be referencing a parameter of function type auto declRef = dyn_cast(expr); if (!declRef || !isa(declRef->getDecl()) || !CS.getType(declRef)->is()) return false; // Must be from non-escaping function to escaping function. For the // destination type, we read through optionality to give better diagnostics in // the event of an implicit promotion. auto srcFT = srcType->getAs(); auto dstFT = dstType->lookThroughAllOptionalTypes()->getAs(); if (!srcFT || !dstFT || !srcFT->isNoEscape() || dstFT->isNoEscape()) return false; // Pick a specific diagnostic for the specific use auto paramDecl = cast(declRef->getDecl()); switch (dstPurpose) { case CTP_CallArgument: CS.TC.diagnose(declRef->getLoc(), diag::passing_noescape_to_escaping, paramDecl->getName()); break; case CTP_AssignSource: CS.TC.diagnose(declRef->getLoc(), diag::assigning_noescape_to_escaping, paramDecl->getName()); break; default: CS.TC.diagnose(declRef->getLoc(), diag::general_noescape_to_escaping, paramDecl->getName()); break; } // Give a note and fixit InFlightDiagnostic note = CS.TC.diagnose( paramDecl->getLoc(), diag::noescape_parameter, paramDecl->getName()); if (!paramDecl->isAutoClosure()) { note.fixItInsert(paramDecl->getTypeLoc().getSourceRange().Start, "@escaping "); } // TODO: add in a fixit for autoclosure return true; } bool FailureDiagnosis::diagnoseContextualConversionError( Expr *expr, Type contextualType, ContextualTypePurpose CTP, Type suggestedType) { // If the constraint system has a contextual type, then we can test to see if // this is the problem that prevents us from solving the system. if (!contextualType) { // This contextual conversion constraint doesn't install an actual type. if (CTP == CTP_CalleeResult) return diagnoseCalleeResultContextualConversionError(); return false; } // Try re-type-checking the expression without the contextual type to see if // it can work without it. If so, the contextual type is the problem. We // force a recheck, because "expr" is likely in our table with the extra // contextual constraint that we know we are relaxing. TCCOptions options = TCC_ForceRecheck; if (contextualType->is()) options |= TCC_AllowLValue; auto *recheckedExpr = typeCheckChildIndependently(expr, options); auto exprType = recheckedExpr ? CS.getType(recheckedExpr) : Type(); // If there is a suggested type and re-typecheck failed, let's use it. if (!exprType) exprType = suggestedType; // If it failed and diagnosed something, then we're done. if (!exprType) return CS.TC.Diags.hadAnyError(); // If we contextually had an inout type, and got a non-lvalue result, then // we fail with a mutability error. if (contextualType->is() && !exprType->is()) { AssignmentFailure failure(recheckedExpr, CS, recheckedExpr->getLoc(), diag::cannot_pass_rvalue_inout_subelement, diag::cannot_pass_rvalue_inout); return failure.diagnose(); } // Try to find the contextual type in a variety of ways. If the constraint // system had a contextual type specified, we use it - it will have a purpose // indicator which allows us to give a very "to the point" diagnostic. Diag diagID; Diag diagIDProtocol; Diag nilDiag; std::function nilFollowup; // If this is conversion failure due to a return statement with an argument // that cannot be coerced to the result type of the function, emit a // specific error. switch (CTP) { case CTP_Unused: case CTP_CannotFail: llvm_unreachable("These contextual type purposes cannot fail with a " "conversion type specified!"); case CTP_CalleeResult: llvm_unreachable("CTP_CalleeResult does not actually install a " "contextual type"); case CTP_Initialization: diagID = diag::cannot_convert_initializer_value; diagIDProtocol = diag::cannot_convert_initializer_value_protocol; nilDiag = diag::cannot_convert_initializer_value_nil; nilFollowup = [this] { TypeRepr *patternTR = CS.getContextualTypeLoc().getTypeRepr(); if (!patternTR) return; auto diag = diagnose(patternTR->getLoc(), diag::note_make_optional, OptionalType::get(CS.getContextualType())); if (patternTR->isSimple()) { diag.fixItInsertAfter(patternTR->getEndLoc(), "?"); } else { diag.fixItInsert(patternTR->getStartLoc(), "("); diag.fixItInsertAfter(patternTR->getEndLoc(), ")?"); } }; break; case CTP_ReturnStmt: // Special case the "conversion to void" case. if (contextualType->isVoid()) { diagnose(expr->getLoc(), diag::cannot_return_value_from_void_func) .highlight(expr->getSourceRange()); return true; } diagID = diag::cannot_convert_to_return_type; diagIDProtocol = diag::cannot_convert_to_return_type_protocol; nilDiag = diag::cannot_convert_to_return_type_nil; break; case CTP_ThrowStmt: { if (isa(expr->getValueProvidingExpr())) { diagnose(expr->getLoc(), diag::cannot_throw_nil); return true; } if (isUnresolvedOrTypeVarType(exprType) || exprType->isEqual(contextualType)) return false; // If we tried to throw the error code of an error type, suggest object // construction. auto &TC = CS.getTypeChecker(); if (auto errorCodeProtocol = TC.Context.getProtocol(KnownProtocolKind::ErrorCodeProtocol)) { if (auto conformance = TC.conformsToProtocol(CS.getType(expr), errorCodeProtocol, CS.DC, ConformanceCheckFlags::InExpression)) { Type errorCodeType = CS.getType(expr); Type errorType = ProtocolConformanceRef::getTypeWitnessByName(errorCodeType, *conformance, TC.Context.Id_ErrorType, &TC)->getCanonicalType(); if (errorType) { auto diag = diagnose(expr->getLoc(), diag::cannot_throw_error_code, errorCodeType, errorType); if (auto unresolvedDot = dyn_cast(expr)) { diag.fixItInsert(unresolvedDot->getDotLoc(), "("); diag.fixItInsertAfter(unresolvedDot->getEndLoc(), ")"); } return true; } } } // The conversion destination of throw is always ErrorType (at the moment) // if this ever expands, this should be a specific form like () is for // return. diagnose(expr->getLoc(), diag::cannot_convert_thrown_type, exprType) .highlight(expr->getSourceRange()); return true; } case CTP_EnumCaseRawValue: diagID = diag::cannot_convert_raw_initializer_value; diagIDProtocol = diag::cannot_convert_raw_initializer_value; nilDiag = diag::cannot_convert_raw_initializer_value_nil; break; case CTP_DefaultParameter: diagID = diag::cannot_convert_default_arg_value; diagIDProtocol = diag::cannot_convert_default_arg_value_protocol; nilDiag = diag::cannot_convert_default_arg_value_nil; break; case CTP_YieldByReference: if (auto contextualLV = contextualType->getAs()) contextualType = contextualLV->getObjectType(); if (auto exprLV = exprType->getAs()) { diagnose(expr->getLoc(), diag::cannot_yield_wrong_type_by_reference, exprLV->getObjectType(), contextualType); } else if (exprType->isEqual(contextualType)) { diagnose(expr->getLoc(), diag::cannot_yield_rvalue_by_reference_same_type, exprType); } else { diagnose(expr->getLoc(), diag::cannot_yield_rvalue_by_reference, exprType, contextualType); } return true; case CTP_YieldByValue: diagID = diag::cannot_convert_yield_value; diagIDProtocol = diag::cannot_convert_yield_value_protocol; nilDiag = diag::cannot_convert_yield_value_nil; break; case CTP_CallArgument: diagID = diag::cannot_convert_argument_value; diagIDProtocol = diag::cannot_convert_argument_value_protocol; nilDiag = diag::cannot_convert_argument_value_nil; break; case CTP_ClosureResult: diagID = diag::cannot_convert_closure_result; diagIDProtocol = diag::cannot_convert_closure_result_protocol; nilDiag = diag::cannot_convert_closure_result_nil; break; case CTP_ArrayElement: diagID = diag::cannot_convert_array_element; diagIDProtocol = diag::cannot_convert_array_element_protocol; nilDiag = diag::cannot_convert_array_element_nil; break; case CTP_DictionaryKey: diagID = diag::cannot_convert_dict_key; diagIDProtocol = diag::cannot_convert_dict_key_protocol; nilDiag = diag::cannot_convert_dict_key_nil; break; case CTP_DictionaryValue: diagID = diag::cannot_convert_dict_value; diagIDProtocol = diag::cannot_convert_dict_value_protocol; nilDiag = diag::cannot_convert_dict_value_nil; break; case CTP_CoerceOperand: diagID = diag::cannot_convert_coerce; diagIDProtocol = diag::cannot_convert_coerce_protocol; nilDiag = diag::cannot_convert_coerce_nil; break; case CTP_AssignSource: diagID = diag::cannot_convert_assign; diagIDProtocol = diag::cannot_convert_assign_protocol; nilDiag = diag::cannot_convert_assign_nil; break; } // If we're diagnostic an issue with 'nil', produce a specific diagnostic, // instead of uttering ExpressibleByNilLiteral. if (isa(expr->getValueProvidingExpr())) { // If the source type is some kind of optional, the contextual conversion // to 'nil' didn't fail, something else did. if (contextualType->getOptionalObjectType()) return false; diagnose(expr->getLoc(), nilDiag, contextualType); if (nilFollowup) nilFollowup(); return true; } // If we don't have a type for the expression, then we cannot use it in // conversion constraint diagnostic generation. If the types match, then it // must not be the contextual type that is the problem. if (isUnresolvedOrTypeVarType(exprType) || exprType->isEqual(contextualType)) { return false; } // If we're trying to convert something of type "() -> T" to T, then we // probably meant to call the value. if (auto srcFT = exprType->getAs()) { if (srcFT->getParams().empty() && !isUnresolvedOrTypeVarType(srcFT->getResult()) && CS.TC.isConvertibleTo(srcFT->getResult(), contextualType, CS.DC)) { diagnose(expr->getLoc(), diag::missing_nullary_call, srcFT->getResult()) .highlight(expr->getSourceRange()) .fixItInsertAfter(expr->getEndLoc(), "()"); return true; } } // If this is a conversion from T to () in a call argument context, it is // almost certainly an extra argument being passed in. if (CTP == CTP_CallArgument && contextualType->isVoid()) { diagnose(expr->getLoc(), diag::extra_argument_to_nullary_call) .highlight(expr->getSourceRange()); return true; } // If we're trying to convert something to Bool, check to see if it is for // a known reason. if (contextualType->isBool() && diagnoseConversionToBool(expr, exprType)) return true; exprType = exprType->getRValueType(); // Special case of some common conversions involving Swift.String // indexes, catching cases where people attempt to index them with an integer. if (isIntegerToStringIndexConversion(exprType, contextualType, CS)) { diagnose(expr->getLoc(), diag::string_index_not_integer, exprType->getRValueType()) .highlight(expr->getSourceRange()); diagnose(expr->getLoc(), diag::string_index_not_integer_note); return true; } // When converting from T to [T] or UnsafePointer, we can offer fixit to wrap // the expr with brackets. auto *genericType = contextualType->getAs(); if (genericType) { auto *contextDecl = genericType->getDecl(); if (contextDecl == CS.TC.Context.getArrayDecl()) { for (Type arg : genericType->getGenericArgs()) { if (arg->isEqual(exprType)) { diagnose(expr->getLoc(), diagID, exprType, contextualType) .fixItInsert(expr->getStartLoc(), "[") .fixItInsert(Lexer::getLocForEndOfToken(CS.TC.Context.SourceMgr, expr->getEndLoc()), "]"); return true; } } } else if (contextDecl == CS.TC.Context.getUnsafePointerDecl() || contextDecl == CS.TC.Context.getUnsafeMutablePointerDecl() || contextDecl == CS.TC.Context.getUnsafeRawPointerDecl() || contextDecl == CS.TC.Context.getUnsafeMutableRawPointerDecl()) { for (Type arg : genericType->getGenericArgs()) { if (arg->isEqual(exprType) && CS.getType(expr)->hasLValueType()) { diagnose(expr->getLoc(), diagID, exprType, contextualType). fixItInsert(expr->getStartLoc(), "&"); return true; } } } } // Try for better/more specific diagnostics for non-escaping to @escaping if (diagnoseNonEscapingParameterToEscaping(expr, exprType, contextualType, CTP)) return true; // Don't attempt fixits if we have an unsolved type variable, since // the recovery path's recursion into the type checker via typeCheckCast() // will confuse matters. if (exprType->hasTypeVariable()) return false; // When complaining about conversion to a protocol type, complain about // conformance instead of "conversion". if (contextualType->is() || contextualType->is()) diagID = diagIDProtocol; // Try to simplify irrelevant details of function types. For example, if // someone passes a "() -> Float" function to a "() throws -> Int" // parameter, then uttering the "throws" may confuse them into thinking that // that is the problem, even though there is a clear subtype relation. if (auto srcFT = exprType->getAs()) if (auto destFT = contextualType->getAs()) { auto destExtInfo = destFT->getExtInfo(); if (!srcFT->isNoEscape()) destExtInfo = destExtInfo.withNoEscape(false); if (!srcFT->throws()) destExtInfo = destExtInfo.withThrows(false); if (destExtInfo != destFT->getExtInfo()) contextualType = FunctionType::get(destFT->getParams(), destFT->getResult(), destExtInfo); // If this is a function conversion that discards throwability or // noescape, emit a specific diagnostic about that. if (srcFT->throws() && !destFT->throws()) diagID = diag::throws_functiontype_mismatch; else if (srcFT->isNoEscape() && !destFT->isNoEscape()) diagID = diag::noescape_functiontype_mismatch; } InFlightDiagnostic diag = diagnose(expr->getLoc(), diagID, exprType, contextualType); diag.highlight(expr->getSourceRange()); // Try to convert between a sequence and its subsequence, notably // String <-> Substring. if (ContextualFailure::trySequenceSubsequenceFixIts(diag, CS, exprType, contextualType, expr)) return true; // Attempt to add a fixit for the error. switch (CTP) { case CTP_CallArgument: case CTP_ArrayElement: case CTP_DictionaryKey: case CTP_DictionaryValue: case CTP_AssignSource: case CTP_Initialization: case CTP_ReturnStmt: tryRawRepresentableFixIts(diag, CS, exprType, contextualType, KnownProtocolKind::ExpressibleByIntegerLiteral, expr) || tryRawRepresentableFixIts(diag, CS, exprType, contextualType, KnownProtocolKind::ExpressibleByStringLiteral, expr) || tryIntegerCastFixIts(diag, CS, exprType, contextualType, expr) || addTypeCoerceFixit(diag, CS, exprType, contextualType, expr); break; default: // FIXME: Other contextual conversions too? break; } return true; } //===----------------------------------------------------------------------===// // Diagnose assigning variable to itself. //===----------------------------------------------------------------------===// static Decl *findSimpleReferencedDecl(const Expr *E) { if (auto *LE = dyn_cast(E)) E = LE->getSubExpr(); if (auto *DRE = dyn_cast(E)) return DRE->getDecl(); return nullptr; } static std::pair findReferencedDecl(const Expr *E) { E = E->getValueProvidingExpr(); if (auto *LE = dyn_cast(E)) return findReferencedDecl(LE->getSubExpr()); if (auto *AE = dyn_cast(E)) return findReferencedDecl(AE->getDest()); if (auto *D = findSimpleReferencedDecl(E)) return std::make_pair(nullptr, D); if (auto *MRE = dyn_cast(E)) { if (auto *BaseDecl = findSimpleReferencedDecl(MRE->getBase())) return std::make_pair(BaseDecl, MRE->getMember().getDecl()); } return std::make_pair(nullptr, nullptr); } bool TypeChecker::diagnoseSelfAssignment(const Expr *E) { auto AE = dyn_cast(E); if (!AE) return false; auto LHSDecl = findReferencedDecl(AE->getDest()); auto RHSDecl = findReferencedDecl(AE->getSrc()); if (LHSDecl.second && LHSDecl == RHSDecl) { diagnose(AE->getLoc(), LHSDecl.first ? diag::self_assignment_prop : diag::self_assignment_var) .highlight(AE->getDest()->getSourceRange()) .highlight(AE->getSrc()->getSourceRange()); return true; } return false; } static bool isSymmetricBinaryOperator(const CalleeCandidateInfo &CCI) { // If we don't have at least one known candidate, don't trigger. if (CCI.candidates.empty()) return false; for (auto &candidate : CCI.candidates) { // Each candidate must be a non-assignment operator function. auto decl = dyn_cast_or_null(candidate.getDecl()); if (!decl) return false; auto op = dyn_cast_or_null(decl->getOperatorDecl()); if (!op || !op->getPrecedenceGroup() || op->getPrecedenceGroup()->isAssignment()) return false; // It must have exactly two parameters. auto params = decl->getParameters(); if (params->size() != 2) return false; // Require the types to be the same. if (!params->get(0)->getInterfaceType()->isEqual( params->get(1)->getInterfaceType())) return false; } return true; } /// Determine whether any of the given callee candidates have a default value. static bool candidatesHaveAnyDefaultValues( const CalleeCandidateInfo &candidates) { for (const auto &cand : candidates.candidates) { auto function = dyn_cast_or_null(cand.getDecl()); if (!function) continue; if (function->hasImplicitSelfDecl()) { if (!cand.skipCurriedSelf) return false; } else { if (cand.skipCurriedSelf) return false; } for (auto param : *function->getParameters()) { if (param->getDefaultArgumentKind() != DefaultArgumentKind::None) return true; } } return false; } /// Find the tuple element that can be initialized by a scalar. static Optional getElementForScalarInitOfArg( const TupleType *tupleTy, const CalleeCandidateInfo &candidates) { // Empty tuples cannot be initialized with a scalar. if (tupleTy->getNumElements() == 0) return None; auto getElementForScalarInitSimple = [](const TupleType *tupleTy) -> Optional { Optional result = None; for (unsigned i = 0, e = tupleTy->getNumElements(); i != e; ++i) { // If we already saw a non-vararg field, then we have more than // one candidate field. if (result.hasValue()) { // Vararg fields are okay; they'll just end up being empty. if (tupleTy->getElement(i).isVararg()) continue; // Give up. return None; } // Otherwise, remember this field number. result = i; } return result; }; // If there aren't any candidates, we're done. if (candidates.empty()) return getElementForScalarInitSimple(tupleTy); // Dig out the candidate. const auto &cand = candidates[0]; auto function = dyn_cast_or_null(cand.getDecl()); if (!function) return getElementForScalarInitSimple(tupleTy); if (function->hasImplicitSelfDecl()) { if (!cand.skipCurriedSelf) return getElementForScalarInitSimple(tupleTy); } else { if (cand.skipCurriedSelf) return getElementForScalarInitSimple(tupleTy); } auto paramList = function->getParameters(); if (tupleTy->getNumElements() != paramList->size()) return getElementForScalarInitSimple(tupleTy); // Find a tuple element without a default. Optional elementWithoutDefault; for (unsigned i : range(tupleTy->getNumElements())) { auto param = paramList->get(i); // Skip parameters with default arguments. if (param->getDefaultArgumentKind() != DefaultArgumentKind::None) continue; // If we already have an element without a default, check whether there are // two fields that need initialization. if (elementWithoutDefault) { // Variadic fields are okay; they'll just end up being empty. if (param->isVariadic()) continue; // If the element we saw before was variadic, it can be empty as well. auto priorParam = paramList->get(*elementWithoutDefault); if (!priorParam->isVariadic()) return None; } elementWithoutDefault = i; } if (elementWithoutDefault) return elementWithoutDefault; // All of the fields have default values; initialize the first one. return 0; } /// Return true if the argument of a CallExpr (or related node) has a trailing /// closure. static bool callArgHasTrailingClosure(Expr *E) { if (!E) return false; if (auto *PE = dyn_cast(E)) return PE->hasTrailingClosure(); else if (auto *TE = dyn_cast(E)) return TE->hasTrailingClosure(); return false; } /// Special magic to handle inout exprs and tuples in argument lists. Expr *FailureDiagnosis:: typeCheckArgumentChildIndependently(Expr *argExpr, Type argType, const CalleeCandidateInfo &candidates, TCCOptions options) { // Grab one of the candidates (if present) and get its input list to help // identify operators that have implicit inout arguments. Type exampleInputType; if (!candidates.empty()) { exampleInputType = candidates[0].getArgumentType(CS.getASTContext()); // If we found a single candidate, and have no contextually known argument // type information, use that one candidate as the type information for // subexpr checking. // // TODO: If all candidates have the same type for some argument, we could // pass down partial information. if (candidates.size() == 1 && !argType) argType = candidates[0].getArgumentType(CS.getASTContext()); } // If our candidates are instance members at curry level #0, then the argument // being provided is the receiver type for the instance. We produce better // diagnostics when we don't force the self type down. if (argType && !candidates.empty()) if (auto decl = candidates[0].getDecl()) if (decl->isInstanceMember() && !candidates[0].skipCurriedSelf && !isa(decl)) argType = Type(); // Similarly, we get better results when we don't push argument types down // to symmetric operators. if (argType && isSymmetricBinaryOperator(candidates)) argType = Type(); // FIXME: This should all just be a matter of getting the type of the // sub-expression, but this doesn't work well when typeCheckChildIndependently // is over-conservative w.r.t. TupleExprs. auto *TE = dyn_cast(argExpr); if (!TE) { // If the argument isn't a tuple, it is some scalar value for a // single-argument call. if (exampleInputType && exampleInputType->is()) options |= TCC_AllowLValue; // If the argtype is a tuple type with default arguments, or a labeled tuple // with a single element, pull the scalar element type for the subexpression // out. If we can't do that and the tuple has default arguments, we have to // punt on passing down the type information, since type checking the // subexpression won't be able to find the default argument provider. if (argType) { if (auto *PT = dyn_cast(argType.getPointer())) { const auto &flags = PT->getParameterFlags(); if (flags.isAutoClosure()) { auto resultTy = PT->castTo()->getResult(); argType = ParenType::get(PT->getASTContext(), resultTy); } } else if (auto argTT = argType->getAs()) { if (auto scalarElt = getElementForScalarInitOfArg(argTT, candidates)) { // If we found the single argument being initialized, use it. auto &arg = argTT->getElement(*scalarElt); // If the argument being specified is actually varargs, then we're // just specifying one element of a variadic list. Use the type of // the individual varargs argument, not the overall array type. if (arg.isVararg()) argType = arg.getVarargBaseTy(); else if (arg.isAutoClosure()) argType = arg.getType()->castTo()->getResult(); else argType = arg.getType(); } else if (candidatesHaveAnyDefaultValues(candidates)) { argType = Type(); } } else if (candidatesHaveAnyDefaultValues(candidates)) { argType = Type(); } } auto CTPurpose = argType ? CTP_CallArgument : CTP_Unused; return typeCheckChildIndependently(argExpr, argType, CTPurpose, options); } // If we know the requested argType to use, use computeTupleShuffle to produce // the shuffle of input arguments to destination values. It requires a // TupleType to compute the mapping from argExpr. Conveniently, it doesn't // care about the actual types though, so we can just use 'void' for them. // FIXME: This doesn't need to be limited to tuple types. if (argType && argType->is()) { // Decompose the parameter type. SmallVector params; AnyFunctionType::decomposeInput(argType, params); // If we have a candidate function around, compute the position of its // default arguments. SmallBitVector defaultMap(params.size()); if (!candidates.empty()) { defaultMap = computeDefaultMap(params, candidates[0].getDecl(), candidates[0].skipCurriedSelf); } // Form a set of call arguments, using a dummy type (Void), because the // argument/parameter matching code doesn't need it. auto voidTy = CS.getASTContext().TheEmptyTupleType; SmallVector args; for (unsigned i = 0, e = TE->getNumElements(); i != e; ++i) { args.push_back(AnyFunctionType::Param(voidTy, TE->getElementName(i), {})); } /// Use a match call argument listener that allows relabeling. struct RelabelMatchCallArgumentListener : MatchCallArgumentListener { bool relabelArguments(ArrayRef newNames) override { return false; } } listener; SmallVector paramBindings; if (!matchCallArguments(args, params, defaultMap, callArgHasTrailingClosure(argExpr), /*allowFixes=*/true, listener, paramBindings)) { SmallVector resultElts(TE->getNumElements(), nullptr); SmallVector resultEltTys(TE->getNumElements(), voidTy); // Perform analysis of the input elements. for (unsigned paramIdx : range(paramBindings.size())) { // Extract the parameter. const auto ¶m = params[paramIdx]; // Determine the parameter type. if (param.isInOut()) options |= TCC_AllowLValue; // Look at each of the arguments assigned to this parameter. auto currentParamType = param.getOldType(); // Since this is diagnostics, let's make sure that parameter // marked as @autoclosure indeed has a function type, because // it can also be an error type and possibly unresolved type. if (param.isAutoClosure()) { if (auto *funcType = currentParamType->getAs()) currentParamType = funcType->getResult(); } for (auto inArgNo : paramBindings[paramIdx]) { // Determine the argument type. auto currentArgType = TE->getElement(inArgNo); auto exprResult = typeCheckChildIndependently(currentArgType, currentParamType, CTP_CallArgument, options); // If there was an error type checking this argument, then we're done. if (!exprResult) return nullptr; // If the caller expected something inout, but we didn't have // something of inout type, diagnose it. if (auto IOE = dyn_cast(exprResult->getSemanticsProvidingExpr())) { if (!param.isInOut()) { diagnose(exprResult->getLoc(), diag::extra_address_of, CS.getType(exprResult)->getInOutObjectType()) .highlight(exprResult->getSourceRange()) .fixItRemove(IOE->getStartLoc()); return nullptr; } } auto resultTy = CS.getType(exprResult); resultElts[inArgNo] = exprResult; resultEltTys[inArgNo] = {resultTy->getInOutObjectType(), TE->getElementName(inArgNo), ParameterTypeFlags().withInOut(resultTy->is())}; } } auto TT = TupleType::get(resultEltTys, CS.getASTContext()); return CS.cacheType(TupleExpr::create( CS.getASTContext(), TE->getLParenLoc(), resultElts, TE->getElementNames(), TE->getElementNameLocs(), TE->getRParenLoc(), TE->hasTrailingClosure(), TE->isImplicit(), TT)); } } // Get the simplified type of each element and rebuild the aggregate. SmallVector resultEltTys; SmallVector resultElts; TupleType *exampleInputTuple = nullptr; if (exampleInputType) exampleInputTuple = exampleInputType->getAs(); for (unsigned i = 0, e = TE->getNumElements(); i != e; i++) { if (exampleInputTuple && i < exampleInputTuple->getNumElements() && exampleInputTuple->getElement(i).isInOut()) options |= TCC_AllowLValue; auto elExpr = typeCheckChildIndependently(TE->getElement(i), options); if (!elExpr) return nullptr; // already diagnosed. resultElts.push_back(elExpr); auto resFlags = ParameterTypeFlags().withInOut(elExpr->isSemanticallyInOutExpr()); resultEltTys.push_back({CS.getType(elExpr)->getInOutObjectType(), TE->getElementName(i), resFlags}); } auto TT = TupleType::get(resultEltTys, CS.getASTContext()); return CS.cacheType(TupleExpr::create( CS.getASTContext(), TE->getLParenLoc(), resultElts, TE->getElementNames(), TE->getElementNameLocs(), TE->getRParenLoc(), TE->hasTrailingClosure(), TE->isImplicit(), TT)); } static DeclName getBaseName(DeclContext *context) { if (auto generic = context->getSelfNominalTypeDecl()) { return generic->getName(); } else if (context->isModuleScopeContext()) return context->getParentModule()->getName(); else llvm_unreachable("Unsupported base"); }; static void emitFixItForExplicitlyQualifiedReference( TypeChecker &tc, UnresolvedDotExpr *UDE, decltype(diag::fix_unqualified_access_top_level) diag, DeclName baseName, DescriptiveDeclKind kind) { auto name = baseName.getBaseIdentifier(); SmallString<32> namePlusDot = name.str(); namePlusDot.push_back('.'); tc.diagnose(UDE->getLoc(), diag, namePlusDot, kind, name) .fixItInsert(UDE->getStartLoc(), namePlusDot); } void ConstraintSystem::diagnoseDeprecatedConditionalConformanceOuterAccess( UnresolvedDotExpr *UDE, ValueDecl *choice) { auto result = TC.lookupUnqualified(DC, UDE->getName(), UDE->getLoc()); assert(result && "names can't just disappear"); // These should all come from the same place. auto exampleInner = result.front(); auto innerChoice = exampleInner.getValueDecl(); auto innerDC = exampleInner.getDeclContext()->getInnermostTypeContext(); auto innerParentDecl = innerDC->getSelfNominalTypeDecl(); auto innerBaseName = getBaseName(innerDC); auto choiceKind = choice->getDescriptiveKind(); auto choiceDC = choice->getDeclContext(); auto choiceBaseName = getBaseName(choiceDC); auto choiceParentDecl = choiceDC->getAsDecl(); auto choiceParentKind = choiceParentDecl ? choiceParentDecl->getDescriptiveKind() : DescriptiveDeclKind::Module; TC.diagnose(UDE->getLoc(), diag::warn_deprecated_conditional_conformance_outer_access, UDE->getName(), choiceKind, choiceParentKind, choiceBaseName, innerChoice->getDescriptiveKind(), innerParentDecl->getDescriptiveKind(), innerBaseName); emitFixItForExplicitlyQualifiedReference( TC, UDE, diag::fix_deprecated_conditional_conformance_outer_access, choiceBaseName, choiceKind); } static SmallVector decomposeArgType(Type argType, ArrayRef argLabels) { SmallVector result; AnyFunctionType::decomposeInput(argType, result); AnyFunctionType::relabelParams(result, argLabels); return result; } bool FailureDiagnosis::diagnoseImplicitSelfErrors( Expr *fnExpr, Expr *argExpr, CalleeCandidateInfo &CCI, ArrayRef argLabels) { // If candidate list is empty it means that problem is somewhere else, // since we need to have candidates which might be shadowing other funcs. if (CCI.empty() || !CCI[0].getDecl()) return false; auto &TC = CS.TC; // Call expression is formed as 'foo.bar' where 'foo' might be an // implicit "Self" reference, such use wouldn't provide good diagnostics // for situations where instance members have equal names to functions in // Swift Standard Library e.g. min/max. auto UDE = dyn_cast(fnExpr); if (!UDE) return false; auto baseExpr = dyn_cast(UDE->getBase()); if (!baseExpr) return false; auto baseDecl = baseExpr->getDecl(); if (!baseExpr->isImplicit() || baseDecl->getFullName() != TC.Context.Id_self) return false; // Our base expression is an implicit 'self.' reference e.g. // // extension Sequence { // func test() -> Int { // return max(1, 2) // } // } // // In this example the Sequence class already has two methods named 'max' // none of which accept two arguments, but there is a function in // Swift Standard Library called 'max' which does accept two arguments, // so user might have called that by mistake without realizing that // compiler would add implicit 'self.' prefix to the call of 'max'. auto argType = CS.getType(argExpr); // If argument wasn't properly type-checked, let's retry without changing AST. if (!argType || argType->hasUnresolvedType() || argType->hasTypeVariable() || argType->hasTypeParameter()) { auto *argTuple = dyn_cast(argExpr); if (!argTuple) { // Bail out if we don't have a well-formed argument list. return false; } // Let's type check individual argument expressions without any // contextual information to try to recover an argument type that // matches what the user actually wrote instead of what the typechecker // expects. SmallVector elts; for (unsigned i = 0, e = argTuple->getNumElements(); i < e; ++i) { ConcreteDeclRef ref = nullptr; auto *el = argTuple->getElement(i); auto typeResult = getTypeOfExpressionWithoutApplying(el, CS.DC, ref); if (!typeResult) return false; auto flags = ParameterTypeFlags().withInOut(typeResult->is()); elts.push_back(TupleTypeElt(typeResult->getInOutObjectType(), argTuple->getElementName(i), flags)); } argType = TupleType::get(elts, CS.getASTContext()); } auto typeKind = argType->getKind(); if (typeKind != TypeKind::Tuple && typeKind != TypeKind::Paren) return false; // If argument type couldn't be properly resolved or has errors, // we can't diagnose anything in here, it points to the different problem. if (isUnresolvedOrTypeVarType(argType) || argType->hasError()) return false; auto context = CS.DC; using CandidateMap = llvm::SmallDenseMap>; auto getBaseKind = [](ValueDecl *base) -> DescriptiveDeclKind { DescriptiveDeclKind kind = DescriptiveDeclKind::Module; if (!base) return kind; auto context = base->getDeclContext(); do { if (isa(context)) return DescriptiveDeclKind::Extension; if (auto nominal = dyn_cast(context)) { kind = nominal->getDescriptiveKind(); break; } context = context->getParent(); } while (context); return kind; }; auto diagnoseShadowing = [&](ValueDecl *base, ArrayRef candidates) -> bool { CalleeCandidateInfo calleeInfo(base ? base->getInterfaceType() : nullptr, candidates, CCI.hasTrailingClosure, CS, base); calleeInfo.filterListArgs(decomposeArgType(argType, argLabels)); auto diagnostic = diag::member_shadows_global_function_near_match; switch (calleeInfo.closeness) { case CC_Unavailable: case CC_Inaccessible: case CC_SelfMismatch: case CC_ArgumentLabelMismatch: case CC_ArgumentCountMismatch: case CC_GeneralMismatch: return false; case CC_NonLValueInOut: case CC_OneArgumentNearMismatch: case CC_OneArgumentMismatch: case CC_OneGenericArgumentNearMismatch: case CC_OneGenericArgumentMismatch: case CC_ArgumentNearMismatch: case CC_ArgumentMismatch: case CC_GenericNonsubstitutableMismatch: break; // Near match cases case CC_ExactMatch: diagnostic = diag::member_shadows_global_function; break; } auto choice = calleeInfo.candidates[0].getDecl(); auto baseKind = getBaseKind(base); auto baseName = getBaseName(choice->getDeclContext()); auto origCandidate = CCI[0].getDecl(); TC.diagnose(UDE->getLoc(), diagnostic, UDE->getName(), origCandidate->getDescriptiveKind(), origCandidate->getFullName(), choice->getDescriptiveKind(), choice->getFullName(), baseKind, baseName); auto topLevelDiag = diag::fix_unqualified_access_top_level; if (baseKind == DescriptiveDeclKind::Module) topLevelDiag = diag::fix_unqualified_access_top_level_multi; emitFixItForExplicitlyQualifiedReference(TC, UDE, topLevelDiag, baseName, choice->getDescriptiveKind()); for (auto &candidate : calleeInfo.candidates) { if (auto decl = candidate.getDecl()) TC.diagnose(decl, diag::decl_declared_here, decl->getFullName()); } return true; }; // For each of the parent contexts, let's try to find any candidates // which have the same name and the same number of arguments as callee. while (context->getParent()) { auto result = TC.lookupUnqualified(context, UDE->getName(), UDE->getLoc()); context = context->getParent(); if (!result || result.empty()) continue; CandidateMap candidates; for (const auto &candidate : result) { auto base = candidate.getBaseDecl(); auto decl = candidate.getValueDecl(); if ((base && base->isInvalid()) || decl->isInvalid()) continue; // If base is present but it doesn't represent a valid nominal, // we can't use current candidate as one of the choices. if (base && !base->getInterfaceType()->getNominalOrBoundGenericNominal()) continue; auto context = decl->getDeclContext(); // We are only interested in static or global functions, because // there is no way to call anything else properly. if (!decl->isStatic() && !context->isModuleScopeContext()) continue; OverloadChoice choice(base ? base->getInterfaceType() : nullptr, decl, UDE->getFunctionRefKind()); if (base) { // Let's group all of the candidates have a common base. candidates[base].push_back(choice); continue; } // If there is no base, it means this is one of the global functions, // let's try to diagnose its shadowing inline. if (diagnoseShadowing(base, choice)) return true; } if (candidates.empty()) continue; for (const auto &candidate : candidates) { if (diagnoseShadowing(candidate.getFirst(), candidate.getSecond())) return true; } } return false; } // It is a somewhat common error to try to access an instance method as a // curried member on the type, instead of using an instance, e.g. the user // wrote: // // Foo.doThing(42, b: 19) // // instead of: // // myFoo.doThing(42, b: 19) // // Check for this situation and handle it gracefully. static bool diagnoseInstanceMethodAsCurriedMemberOnType(CalleeCandidateInfo &CCI, Expr *fnExpr, Expr *argExpr) { for (auto &candidate : CCI.candidates) { if (!candidate.hasParameters()) return false; auto *decl = candidate.getDecl(); if (!decl) return false; // If this is an exact match at the level 1 of the parameters, but // there is still something wrong with the expression nevertheless // it might be worth while to check if it's instance method as curried // member of type problem. if (CCI.closeness == CC_ExactMatch && (decl->isInstanceMember() && candidate.skipCurriedSelf)) continue; auto params = candidate.getParameters(); // If one of the candidates is an instance method with a single parameter // at the level 0, this might be viable situation for calling instance // method as curried member of type problem. if (params.size() != 1 || !decl->isInstanceMember() || candidate.skipCurriedSelf) return false; } auto &TC = CCI.CS.TC; if (auto UDE = dyn_cast(fnExpr)) { auto baseExpr = UDE->getBase(); auto baseType = CCI.CS.getType(baseExpr); if (auto *MT = baseType->getAs()) { auto DC = CCI.CS.DC; auto instanceType = MT->getInstanceType(); // If the base is an implicit self type reference, and we're in a // an initializer, then the user wrote something like: // // class Foo { let val = initFn() } // or // class Bar { func something(x: Int = initFn()) } // // which runs in type context, not instance context. Produce a tailored // diagnostic since this comes up and is otherwise non-obvious what is // going on. if (baseExpr->isImplicit() && isa(DC)) { auto *TypeDC = DC->getParent(); bool propertyInitializer = true; // If the parent context is not a type context, we expect it // to be a defaulted parameter in a function declaration. if (!TypeDC->isTypeContext()) { assert(TypeDC->getContextKind() == DeclContextKind::AbstractFunctionDecl && "Expected function decl context for initializer!"); TypeDC = TypeDC->getParent(); propertyInitializer = false; } assert(TypeDC->isTypeContext() && "Expected type decl context!"); if (TypeDC->getSelfNominalTypeDecl() == instanceType->getAnyNominal()) { if (propertyInitializer) TC.diagnose(UDE->getLoc(), diag::instance_member_in_initializer, UDE->getName()); else TC.diagnose(UDE->getLoc(), diag::instance_member_in_default_parameter, UDE->getName()); return true; } } // If this is a situation like this `self.foo(A())()` and self != A // let's say that `self` is not convertible to A. if (auto nominalType = CCI.CS.getType(argExpr)->getAs()) { if (!instanceType->isEqual(nominalType)) { TC.diagnose(argExpr->getStartLoc(), diag::types_not_convertible, false, nominalType, instanceType); return true; } } // Otherwise, complain about use of instance value on type. if (isa(baseExpr)) { TC.diagnose(UDE->getLoc(), diag::instance_member_use_on_type, instanceType, UDE->getName()) .highlight(baseExpr->getSourceRange()); } else { TC.diagnose(UDE->getLoc(), diag::could_not_use_instance_member_on_type, instanceType, UDE->getName(), instanceType, false) .highlight(baseExpr->getSourceRange()); } return true; } } return false; } static bool diagnoseTupleParameterMismatch(CalleeCandidateInfo &CCI, ArrayRef params, ArrayRef args, Expr *fnExpr, Expr *argExpr, bool isTopLevel = true) { // Try to diagnose function call tuple parameter splat only if // there is no trailing or argument closure, because // FailureDiagnosis::visitClosureExpr will produce better // diagnostic and fix-it for trailing closure case. if (isTopLevel) { if (CCI.hasTrailingClosure) return false; if (auto *parenExpr = dyn_cast(argExpr)) { if (isa(parenExpr->getSubExpr())) return false; } } if (params.size() == 1 && args.size() == 1) { auto paramType = params.front().getOldType(); auto argType = args.front().getOldType(); if (auto *paramFnType = paramType->getAs()) { // Only if both of the parameter and argument types are functions // let's recur into diagnosing their arguments. if (auto *argFnType = argType->getAs()) return diagnoseTupleParameterMismatch(CCI, paramFnType->getParams(), argFnType->getParams(), fnExpr, argExpr, /* isTopLevel */ false); return false; } } if (params.size() != 1 || args.empty()) return false; auto paramType = params.front().getOldType(); if (args.size() == 1) { auto argType = args.front().getOldType(); if (auto *paramFnType = paramType->getAs()) { // Only if both of the parameter and argument types are functions // let's recur into diagnosing their arguments. if (auto *argFnType = argType->getAs()) return diagnoseTupleParameterMismatch(CCI, paramFnType->getParams(), argFnType->getParams(), fnExpr, argExpr, /* isTopLevel */ false); } return false; } // Let's see if inferred argument is actually a tuple inside of Paren. auto *paramTupleTy = paramType->getAs(); if (!paramTupleTy) return false; if (paramTupleTy->getNumElements() != args.size()) return false; // Looks like the number of tuple elements matches number // of function arguments, which means we can we can emit an // error about an attempt to make use of tuple splat or tuple // destructuring, unfortunately we can't provide a fix-it for // this case. auto &TC = CCI.CS.TC; if (isTopLevel) { if (auto *decl = CCI[0].getDecl()) { Identifier name; auto kind = decl->getDescriptiveKind(); // Constructors/descructors and subscripts don't really have names. if (!(isa(decl) || isa(decl) || isa(decl))) { name = decl->getBaseName().getIdentifier(); } TC.diagnose(argExpr->getLoc(), diag::single_tuple_parameter_mismatch, kind, name, paramTupleTy, !name.empty()) .highlight(argExpr->getSourceRange()) .fixItInsertAfter(argExpr->getStartLoc(), "(") .fixItInsert(argExpr->getEndLoc(), ")"); } else { TC.diagnose(argExpr->getLoc(), diag::unknown_single_tuple_parameter_mismatch, paramTupleTy) .highlight(argExpr->getSourceRange()) .fixItInsertAfter(argExpr->getStartLoc(), "(") .fixItInsert(argExpr->getEndLoc(), ")"); } } else { TC.diagnose(argExpr->getLoc(), diag::nested_tuple_parameter_destructuring, paramTupleTy, CCI.CS.getType(fnExpr)); } return true; } static bool diagnoseTupleParameterMismatch(CalleeCandidateInfo &CCI, ArrayRef params, Type argType, Expr *fnExpr, Expr *argExpr, bool isTopLevel = true) { llvm::SmallVector args; FunctionType::decomposeInput(argType, args); return diagnoseTupleParameterMismatch(CCI, params, args, fnExpr, argExpr, isTopLevel); } class ArgumentMatcher : public MatchCallArgumentListener { TypeChecker &TC; Expr *FnExpr; Expr *ArgExpr; ArrayRef &Parameters; const SmallBitVector &DefaultMap; SmallVectorImpl &Arguments; CalleeCandidateInfo CandidateInfo; // Indicates if problem has been found and diagnostic was emitted. bool Diagnosed = false; // Indicates if functions we are trying to call is a subscript. bool IsSubscript; // Stores parameter bindings determined by call to matchCallArguments. SmallVector Bindings; unsigned NumLabelFailures = 0; public: ArgumentMatcher(Expr *fnExpr, Expr *argExpr, ArrayRef ¶ms, const SmallBitVector &defaultMap, SmallVectorImpl &args, CalleeCandidateInfo &CCI, bool isSubscript) : TC(CCI.CS.TC), FnExpr(fnExpr), ArgExpr(argExpr), Parameters(params), DefaultMap(defaultMap), Arguments(args), CandidateInfo(CCI), IsSubscript(isSubscript) {} void extraArgument(unsigned extraArgIdx) override { auto name = Arguments[extraArgIdx].getLabel(); Expr *arg = ArgExpr; auto tuple = dyn_cast(ArgExpr); if (tuple) arg = tuple->getElement(extraArgIdx); auto loc = arg->getLoc(); if (tuple && extraArgIdx == tuple->getNumElements() - 1 && tuple->hasTrailingClosure()) TC.diagnose(loc, diag::extra_trailing_closure_in_call) .highlight(arg->getSourceRange()); else if (Parameters.empty()) { auto Paren = dyn_cast(ArgExpr); Expr *SubExpr = nullptr; if (Paren) { SubExpr = Paren->getSubExpr(); } if (SubExpr && CandidateInfo.CS.getType(SubExpr) && CandidateInfo.CS.getType(SubExpr)->isVoid()) { TC.diagnose(loc, diag::extra_argument_to_nullary_call) .fixItRemove(SubExpr->getSourceRange()); } else { TC.diagnose(loc, diag::extra_argument_to_nullary_call) .highlight(ArgExpr->getSourceRange()); } } else if (name.empty()) TC.diagnose(loc, diag::extra_argument_positional) .highlight(arg->getSourceRange()); else TC.diagnose(loc, diag::extra_argument_named, name) .highlight(arg->getSourceRange()); Diagnosed = true; } void missingArgument(unsigned missingParamIdx) override { auto ¶m = Parameters[missingParamIdx]; Identifier name = param.getLabel(); // Search insertion index. unsigned argIdx = 0; for (int Idx = missingParamIdx - 1; Idx >= 0; --Idx) { if (Bindings[Idx].empty()) continue; argIdx = Bindings[Idx].back() + 1; break; } unsigned insertableEndIdx = Arguments.size(); if (CandidateInfo.hasTrailingClosure) insertableEndIdx -= 1; // Build argument string for fix-it. SmallString<32> insertBuf; llvm::raw_svector_ostream insertText(insertBuf); if (argIdx != 0) insertText << ", "; if (!name.empty()) insertText << name.str() << ": "; Type Ty = param.getOldType(); // Explode inout type. if (param.isInOut()) { insertText << "&"; Ty = param.getPlainType(); } // @autoclosure; the type should be the result type. if (param.isAutoClosure()) Ty = param.getPlainType()->castTo()->getResult(); insertText << "<#" << Ty << "#>"; if (argIdx == 0 && insertableEndIdx != 0) insertText << ", "; SourceLoc insertLoc; if (argIdx > insertableEndIdx) { // Unreachable for now. // FIXME: matchCallArguments() doesn't detect "missing argument after // trailing closure". E.g. // func fn(x: Int, y: () -> Int, z: Int) { ... } // fn(x: 1) { return 1 } // is diagnosed as "missing argument for 'y'" (missingParamIdx 1). // It should be "missing argument for 'z'" (missingParamIdx 2). } else if (auto *TE = dyn_cast(ArgExpr)) { // fn(): // fn([argMissing]) // fn(argX, argY): // fn([argMissing, ]argX, argY) // fn(argX[, argMissing], argY) // fn(argX, argY[, argMissing]) // fn(argX) { closure }: // fn([argMissing, ]argX) { closure } // fn(argX[, argMissing]) { closure } // fn(argX[, closureLabel: ]{closure}[, argMissing)] // Not impl. if (insertableEndIdx == 0) insertLoc = TE->getRParenLoc(); else if (argIdx != 0) insertLoc = Lexer::getLocForEndOfToken( TC.Context.SourceMgr, TE->getElement(argIdx - 1)->getEndLoc()); else { insertLoc = TE->getElementNameLoc(0); if (insertLoc.isInvalid()) insertLoc = TE->getElement(0)->getStartLoc(); } } else if (auto *PE = dyn_cast(ArgExpr)) { assert(argIdx <= 1); if (PE->getRParenLoc().isValid()) { // fn(argX): // fn([argMissing, ]argX) // fn(argX[, argMissing]) // fn() { closure }: // fn([argMissing]) {closure} // fn([closureLabel: ]{closure}[, argMissing]) // Not impl. if (insertableEndIdx == 0) insertLoc = PE->getRParenLoc(); else if (argIdx == 0) insertLoc = PE->getSubExpr()->getStartLoc(); else insertLoc = Lexer::getLocForEndOfToken(TC.Context.SourceMgr, PE->getSubExpr()->getEndLoc()); } else { // fn { closure }: // fn[(argMissing)] { closure } // fn[(closureLabel:] { closure }[, missingArg)] // Not impl. assert(!IsSubscript && "bracket less subscript"); assert(PE->hasTrailingClosure() && "paren less ParenExpr without trailing closure"); insertBuf.insert(insertBuf.begin(), '('); insertBuf.insert(insertBuf.end(), ')'); insertLoc = Lexer::getLocForEndOfToken(TC.Context.SourceMgr, FnExpr->getEndLoc()); } } else { auto &CS = CandidateInfo.CS; (void)CS; // FIXME: Due to a quirk of CSApply, we can end up without a // ParenExpr if the argument has an '@lvalue TupleType'. assert((isa(CS.getType(ArgExpr).getPointer()) || CS.getType(ArgExpr)->hasParenSugar()) && "unexpected argument expression type"); insertLoc = ArgExpr->getLoc(); // Can't be TupleShuffleExpr because this argExpr is not yet resolved. } assert(insertLoc.isValid() && "missing argument after trailing closure?"); if (name.empty()) TC.diagnose(insertLoc, diag::missing_argument_positional, missingParamIdx + 1) .fixItInsert(insertLoc, insertText.str()); else TC.diagnose(insertLoc, diag::missing_argument_named, name) .fixItInsert(insertLoc, insertText.str()); auto candidate = CandidateInfo[0]; if (candidate.getDecl()) TC.diagnose(candidate.getDecl(), diag::decl_declared_here, candidate.getDecl()->getFullName()); Diagnosed = true; } bool missingLabel(unsigned paramIdx) override { ++NumLabelFailures; return false; } bool extraneousLabel(unsigned paramIdx) override { ++NumLabelFailures; return false; } bool incorrectLabel(unsigned paramIdx) override { ++NumLabelFailures; return false; } void outOfOrderArgument(unsigned argIdx, unsigned prevArgIdx) override { auto tuple = cast(ArgExpr); Identifier first = tuple->getElementName(argIdx); Identifier second = tuple->getElementName(prevArgIdx); // If we've seen label failures and now there is an out-of-order // parameter (or even worse - OoO parameter with label re-naming), // we most likely have no idea what would be the best // diagnostic for this situation, so let's just try to re-label. auto shouldDiagnoseOoO = [&](Identifier newLabel, Identifier oldLabel) { if (NumLabelFailures > 0) return false; unsigned actualIndex = prevArgIdx; for (; actualIndex != argIdx; ++actualIndex) { // Looks like new position (excluding defaulted parameters), // has a valid label. if (newLabel == Parameters[actualIndex].getLabel()) break; // If we are moving the the position with a different label // and there is no default value for it, can't diagnose the // problem as a simple re-ordering. if (!DefaultMap.test(actualIndex)) return false; } for (unsigned i = actualIndex + 1, n = Parameters.size(); i != n; ++i) { if (oldLabel == Parameters[i].getLabel()) break; if (!DefaultMap.test(i)) return false; } return true; }; if (!shouldDiagnoseOoO(first, second)) { SmallVector paramLabels; llvm::transform(Parameters, std::back_inserter(paramLabels), [](const AnyFunctionType::Param ¶m) { return param.getLabel(); }); relabelArguments(paramLabels); return; } // Build a mapping from arguments to parameters. SmallVector argBindings(tuple->getNumElements()); for (unsigned paramIdx = 0; paramIdx != Bindings.size(); ++paramIdx) { for (auto argIdx : Bindings[paramIdx]) argBindings[argIdx] = paramIdx; } auto argRange = [&](unsigned argIdx, Identifier label) -> SourceRange { auto range = tuple->getElement(argIdx)->getSourceRange(); if (!label.empty()) range.Start = tuple->getElementNameLoc(argIdx); unsigned paramIdx = argBindings[argIdx]; if (Bindings[paramIdx].size() > 1) range.End = tuple->getElement(Bindings[paramIdx].back())->getEndLoc(); return range; }; auto firstRange = argRange(argIdx, first); auto secondRange = argRange(prevArgIdx, second); SourceLoc diagLoc = firstRange.Start; auto addFixIts = [&](InFlightDiagnostic diag) { diag.highlight(firstRange).highlight(secondRange); // Move the misplaced argument by removing it from one location and // inserting it in another location. To maintain argument comma // separation, since the argument is always moving to an earlier index // the preceding comma and whitespace is removed and a new trailing // comma and space is inserted with the moved argument. auto &SM = TC.Context.SourceMgr; auto text = SM.extractText( Lexer::getCharSourceRangeFromSourceRange(SM, firstRange)); auto removalRange = SourceRange(Lexer::getLocForEndOfToken( SM, tuple->getElement(argIdx - 1)->getEndLoc()), firstRange.End); diag.fixItRemove(removalRange); diag.fixItInsert(secondRange.Start, text.str() + ", "); }; // There are 4 diagnostic messages variations depending on // labeled/unlabeled arguments. if (first.empty() && second.empty()) { addFixIts(TC.diagnose(diagLoc, diag::argument_out_of_order_unnamed_unnamed, argIdx + 1, prevArgIdx + 1)); } else if (first.empty() && !second.empty()) { addFixIts(TC.diagnose(diagLoc, diag::argument_out_of_order_unnamed_named, argIdx + 1, second)); } else if (!first.empty() && second.empty()) { addFixIts(TC.diagnose(diagLoc, diag::argument_out_of_order_named_unnamed, first, prevArgIdx + 1)); } else { addFixIts(TC.diagnose(diagLoc, diag::argument_out_of_order_named_named, first, second)); } Diagnosed = true; } bool relabelArguments(ArrayRef newNames) override { assert(!newNames.empty() && "No arguments were re-labeled"); // Let's diagnose labeling problem but only related to corrected ones. if (diagnoseArgumentLabelError(TC.Context, ArgExpr, newNames, IsSubscript)) Diagnosed = true; return true; } bool diagnose() { // Use matchCallArguments to determine how close the argument list is (in // shape) to the specified candidates parameters. This ignores the // concrete types of the arguments, looking only at the argument labels. matchCallArguments(Arguments, Parameters, DefaultMap, CandidateInfo.hasTrailingClosure, /*allowFixes:*/ true, *this, Bindings); return Diagnosed; } }; /// Emit a class of diagnostics that we only know how to generate when /// there is exactly one candidate we know about. Return true if an error /// is emitted. static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, Expr *fnExpr, Expr *argExpr, ArrayRef argLabels) { // We only handle the situation where there is exactly one candidate // here. if (CCI.size() != 1) return false; auto candidate = CCI[0]; auto &TC = CCI.CS.TC; if (!candidate.hasParameters()) return false; auto params = candidate.getParameters(); SmallBitVector defaultMap = computeDefaultMap(params, candidate.getDecl(), candidate.skipCurriedSelf); auto args = decomposeArgType(CCI.CS.getType(argExpr), argLabels); // Check the case where a raw-representable type is constructed from an // argument with the same type: // // MyEnumType(MyEnumType.foo) // // This is missing 'rawValue:' label, but a better fix is to just remove // the unnecessary constructor call: // // MyEnumType.foo // if (params.size() == 1 && args.size() == 1 && candidate.getDecl() && isa(candidate.getDecl()) && candidate.skipCurriedSelf) { AnyFunctionType::Param &arg = args[0]; auto resTy = candidate.getResultType()->lookThroughAllOptionalTypes(); auto rawTy = isRawRepresentable(resTy, CCI.CS); if (rawTy && arg.getOldType() && resTy->isEqual(arg.getOldType())) { auto getInnerExpr = [](Expr *E) -> Expr * { auto *parenE = dyn_cast(E); if (!parenE) return nullptr; return parenE->getSubExpr(); }; Expr *innerE = getInnerExpr(argExpr); InFlightDiagnostic diag = TC.diagnose( fnExpr->getLoc(), diag::invalid_initialization_parameter_same_type, resTy); diag.highlight((innerE ? innerE : argExpr)->getSourceRange()); if (innerE) { // Remove the unnecessary constructor call. diag.fixItRemoveChars(fnExpr->getLoc(), innerE->getStartLoc()) .fixItRemove(argExpr->getEndLoc()); } return true; } } if (diagnoseTupleParameterMismatch(CCI, candidate.getParameters(), CCI.CS.getType(argExpr), fnExpr, argExpr)) return true; // We only handle structural errors here. if (CCI.closeness != CC_ArgumentLabelMismatch && CCI.closeness != CC_ArgumentCountMismatch) return false; // If we have a single candidate that failed to match the argument list, // attempt to use matchCallArguments to diagnose the problem. return ArgumentMatcher(fnExpr, argExpr, params, defaultMap, args, CCI, isa(fnExpr)) .diagnose(); } namespace { enum class RawRepresentableMismatch { NotApplicable, Convertible, ExactMatch }; } static RawRepresentableMismatch checkRawRepresentableMismatch(Type fromType, Type toType, KnownProtocolKind kind, const ConstraintSystem &CS) { toType = toType->lookThroughAllOptionalTypes(); fromType = fromType->lookThroughAllOptionalTypes(); // First check if this is an attempt to convert from something to // raw representable. if (conformsToKnownProtocol(fromType, kind, CS)) { if (auto rawType = isRawRepresentable(toType, kind, CS)) { if (rawType->isEqual(fromType)) return RawRepresentableMismatch::ExactMatch; return RawRepresentableMismatch::Convertible; } } // Otherwise, it might be an attempt to convert from raw representable // to its raw value. if (auto rawType = isRawRepresentable(fromType, kind, CS)) { if (conformsToKnownProtocol(toType, kind, CS)) { if (rawType->isEqual(toType)) return RawRepresentableMismatch::ExactMatch; return RawRepresentableMismatch::Convertible; } } return RawRepresentableMismatch::NotApplicable; } static bool diagnoseRawRepresentableMismatch(CalleeCandidateInfo &CCI, Expr *argExpr, ArrayRef argLabels) { // We are only interested in cases which are // unrelated to argument count or label mismatches. switch (CCI.closeness) { case CC_OneArgumentNearMismatch: case CC_OneArgumentMismatch: case CC_OneGenericArgumentNearMismatch: case CC_OneGenericArgumentMismatch: case CC_ArgumentNearMismatch: case CC_ArgumentMismatch: break; default: return false; } auto argType = CCI.CS.getType(argExpr); if (!argType || argType->hasTypeVariable() || argType->hasUnresolvedType()) return false; KnownProtocolKind rawRepresentableProtocols[] = { KnownProtocolKind::ExpressibleByStringLiteral, KnownProtocolKind::ExpressibleByIntegerLiteral}; const auto &CS = CCI.CS; auto arguments = decomposeArgType(argType, argLabels); auto bestMatchKind = RawRepresentableMismatch::NotApplicable; const OverloadCandidate *bestMatchCandidate = nullptr; KnownProtocolKind bestMatchProtocol; size_t bestMatchIndex; for (auto &candidate : CCI.candidates) { auto *decl = candidate.getDecl(); if (!decl) continue; if (!candidate.hasParameters()) continue; auto parameters = candidate.getParameters(); // FIXME: Default arguments? if (parameters.size() != arguments.size()) continue; for (unsigned i = 0, n = parameters.size(); i != n; ++i) { auto paramType = parameters[i].getOldType(); auto argType = arguments[i].getOldType(); for (auto kind : rawRepresentableProtocols) { // If trying to convert from raw type to raw representable, // or vice versa from raw representable (e.g. enum) to raw type. auto matchKind = checkRawRepresentableMismatch(argType, paramType, kind, CS); if (matchKind > bestMatchKind) { bestMatchKind = matchKind; bestMatchProtocol = kind; bestMatchCandidate = &candidate; bestMatchIndex = i; } } } } if (bestMatchKind == RawRepresentableMismatch::NotApplicable) return false; const Expr *expr = argExpr; if (auto *tupleArgs = dyn_cast(argExpr)) expr = tupleArgs->getElement(bestMatchIndex); expr = expr->getValueProvidingExpr(); auto parameters = bestMatchCandidate->getParameters(); auto paramType = parameters[bestMatchIndex].getOldType(); auto singleArgType = arguments[bestMatchIndex].getOldType(); auto diag = CS.TC.diagnose(expr->getLoc(), diag::cannot_convert_argument_value, singleArgType, paramType); tryRawRepresentableFixIts(diag, CS, singleArgType, paramType, bestMatchProtocol, expr); return true; } // Extract expression for failed argument number static Expr *getFailedArgumentExpr(CalleeCandidateInfo CCI, Expr *argExpr) { if (auto *TE = dyn_cast(argExpr)) return TE->getElement(CCI.failedArgument.argumentNumber); else if (auto *PE = dyn_cast(argExpr)) { assert(CCI.failedArgument.argumentNumber == 0 && "Unexpected argument #"); return PE->getSubExpr(); } else { assert(CCI.failedArgument.argumentNumber == 0 && "Unexpected argument #"); return argExpr; } } /// If the candidate set has been narrowed down to a specific structural /// problem, e.g. that there are too few parameters specified or that argument /// labels don't match up, diagnose that error and return true. bool FailureDiagnosis::diagnoseParameterErrors(CalleeCandidateInfo &CCI, Expr *fnExpr, Expr *argExpr, ArrayRef argLabels) { if (auto *MTT = CS.getType(fnExpr)->getAs()) { auto instTy = MTT->getInstanceType(); if (instTy->getAnyNominal()) { // If we are invoking a constructor on a nominal type and there are // absolutely no candidates, then they must all be private. if (CCI.empty() || (CCI.size() == 1 && CCI.candidates[0].getDecl() && isa(CCI.candidates[0].getDecl()))) { CS.TC.diagnose(fnExpr->getLoc(), diag::no_accessible_initializers, instTy); return true; } // continue below } else if (!instTy->is()) { // If we are invoking a constructor on a non-nominal type, the expression // is malformed. SourceRange initExprRange(fnExpr->getSourceRange().Start, argExpr->getSourceRange().End); CS.TC.diagnose(fnExpr->getLoc(), instTy->isExistentialType() ? diag::construct_protocol_by_name : diag::non_nominal_no_initializers, instTy) .highlight(initExprRange); return true; } } // Try to diagnose errors related to the use of implicit self reference. if (diagnoseImplicitSelfErrors(fnExpr, argExpr, CCI, argLabels)) return true; if (diagnoseInstanceMethodAsCurriedMemberOnType(CCI, fnExpr, argExpr)) return true; // Do all the stuff that we only have implemented when there is a single // candidate. if (diagnoseSingleCandidateFailures(CCI, fnExpr, argExpr, argLabels)) return true; // If we have a failure where the candidate set differs on exactly one // argument, and where we have a consistent mismatch across the candidate set // (often because there is only one candidate in the set), then diagnose this // as a specific problem of passing something of the wrong type into a // parameter. // // We don't generally want to use this path to diagnose calls to // symmetrically-typed binary operators because it's likely that both // operands contributed to the type. if ((CCI.closeness == CC_OneArgumentMismatch || CCI.closeness == CC_OneArgumentNearMismatch || CCI.closeness == CC_OneGenericArgumentMismatch || CCI.closeness == CC_OneGenericArgumentNearMismatch || CCI.closeness == CC_GenericNonsubstitutableMismatch) && CCI.failedArgument.isValid() && !isSymmetricBinaryOperator(CCI)) { // Map the argument number into an argument expression. TCCOptions options = TCC_ForceRecheck; if (CCI.failedArgument.parameterType->is()) options |= TCC_AllowLValue; // It could be that the argument doesn't conform to an archetype. Expr *badArgExpr = getFailedArgumentExpr(CCI, argExpr); if (CCI.diagnoseGenericParameterErrors(badArgExpr)) return true; // Re-type-check the argument with the expected type of the candidate set. // This should produce a specific and tailored diagnostic saying that the // type mismatches with expectations. Type paramType = CCI.failedArgument.parameterType; if (!typeCheckChildIndependently(badArgExpr, paramType, CTP_CallArgument, options)) return true; } return false; } bool FailureDiagnosis::diagnoseSubscriptErrors(SubscriptExpr *SE, bool inAssignmentDestination) { auto baseExpr = typeCheckChildIndependently(SE->getBase()); if (!baseExpr) return true; auto baseType = CS.getType(baseExpr); if (isa(baseExpr)) { diagnose(baseExpr->getLoc(), diag::cannot_subscript_nil_literal) .highlight(baseExpr->getSourceRange()); return true; } std::function)> callback = [&](ArrayRef candidates) -> bool { CalleeCandidateInfo calleeInfo(Type(), candidates, SE->hasTrailingClosure(), CS, /*selfAlreadyApplied*/ false); // We're about to typecheck the index list, which needs to be processed with // self already applied. for (unsigned i = 0, e = calleeInfo.size(); i != e; ++i) calleeInfo.candidates[i].skipCurriedSelf = true; auto indexExpr = typeCheckArgumentChildIndependently(SE->getIndex(), Type(), calleeInfo); if (!indexExpr) return true; // Back to analyzing the candidate list with self applied. for (unsigned i = 0, e = calleeInfo.size(); i != e; ++i) calleeInfo.candidates[i].skipCurriedSelf = false; ArrayRef argLabels = SE->getArgumentLabels(); if (diagnoseParameterErrors(calleeInfo, SE, indexExpr, argLabels)) return true; auto indexType = CS.getType(indexExpr); auto decomposedBaseType = decomposeArgType(baseType, {Identifier()}); auto decomposedIndexType = decomposeArgType(indexType, argLabels); calleeInfo.filterList( [&](OverloadCandidate cand) -> CalleeCandidateInfo::ClosenessResultTy { // Classify how close this match is. Non-subscript decls don't match. auto subscriptDecl = dyn_cast_or_null(cand.getDecl()); if (!subscriptDecl || (inAssignmentDestination && !subscriptDecl->isSettable())) return {CC_GeneralMismatch, {}}; // Check whether the self type matches. auto selfConstraint = CC_ExactMatch; if (calleeInfo.evaluateCloseness(cand, decomposedBaseType).first != CC_ExactMatch) selfConstraint = CC_SelfMismatch; // Set a flag to look past the self argument to the indices. cand.skipCurriedSelf = true; // Explode out multi-index subscripts to find the best match. auto indexResult = calleeInfo.evaluateCloseness(cand, decomposedIndexType); if (selfConstraint > indexResult.first) return {selfConstraint, {}}; return indexResult; }); // If the closest matches all mismatch on self, we either have something // that cannot be subscripted, or an ambiguity. if (calleeInfo.closeness == CC_SelfMismatch) { diagnose(SE->getLoc(), diag::cannot_subscript_base, baseType) .highlight(SE->getBase()->getSourceRange()); // FIXME: Should suggest overload set, but we're not ready for that until // it points to candidates and identifies the self type in the diagnostic. // calleeInfo.suggestPotentialOverloads(SE->getLoc()); return true; } // Any other failures relate to the index list. for (unsigned i = 0, e = calleeInfo.size(); i != e; ++i) calleeInfo.candidates[i].skipCurriedSelf = true; // TODO: Is there any reason to check for CC_NonLValueInOut here? if (calleeInfo.closeness == CC_ExactMatch) { auto message = diag::ambiguous_subscript; // If there is an exact match on the argument with // a single candidate, let's type-check subscript // as a whole to figure out if there is any structural // problem after all. if (calleeInfo.size() == 1) { Expr *expr = SE; ConcreteDeclRef decl = nullptr; message = diag::cannot_subscript_with_index; if (getTypeOfExpressionWithoutApplying(expr, CS.DC, decl)) return false; // If we are down to a single candidate but with an unresolved // index type, we can substitute in the base type to get a simpler // and more concrete expected type for this subscript decl, in order // to diagnose a better error. if (baseType && indexType->hasUnresolvedType()) { auto cand = calleeInfo.candidates[0]; auto candType = baseType->getTypeOfMember(CS.DC->getParentModule(), cand.getDecl(), nullptr); if (auto *candFunc = candType->getAs()) { auto paramsType = FunctionType::composeInput(CS.getASTContext(), candFunc->getParams(), false); if (!typeCheckChildIndependently( indexExpr, paramsType, CTP_CallArgument, TCC_ForceRecheck)) return true; } } } diagnose(SE->getLoc(), message, baseType, indexType) .highlight(indexExpr->getSourceRange()) .highlight(baseExpr->getSourceRange()); // FIXME: suggestPotentialOverloads should do this. // calleeInfo.suggestPotentialOverloads(SE->getLoc()); for (auto candidate : calleeInfo.candidates) if (auto decl = candidate.getDecl()) diagnose(decl, diag::found_candidate); else diagnose(candidate.getExpr()->getLoc(), diag::found_candidate); return true; } if (diagnoseParameterErrors(calleeInfo, SE, indexExpr, argLabels)) return true; // Diagnose some simple and common errors. if (calleeInfo.diagnoseSimpleErrors(SE)) return true; diagnose(SE->getLoc(), diag::cannot_subscript_with_index, baseType, indexType); calleeInfo.suggestPotentialOverloads(SE->getLoc()); return true; }; auto locator = CS.getConstraintLocator(SE, ConstraintLocator::SubscriptMember); return diagnoseMemberFailures(SE, baseExpr, ConstraintKind::ValueMember, DeclBaseName::createSubscript(), FunctionRefKind::DoubleApply, locator, callback); } bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) { return diagnoseSubscriptErrors(SE, /* inAssignmentDestination = */ false); } namespace { /// Type checking listener for pattern binding initializers. class CalleeListener : public ExprTypeCheckListener { Type contextualType; public: explicit CalleeListener(Type contextualType) : contextualType(contextualType) { } bool builtConstraints(ConstraintSystem &cs, Expr *expr) override { // If we have no contextual type, there is nothing to do. if (!contextualType) return false; // If the expression is obviously something that produces a metatype, // then don't put a constraint on it. auto semExpr = expr->getValueProvidingExpr(); if (isa(semExpr)) return false; auto resultLocator = cs.getConstraintLocator(expr, ConstraintLocator::FunctionResult); auto resultType = cs.createTypeVariable(resultLocator, TVO_CanBindToLValue); auto locator = cs.getConstraintLocator(expr); cs.addConstraint(ConstraintKind::FunctionResult, cs.getType(expr), resultType, locator); cs.addConstraint(ConstraintKind::Conversion, resultType, contextualType, locator); return false; } }; } // end anonymous namespace /// Return true if this function name is a comparison operator. This is a /// simple heuristic used to guide comparison related diagnostics. static bool isNameOfStandardComparisonOperator(StringRef opName) { return opName == "==" || opName == "!=" || opName == "===" || opName == "!==" || opName == "<" || opName == ">" || opName == "<=" || opName == ">="; } bool FailureDiagnosis::diagnoseNilLiteralComparison( Expr *lhsExpr, Expr *rhsExpr, CalleeCandidateInfo &calleeInfo, SourceLoc applyLoc) { auto overloadName = calleeInfo.declName; // Only diagnose for comparison operators. if (!isNameOfStandardComparisonOperator(overloadName)) return false; Expr *otherExpr = lhsExpr; Expr *nilExpr = rhsExpr; // Swap if we picked the wrong side as the nil literal. if (!isa(nilExpr->getValueProvidingExpr())) std::swap(otherExpr, nilExpr); // Bail if neither side is a nil literal. if (!isa(nilExpr->getValueProvidingExpr())) return false; // Bail if both sides are a nil literal. if (isa(otherExpr->getValueProvidingExpr())) return false; auto otherType = CS.getType(otherExpr)->getRValueType(); // Bail if we were unable to determine the other type. if (isUnresolvedOrTypeVarType(otherType)) return false; // Regardless of whether the type has reference or value semantics, // comparison with nil is illegal, albeit for different reasons spelled // out by the diagnosis. if (otherType->getOptionalObjectType() && (overloadName == "!==" || overloadName == "===")) { auto revisedName = overloadName; revisedName.pop_back(); // If we made it here, then we're trying to perform a comparison with // reference semantics rather than value semantics. The fixit will // lop off the extra '=' in the operator. diagnose(applyLoc, diag::value_type_comparison_with_nil_illegal_did_you_mean, otherType) .fixItReplace(applyLoc, revisedName); } else { diagnose(applyLoc, diag::value_type_comparison_with_nil_illegal, otherType) .highlight(otherExpr->getSourceRange()); } return true; } bool FailureDiagnosis::diagnoseMethodAttributeFailures( swift::ApplyExpr *callExpr, ArrayRef argLabels, bool hasTrailingClosure, CalleeCandidateInfo &candidates) { auto UDE = dyn_cast(callExpr->getFn()); if (!UDE) return false; auto argExpr = callExpr->getArg(); auto argType = CS.getType(argExpr); // If type of the argument hasn't been established yet, we can't diagnose. if (!argType || isUnresolvedOrTypeVarType(argType)) return false; // Let's filter our candidate list based on that type. candidates.filterListArgs(decomposeArgType(argType, argLabels)); if (candidates.closeness == CC_ExactMatch) return false; // And if filtering didn't give an exact match, such means that problem // might be related to function attributes which is best diagnosed by // unviable member candidates, if any. auto base = UDE->getBase(); auto baseType = CS.getType(base); // This handles following situation: // struct S { // mutating func f(_ i: Int) {} // func f(_ f: Float) {} // } // // Given struct has an overloaded method "f" with a single argument of // multiple different types, one of the overloads is marked as // "mutating", which means it can only be applied on LValue base type. // So when struct is used like this: // // let answer: Int = 42 // S().f(answer) // // Constraint system generator is going to pick `f(_ f: Float)` as // only possible overload candidate because "base" of the call is immutable // and contextual information about argument type is not available yet. // Such leads to incorrect contextual conversion failure diagnostic because // type of the argument is going to resolved as (Int) no matter what. // To workaround that fact and improve diagnostic of such cases we are going // to try and collect all unviable candidates for a given call and check if // at least one of them matches established argument type before even trying // to re-check argument expression. auto results = CS.performMemberLookup( ConstraintKind::ValueMember, UDE->getName(), baseType, UDE->getFunctionRefKind(), CS.getConstraintLocator(UDE), /*includeInaccessibleMembers=*/false); if (results.UnviableCandidates.empty()) return false; SmallVector choices; for (auto &unviable : results.UnviableCandidates) choices.push_back(OverloadChoice(baseType, unviable.first.getDecl(), UDE->getFunctionRefKind())); CalleeCandidateInfo unviableCandidates(baseType, choices, hasTrailingClosure, CS); // Filter list of the unviable candidates based on the // already established type of the argument expression. unviableCandidates.filterListArgs(decomposeArgType(argType, argLabels)); // If one of the unviable candidates matches arguments exactly, // that means that actual problem is related to function attributes. if (unviableCandidates.closeness == CC_ExactMatch) { diagnoseUnviableLookupResults(results, UDE, baseType, base, UDE->getName(), UDE->getNameLoc(), UDE->getLoc()); return true; } return false; } bool FailureDiagnosis::diagnoseArgumentGenericRequirements( TypeChecker &TC, Expr *callExpr, Expr *fnExpr, Expr *argExpr, CalleeCandidateInfo &candidates, ArrayRef argLabels) { if (candidates.closeness != CC_ExactMatch || candidates.size() != 1) return false; AbstractFunctionDecl *AFD = nullptr; if (auto *DRE = dyn_cast(fnExpr)) { AFD = dyn_cast(DRE->getDecl()); } else if (auto *candidate = candidates[0].getDecl()) { AFD = dyn_cast(candidate); } if (!AFD || !AFD->getGenericSignature() || !AFD->hasInterfaceType()) return false; auto env = AFD->getGenericEnvironment(); if (!env) return false; auto const &candidate = candidates.candidates[0]; if (!candidate.hasParameters()) return false; auto params = candidate.getParameters(); SmallBitVector defaultMap = computeDefaultMap(params, candidate.getDecl(), candidate.skipCurriedSelf); auto args = decomposeArgType(CS.getType(argExpr), argLabels); SmallVector bindings; MatchCallArgumentListener listener; if (matchCallArguments(args, params, defaultMap, candidates.hasTrailingClosure, /*allowFixes=*/false, listener, bindings)) return false; TypeSubstitutionMap substitutions; // First, let's collect all of the archetypes and their substitutions, // that's going to help later on if there are cross-archetype // requirements e.g. . for (unsigned i = 0, e = bindings.size(); i != e; ++i) { auto param = params[i]; auto paramType = param.getPlainType(); auto archetype = paramType->getAs(); if (!archetype) continue; // Bindings specify the arguments that source the parameter. The only case // this returns a non-singular value is when there are varargs in play. for (auto argNo : bindings[i]) { auto argType = args[argNo] .getOldType() ->getWithoutSpecifierType(); if (auto *archetype = argType->getAs()) { auto interfaceTy = archetype->getInterfaceType(); if (auto *paramTy = interfaceTy->getAs()) { diagnoseAmbiguousGenericParameter(paramTy, fnExpr); return true; } } if (isUnresolvedOrTypeVarType(argType) || argType->hasError()) return false; // Record substitution from generic parameter to the argument type. substitutions[archetype->getInterfaceType()->getCanonicalType() ->castTo()] = argType; } } if (substitutions.empty()) return false; class RequirementsListener : public GenericRequirementsCheckListener { ConstraintSystem &CS; AbstractFunctionDecl *Candidate; TypeSubstitutionFn Substitutions; Expr *CallExpr; Expr *FnExpr; Expr *ArgExpr; public: RequirementsListener(ConstraintSystem &cs, AbstractFunctionDecl *AFD, TypeSubstitutionFn subs, Expr *callExpr, Expr *fnExpr, Expr *argExpr) : CS(cs), Candidate(AFD), Substitutions(subs), CallExpr(callExpr), FnExpr(fnExpr), ArgExpr(argExpr) {} bool shouldCheck(RequirementKind kind, Type first, Type second) override { // This means that we have encountered requirement which references // generic parameter not used in the arguments, we can't diagnose it here. return !(first->hasTypeParameter() || first->isTypeVariableOrMember()); } bool diagnoseUnsatisfiedRequirement( const Requirement &req, Type first, Type second, ArrayRef parents) override { Diag note; switch (req.getKind()) { case RequirementKind::Conformance: case RequirementKind::Layout: return false; case RequirementKind::Superclass: note = diag::candidate_types_inheritance_requirement; break; case RequirementKind::SameType: note = diag::candidate_types_equal_requirement; break; } TypeChecker &TC = CS.TC; SmallVector scratch; auto overloadName = Candidate->getFullName().getString(scratch); if (isa(CallExpr) && isa(ArgExpr)) { auto argTuple = cast(ArgExpr); auto lhsExpr = argTuple->getElement(0), rhsExpr = argTuple->getElement(1); auto lhsType = CS.getType(lhsExpr)->getRValueType(); auto rhsType = CS.getType(rhsExpr)->getRValueType(); TC.diagnose(FnExpr->getLoc(), diag::cannot_apply_binop_to_args, overloadName, lhsType, rhsType) .highlight(lhsExpr->getSourceRange()) .highlight(rhsExpr->getSourceRange()); } else if (isa(CallExpr) || isa(CallExpr)) { TC.diagnose(ArgExpr->getLoc(), diag::cannot_apply_unop_to_arg, overloadName, CS.getType(ArgExpr)); } else { bool isInitializer = isa(Candidate); TC.diagnose(ArgExpr->getLoc(), diag::cannot_call_with_params, overloadName, getTypeListString(CS.getType(ArgExpr)), isInitializer); } auto rawFirstType = req.getFirstType(); auto rawSecondType = req.getSecondType(); auto *genericSig = Candidate->getGenericSignature(); TC.diagnose(Candidate, note, first, second, rawFirstType, rawSecondType, TypeChecker::gatherGenericParamBindingsText( {rawFirstType, rawSecondType}, genericSig->getGenericParams(), Substitutions)); ParentConditionalConformance::diagnoseConformanceStack( TC.Diags, Candidate->getLoc(), parents); return true; } }; auto *dc = env->getOwningDeclContext(); auto substitutionFn = QueryTypeSubstitutionMap{substitutions}; RequirementsListener genericReqListener(CS, AFD, substitutionFn, callExpr, fnExpr, argExpr); auto result = TC.checkGenericArguments( dc, callExpr->getLoc(), fnExpr->getLoc(), AFD->getInterfaceType(), env->getGenericSignature()->getGenericParams(), env->getGenericSignature()->getRequirements(), substitutionFn, LookUpConformanceInModule{dc->getParentModule()}, ConformanceCheckFlags::SuppressDependencyTracking, &genericReqListener); // Note: If result is RequirementCheckResult::SubstitutionFailure, we did // not emit a diagnostic, so we must return false in that case. return result == RequirementCheckResult::Failure; } /// When initializing Unsafe[Mutable]Pointer from Unsafe[Mutable]RawPointer, /// issue a diagnostic that refers to the API for binding memory to a type. static bool isCastToTypedPointer(ConstraintSystem &CS, const Expr *Fn, const Expr *Arg) { auto &Ctx = CS.DC->getASTContext(); auto *TypeExp = dyn_cast(Fn); auto *ParenExp = dyn_cast(Arg); if (!TypeExp || !ParenExp) return false; auto InitType = CS.getInstanceType(TypeExp); auto ArgType = CS.getType(ParenExp->getSubExpr()); if (InitType.isNull() || ArgType.isNull()) return false; // unwrap one level of Optional if (auto ArgOptType = ArgType->getOptionalObjectType()) ArgType = ArgOptType; auto *InitNom = InitType->getAnyNominal(); if (!InitNom) return false; if (InitNom != Ctx.getUnsafeMutablePointerDecl() && InitNom != Ctx.getUnsafePointerDecl()) { return false; } auto *ArgNom = ArgType->getAnyNominal(); if (!ArgNom) return false; if (ArgNom != Ctx.getUnsafeMutableRawPointerDecl() && ArgNom != Ctx.getUnsafeRawPointerDecl()) { return false; } return true; } static bool diagnoseClosureExplicitParameterMismatch( ConstraintSystem &CS, SourceLoc loc, ArrayRef params, ArrayRef args) { // We are not trying to diagnose structural problems with top-level // arguments here. if (params.size() != args.size()) return false; for (unsigned i = 0, n = params.size(); i != n; ++i) { auto paramType = params[i].getOldType(); auto argType = args[i].getOldType(); if (auto paramFnType = paramType->getAs()) { if (auto argFnType = argType->getAs()) return diagnoseClosureExplicitParameterMismatch( CS, loc, paramFnType->getParams(), argFnType->getParams()); } if (!paramType || !argType || isUnresolvedOrTypeVarType(paramType) || isUnresolvedOrTypeVarType(argType)) continue; if (!CS.TC.isConvertibleTo(argType, paramType, CS.DC)) { CS.TC.diagnose(loc, diag::types_not_convertible, false, paramType, argType); return true; } } return false; } bool FailureDiagnosis::diagnoseTrailingClosureErrors(ApplyExpr *callExpr) { if (!callExpr->hasTrailingClosure()) return false; auto *DC = CS.DC; auto *fnExpr = callExpr->getFn(); auto *argExpr = callExpr->getArg(); ClosureExpr *closureExpr = nullptr; if (auto *PE = dyn_cast(argExpr)) { closureExpr = dyn_cast(PE->getSubExpr()); } else { return false; } if (!closureExpr) return false; class CallResultListener : public ExprTypeCheckListener { Type expectedResultType; public: explicit CallResultListener(Type resultType) : expectedResultType(resultType) {} bool builtConstraints(ConstraintSystem &cs, Expr *expr) override { if (!expectedResultType) return false; auto resultType = cs.getType(expr); auto *locator = cs.getConstraintLocator(expr); // Since we know that this is trailing closure, format of the // type could be like this - ((Input) -> Result) -> ClosureResult // which we can leverage to create specific conversion for // result type of the call itself, this might help us gain // some valuable contextual information. if (auto *fnType = resultType->getAs()) { cs.addConstraint(ConstraintKind::Conversion, fnType->getResult(), expectedResultType, locator); } else if (auto *typeVar = resultType->getAs()) { auto tv = cs.createTypeVariable(cs.getConstraintLocator(expr), TVO_CanBindToLValue | TVO_PrefersSubtypeBinding); auto extInfo = FunctionType::ExtInfo().withThrows(); FunctionType::Param tvParam(tv); auto fTy = FunctionType::get({tvParam}, expectedResultType, extInfo); // Add a conversion constraint between the types. cs.addConstraint(ConstraintKind::Conversion, typeVar, fTy, locator, /*isFavored*/ true); } return false; } }; SmallPtrSet possibleTypes; auto currentType = CS.getType(fnExpr); // If current type has type variables or unresolved types // let's try to re-typecheck it to see if we can get some // more information about what is going on. if (currentType->hasTypeVariable() || currentType->hasUnresolvedType()) { auto contextualType = CS.getContextualType(); CallResultListener listener(contextualType); getPossibleTypesOfExpressionWithoutApplying( fnExpr, CS.DC, possibleTypes, FreeTypeVariableBinding::UnresolvedType, &listener); // Looks like there is there a contextual mismatch // related to function type, let's try to diagnose it. if (possibleTypes.empty() && contextualType && !contextualType->hasUnresolvedType()) return diagnoseContextualConversionError(callExpr, contextualType, CS.getContextualTypePurpose()); } else { possibleTypes.insert(currentType.getPointer()); } for (Type type : possibleTypes) { auto *fnType = type->getAs(); if (!fnType) continue; auto params = fnType->getParams(); if (params.size() != 1) return false; Type paramType = params.front().getOldType(); if (auto paramFnType = paramType->getAs()) { auto closureType = CS.getType(closureExpr); if (auto *argFnType = closureType->getAs()) { auto *params = closureExpr->getParameters(); auto loc = params ? params->getStartLoc() : closureExpr->getStartLoc(); if (diagnoseClosureExplicitParameterMismatch( CS, loc, argFnType->getParams(), paramFnType->getParams())) return true; } } auto processor = [&](Type resultType, Type expectedResultType) -> bool { if (resultType && expectedResultType) { if (!resultType->isEqual(expectedResultType)) { CS.TC.diagnose(closureExpr->getEndLoc(), diag::cannot_convert_closure_result, resultType, expectedResultType); return true; } // Looks like both actual and expected result types match, // there is nothing we can diagnose in this case. return false; } // If we got a result type, let's re-typecheck the function using it, // maybe we can find a problem where contextually we expect one type // but trailing closure produces completely different one. auto fnType = paramType->getAs(); if (!fnType) return false; class ClosureCalleeListener : public ExprTypeCheckListener { FunctionType *InputType; Type ResultType; public: explicit ClosureCalleeListener(FunctionType *inputType, Type resultType) : InputType(inputType), ResultType(resultType) {} bool builtConstraints(ConstraintSystem &cs, Expr *expr) override { if (!ResultType) return false; AnyFunctionType::Param Input(InputType); auto expectedType = FunctionType::get({Input}, ResultType); cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr), expectedType, cs.getConstraintLocator(expr), /*isFavored*/ true); return false; } }; auto expectedArgType = FunctionType::get(fnType->getParams(), resultType, fnType->getExtInfo()); llvm::SaveAndRestore SavedDC(CS.DC, DC); ClosureCalleeListener listener(expectedArgType, CS.getContextualType()); return !typeCheckChildIndependently(callExpr->getFn(), Type(), CTP_CalleeResult, TCC_ForceRecheck, &listener); }; // Let's see if there are any structural problems with closure itself. if (diagnoseClosureExpr(closureExpr, paramType, processor)) return true; } return false; } /// Check if there failure associated with expression is related /// to given contextual type. bool FailureDiagnosis::diagnoseCallContextualConversionErrors( ApplyExpr *callExpr, Type contextualType, ContextualTypePurpose CTP) { if (!contextualType || contextualType->hasUnresolvedType()) return false; auto &TC = CS.TC; auto *DC = CS.DC; auto typeCheckExpr = [&](TypeChecker &TC, Expr *expr, DeclContext *DC, SmallPtrSetImpl &types) { getPossibleTypesOfExpressionWithoutApplying( expr, DC, types, FreeTypeVariableBinding::Disallow); }; // First let's type-check expression without contextual type, and // see if that's going to produce a type, if so, let's type-check // again, this time using given contextual type. SmallPtrSet withoutContextual; typeCheckExpr(TC, callExpr, DC, withoutContextual); // If there are no types returned, it means that problem was // nothing to do with contextual information, probably parameter/argument // mismatch. if (withoutContextual.empty()) return false; Type exprType = withoutContextual.size() == 1 ? *withoutContextual.begin() : Type(); return diagnoseContextualConversionError(callExpr, contextualType, CTP, exprType); } // Check if there is a structural problem in the function expression // by performing type checking with the option to allow unresolved // type variables. If that is going to produce a function type with // unresolved result let's not re-typecheck the function expression, // because it might produce unrelated diagnostics due to lack of // contextual information. static bool shouldTypeCheckFunctionExpr(FailureDiagnosis &FD, DeclContext *DC, Expr *fnExpr) { if (!isa(fnExpr)) return true; SmallPtrSet fnTypes; FD.getPossibleTypesOfExpressionWithoutApplying( fnExpr, DC, fnTypes, FreeTypeVariableBinding::UnresolvedType); if (fnTypes.size() == 1) { // Some member types depend on the arguments to produce a result type, // type-checking such expressions without associated arguments is // going to produce unrelated diagnostics. if (auto fn = (*fnTypes.begin())->getAs()) { auto resultType = fn->getResult(); if (resultType->hasUnresolvedType() || resultType->hasTypeVariable()) return false; } } // Might be a structural problem related to the member itself. return true; } // Check if any candidate of the overload set can accept a specified // number of arguments, regardless of parameter type or label information. static bool isViableOverloadSet(const CalleeCandidateInfo &CCI, size_t numArgs) { for (unsigned i = 0; i < CCI.size(); ++i) { auto &&cand = CCI[i]; auto funcDecl = dyn_cast_or_null(cand.getDecl()); if (!funcDecl) continue; auto params = cand.getParameters(); bool hasVariadicParameter = false; auto pairMatcher = [&](unsigned argIdx, unsigned paramIdx) { hasVariadicParameter |= params[paramIdx].isVariadic(); return true; }; auto defaultMap = computeDefaultMap(params, funcDecl, cand.skipCurriedSelf); InputMatcher IM(params, defaultMap); auto result = IM.match(numArgs, pairMatcher); if (result == InputMatcher::IM_Succeeded) return true; if (result == InputMatcher::IM_HasUnclaimedInput && hasVariadicParameter) return true; } return false; } bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { // If this call involves trailing closure as an argument, // let's treat it specially, because re-typecheck of the // either function or arguments might results in diagnosing // of the unrelated problems due to luck of context. if (diagnoseTrailingClosureErrors(callExpr)) return true; if (diagnoseCallContextualConversionErrors(callExpr, CS.getContextualType(), CS.getContextualTypePurpose())) return true; auto *fnExpr = callExpr->getFn(); auto originalFnType = CS.getType(callExpr->getFn()); if (shouldTypeCheckFunctionExpr(*this, CS.DC, fnExpr)) { // Type check the function subexpression to resolve a type for it if // possible. fnExpr = typeCheckChildIndependently(callExpr->getFn()); if (!fnExpr) { return CS.TC.Diags.hadAnyError(); } } SWIFT_DEFER { if (!fnExpr) return; // If it's a member operator reference, put the operator back. if (auto operatorRef = fnExpr->getMemberOperatorRef()) callExpr->setFn(operatorRef); }; auto getFuncType = [](Type type) -> Type { return type->getRValueType(); }; auto fnType = getFuncType(CS.getType(fnExpr)); // Let's see if this has to do with member vs. property error // because sometimes when there is a member and a property declared // on the nominal type with the same name. Type-checking function // expression separately from arguments might produce solution for // the property instead of the member. if (!fnType->is() && isa(callExpr->getFn())) { fnExpr = callExpr->getFn(); SmallPtrSet types; getPossibleTypesOfExpressionWithoutApplying(fnExpr, CS.DC, types); auto isFunctionType = [getFuncType](Type type) -> bool { return type && getFuncType(type)->is(); }; auto fnTypes = std::find_if(types.begin(), types.end(), isFunctionType); if (fnTypes != types.end()) { auto funcType = getFuncType(*fnTypes); // If there is only one function type, let's use it. if (std::none_of(std::next(fnTypes), types.end(), isFunctionType)) fnType = funcType; } else { fnType = getFuncType(originalFnType); } } // If we have a contextual type, and if we have an ambiguously typed function // result from our previous check, we re-type-check it using this contextual // type to inform the result type of the callee. // // We only do this as a second pass because the first pass we just did may // return something of obviously non-function-type. If this happens, we // produce better diagnostics below by diagnosing this here rather than trying // to peel apart the failed conversion to function type. if (CS.getContextualType() && (isUnresolvedOrTypeVarType(fnType) || (fnType->is() && fnType->hasUnresolvedType()))) { // FIXME: Prevent typeCheckChildIndependently from transforming expressions, // because if we try to typecheck OSR expression with contextual type, // it'll end up converting it into DeclRefExpr based on contextual info, // instead let's try to get a type without applying and filter callee // candidates later on. CalleeListener listener(CS.getContextualType()); if (isa(fnExpr)) { assert(!cast(fnExpr)->getReferencedDecl() && "unexpected declaration reference"); ConcreteDeclRef decl = nullptr; Type type = getTypeOfExpressionWithoutApplying( fnExpr, CS.DC, decl, FreeTypeVariableBinding::UnresolvedType, &listener); if (type) fnType = getFuncType(type); } else { fnExpr = typeCheckChildIndependently(callExpr->getFn(), Type(), CTP_CalleeResult, TCC_ForceRecheck, &listener); if (!fnExpr) return true; fnType = getFuncType(CS.getType(fnExpr)); } } // If we resolved a concrete expression for the callee, and it has // non-function/non-metatype type, then we cannot call it! if (!isUnresolvedOrTypeVarType(fnType) && !fnType->is() && !fnType->is()) { auto arg = callExpr->getArg(); // Diagnose @dynamicCallable errors. if (CS.DynamicCallableCache[fnType->getCanonicalType()].isValid()) { auto dynamicCallableMethods = CS.DynamicCallableCache[fnType->getCanonicalType()]; // Diagnose dynamic calls with keywords on @dynamicCallable types that // don't define the `withKeywordArguments` method. if (auto tuple = dyn_cast(arg)) { bool hasArgLabel = llvm::any_of( tuple->getElementNames(), [](Identifier i) { return !i.empty(); }); if (hasArgLabel && dynamicCallableMethods.keywordArgumentsMethods.empty()) { diagnose(callExpr->getFn()->getStartLoc(), diag::missing_dynamic_callable_kwargs_method, fnType); return true; } } } if (fnType->is()) { auto diag = diagnose(arg->getStartLoc(), diag::missing_init_on_metatype_initialization); diag.highlight(fnExpr->getSourceRange()); } if (!fnType->is()) { auto diag = diagnose(arg->getStartLoc(), diag::cannot_call_non_function_value, fnType); diag.highlight(fnExpr->getSourceRange()); // If the argument is an empty tuple, then offer a // fix-it to remove the empty tuple and use the value // directly. if (auto tuple = dyn_cast(arg)) { if (tuple->getNumElements() == 0) { diag.fixItRemove(arg->getSourceRange()); } } } // If the argument is a trailing ClosureExpr (i.e. {....}) and it is on // the line after the callee, then it's likely the user forgot to // write "do" before their brace stmt. // Note that line differences of more than 1 are diagnosed during parsing. if (auto *PE = dyn_cast(arg)) if (PE->hasTrailingClosure() && isa(PE->getSubExpr())) { auto *closure = cast(PE->getSubExpr()); auto &SM = CS.getASTContext().SourceMgr; if (closure->hasAnonymousClosureVars() && closure->getParameters()->size() == 0 && 1 + SM.getLineNumber(callExpr->getFn()->getEndLoc()) == SM.getLineNumber(closure->getStartLoc())) { diagnose(closure->getStartLoc(), diag::brace_stmt_suggest_do) .fixItInsert(closure->getStartLoc(), "do "); } } return true; } bool hasTrailingClosure = callArgHasTrailingClosure(callExpr->getArg()); // Collect a full candidate list of callees based on the partially type // checked function. CalleeCandidateInfo calleeInfo(fnExpr, hasTrailingClosure, CS); // In the case that function subexpression was resolved independently in // the first place, the resolved type may not provide the best diagnostic. // We consider the number of arguments to decide whether we'd go with it or // stay with the original one. if (fnExpr != callExpr->getFn()) { bool isInstanceMethodAsCurriedMemberOnType = false; if (!calleeInfo.empty()) { auto &&cand = calleeInfo[0]; auto decl = cand.getDecl(); if (decl && decl->isInstanceMember() && !cand.skipCurriedSelf && cand.getParameters().size() == 1) isInstanceMethodAsCurriedMemberOnType = true; } // In terms of instance method as curried member on type, we should not // take the number of arguments into account. if (!isInstanceMethodAsCurriedMemberOnType) { size_t numArgs = 1; auto arg = callExpr->getArg(); if (auto tuple = dyn_cast(arg)) { numArgs = tuple->getNumElements(); } if (!isViableOverloadSet(calleeInfo, numArgs)) { CalleeCandidateInfo calleeInfoOrig(callExpr->getFn(), hasTrailingClosure, CS); if (isViableOverloadSet(calleeInfoOrig, numArgs)) { fnExpr = callExpr->getFn(); fnType = getFuncType(CS.getType(fnExpr)); calleeInfo = calleeInfoOrig; } } } } // Filter list of the candidates based on the known function type. if (auto fn = fnType->getAs()) { using Closeness = CalleeCandidateInfo::ClosenessResultTy; calleeInfo.filterList([&](OverloadCandidate candidate) -> Closeness { auto resultType = candidate.getResultType(); if (!resultType) return {CC_GeneralMismatch, {}}; // FIXME: Handle matching of the generic types properly. // Currently we don't filter result types containing generic parameters // because there is no easy way to do that, and candidate set is going // to be pruned by matching of the argument types later on anyway, so // it's better to over report than to be too conservative. if (resultType->isEqual(fn->getResult())) return {CC_ExactMatch, {}}; return {CC_GeneralMismatch, {}}; }); } // Filter the candidate list based on the argument we may or may not have. calleeInfo.filterContextualMemberList(callExpr->getArg()); SmallVector argLabelsScratch; ArrayRef argLabels = callExpr->getArgumentLabels(argLabelsScratch); if (diagnoseParameterErrors(calleeInfo, callExpr->getFn(), callExpr->getArg(), argLabels)) return true; // There might be a candidate with correct argument types but it's not // used by constraint solver because it doesn't have correct attributes, // let's try to diagnose such situation there right before type checking // argument expression, because that would overwrite original argument types. if (diagnoseMethodAttributeFailures(callExpr, argLabels, hasTrailingClosure, calleeInfo)) return true; Type argType; // argument list, if known. if (auto FTy = fnType->getAs()) { argType = FunctionType::composeInput(CS.getASTContext(), FTy->getParams(), false); } else if (auto MTT = fnType->getAs()) { // If we are constructing a tuple with initializer syntax, the expected // argument list is the tuple type itself - and there is no initdecl. auto instanceTy = MTT->getInstanceType(); if (auto tupleTy = instanceTy->getAs()) { argType = tupleTy; } } auto isFailingConstraintRelevant = [&]() -> bool { auto *constraint = CS.failedConstraint; if (!constraint) return false; auto *locator = constraint->getLocator(); return locator && locator->getAnchor() == callExpr; }; // If there is a failing constraint associated with current constraint // system which points to the argument/parameter mismatch, let's use // that information while re-typechecking argument expression, this // makes it a lot easier to determine contextual mismatch. if (isFailingConstraintRelevant() && !hasTrailingClosure) { auto *constraint = CS.failedConstraint; if (constraint->getKind() == ConstraintKind::ApplicableFunction) { auto calleeType = CS.simplifyType(constraint->getSecondType()); if (auto *fnType = calleeType->getAs()) argType = AnyFunctionType::composeInput(fnType->getASTContext(), fnType->getParams(), /*canonicalVararg=*/false); } else if (constraint->getKind() == ConstraintKind::ArgumentConversion || constraint->getKind() == ConstraintKind::OperatorArgumentConversion) { using PathEltKind = ConstraintLocator::PathElementKind; // Dig up type variable which represents the overload choice that fit // this call expression after simplifying `ApplicableFunction` constraint. for (auto *typeVar : CS.getTypeVariables()) { auto *locator = typeVar->getImpl().getLocator(); auto path = locator->getPath(); // Check whether this type variable in anchored at current // expression and path ends with `apply function`, which means // that it's related to `ApplicableFunction` constraint. if (locator->getAnchor() != callExpr || path.empty() || path.back().getKind() != PathEltKind::ApplyFunction) continue; if (auto type = typeVar->getImpl().getFixedType(nullptr)) { fnType = type; if (auto *FT = fnType->getAs()) argType = AnyFunctionType::composeInput(FT->getASTContext(), FT->getParams(), /*canonicalVararg=*/false); } break; } } } // Get the expression result of type checking the arguments to the call // independently, so we have some idea of what we're working with. // auto argExpr = typeCheckArgumentChildIndependently(callExpr->getArg(), argType, calleeInfo, TCC_AllowUnresolvedTypeVariables); if (!argExpr) return true; // already diagnosed. calleeInfo.filterListArgs(decomposeArgType(CS.getType(argExpr), argLabels)); if (diagnoseParameterErrors(calleeInfo, callExpr->getFn(), argExpr, argLabels)) return true; // Diagnose some simple and common errors. if (calleeInfo.diagnoseSimpleErrors(callExpr)) return true; // Force recheck of the arg expression because we allowed unresolved types // before, and that turned out not to help, and now we want any diagnoses // from disallowing them. argExpr = typeCheckArgumentChildIndependently(callExpr->getArg(), argType, calleeInfo, TCC_ForceRecheck); if (!argExpr) return true; // already diagnosed. // Handle argument label mismatches when we have multiple candidates. if (calleeInfo.closeness == CC_ArgumentLabelMismatch) { auto args = decomposeArgType(CS.getType(argExpr), argLabels); // If we have multiple candidates that we fail to match, just say we have // the wrong labels and list the candidates out. // TODO: It would be nice to use an analog of getTypeListString that // doesn't include the argument types. diagnose(callExpr->getLoc(), diag::wrong_argument_labels_overload, getParamListAsString(args)) .highlight(argExpr->getSourceRange()); // Did the user intend on invoking a different overload? calleeInfo.suggestPotentialOverloads(fnExpr->getLoc()); return true; } auto overloadName = calleeInfo.declName; // Local function to check if the error with argument type is // related to contextual type information of the enclosing expression // rather than resolution of argument expression itself. auto isContextualConversionFailure = [&](Expr *argExpr) -> bool { // If we found an exact match, this must be a problem with a conversion from // the result of the call to the expected type. Diagnose this as a // conversion failure. if (calleeInfo.closeness == CC_ExactMatch) return true; if (!CS.getContextualType() || (calleeInfo.closeness != CC_ArgumentMismatch && calleeInfo.closeness != CC_OneGenericArgumentMismatch)) return false; CalleeCandidateInfo candidates(fnExpr, hasTrailingClosure, CS); // Filter original list of choices based on the deduced type of // argument expression after force re-check. candidates.filterContextualMemberList(argExpr); // One of the candidates matches exactly, which means that // this is a contextual type conversion failure, we can't diagnose here. return candidates.closeness == CC_ExactMatch; }; // Otherwise, we have a generic failure. Diagnose it with a generic error // message now. if (isa(callExpr) && isa(argExpr)) { auto argTuple = cast(argExpr); auto lhsExpr = argTuple->getElement(0), rhsExpr = argTuple->getElement(1); auto lhsType = CS.getType(lhsExpr)->getRValueType(); auto rhsType = CS.getType(rhsExpr)->getRValueType(); // Diagnose any comparisons with the nil literal. if (diagnoseNilLiteralComparison(lhsExpr, rhsExpr, calleeInfo, callExpr->getLoc())) return true; if (callExpr->isImplicit() && overloadName == "~=") { // This binop was synthesized when typechecking an expression pattern. auto diag = lhsType->is() ? diagnose(lhsExpr->getLoc(), diag::cannot_match_unresolved_expr_pattern_with_value, rhsType) : diagnose(lhsExpr->getLoc(), diag::cannot_match_expr_pattern_with_value, lhsType, rhsType); diag.highlight(lhsExpr->getSourceRange()); diag.highlight(rhsExpr->getSourceRange()); if (auto optUnwrappedType = rhsType->getOptionalObjectType()) { if (lhsType->isEqual(optUnwrappedType)) { diag.fixItInsertAfter(lhsExpr->getEndLoc(), "?"); } } return true; } // Diagnose attempts to compare reference equality of certain types. if (overloadName == "===" || overloadName == "!==") { // Functions. if (lhsType->is() || rhsType->is()) { diagnose(callExpr->getLoc(), diag::cannot_reference_compare_types, overloadName, lhsType, rhsType) .highlight(lhsExpr->getSourceRange()) .highlight(rhsExpr->getSourceRange()); return true; } } if (diagnoseArgumentGenericRequirements(CS.TC, callExpr, fnExpr, argExpr, calleeInfo, argLabels)) return true; if (isContextualConversionFailure(argTuple)) return false; if (diagnoseRawRepresentableMismatch(calleeInfo, argExpr, argLabels)) return true; if (!lhsType->isEqual(rhsType)) { auto diag = diagnose(callExpr->getLoc(), diag::cannot_apply_binop_to_args, overloadName, lhsType, rhsType); diag.highlight(lhsExpr->getSourceRange()) .highlight(rhsExpr->getSourceRange()); auto tryFixIts = [&]() -> bool { if (calleeInfo.size() != 1) return false; auto candidate = calleeInfo[0]; auto *fnType = candidate.getFunctionType(); if (!fnType) return false; auto params = fnType->getParams(); if (params.size() != 2) return false; auto lhsCandidate = params[0].getOldType(); auto rhsCandidate = params[1].getOldType(); auto lhsIsCandidate = lhsType->isEqual(lhsCandidate); auto rhsIsCandidate = rhsType->isEqual(rhsCandidate); if (!lhsIsCandidate && !rhsIsCandidate) return false; if (!lhsIsCandidate) return tryIntegerCastFixIts(diag, CS, lhsType, lhsCandidate, lhsExpr); if (!rhsIsCandidate) return tryIntegerCastFixIts(diag, CS, rhsType, rhsCandidate, rhsExpr); return false; }; tryFixIts(); } else { diagnose(callExpr->getLoc(), diag::cannot_apply_binop_to_same_args, overloadName, lhsType) .highlight(lhsExpr->getSourceRange()) .highlight(rhsExpr->getSourceRange()); } if (lhsType->isEqual(rhsType) && isNameOfStandardComparisonOperator(overloadName) && lhsType->is() && !lhsType->getAs()->getDecl() ->hasOnlyCasesWithoutAssociatedValues()) { diagnose(callExpr->getLoc(), diag::no_binary_op_overload_for_enum_with_payload, overloadName); } else { calleeInfo.suggestPotentialOverloads(callExpr->getLoc()); } return true; } // If all of the arguments are a perfect match, let's check if there // are problems with requirements placed on generic parameters, because // CalleeCandidateInfo validates only conformance of the parameters // to their protocol types (if any) but it doesn't check additional // requirements placed on e.g. nested types or between parameters. if (diagnoseArgumentGenericRequirements(CS.TC, callExpr, fnExpr, argExpr, calleeInfo, argLabels)) return true; // If we have a failure where closeness is an exact match, but there is // still a failed argument, it is because one (or more) of the arguments // types are unresolved. if (calleeInfo.closeness == CC_ExactMatch && calleeInfo.failedArgument.isValid()) { diagnoseAmbiguity(getFailedArgumentExpr(calleeInfo, argExpr)); return true; } if (isContextualConversionFailure(argExpr)) return false; // Generate specific error messages for unary operators. if (isa(callExpr) || isa(callExpr)) { assert(!overloadName.empty()); diagnose(argExpr->getLoc(), diag::cannot_apply_unop_to_arg, overloadName, CS.getType(argExpr)); calleeInfo.suggestPotentialOverloads(argExpr->getLoc()); return true; } if (CS.getType(argExpr)->hasUnresolvedType()) return false; if (diagnoseRawRepresentableMismatch(calleeInfo, argExpr, argLabels)) return true; std::string argString = getTypeListString(CS.getType(argExpr)); // If we couldn't get the name of the callee, then it must be something of a // more complex "value of function type". if (overloadName.empty()) { // If we couldn't infer the result type of the closure expr, then we have // some sort of ambiguity, let the ambiguity diagnostic stuff handle this. if (auto ffty = fnType->getAs()) if (ffty->getResult()->hasTypeVariable()) { diagnoseAmbiguity(fnExpr); return true; } // The most common unnamed value of closure type is a ClosureExpr, so // special case it. if (isa(fnExpr->getValueProvidingExpr())) { if (fnType->hasTypeVariable()) diagnose(argExpr->getStartLoc(), diag::cannot_invoke_closure, argString) .highlight(fnExpr->getSourceRange()); else diagnose(argExpr->getStartLoc(), diag::cannot_invoke_closure_type, fnType, argString) .highlight(fnExpr->getSourceRange()); } else if (fnType->hasTypeVariable()) { diagnose(argExpr->getStartLoc(), diag::cannot_call_function_value, argString) .highlight(fnExpr->getSourceRange()); } else { diagnose(argExpr->getStartLoc(), diag::cannot_call_value_of_function_type, fnType, argString) .highlight(fnExpr->getSourceRange()); } return true; } if (auto MTT = fnType->getAs()) { if (MTT->getInstanceType()->isExistentialType()) { diagnose(fnExpr->getLoc(), diag::construct_protocol_value, fnType); return true; } } // If we have an argument list (i.e., a scalar, or a non-zero-element tuple) // then diagnose with some specificity about the arguments. bool isInitializer = isa(fnExpr); if (!fnType->is() && ((isa(argExpr) && cast(argExpr)->getNumElements() == 1) || (isa(argExpr) && !isa(cast(argExpr)->getSubExpr())))) { if (auto ctorRef = dyn_cast(fnExpr)) { if (ctorRef->getName().isSimpleName(DeclBaseName::createConstructor())) { // Diagnose 'super.init', which can only appear inside another // initializer, specially. if (isa(ctorRef->getBase())) { diagnose(fnExpr->getLoc(), diag::super_initializer_not_in_initializer); calleeInfo.suggestPotentialOverloads(fnExpr->getLoc()); return true; } // Suggest inserting a call to 'type(of:)' to construct another object // of the same dynamic type. SourceRange fixItRng = ctorRef->getNameLoc().getSourceRange(); // Surround the caller in `type(of:)`. diagnose(fnExpr->getLoc(), diag::init_not_instance_member) .fixItInsert(fixItRng.Start, "type(of: ") .fixItInsertAfter(fixItRng.End, ")"); calleeInfo.suggestPotentialOverloads(fnExpr->getLoc()); return true; } } } if (isa(argExpr) && cast(argExpr)->getNumElements() == 0) { // Emit diagnostics that say "no arguments". diagnose(fnExpr->getLoc(), diag::cannot_call_with_no_params, overloadName, isInitializer); } else { diagnose(fnExpr->getLoc(), diag::cannot_call_with_params, overloadName, argString, isInitializer); } if (isCastToTypedPointer(CS, fnExpr, argExpr)) { diagnose(fnExpr->getLoc(), diag::pointer_init_to_type) .highlight(argExpr->getSourceRange()); } // Did the user intend on invoking a different overload? calleeInfo.suggestPotentialOverloads(fnExpr->getLoc()); return true; } bool FailureDiagnosis::visitAssignExpr(AssignExpr *assignExpr) { // Diagnose obvious assignments to literals. if (isa(assignExpr->getDest()->getValueProvidingExpr())) { diagnose(assignExpr->getLoc(), diag::cannot_assign_to_literal); return true; } // Situation like `var foo = &bar` didn't get diagnosed early // because originally its parent is a `SequenceExpr` which hasn't // been folded yet, and could represent an operator which accepts // `inout` arguments. if (auto *AddrOf = dyn_cast(assignExpr->getSrc())) { diagnose(AddrOf->getLoc(), diag::extraneous_address_of); return true; } if (CS.TC.diagnoseSelfAssignment(assignExpr)) return true; // Type check the destination first, so we can coerce the source to it. auto destExpr = typeCheckChildIndependently(assignExpr->getDest(), TCC_AllowLValue); if (!destExpr) return true; auto destType = CS.getType(destExpr); if (destType->is() || destType->hasTypeVariable()) { // Look closer into why destination has unresolved types since such // means that destination has diagnosable structural problems, and it's // better to diagnose destination (if possible) before moving on to // the source of the assignment. destExpr = typeCheckChildIndependently( destExpr, TCC_AllowLValue | TCC_ForceRecheck, false); if (!destExpr) return true; // If re-checking destination didn't produce diagnostic, let's just type // check the source without contextual information. If it succeeds, then we // win, but if it fails, we'll have to diagnose this another way. return !typeCheckChildIndependently(assignExpr->getSrc()); } // If the result type is a non-lvalue, then we are failing because it is // immutable and that's not a great thing to assign to. if (!destType->hasLValueType()) { // If the destination is a subscript, the problem may actually be that we // incorrectly decided on a get-only subscript overload, and we may be able // to come up with a better diagnosis by looking only at subscript candidates // that are set-able. if (auto subscriptExpr = dyn_cast(destExpr)) { if (diagnoseSubscriptErrors(subscriptExpr, /* inAssignmentDestination = */ true)) return true; } // Member ref assignment errors detected elsewhere, so not an assignment issue if found here. // The remaining exception involves mutable pointer conversions which aren't always caught elsewhere. PointerTypeKind ptk; if (!isa(destExpr) || CS.getType(destExpr) ->lookThroughAllOptionalTypes() ->getAnyPointerElementType(ptk)) { AssignmentFailure failure(destExpr, CS, assignExpr->getLoc()); if (failure.diagnoseAsError()) return true; } } auto *srcExpr = assignExpr->getSrc(); auto contextualType = destType->getRValueType(); // Let's try to type-check assignment source expression without using // destination as a contextual type, that allows us to diagnose // contextual problems related to source much easier. // // If source expression requires contextual type to be present, // let's avoid this step because it's always going to fail. { auto *srcExpr = assignExpr->getSrc(); ExprTypeSaverAndEraser eraser(srcExpr); ConcreteDeclRef ref = nullptr; auto type = getTypeOfExpressionWithoutApplying(srcExpr, CS.DC, ref); if (type && !type->isEqual(contextualType)) return diagnoseContextualConversionError( assignExpr->getSrc(), contextualType, CTP_AssignSource); } srcExpr = typeCheckChildIndependently(assignExpr->getSrc(), contextualType, CTP_AssignSource); if (!srcExpr) return true; // If we are assigning to _ and have unresolved types on the RHS, then we have // an ambiguity problem. if (isa(destExpr->getSemanticsProvidingExpr()) && CS.getType(srcExpr)->hasUnresolvedType()) { diagnoseAmbiguity(srcExpr); return true; } return false; } /// Return true if this type is known to be an ArrayType. static bool isKnownToBeArrayType(Type ty) { if (!ty) return false; auto bgt = ty->getAs(); if (!bgt) return false; auto &ctx = bgt->getASTContext(); return bgt->getDecl() == ctx.getArrayDecl(); } bool FailureDiagnosis::visitInOutExpr(InOutExpr *IOE) { // If we have a contextual type, it must be an inout type. auto contextualType = CS.getContextualType(); if (contextualType) { // If the contextual type is one of the UnsafePointer types, then the // contextual type of the subexpression must be T. Type unwrappedType = contextualType; if (auto unwrapped = contextualType->getOptionalObjectType()) unwrappedType = unwrapped; if (auto pointerEltType = unwrappedType->getAnyPointerElementType()) { // If the element type is Void, then we allow any input type, since // everything is convertible to UnsafeRawPointer if (pointerEltType->isVoid()) contextualType = Type(); else contextualType = pointerEltType; // Furthermore, if the subexpr type is already known to be an array type, // then we must have an attempt at an array to pointer conversion. if (isKnownToBeArrayType(CS.getType(IOE->getSubExpr()))) { contextualType = ArraySliceType::get(contextualType); } } else if (contextualType->is()) { contextualType = contextualType->getInOutObjectType(); } else { // If the caller expected something inout, but we didn't have // something of inout type, diagnose it. diagnose(IOE->getLoc(), diag::extra_address_of, contextualType) .highlight(IOE->getSourceRange()) .fixItRemove(IOE->getStartLoc()); return true; } } if (!typeCheckChildIndependently(IOE->getSubExpr(), contextualType, CS.getContextualTypePurpose(), TCC_AllowLValue)) { return true; } return false; } bool FailureDiagnosis::visitCoerceExpr(CoerceExpr *CE) { // Coerce the input to whatever type is specified by the CoerceExpr. auto expr = typeCheckChildIndependently(CE->getSubExpr(), CS.getType(CE->getCastTypeLoc()), CTP_CoerceOperand); if (!expr) return true; auto ref = expr->getReferencedDecl(); if (auto *decl = ref.getDecl()) { // Without explicit coercion we might end up // type-checking sub-expression as unavaible // declaration, let's try to diagnose that here. if (AvailableAttr::isUnavailable(decl)) return diagnoseExplicitUnavailability( decl, expr->getSourceRange(), CS.DC, dyn_cast(expr)); } return false; } bool FailureDiagnosis::visitForceValueExpr(ForceValueExpr *FVE) { auto argExpr = typeCheckChildIndependently(FVE->getSubExpr()); if (!argExpr) return true; auto argType = CS.getType(argExpr); // If the subexpression type checks as a non-optional type, then that is the // error. Produce a specific diagnostic about this. if (!isUnresolvedOrTypeVarType(argType) && argType->getOptionalObjectType().isNull()) { diagnose(FVE->getLoc(), diag::invalid_force_unwrap, argType) .fixItRemove(FVE->getExclaimLoc()) .highlight(FVE->getSourceRange()); return true; } return false; } bool FailureDiagnosis::visitBindOptionalExpr(BindOptionalExpr *BOE) { auto argExpr = typeCheckChildIndependently(BOE->getSubExpr()); if (!argExpr) return true; auto argType = CS.getType(argExpr); // If the subexpression type checks as a non-optional type, then that is the // error. Produce a specific diagnostic about this. if (!isUnresolvedOrTypeVarType(argType) && argType->getOptionalObjectType().isNull()) { diagnose(BOE->getQuestionLoc(), diag::invalid_optional_chain, argType) .highlight(BOE->getSourceRange()) .fixItRemove(BOE->getQuestionLoc()); return true; } return false; } bool FailureDiagnosis::visitIfExpr(IfExpr *IE) { auto typeCheckClauseExpr = [&](Expr *clause, Type contextType = Type(), ContextualTypePurpose convertPurpose = CTP_Unused) -> Expr * { // Provide proper contextual type when type conversion is specified. return typeCheckChildIndependently(clause, contextType, convertPurpose, TCCOptions(), nullptr, false); }; // Check all of the subexpressions independently. auto condExpr = typeCheckClauseExpr(IE->getCondExpr()); if (!condExpr) return true; auto trueExpr = typeCheckClauseExpr(IE->getThenExpr(), CS.getContextualType(), CS.getContextualTypePurpose()); if (!trueExpr) return true; auto falseExpr = typeCheckClauseExpr( IE->getElseExpr(), CS.getContextualType(), CS.getContextualTypePurpose()); if (!falseExpr) return true; // If the true/false values already match, it must be a contextual problem. if (CS.getType(trueExpr)->isEqual(CS.getType(falseExpr))) return false; // Otherwise, the true/false result types must not be matching. diagnose(IE->getColonLoc(), diag::if_expr_cases_mismatch, CS.getType(trueExpr), CS.getType(falseExpr)) .highlight(trueExpr->getSourceRange()) .highlight(falseExpr->getSourceRange()); return true; } bool FailureDiagnosis:: visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E) { // Don't walk the children for this node, it leads to multiple diagnostics // because of how sema injects this node into the type checker. return false; } bool FailureDiagnosis::visitCaptureListExpr(CaptureListExpr *CLE) { // Always walk into the closure of a capture list expression. return visitClosureExpr(CLE->getClosureBody()); } static bool isInvalidClosureResultType(Type resultType) { return !resultType || resultType->hasUnresolvedType() || resultType->hasTypeVariable() || resultType->hasArchetype(); } bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) { return diagnoseClosureExpr( CE, CS.getContextualType(), [&](Type resultType, Type expectedResultType) -> bool { if (isInvalidClosureResultType(expectedResultType)) return false; // Following situations are possible: // * No result type - possible structurable problem in the body; // * Function result type - possible use of function without calling it, // which is properly diagnosed by actual type-check call. if (resultType && !resultType->getRValueType()->is()) { if (!resultType->isEqual(expectedResultType)) { diagnose(CE->getEndLoc(), diag::cannot_convert_closure_result, resultType, expectedResultType); return true; } } return false; }); } bool FailureDiagnosis::diagnoseClosureExpr( ClosureExpr *CE, Type contextualType, llvm::function_ref resultTypeProcessor) { // Look through IUO because it doesn't influence // neither parameter nor return type diagnostics itself, // but if we have function type inside, that might // signficantly improve diagnostic quality. // FIXME: We need to rework this with IUOs out of the type system. // if (contextualType) { // if (auto IUO = // CS.lookThroughImplicitlyUnwrappedOptionalType(contextualType)) // contextualType = IUO; // } Type expectedResultType; // If we have a contextual type available for this closure, apply it to the // ParamDecls in our parameter list. This ensures that any uses of them get // appropriate types. if (contextualType && contextualType->is()) { auto fnType = contextualType->getAs(); auto *params = CE->getParameters(); auto inferredArgs = fnType->getParams(); // It is very common for a contextual type to disagree with the argument // list built into the closure expr. This can be because the closure expr // had an explicitly specified pattern, a la: // { a,b in ... } // or could be because the closure has an implicitly generated one: // { $0 + $1 } // in either case, we want to produce nice and clear diagnostics. unsigned actualArgCount = params->size(); unsigned inferredArgCount = inferredArgs.size(); if (actualArgCount != inferredArgCount) { if (inferredArgCount == 1 && actualArgCount > 1) { auto *argTupleTy = inferredArgs.front().getOldType()->getAs(); // Let's see if inferred argument is actually a tuple inside of Paren. if (argTupleTy) { // Looks like the number of closure parameters matches number // of inferred arguments, which means we can we can emit an // error about an attempt to make use of tuple splat or tuple // destructuring and provide a proper fix-it. if (argTupleTy->getNumElements() == actualArgCount) { // In case of implicit parameters e.g. $0, $1 we // can't really provide good fix-it because // structure of parameter type itself is unclear. for (auto *param : params->getArray()) { if (param->isImplicit()) { diagnose(params->getStartLoc(), diag::closure_tuple_parameter_destructuring_implicit, argTupleTy); return true; } } auto diag = diagnose(params->getStartLoc(), diag::closure_tuple_parameter_destructuring, argTupleTy); auto *closureBody = CE->getBody(); if (!closureBody) return true; auto &sourceMgr = CS.getASTContext().SourceMgr; auto bodyStmts = closureBody->getElements(); SourceLoc bodyLoc; // If the body is empty let's put the cursor // right after "in", otherwise make it start // location of the first statement in the body. if (bodyStmts.empty()) bodyLoc = Lexer::getLocForEndOfToken(sourceMgr, CE->getInLoc()); else bodyLoc = bodyStmts.front().getStartLoc(); SmallString<64> fixIt; llvm::raw_svector_ostream OS(fixIt); // If this is multi-line closure we'd have to insert new lines // in the suggested 'let' to keep the structure of the code intact, // otherwise just use ';' to keep everything on the same line. auto inLine = sourceMgr.getLineNumber(CE->getInLoc()); auto bodyLine = sourceMgr.getLineNumber(bodyLoc); auto isMultiLineClosure = bodyLine > inLine; auto indent = bodyStmts.empty() ? "" : Lexer::getIndentationForLine( sourceMgr, bodyLoc); SmallString<16> parameter; llvm::raw_svector_ostream parameterOS(parameter); parameterOS << "("; interleave(params->getArray(), [&](const ParamDecl *param) { parameterOS << param->getNameStr(); }, [&] { parameterOS << ", "; }); parameterOS << ")"; // Check if there are any explicit types associated // with parameters, if there are, we'll have to add // type information to the replacement argument. bool explicitTypes = false; for (auto *param : params->getArray()) { if (param->getTypeLoc().getTypeRepr()) { explicitTypes = true; break; } } if (isMultiLineClosure) OS << '\n' << indent; // Let's form 'let : []? = arg' expression. OS << "let " << parameterOS.str() << " = arg" << (isMultiLineClosure ? "\n" + indent : "; "); SmallString<64> argName; llvm::raw_svector_ostream nameOS(argName); if (explicitTypes) { nameOS << "(arg: " << argTupleTy->getString() << ")"; } else { nameOS << "(arg)"; } if (CE->hasSingleExpressionBody()) { // Let's see if we need to add result type to the argument/fix-it: // - if the there is a result type associated with the closure; // - and it's not a void type; // - and it hasn't been explicitly written. auto resultType = fnType->getResult(); auto hasResult = [](Type resultType) -> bool { return resultType && !resultType->isVoid(); }; auto isValidType = [](Type resultType) -> bool { return resultType && !resultType->hasUnresolvedType() && !resultType->hasTypeVariable(); }; // If there an expected result type but it hasn't been explicitly // provided, let's add it to the argument. if (hasResult(resultType) && !CE->hasExplicitResultType()) { nameOS << " -> "; if (isValidType(resultType)) nameOS << resultType->getString(); else nameOS << "<#Result#>"; } if (auto stmt = bodyStmts.front().get()) { // If the body is a single expression with implicit return. if (isa(stmt) && stmt->isImplicit()) { // And there is non-void expected result type, // because we add 'let' expression to the body // we need to make such 'return' explicit. if (hasResult(resultType)) OS << "return "; } } } diag.fixItReplace(params->getSourceRange(), nameOS.str()) .fixItInsert(bodyLoc, OS.str()); return true; } } } // Extraneous arguments. if (inferredArgCount < actualArgCount) { auto diag = diagnose( params->getStartLoc(), diag::closure_argument_list_tuple, fnType, inferredArgCount, actualArgCount, (actualArgCount == 1)); bool onlyAnonymousParams = std::all_of(params->begin(), params->end(), [](ParamDecl *param) { return !param->hasName(); }); // If closure expects no parameters but N was given, // and all of them are anonymous let's suggest removing them. if (inferredArgCount == 0 && onlyAnonymousParams) { auto inLoc = CE->getInLoc(); auto &sourceMgr = CS.getASTContext().SourceMgr; if (inLoc.isValid()) diag.fixItRemoveChars(params->getStartLoc(), Lexer::getLocForEndOfToken(sourceMgr, inLoc)); } return true; } MissingArgumentsFailure failure( expr, CS, fnType, inferredArgCount - actualArgCount, CS.getConstraintLocator(CE, ConstraintLocator::ContextualType)); return failure.diagnoseAsError(); } // Coerce parameter types here only if there are no unresolved if (CS.TC.coerceParameterListToType(params, CE, fnType)) return true; expectedResultType = fnType->getResult(); } // Defend against type variables from our constraint system leaking into // recursive constraints systems formed when checking the body of the // closure. These typevars come into them when the body does name // lookups against the parameter decls. // // Handle this by rewriting the arguments to UnresolvedType(). for (auto VD : *CE->getParameters()) { if (VD->hasType() && (VD->getType()->hasTypeVariable() || VD->getType()->hasError())) { VD->setType(CS.getASTContext().TheUnresolvedType); VD->setInterfaceType(VD->getType()); } } // If this is a complex leaf closure, there is nothing more we can do. if (!CE->hasSingleExpressionBody()) return false; if (isInvalidClosureResultType(expectedResultType)) expectedResultType = Type(); // When we're type checking a single-expression closure, we need to reset the // DeclContext to this closure for the recursive type checking. Otherwise, // if there is a closure in the subexpression, we can violate invariants. { llvm::SaveAndRestore SavedDC(CS.DC, CE); // Explicitly disallow to produce solutions with unresolved type variables, // because there is no auxiliary logic which would handle that and it's // better to allow failure diagnosis to run directly on the closure body. // Note that presence of contextual type implicitly forbids such solutions, // but it's not always reset. if (expectedResultType && !CE->hasExplicitResultType()) { auto closure = CE->getSingleExpressionBody(); ConcreteDeclRef decl = nullptr; // Let's try to compute result type without mutating AST and // using expected (contextual) result type, that's going to help // diagnose situations where contextual type expected one result // type but actual closure produces a different one without explicitly // declaring it (e.g. by using anonymous parameters). auto type = getTypeOfExpressionWithoutApplying( closure, CS.DC, decl, FreeTypeVariableBinding::Disallow); if (type && resultTypeProcessor(type, expectedResultType)) return true; } // If the closure had an expected result type, use it. if (CE->hasExplicitResultType()) expectedResultType = CE->getExplicitResultTypeLoc().getType(); // If we couldn't diagnose anything related to the contextual result type // let's run proper type-check with expected type and try to verify it. auto CTP = expectedResultType ? CTP_ClosureResult : CTP_Unused; auto *bodyExpr = typeCheckChildIndependently(CE->getSingleExpressionBody(), expectedResultType, CTP, TCCOptions(), nullptr, false); if (!bodyExpr) return true; if (resultTypeProcessor(CS.getType(bodyExpr), expectedResultType)) return true; } // If the body of the closure looked ok, then look for a contextual type // error. This is necessary because FailureDiagnosis::diagnoseExprFailure // doesn't do this for closures. if (contextualType) { auto fnType = contextualType->getAs(); if (!fnType || fnType->isEqual(CS.getType(CE))) return false; auto contextualResultType = fnType->getResult(); // If the result type was unknown, it doesn't really make // sense to diagnose from expected to unknown here. if (isInvalidClosureResultType(contextualResultType)) return false; // If the closure had an explicitly written return type incompatible with // the contextual type, diagnose that. if (CE->hasExplicitResultType() && CE->getExplicitResultTypeLoc().getTypeRepr()) { auto explicitResultTy = CE->getExplicitResultTypeLoc().getType(); if (fnType && !explicitResultTy->isEqual(contextualResultType)) { auto repr = CE->getExplicitResultTypeLoc().getTypeRepr(); diagnose(repr->getStartLoc(), diag::incorrect_explicit_closure_result, explicitResultTy, fnType->getResult()) .fixItReplace(repr->getSourceRange(),fnType->getResult().getString()); return true; } } } // Otherwise, we can't produce a specific diagnostic. return false; } // Ported version of TypeChecker::checkObjCKeyPathExpr which works // with new Smart KeyPath feature. static bool diagnoseKeyPathComponents(ConstraintSystem &CS, KeyPathExpr *KPE, Type rootType) { auto &TC = CS.TC; // The constraint system may have been unable to resolve the actual root // type. The generic interface type of the root produces better // diagnostics in this case. if (rootType->hasUnresolvedType() && !KPE->isObjC() && KPE->getRootType()) { if (auto ident = dyn_cast(KPE->getRootType())) { if (auto decl = ident->getBoundDecl()) { if (auto metaType = decl->getInterfaceType()->castTo()) { rootType = metaType->getInstanceType(); } } } } // The key path string we're forming. SmallString<32> keyPathScratch; llvm::raw_svector_ostream keyPathOS(keyPathScratch); // Captures the state of semantic resolution. enum State { Beginning, ResolvingType, ResolvingProperty, ResolvingArray, ResolvingSet, ResolvingDictionary, } state = Beginning; /// Determine whether we are currently resolving a property. auto isResolvingProperty = [&] { switch (state) { case Beginning: case ResolvingType: return false; case ResolvingProperty: case ResolvingArray: case ResolvingSet: case ResolvingDictionary: return true; } llvm_unreachable("Unhandled State in switch."); }; // The type of AnyObject, which is used whenever we don't have // sufficient type information. Type anyObjectType = TC.Context.getAnyObjectType(); // Local function to update the state after we've resolved a // component. Type currentType = rootType; auto updateState = [&](bool isProperty, Type newType) { // Strip off optionals. newType = newType->lookThroughAllOptionalTypes(); // If updating to a type, just set the new type; there's nothing // more to do. if (!isProperty) { assert(state == Beginning || state == ResolvingType); state = ResolvingType; currentType = newType; return; } // We're updating to a property. Determine whether we're looking // into a bridged Swift collection of some sort. if (auto boundGeneric = newType->getAs()) { auto nominal = boundGeneric->getDecl(); // Array if (nominal == TC.Context.getArrayDecl()) { // Further lookups into the element type. state = ResolvingArray; currentType = boundGeneric->getGenericArgs()[0]; return; } // Set if (nominal == TC.Context.getSetDecl()) { // Further lookups into the element type. state = ResolvingSet; currentType = boundGeneric->getGenericArgs()[0]; return; } // Dictionary if (nominal == TC.Context.getDictionaryDecl()) { // Key paths look into the keys of a dictionary; further // lookups into the value type. state = ResolvingDictionary; currentType = boundGeneric->getGenericArgs()[1]; return; } } // Determine whether we're looking into a Foundation collection. if (auto classDecl = newType->getClassOrBoundGenericClass()) { if (classDecl->isObjC() && classDecl->hasClangNode()) { SmallString<32> scratch; StringRef objcClassName = classDecl->getObjCRuntimeName(scratch); // NSArray if (objcClassName == "NSArray") { // The element type is unknown, so use AnyObject. state = ResolvingArray; currentType = anyObjectType; return; } // NSSet if (objcClassName == "NSSet") { // The element type is unknown, so use AnyObject. state = ResolvingSet; currentType = anyObjectType; return; } // NSDictionary if (objcClassName == "NSDictionary") { // Key paths look into the keys of a dictionary; there's no // type to help us here. state = ResolvingDictionary; currentType = anyObjectType; return; } } } // It's just a property. state = ResolvingProperty; currentType = newType; }; // Local function to perform name lookup for the current index. auto performLookup = [&](DeclBaseName componentName, SourceLoc componentNameLoc, Type &lookupType) -> LookupResult { assert(currentType && "Non-beginning state must have a type"); if (!currentType->mayHaveMembers()) return LookupResult(); // Determine the type in which the lookup should occur. If we have // a bridged value type, this will be the Objective-C class to // which it is bridged. if (auto bridgedClass = TC.Context.getBridgedToObjC(CS.DC, currentType)) lookupType = bridgedClass; else lookupType = currentType; // Look for a member with the given name within this type. return TC.lookupMember(CS.DC, lookupType, componentName); }; // Local function to print a component to the string. bool needDot = false; auto printComponent = [&](DeclBaseName component) { if (needDot) keyPathOS << "."; else needDot = true; keyPathOS << component; }; bool isInvalid = false; SmallVector resolvedComponents; for (auto &component : KPE->getComponents()) { auto componentNameLoc = component.getLoc(); DeclBaseName componentName; switch (auto kind = component.getKind()) { case KeyPathExpr::Component::Kind::UnresolvedProperty: { auto componentFullName = component.getUnresolvedDeclName(); componentName = componentFullName.getBaseIdentifier(); break; } case KeyPathExpr::Component::Kind::UnresolvedSubscript: componentName = DeclBaseName::createSubscript(); break; case KeyPathExpr::Component::Kind::Invalid: case KeyPathExpr::Component::Kind::Identity: case KeyPathExpr::Component::Kind::OptionalChain: case KeyPathExpr::Component::Kind::OptionalForce: // FIXME: Diagnose optional chaining and forcing properly. return false; case KeyPathExpr::Component::Kind::OptionalWrap: case KeyPathExpr::Component::Kind::Property: case KeyPathExpr::Component::Kind::Subscript: case KeyPathExpr::Component::Kind::TupleElement: llvm_unreachable("already resolved!"); } // If we are resolving into a dictionary, any component is // well-formed because the keys are unknown dynamically. if (state == ResolvingDictionary) { // Just print the component unchanged; there's no checking we // can do here. printComponent(componentName); // From here, we're resolving a property. Use the current type. updateState(/*isProperty=*/true, currentType); continue; } // Look for this component. Type lookupType; LookupResult lookup = performLookup(componentName, componentNameLoc, lookupType); // If we didn't find anything, try to apply typo-correction. bool resultsAreFromTypoCorrection = false; if (!lookup) { TypoCorrectionResults corrections(TC, componentName, DeclNameLoc(componentNameLoc)); TC.performTypoCorrection(CS.DC, DeclRefKind::Ordinary, lookupType, (lookupType ? defaultMemberTypeLookupOptions : defaultUnqualifiedLookupOptions), corrections); if (currentType) { TC.diagnose(componentNameLoc, diag::could_not_find_type_member, currentType, componentName); } else { TC.diagnose(componentNameLoc, diag::use_unresolved_identifier, componentName, false); } // Note all the correction candidates. corrections.noteAllCandidates(); corrections.addAllCandidatesToLookup(lookup); isInvalid = true; if (!lookup) break; // Remember that these are from typo correction. resultsAreFromTypoCorrection = true; } // If we have more than one result, filter out unavailable or // obviously unusable candidates. if (lookup.size() > 1) { lookup.filter([&](LookupResultEntry result, bool isOuter) -> bool { // Drop unavailable candidates. if (result.getValueDecl()->getAttrs().isUnavailable(TC.Context)) return false; // Drop non-property, non-type candidates. if (!isa(result.getValueDecl()) && !isa(result.getValueDecl()) && !isa(result.getValueDecl())) return false; return true; }); } // If all results were unavailable, fail. if (!lookup) break; // If we *still* have more than one result, fail. if (lookup.size() > 1) { // Don't diagnose ambiguities if the results are from typo correction. if (resultsAreFromTypoCorrection) break; if (lookupType) TC.diagnose(componentNameLoc, diag::ambiguous_member_overload_set, componentName); else TC.diagnose(componentNameLoc, diag::ambiguous_decl_ref, componentName); for (auto result : lookup) { TC.diagnose(result.getValueDecl(), diag::decl_declared_here, result.getValueDecl()->getFullName()); } isInvalid = true; break; } auto found = lookup.front().getValueDecl(); // Handle property references. if (auto var = dyn_cast(found)) { TC.validateDecl(var); // Resolve this component to the variable we found. auto varRef = ConcreteDeclRef(var); auto resolved = KeyPathExpr::Component::forProperty(varRef, Type(), componentNameLoc); resolvedComponents.push_back(resolved); updateState(/*isProperty=*/true, var->getInterfaceType()); continue; } // Handle type references. if (auto type = dyn_cast(found)) { // We cannot refer to a type via a property. if (isResolvingProperty()) { TC.diagnose(componentNameLoc, diag::expr_keypath_type_of_property, componentName, currentType); isInvalid = true; break; } // We cannot refer to a generic type. if (type->getDeclaredInterfaceType()->hasTypeParameter()) { TC.diagnose(componentNameLoc, diag::expr_keypath_generic_type, componentName); isInvalid = true; break; } Type newType; if (lookupType && !lookupType->isAnyObject()) { newType = lookupType->getTypeOfMember(CS.DC->getParentModule(), type, type->getDeclaredInterfaceType()); } else { newType = type->getDeclaredInterfaceType(); } if (!newType) { isInvalid = true; break; } updateState(/*isProperty=*/false, newType); continue; } continue; } return isInvalid; } bool FailureDiagnosis::visitKeyPathExpr(KeyPathExpr *KPE) { auto contextualType = CS.getContextualType(); auto components = KPE->getComponents(); assert(!components.empty() && "smart key path components cannot be empty."); auto &firstComponent = components.front(); using ComponentKind = KeyPathExpr::Component::Kind; ClassDecl *klass; Type parentType, rootType, valueType; switch (firstComponent.getKind()) { case ComponentKind::UnresolvedProperty: case ComponentKind::UnresolvedSubscript: { // If there is no contextual type we can't really do anything, // as in case of unresolved member expression, which relies on // contextual information. if (!contextualType) return false; if (auto *BGT = contextualType->getAs()) { auto genericArgs = BGT->getGenericArgs(); klass = BGT->getDecl(); parentType = BGT->getParent(); // Smart Key Path can either have 1 argument - root type or // two arguments - root and value type. assert(genericArgs.size() == 1 || genericArgs.size() == 2); rootType = genericArgs.front(); if (genericArgs.size() == 2) valueType = genericArgs.back(); } break; } default: return false; } // If there is no root type associated with expression we can't // really diagnose anything here, it's most likely ambiguity. if (!rootType) return false; // If we know value type, it might be contextual mismatch between // the actual type of the path vs. given by the caller. if (valueType && !valueType->hasUnresolvedType()) { struct KeyPathListener : public ExprTypeCheckListener { ClassDecl *Decl; Type ParentType; Type RootType; KeyPathListener(ClassDecl *decl, Type parent, Type root) : Decl(decl), ParentType(parent), RootType(root) {} bool builtConstraints(ConstraintSystem &cs, Expr *expr) override { auto *locator = cs.getConstraintLocator(expr); auto valueType = cs.createTypeVariable(locator); auto keyPathType = BoundGenericClassType::get(Decl, ParentType, {RootType, valueType}); cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr), keyPathType, locator, /*isFavored*/ true); return false; } }; Expr *expr = KPE; KeyPathListener listener(klass, parentType, rootType); ConcreteDeclRef concreteDecl; auto derivedType = getTypeOfExpressionWithoutApplying( expr, CS.DC, concreteDecl, FreeTypeVariableBinding::Disallow, &listener); if (derivedType) { if (auto *BGT = derivedType->getAs()) { auto derivedValueType = BGT->getGenericArgs().back(); if (!CS.TC.isConvertibleTo(valueType, derivedValueType, CS.DC)) { diagnose(KPE->getLoc(), diag::expr_smart_keypath_value_covert_to_contextual_type, derivedValueType, valueType); return true; } } } } // Looks like this is not a problem with contextual value type, let's see // if there is something wrong with the path itself, maybe one of the // components is incorrectly typed or doesn't exist... return diagnoseKeyPathComponents(CS, KPE, rootType); } bool FailureDiagnosis::visitArrayExpr(ArrayExpr *E) { // If we had a contextual type, then it either conforms to // ExpressibleByArrayLiteral or it is an invalid contextual type. auto contextualType = CS.getContextualType(); if (!contextualType) { return false; } // If our contextual type is an optional, look through them, because we're // surely initializing whatever is inside. contextualType = contextualType->lookThroughAllOptionalTypes(); // Validate that the contextual type conforms to ExpressibleByArrayLiteral and // figure out what the contextual element type is in place. auto ALC = CS.TC.getProtocol(E->getLoc(), KnownProtocolKind::ExpressibleByArrayLiteral); if (!ALC) return visitExpr(E); // Check to see if the contextual type conforms. if (auto Conformance = CS.TC.conformsToProtocol(contextualType, ALC, CS.DC, ConformanceCheckFlags::InExpression)) { Type contextualElementType = ProtocolConformanceRef::getTypeWitnessByName( contextualType, *Conformance, CS.getASTContext().Id_ArrayLiteralElement, &CS.TC) ->getDesugaredType(); // Type check each of the subexpressions in place, passing down the contextual // type information if we have it. for (auto elt : E->getElements()) { if (typeCheckChildIndependently(elt, contextualElementType, CTP_ArrayElement) == nullptr) { return true; } } return false; } auto DLC = CS.TC.getProtocol(E->getLoc(), KnownProtocolKind::ExpressibleByDictionaryLiteral); if (!DLC) return visitExpr(E); if (CS.TC.conformsToProtocol(contextualType, DLC, CS.DC, ConformanceCheckFlags::InExpression)) { // If the contextual type conforms to ExpressibleByDictionaryLiteral and // this is an empty array, then they meant "[:]". auto numElements = E->getNumElements(); if (numElements == 0) { diagnose(E->getStartLoc(), diag::should_use_empty_dictionary_literal) .fixItInsert(E->getEndLoc(), ":"); return true; } // If the contextual type conforms to ExpressibleByDictionaryLiteral, then // they wrote "x = [1,2]" but probably meant "x = [1:2]". if ((numElements & 1) == 0 && numElements > 0) { bool isIniting = CS.getContextualTypePurpose() == CTP_Initialization; diagnose(E->getStartLoc(), diag::should_use_dictionary_literal, contextualType, isIniting); auto diag = diagnose(E->getStartLoc(), diag::meant_dictionary_lit); // Change every other comma into a colon, only if the number // of commas present matches the number of elements, because // otherwise it might a structural problem with the expression // e.g. ["a""b": 1]. const auto commaLocs = E->getCommaLocs(); if (commaLocs.size() == numElements - 1) { for (unsigned i = 0, e = numElements / 2; i != e; ++i) diag.fixItReplace(commaLocs[i*2], ":"); } return true; } return false; } // If that didn't turn up an issue, then we don't know what to do. // TODO: When a contextual type is missing, we could try to diagnose cases // where the element types mismatch... but theoretically they should type // unify to Any, so that could never happen? return false; } bool FailureDiagnosis::visitDictionaryExpr(DictionaryExpr *E) { Type contextualKeyType, contextualValueType; auto keyTypePurpose = CTP_Unused, valueTypePurpose = CTP_Unused; // If we had a contextual type, then it either conforms to // ExpressibleByDictionaryLiteral or it is an invalid contextual type. if (auto contextualType = CS.getContextualType()) { // If our contextual type is an optional, look through them, because we're // surely initializing whatever is inside. contextualType = contextualType->lookThroughAllOptionalTypes(); auto DLC = CS.TC.getProtocol( E->getLoc(), KnownProtocolKind::ExpressibleByDictionaryLiteral); if (!DLC) return visitExpr(E); // Validate the contextual type conforms to ExpressibleByDictionaryLiteral // and figure out what the contextual Key/Value types are in place. auto Conformance = CS.TC.conformsToProtocol( contextualType, DLC, CS.DC, ConformanceCheckFlags::InExpression); if (!Conformance) { diagnose(E->getStartLoc(), diag::type_is_not_dictionary, contextualType) .highlight(E->getSourceRange()); return true; } contextualKeyType = ProtocolConformanceRef::getTypeWitnessByName( contextualType, *Conformance, CS.getASTContext().Id_Key, &CS.TC) ->getDesugaredType(); contextualValueType = ProtocolConformanceRef::getTypeWitnessByName( contextualType, *Conformance, CS.getASTContext().Id_Value, &CS.TC) ->getDesugaredType(); assert(contextualKeyType && contextualValueType && "Could not find Key/Value DictionaryLiteral associated types from" " contextual type conformance"); keyTypePurpose = CTP_DictionaryKey; valueTypePurpose = CTP_DictionaryValue; } // Type check each of the subexpressions in place, passing down the contextual // type information if we have it. for (auto elt : E->getElements()) { auto TE = dyn_cast(elt); if (!TE || TE->getNumElements() != 2) continue; if (!typeCheckChildIndependently(TE->getElement(0), contextualKeyType, keyTypePurpose)) return true; if (!typeCheckChildIndependently(TE->getElement(1), contextualValueType, valueTypePurpose)) return true; } // If that didn't turn up an issue, then we don't know what to do. // TODO: When a contextual type is missing, we could try to diagnose cases // where the element types mismatch. There is no Any equivalent since they // keys need to be hashable. return false; } /// When an object literal fails to typecheck because its protocol's /// corresponding default type has not been set in the global namespace (e.g. /// _ColorLiteralType), suggest that the user import the appropriate module for /// the target. bool FailureDiagnosis::visitObjectLiteralExpr(ObjectLiteralExpr *E) { auto &TC = CS.getTypeChecker(); // Type check the argument first. auto protocol = TC.getLiteralProtocol(E); if (!protocol) return false; DeclName constrName = TC.getObjectLiteralConstructorName(E); assert(constrName); auto constrs = protocol->lookupDirect(constrName); if (constrs.size() != 1 || !isa(constrs.front())) return false; auto *constr = cast(constrs.front()); auto paramType = TC.getObjectLiteralParameterType(E, constr); if (!typeCheckChildIndependently( E->getArg(), paramType, CTP_CallArgument)) return true; // Conditions for showing this diagnostic: // * The object literal protocol's default type is unimplemented if (TC.getDefaultType(protocol, CS.DC)) return false; // * The object literal has no contextual type if (CS.getContextualType()) return false; // Figure out what import to suggest. auto &Ctx = CS.getASTContext(); const auto &target = Ctx.LangOpts.Target; StringRef importModule; StringRef importDefaultTypeName; if (protocol == Ctx.getProtocol(KnownProtocolKind::ExpressibleByColorLiteral)) { if (target.isMacOSX()) { importModule = "AppKit"; importDefaultTypeName = "NSColor"; } else if (target.isiOS() || target.isTvOS()) { importModule = "UIKit"; importDefaultTypeName = "UIColor"; } } else if (protocol == Ctx.getProtocol( KnownProtocolKind::ExpressibleByImageLiteral)) { if (target.isMacOSX()) { importModule = "AppKit"; importDefaultTypeName = "NSImage"; } else if (target.isiOS() || target.isTvOS()) { importModule = "UIKit"; importDefaultTypeName = "UIImage"; } } else if (protocol == Ctx.getProtocol( KnownProtocolKind::ExpressibleByFileReferenceLiteral)) { importModule = "Foundation"; importDefaultTypeName = "URL"; } // Emit the diagnostic. const auto plainName = E->getLiteralKindPlainName(); TC.diagnose(E->getLoc(), diag::object_literal_default_type_missing, plainName); if (!importModule.empty()) { TC.diagnose(E->getLoc(), diag::object_literal_resolve_import, importModule, importDefaultTypeName, plainName); } return true; } bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { // If we have no contextual type, there is no way to resolve this. Just // diagnose this as an ambiguity. if (!CS.getContextualType()) return false; // OTOH, if we do have a contextual type, we can provide a more specific // error. Dig out the UnresolvedValueMember constraint for this expr node. Constraint *memberConstraint = nullptr; auto checkConstraint = [&](Constraint *C) { if (C->getKind() == ConstraintKind::UnresolvedValueMember && simplifyLocatorToAnchor(CS, C->getLocator()) == E) memberConstraint = C; }; if (CS.failedConstraint) checkConstraint(CS.failedConstraint); for (auto &C : CS.getConstraints()) { if (memberConstraint) break; checkConstraint(&C); } // If we can't find the member constraint in question, then we failed. if (!memberConstraint) return false; std::function)> callback = [&]( ArrayRef candidates) { bool hasTrailingClosure = callArgHasTrailingClosure(E->getArgument()); // Dump all of our viable candidates into a CalleeCandidateInfo & sort it // out. CalleeCandidateInfo candidateInfo(Type(), candidates, hasTrailingClosure, CS); // Filter the candidate list based on the argument we may or may not have. candidateInfo.filterContextualMemberList(E->getArgument()); // If we have multiple candidates, then we have an ambiguity. if (candidateInfo.size() != 1) { SourceRange argRange; if (auto arg = E->getArgument()) argRange = arg->getSourceRange(); diagnose(E->getNameLoc(), diag::ambiguous_member_overload_set, E->getName()) .highlight(argRange); candidateInfo.suggestPotentialOverloads(E->getNameLoc().getBaseNameLoc()); return true; } auto *argExpr = E->getArgument(); auto candidateArgTy = candidateInfo[0].getArgumentType(CS.getASTContext()); // Depending on how we matched, produce tailored diagnostics. switch (candidateInfo.closeness) { case CC_NonLValueInOut: // First argument is inout but no lvalue present. case CC_OneArgumentMismatch: // All arguments except one match. case CC_OneArgumentNearMismatch: case CC_OneGenericArgumentMismatch: case CC_OneGenericArgumentNearMismatch: case CC_GenericNonsubstitutableMismatch: case CC_SelfMismatch: // Self argument mismatches. case CC_ArgumentNearMismatch: // Argument list mismatch. case CC_ArgumentMismatch: // Argument list mismatch. llvm_unreachable("These aren't produced by filterContextualMemberList"); return false; case CC_ExactMatch: { // This is a perfect match for the arguments. // If we have an exact match, then we must have an argument list, check // it. if (candidateArgTy) { assert(argExpr && "Exact match without argument?"); if (!typeCheckArgumentChildIndependently(argExpr, candidateArgTy, candidateInfo)) return true; } // If the argument is a match, then check the result type. We might have // looked up a contextual member whose result type disagrees with the // expected result type. auto resultTy = candidateInfo[0].getResultType(); if (!resultTy) resultTy = candidateInfo[0].getType(); if (resultTy && !CS.getContextualType()->is() && !CS.TC.isConvertibleTo(resultTy, CS.getContextualType(), CS.DC)) { diagnose(E->getNameLoc(), diag::expected_result_in_contextual_member, E->getName(), resultTy, CS.getContextualType()); return true; } // Otherwise, this is an exact match, return false to diagnose this as an // ambiguity. It must be some other problem, such as failing to infer a // generic argument on the enum type. return false; } case CC_Unavailable: case CC_Inaccessible: // Diagnose some simple and common errors. return candidateInfo.diagnoseSimpleErrors(E); case CC_ArgumentLabelMismatch: case CC_ArgumentCountMismatch: { // If we have no argument, the candidates must have expected one. if (!argExpr) { if (!candidateArgTy) return false; // Candidate must be incorrect for some other reason. // Pick one of the arguments that are expected as an exemplar. if (candidateArgTy->isVoid()) { // If this member is () -> T, suggest adding parentheses. diagnose(E->getNameLoc(), diag::expected_parens_in_contextual_member, E->getName()) .fixItInsertAfter(E->getEndLoc(), "()"); } else { diagnose(E->getNameLoc(), diag::expected_argument_in_contextual_member, E->getName(), candidateArgTy); } return true; } assert(argExpr && candidateArgTy && "Exact match without an argument?"); return diagnoseSingleCandidateFailures(candidateInfo, E, argExpr, E->getArgumentLabels()); } case CC_GeneralMismatch: { // Something else is wrong. // If an argument value was specified, but this member expects no // arguments, // then we fail with a nice error message. if (!candidateArgTy) { auto kind = candidateInfo[0].getDecl()->getDescriptiveKind(); bool isVoid = CS.getType(argExpr)->isVoid(); auto argumentRange = E->getArgument()->getSourceRange(); if (kind == DescriptiveDeclKind::EnumElement) { if (isVoid) { diagnose(E->getNameLoc(), diag::unexpected_arguments_in_enum_case, E->getName()) .fixItRemove(argumentRange); } else { diagnose(E->getNameLoc(), diag::unexpected_arguments_in_enum_case, E->getName()) .highlight(argumentRange); } } else { if (isVoid) { diagnose(E->getNameLoc(), diag::unexpected_arguments_in_contextual_member, kind, E->getName()) .fixItRemove(argumentRange); } else { diagnose(E->getNameLoc(), diag::unexpected_arguments_in_contextual_member, kind, E->getName()) .highlight(argumentRange); } } return true; } return false; } } llvm_unreachable("all cases should be handled"); }; return diagnoseMemberFailures(E, nullptr, memberConstraint->getKind(), memberConstraint->getMember(), memberConstraint->getFunctionRefKind(), memberConstraint->getLocator(), callback); } bool FailureDiagnosis::diagnoseMemberFailures( Expr *E, Expr *baseExpr, ConstraintKind lookupKind, DeclName memberName, FunctionRefKind funcRefKind, ConstraintLocator *locator, Optional)>> callback, bool includeInaccessibleMembers) { auto isInitializer = memberName.isSimpleName(DeclBaseName::createConstructor()); // Get the referenced base expression from the failed constraint, along with // the SourceRange for the member ref. In "x.y", this returns the expr for x // and the source range for y. SourceRange memberRange; SourceLoc BaseLoc; DeclNameLoc NameLoc; Type baseTy, baseObjTy; // UnresolvedMemberExpr doesn't have "base" expression, // it's represented as ".foo", which means that we need // to get base from the context. if (auto *UME = dyn_cast(E)) { memberRange = E->getSourceRange(); BaseLoc = E->getLoc(); NameLoc = UME->getNameLoc(); baseTy = CS.getContextualType(); if (!baseTy) return false; // If we succeeded, get ready to do the member lookup. baseObjTy = baseTy->getRValueType(); // If the base object is already a metatype type, then something weird is // going on. For now, just generate a generic error. if (baseObjTy->is()) return false; baseTy = baseObjTy = MetatypeType::get(baseObjTy); } else { memberRange = baseExpr->getSourceRange(); if (locator) locator = simplifyLocator(CS, locator, memberRange); BaseLoc = baseExpr->getLoc(); NameLoc = DeclNameLoc(memberRange.Start); // Retypecheck the anchor type, which is the base of the member expression. baseExpr = typeCheckArbitrarySubExprIndependently(baseExpr, TCC_AllowLValue); if (!baseExpr) return true; baseTy = CS.getType(baseExpr); baseObjTy = baseTy->getWithoutSpecifierType(); } // If the base type is an IUO, look through it. Odds are, the code is not // trying to find a member of it. // FIXME: We need to rework this with IUOs out of the type system. // if (auto objTy = CS.lookThroughImplicitlyUnwrappedOptionalType(baseObjTy)) // baseTy = baseObjTy = objTy; // If the base of this property access is a function that takes an empty // argument list, then the most likely problem is that the user wanted to // call the function, e.g. in "a.b.c" where they had to write "a.b().c". // Produce a specific diagnostic + fixit for this situation. if (auto baseFTy = baseObjTy->getAs()) { if (baseExpr && baseFTy->getParams().empty()) { auto failure = MissingCallFailure(expr, CS, CS.getConstraintLocator(baseExpr)); return failure.diagnoseAsError(); } } // If this is a tuple, then the index needs to be valid. if (auto tuple = baseObjTy->getAs()) { auto baseName = memberName.getBaseName(); if (!baseName.isSpecial()) { StringRef nameStr = baseName.userFacingName(); int fieldIdx = -1; // Resolve a number reference into the tuple type. unsigned Value = 0; if (!nameStr.getAsInteger(10, Value) && Value < tuple->getNumElements()) { fieldIdx = Value; } else { fieldIdx = tuple->getNamedElementId(memberName.getBaseIdentifier()); } if (fieldIdx != -1) return false; // Lookup is valid. } diagnose(BaseLoc, diag::could_not_find_tuple_member, baseObjTy, memberName) .highlight(memberRange); return true; } // If this is initializer/constructor lookup we are dealing this. if (isInitializer) { // Let's check what is the base type we are trying to look it up on // because only MetatypeType is viable to find constructor on, as per // rules in ConstraintSystem::performMemberLookup. if (!baseTy->is()) { baseTy = MetatypeType::get(baseTy, CS.getASTContext()); } } // If base type has unresolved generic parameters, such might mean // that it's initializer with erroneous argument, otherwise this would // be a simple ambiguous archetype case, neither can be diagnosed here. if (baseTy->hasTypeParameter() && baseTy->hasUnresolvedType()) return false; MemberLookupResult result = CS.performMemberLookup(lookupKind, memberName, baseTy, funcRefKind, locator, includeInaccessibleMembers); switch (result.OverallResult) { case MemberLookupResult::Unsolved: // If we couldn't resolve a specific type for the base expression, then we // cannot produce a specific diagnostic. return false; case MemberLookupResult::ErrorAlreadyDiagnosed: // If an error was already emitted, then we're done, don't emit anything // redundant. return true; case MemberLookupResult::HasResults: break; } SmallVector viableCandidatesToReport; for (auto candidate : result.ViableCandidates) if (candidate.getKind() != OverloadChoiceKind::KeyPathApplication) viableCandidatesToReport.push_back(candidate); // Since the lookup was allowing inaccessible members, let's check // if it found anything of that sort, which is easy to diagnose. bool allUnavailable = !CS.TC.getLangOpts().DisableAvailabilityChecking; bool allInaccessible = true; for (auto &member : viableCandidatesToReport) { if (!member.isDecl()) { // if there is no declaration, this choice is implicitly available. allUnavailable = false; continue; } auto decl = member.getDecl(); // Check availability of the found choice. if (!decl->getAttrs().isUnavailable(CS.getASTContext())) allUnavailable = false; if (decl->isAccessibleFrom(CS.DC)) allInaccessible = false; } // diagnoseSimpleErrors() should have diagnosed this scenario. assert(!allInaccessible || viableCandidatesToReport.empty()); if (result.UnviableCandidates.empty() && isInitializer && !baseObjTy->is()) { if (auto ctorRef = dyn_cast(E)) { // Diagnose 'super.init', which can only appear inside another // initializer, specially. if (isa(ctorRef->getBase())) { diagnose(BaseLoc, diag::super_initializer_not_in_initializer); return true; } // Suggest inserting a call to 'type(of:)' to construct another object // of the same dynamic type. SourceRange fixItRng = ctorRef->getNameLoc().getSourceRange(); // Surround the caller in `type(of:)`. diagnose(BaseLoc, diag::init_not_instance_member) .fixItInsert(fixItRng.Start, "type(of: ") .fixItInsertAfter(fixItRng.End, ")"); return true; } } if (viableCandidatesToReport.empty()) { // If this was an optional type let's check if the base type // has requested member, if so - generate nice error saying that // optional was not unwrapped, otherwise say that type value has // no such member. if (auto *OT = dyn_cast(baseObjTy.getPointer())) { auto optionalResult = CS.performMemberLookup( lookupKind, memberName, OT->getBaseType(), funcRefKind, locator, /*includeInaccessibleMembers*/ false); switch (optionalResult.OverallResult) { case MemberLookupResult::ErrorAlreadyDiagnosed: // If an error was already emitted, then we're done, don't emit anything // redundant. return true; case MemberLookupResult::Unsolved: case MemberLookupResult::HasResults: break; } if (!optionalResult.ViableCandidates.empty()) { if (diagnoseBaseUnwrapForMemberAccess(baseExpr, baseObjTy, memberName, /* additionalOptional= */ false, memberRange)) return true; } } // FIXME: Dig out the property DeclNameLoc. diagnoseUnviableLookupResults(result, E, baseObjTy, baseExpr, memberName, NameLoc, BaseLoc); return true; } if (allUnavailable) { auto firstDecl = viableCandidatesToReport[0].getDecl(); // FIXME: We need the enclosing CallExpr to rewrite the argument labels. if (diagnoseExplicitUnavailability(firstDecl, BaseLoc, CS.DC, /*call*/ nullptr)) return true; } return callback.hasValue() ? (*callback)(viableCandidatesToReport) : false; } bool FailureDiagnosis::visitUnresolvedDotExpr(UnresolvedDotExpr *UDE) { auto *baseExpr = UDE->getBase(); auto *locator = CS.getConstraintLocator(UDE, ConstraintLocator::Member); if (!locator) return false; return diagnoseMemberFailures(UDE, baseExpr, ConstraintKind::ValueMember, UDE->getName(), UDE->getFunctionRefKind(), locator); } /// A TupleExpr propagate contextual type information down to its children and /// can be erroneous when there is a label mismatch etc. bool FailureDiagnosis::visitTupleExpr(TupleExpr *TE) { // If we know the requested argType to use, use computeTupleShuffle to produce // the shuffle of input arguments to destination values. It requires a // TupleType to compute the mapping from argExpr. Conveniently, it doesn't // care about the actual types though, so we can just use 'void' for them. if (!CS.getContextualType() || !CS.getContextualType()->is()) return visitExpr(TE); auto contextualTT = CS.getContextualType()->castTo(); SmallVector ArgElts; auto voidTy = CS.getASTContext().TheEmptyTupleType; for (unsigned i = 0, e = TE->getNumElements(); i != e; ++i) ArgElts.push_back({ voidTy, TE->getElementName(i) }); auto TEType = TupleType::get(ArgElts, CS.getASTContext()); if (!TEType->is()) return visitExpr(TE); SmallVector sources; // If the shuffle is invalid, then there is a type error. We could diagnose // it specifically here, but the general logic does a fine job so we let it // do it. if (computeTupleShuffle(TEType->castTo()->getElements(), contextualTT->getElements(), sources)) return visitExpr(TE); // If we got a correct shuffle, we can perform the analysis of all of // the input elements, with their expected types. for (unsigned i = 0, e = sources.size(); i != e; ++i) { // Otherwise, it must match the corresponding expected argument type. unsigned inArgNo = sources[i]; TCCOptions options; if (contextualTT->getElement(i).isInOut()) options |= TCC_AllowLValue; auto actualType = contextualTT->getElementType(i); auto exprResult = typeCheckChildIndependently(TE->getElement(inArgNo), actualType, CS.getContextualTypePurpose(), options); // If there was an error type checking this argument, then we're done. if (!exprResult) return true; // If the caller expected something inout, but we didn't have // something of inout type, diagnose it. if (auto IOE = dyn_cast(exprResult->getSemanticsProvidingExpr())) { if (!contextualTT->getElement(i).isInOut()) { diagnose(exprResult->getLoc(), diag::extra_address_of, CS.getType(exprResult)->getInOutObjectType()) .highlight(exprResult->getSourceRange()) .fixItRemove(IOE->getStartLoc()); return true; } } } return false; } /// An IdentityExpr doesn't change its argument, but it *can* propagate its /// contextual type information down. bool FailureDiagnosis::visitIdentityExpr(IdentityExpr *E) { auto contextualType = CS.getContextualType(); // If we have a paren expr and our contextual type is a ParenType, remove the // paren expr sugar. if (contextualType) contextualType = contextualType->getWithoutParens(); if (!typeCheckChildIndependently(E->getSubExpr(), contextualType, CS.getContextualTypePurpose())) return true; return false; } /// A TryExpr doesn't change it's argument, nor does it change the contextual /// type. bool FailureDiagnosis::visitTryExpr(TryExpr *E) { return visit(E->getSubExpr()); } bool FailureDiagnosis::visitExpr(Expr *E) { // Check each of our immediate children to see if any of them are // independently invalid. bool errorInSubExpr = false; E->forEachImmediateChildExpr([&](Expr *Child) -> Expr* { // If we already found an error, stop checking. if (errorInSubExpr) return Child; // Otherwise just type check the subexpression independently. If that // succeeds, then we stitch the result back into our expression. if (typeCheckChildIndependently(Child, TCC_AllowLValue)) return Child; // Otherwise, it failed, which emitted a diagnostic. Keep track of this // so that we don't emit multiple diagnostics. errorInSubExpr = true; return Child; }); // If any of the children were errors, we're done. if (errorInSubExpr) return true; // Otherwise, produce a more generic error. return false; } bool FailureDiagnosis::diagnoseExprFailure() { assert(expr); // Our general approach is to do a depth first traversal of the broken // expression tree, type checking as we go. If we find a subtree that cannot // be type checked on its own (even to an incomplete type) then that is where // we focus our attention. If we do find a type, we use it to check for // contextual type mismatches. return visit(expr); } /// Given a specific expression and the remnants of the failed constraint /// system, produce a specific diagnostic. /// /// This is guaranteed to always emit an error message. /// void ConstraintSystem::diagnoseFailureForExpr(Expr *expr) { // Continue simplifying any active constraints left in the system. We can end // up with them because the solver bails out as soon as it sees a Failure. We // don't want to leave them around in the system because later diagnostics // will assume they are unsolvable and may otherwise leave the system in an // inconsistent state. simplify(/*ContinueAfterFailures*/true); // Look through RebindSelfInConstructorExpr to avoid weird Sema issues. if (auto *RB = dyn_cast(expr)) expr = RB->getSubExpr(); FailureDiagnosis diagnosis(expr, *this); // Now, attempt to diagnose the failure from the info we've collected. if (diagnosis.diagnoseExprFailure()) return; // If this is a contextual conversion problem, dig out some information. if (diagnosis.diagnoseContextualConversionError(expr, getContextualType(), getContextualTypePurpose())) return; // If we can diagnose a problem based on the constraints left laying around in // the system, do so now. if (diagnosis.diagnoseConstraintFailure()) return; // If no one could find a problem with this expression or constraint system, // then it must be well-formed... but is ambiguous. Handle this by diagnostic // various cases that come up. diagnosis.diagnoseAmbiguity(expr); } static bool hasGenericParameter(const GenericTypeDecl *generic, GenericTypeParamType *paramTy) { auto *decl = paramTy->getDecl(); if (!decl) return false; return decl->getDeclContext() == generic; } static void noteGenericParameterSource(const TypeLoc &loc, GenericTypeParamType *paramTy, ConstraintSystem &cs) { const GenericTypeDecl *FoundDecl = nullptr; const ComponentIdentTypeRepr *FoundGenericTypeBase = nullptr; // Walk the TypeRepr to find the type in question. if (auto typerepr = loc.getTypeRepr()) { struct FindGenericTypeDecl : public ASTWalker { const GenericTypeDecl *FoundDecl = nullptr; const ComponentIdentTypeRepr *FoundGenericTypeBase = nullptr; GenericTypeParamType *ParamTy; FindGenericTypeDecl(GenericTypeParamType *ParamTy) : ParamTy(ParamTy) {} bool walkToTypeReprPre(TypeRepr *T) override { // If we already emitted the note, we're done. if (FoundDecl) return false; if (auto ident = dyn_cast(T)) { auto *generic = dyn_cast_or_null(ident->getBoundDecl()); if (generic && hasGenericParameter(generic, ParamTy)) { FoundDecl = generic; FoundGenericTypeBase = ident; return false; } } // Keep walking. return true; } } findGenericTypeDecl(paramTy); typerepr->walk(findGenericTypeDecl); FoundDecl = findGenericTypeDecl.FoundDecl; FoundGenericTypeBase = findGenericTypeDecl.FoundGenericTypeBase; } // If we didn't find the type in the TypeRepr, fall back to the type in the // type checked expression. if (!FoundDecl) { if (const GenericTypeDecl *generic = loc.getType()->getAnyGeneric()) if (hasGenericParameter(generic, paramTy)) FoundDecl = generic; } auto &tc = cs.getTypeChecker(); if (FoundDecl) { Type type; if (auto *nominal = dyn_cast(FoundDecl)) type = nominal->getDeclaredType(); else if (auto *typeAlias = dyn_cast(FoundDecl)) type = typeAlias->getUnboundGenericType(); else type = FoundDecl->getDeclaredInterfaceType(); tc.diagnose(FoundDecl, diag::archetype_declared_in_type, paramTy, type); } if (FoundGenericTypeBase && !isa(FoundGenericTypeBase)){ assert(FoundDecl); // If we can, prefer using any types already fixed by the constraint system. // This lets us produce fixes like `Pair` instead of defaulting to // `Pair`. // Right now we only handle this when the type that's at fault is the // top-level type passed to this function. auto type = loc.getType(); if (!type) type = cs.getType(loc); ArrayRef genericArgs; if (auto *boundGenericTy = type->getAs()) { if (boundGenericTy->getDecl() == FoundDecl) genericArgs = boundGenericTy->getGenericArgs(); } auto getPreferredType = [&](const GenericTypeParamDecl *genericParam) -> Type { // If we were able to get the generic arguments (i.e. the types used at // FoundDecl's use site), we can prefer those... if (genericArgs.empty()) return Type(); Type preferred = genericArgs[genericParam->getIndex()]; if (!preferred || preferred->hasError()) return Type(); // ...but only if they were actually resolved by the constraint system // despite the failure. Type maybeFixedType = cs.getFixedTypeRecursive(preferred, /*wantRValue*/true); if (maybeFixedType->hasTypeVariable() || maybeFixedType->hasUnresolvedType()) { return Type(); } return maybeFixedType; }; SmallString<64> genericParamBuf; if (tc.getDefaultGenericArgumentsString(genericParamBuf, FoundDecl, getPreferredType)) { tc.diagnose(FoundGenericTypeBase->getLoc(), diag::unbound_generic_parameter_explicit_fix) .fixItInsertAfter(FoundGenericTypeBase->getEndLoc(), genericParamBuf); } } } std::pair FailureDiagnosis::validateContextualType(Type contextualType, ContextualTypePurpose CTP) { if (!contextualType) return {contextualType, CTP}; // Since some of the contextual types might be tuples e.g. subscript argument // is a tuple or paren wrapping a tuple, it's required to recursively check // its elements to determine nullability of the contextual type, because it // might contain archetypes. std::function shouldNullifyType = [&](Type type) -> bool { switch (type->getDesugaredType()->getKind()) { case TypeKind::PrimaryArchetype: case TypeKind::OpenedArchetype: case TypeKind::NestedArchetype: case TypeKind::Unresolved: return true; case TypeKind::BoundGenericEnum: case TypeKind::BoundGenericClass: case TypeKind::BoundGenericStruct: case TypeKind::UnboundGeneric: case TypeKind::GenericFunction: case TypeKind::Metatype: return type->hasUnresolvedType(); case TypeKind::Tuple: { auto tupleType = type->getAs(); for (auto &element : tupleType->getElements()) { if (shouldNullifyType(element.getType())) return true; } break; } default: return false; } return false; }; bool shouldNullify = false; if (auto objectType = contextualType->getWithoutSpecifierType()) { // Note that simply checking for `objectType->hasUnresolvedType()` is not // appropriate in this case standalone, because if it's in a function, // for example, or inout type, we still want to preserve it's skeleton /// because that helps to diagnose inout argument issues. Complete // nullification is only appropriate for generic types with unresolved // types or standalone archetypes because that's going to give // sub-expression solver a chance to try and compute type as it sees fit // and higher level code would have a chance to check it, which avoids // diagnostic messages like `cannot convert (_) -> _ to (Int) -> Void`. shouldNullify = shouldNullifyType(objectType); } // If the conversion type contains no info, drop it. if (shouldNullify) return {Type(), CTP_Unused}; // Remove all of the potentially leftover type variables or type parameters // from the contextual type to be used by new solver. contextualType = replaceTypeParametersWithUnresolved(contextualType); contextualType = replaceTypeVariablesWithUnresolved(contextualType); return {contextualType, CTP}; } /// Check the specified closure to see if it is a multi-statement closure with /// an uninferred type. If so, diagnose the problem with an error and return /// true. bool FailureDiagnosis:: diagnoseAmbiguousMultiStatementClosure(ClosureExpr *closure) { if (closure->hasSingleExpressionBody() || closure->hasExplicitResultType()) return false; auto closureType = CS.getType(closure)->getAs(); if (!closureType || !(closureType->getResult()->hasUnresolvedType() || closureType->getResult()->hasTypeVariable())) return false; // Okay, we have a multi-statement closure expr that has no inferred result, // type, in the context of a larger expression. The user probably expected // the compiler to infer the result type of the closure from the body of the // closure, which Swift doesn't do for multi-statement closures. Try to be // helpful by digging into the body of the closure, looking for a return // statement, and inferring the result type from it. If we can figure that // out, we can produce a fixit hint. class ReturnStmtFinder : public ASTWalker { SmallVectorImpl &returnStmts; public: ReturnStmtFinder(SmallVectorImpl &returnStmts) : returnStmts(returnStmts) {} // Walk through statements, so we find returns hiding in if/else blocks etc. std::pair walkToStmtPre(Stmt *S) override { // Keep track of any return statements we find. if (auto RS = dyn_cast(S)) returnStmts.push_back(RS); return { true, S }; } // Don't walk into anything else, since they cannot contain statements // that can return from the current closure. std::pair walkToExprPre(Expr *E) override { return { false, E }; } std::pair walkToPatternPre(Pattern *P) override { return { false, P }; } bool walkToDeclPre(Decl *D) override { return false; } bool walkToTypeLocPre(TypeLoc &TL) override { return false; } bool walkToTypeReprPre(TypeRepr *T) override { return false; } bool walkToParameterListPre(ParameterList *PL) override { return false; } }; SmallVector Returns; closure->getBody()->walk(ReturnStmtFinder(Returns)); // If we found a return statement inside of the closure expression, then go // ahead and type check the body to see if we can determine a type. for (auto RS : Returns) { llvm::SaveAndRestore SavedDC(CS.DC, closure); // Otherwise, we're ok to type check the subexpr. Type resultType; if (RS->hasResult()) { auto resultExpr = RS->getResult(); ConcreteDeclRef decl = nullptr; // If return expression uses closure parameters, which have/are // type variables, such means that we won't be able to // type-check result correctly and, unfortunately, // we are going to leak type variables from the parent // constraint system through declaration types. bool hasUnresolvedParams = false; resultExpr->forEachChildExpr([&](Expr *childExpr) -> Expr *{ if (auto DRE = dyn_cast(childExpr)) { if (auto param = dyn_cast(DRE->getDecl())) { auto paramType = param->hasValidSignature() ? param->getType() : Type(); if (!paramType || paramType->hasTypeVariable()) { hasUnresolvedParams = true; return nullptr; } } } return childExpr; }); if (hasUnresolvedParams) continue; CS.TC.preCheckExpression(resultExpr, CS.DC); // Obtain type of the result expression without applying solutions, // because otherwise this might result in leaking of type variables, // since we are not resetting result statement and if expression is // successfully type-checked its type cleanup is going to be disabled // (we are allowing unresolved types), and as a side-effect it might // also be transformed e.g. OverloadedDeclRefExpr -> DeclRefExpr. auto type = getTypeOfExpressionWithoutApplying( resultExpr, CS.DC, decl, FreeTypeVariableBinding::UnresolvedType); if (type) resultType = type; } // If we found a type, presuppose it was the intended result and insert a // fixit hint. if (resultType && !isUnresolvedOrTypeVarType(resultType)) { std::string resultTypeStr = resultType->getString(); // If there is a location for an 'in' token, then the argument list was // specified somehow but no return type was. Insert a "-> ReturnType " // before the in token. if (closure->getInLoc().isValid()) { diagnose(closure->getLoc(), diag::cannot_infer_closure_result_type) .fixItInsert(closure->getInLoc(), "-> " + resultTypeStr + " "); return true; } // Otherwise, the closure must take zero arguments. We know this // because the if one or more argument is specified, a multi-statement // closure *must* name them, or explicitly ignore them with "_ in". // // As such, we insert " () -> ReturnType in " right after the '{' that // starts the closure body. auto insertString = " () -> " + resultTypeStr + " " + "in "; diagnose(closure->getLoc(), diag::cannot_infer_closure_result_type) .fixItInsertAfter(closure->getBody()->getLBraceLoc(), insertString); return true; } } diagnose(closure->getLoc(), diag::cannot_infer_closure_result_type); return true; } /// Check the associated constraint system to see if it has any archetypes /// not properly resolved or missing. If so, diagnose the problem with /// an error and return true. bool FailureDiagnosis::diagnoseAmbiguousGenericParameters() { using GenericParameter = std::tuple; llvm::SmallVector unboundParams; // Check out all of the type variables lurking in the system. If any free // type variables were created when opening generic parameters, diagnose // that the generic parameter could not be inferred. for (auto tv : CS.getTypeVariables()) { auto &impl = tv->getImpl(); if (impl.hasRepresentativeOrFixed()) continue; auto *paramTy = impl.getGenericParameter(); if (!paramTy) continue; // Number of constraints related to particular unbound parameter // is significant indicator of the problem, because if there are // no constraints associated with it, that means it can't ever be resolved, // such helps to diagnose situations like: struct S { init(_ a: A) {}} // because type B would have no constraints associated with it. unsigned numConstraints = 0; { llvm::SetVector constraints; CS.getConstraintGraph().gatherConstraints( tv, constraints, ConstraintGraph::GatheringKind::EquivalenceClass, [&](Constraint *constraint) -> bool { // We are not interested in ConformsTo constraints because // we can't derive any concrete type information from them. if (constraint->getKind() == ConstraintKind::ConformsTo) return false; if (constraint->getKind() == ConstraintKind::Bind) { if (auto locator = constraint->getLocator()) { auto anchor = locator->getAnchor(); if (anchor && isa(anchor)) return false; } } return true; }); numConstraints = constraints.size(); } auto locator = impl.getLocator(); unboundParams.emplace_back(paramTy, locator, numConstraints); } // We've found unbound generic parameters, let's diagnose // based on the number of constraints each one is related to. if (!unboundParams.empty()) { // Let's prioritize generic parameters that don't have any constraints // associated. std::stable_sort(unboundParams.begin(), unboundParams.end(), [](GenericParameter a, GenericParameter b) { return std::get<2>(a) < std::get<2>(b); }); auto param = unboundParams.front(); diagnoseAmbiguousGenericParameter(std::get<0>(param), std::get<1>(param)->getAnchor()); return true; } return false; } /// Emit an error message about an unbound generic parameter existing, and /// emit notes referring to the target of a diagnostic, e.g., the function /// or parameter being used. void FailureDiagnosis:: diagnoseAmbiguousGenericParameter(GenericTypeParamType *paramTy, Expr *anchor) { auto &tc = CS.getTypeChecker(); // The generic parameter may come from the explicit type in a cast expression. if (auto *ECE = dyn_cast_or_null(anchor)) { tc.diagnose(ECE->getLoc(), diag::unbound_generic_parameter_cast, paramTy, ECE->getCastTypeLoc().getType()) .highlight(ECE->getCastTypeLoc().getSourceRange()); // Emit a note specifying where this came from, if we can find it. noteGenericParameterSource(ECE->getCastTypeLoc(), paramTy, CS); return; } // A very common cause of this diagnostic is a situation where a closure expr // has no inferred type, due to being a multiline closure. Check to see if // this is the case and (if so), speculatively diagnose that as the problem. bool didDiagnose = false; expr->forEachChildExpr([&](Expr *subExpr) -> Expr*{ auto closure = dyn_cast(subExpr); if (!didDiagnose && closure) didDiagnose = diagnoseAmbiguousMultiStatementClosure(closure); return subExpr; }); if (didDiagnose) return; // Otherwise, emit an error message on the expr we have, and emit a note // about where the generic parameter came from. tc.diagnose(expr->getLoc(), diag::unbound_generic_parameter, paramTy); // If we have an anchor, drill into it to emit a // "note: generic parameter declared here". if (!anchor) return; if (auto TE = dyn_cast(anchor)) { // Emit a note specifying where this came from, if we can find it. noteGenericParameterSource(TE->getTypeLoc(), paramTy, CS); return; } ConcreteDeclRef resolved; // Simple case: direct reference to a declaration. if (auto dre = dyn_cast(anchor)) resolved = dre->getDeclRef(); // Simple case: direct reference to a declaration. if (auto MRE = dyn_cast(anchor)) resolved = MRE->getMember(); if (auto OCDRE = dyn_cast(anchor)) resolved = OCDRE->getDeclRef(); // We couldn't resolve the locator to a declaration, so we're done. if (!resolved) return; auto decl = resolved.getDecl(); if (auto FD = dyn_cast(decl)) { auto name = FD->getFullName(); auto diagID = name.isOperator() ? diag::note_call_to_operator : diag::note_call_to_func; tc.diagnose(decl, diagID, name); return; } // FIXME: Specialize for implicitly-generated constructors. if (isa(decl)) { tc.diagnose(decl, diag::note_call_to_initializer); return; } if (auto PD = dyn_cast(decl)) { tc.diagnose(decl, diag::note_init_parameter, PD->getName()); return; } // FIXME: Other decl types too. } /// Emit an ambiguity diagnostic about the specified expression. void FailureDiagnosis::diagnoseAmbiguity(Expr *E) { // First, let's try to diagnose any problems related to ambiguous // generic parameters present in the constraint system. if (diagnoseAmbiguousGenericParameters()) return; // Unresolved/Anonymous ClosureExprs are common enough that we should give // them tailored diagnostics. if (auto CE = dyn_cast(E->getValueProvidingExpr())) { // If this is a multi-statement closure with no explicit result type, emit // a note to clue the developer in. if (diagnoseAmbiguousMultiStatementClosure(CE)) return; diagnose(E->getLoc(), diag::cannot_infer_closure_type) .highlight(E->getSourceRange()); return; } // A DiscardAssignmentExpr (spelled "_") needs contextual type information to // infer its type. If we see one at top level, diagnose that it must be part // of an assignment so we don't get a generic "expression is ambiguous" error. if (isa(E)) { diagnose(E->getLoc(), diag::discard_expr_outside_of_assignment) .highlight(E->getSourceRange()); return; } // Diagnose ".foo" expressions that lack context specifically. if (auto UME = dyn_cast(E->getSemanticsProvidingExpr())) { if (!CS.getContextualType()) { diagnose(E->getLoc(), diag::unresolved_member_no_inference,UME->getName()) .highlight(SourceRange(UME->getDotLoc(), UME->getNameLoc().getSourceRange().End)); return; } } // Diagnose empty collection literals that lack context specifically. if (auto CE = dyn_cast(E->getSemanticsProvidingExpr())) { if (CE->getNumElements() == 0) { diagnose(E->getLoc(), diag::unresolved_collection_literal) .highlight(E->getSourceRange()); return; } } // Diagnose 'nil' without a contextual type. if (isa(E->getSemanticsProvidingExpr())) { diagnose(E->getLoc(), diag::unresolved_nil_literal) .highlight(E->getSourceRange()); return; } // A very common cause of this diagnostic is a situation where a closure expr // has no inferred type, due to being a multiline closure. Check to see if // this is the case and (if so), speculatively diagnose that as the problem. bool didDiagnose = false; E->forEachChildExpr([&](Expr *subExpr) -> Expr*{ auto closure = dyn_cast(subExpr); if (!didDiagnose && closure) didDiagnose = diagnoseAmbiguousMultiStatementClosure(closure); return subExpr; }); if (didDiagnose) return; // Attempt to re-type-check the entire expression, allowing ambiguity, but // ignoring a contextual type. if (expr == E) { auto exprType = getTypeOfTypeCheckedChildIndependently(expr); // If it failed and diagnosed something, then we're done. if (!exprType) return; // If we were able to find something more specific than "unknown" (perhaps // something like "[_:_]" for a dictionary literal), include it in the // diagnostic. if (!isUnresolvedOrTypeVarType(exprType)) { diagnose(E->getLoc(), diag::specific_type_of_expression_is_ambiguous, exprType) .highlight(E->getSourceRange()); return; } } // Before giving up completely let's try to see if there are any // fixes recorded by constraint generator, which point to structural // problems that might not result in solution even if fixed e.g. // missing members involved in protocol composition in expression // context which are interpreted as binary operator expressions instead. { bool diagnosed = false; for (auto *fix : CS.getFixes()) diagnosed |= fix->diagnose(expr); if (diagnosed) return; } // If there are no posted constraints or failures, then there was // not enough contextual information available to infer a type for the // expression. diagnose(E->getLoc(), diag::type_of_expression_is_ambiguous) .highlight(E->getSourceRange()); } /// If an UnresolvedDotExpr, SubscriptMember, etc has been resolved by the /// constraint system, return the decl that it references. ValueDecl *ConstraintSystem::findResolvedMemberRef(ConstraintLocator *locator) { auto *resolvedOverloadSets = this->getResolvedOverloadSets(); if (!resolvedOverloadSets) return nullptr; // Search through the resolvedOverloadSets to see if we have a resolution for // this member. This is an O(n) search, but only happens when producing an // error diagnostic. for (auto resolved = resolvedOverloadSets; resolved; resolved = resolved->Previous) { if (resolved->Locator != locator) continue; // We only handle the simplest decl binding. if (resolved->Choice.getKind() != OverloadChoiceKind::Decl) return nullptr; return resolved->Choice.getDecl(); } return nullptr; } bool swift::diagnoseBaseUnwrapForMemberAccess(Expr *baseExpr, Type baseType, DeclName memberName, bool resultOptional, SourceRange memberRange) { auto unwrappedBaseType = baseType->getOptionalObjectType(); if (!unwrappedBaseType) return false; ASTContext &ctx = baseType->getASTContext(); DiagnosticEngine &diags = ctx.Diags; diags.diagnose(baseExpr->getLoc(), diag::optional_base_not_unwrapped, baseType, memberName, unwrappedBaseType); // FIXME: It would be nice to immediately offer "base?.member ?? defaultValue" // for non-optional results where that would be appropriate. For the moment // always offering "?" means that if the user chooses chaining, we'll end up // in MissingOptionalUnwrapFailure:diagnose() to offer a default value during // the next compile. diags.diagnose(baseExpr->getLoc(), diag::optional_base_chain, memberName) .fixItInsertAfter(baseExpr->getEndLoc(), "?"); if (!resultOptional) { diags.diagnose(baseExpr->getLoc(), diag::unwrap_with_force_value) .fixItInsertAfter(baseExpr->getEndLoc(), "!"); } return true; }