From 6b520166070c0b6809331dc4e59413b777e5a028 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 4 May 2020 11:14:28 -0700 Subject: [PATCH 01/22] [ConstraintSystem] Rank solutions based on overload choices only after fix diagnostics have failed If there are multiple solutions with fixes, let's not try to rank them based on overload choices because doing so would filter out viable candidates. --- lib/Sema/ConstraintSystem.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 7b28796ae60b1..35300f3adff77 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -2719,6 +2719,11 @@ SolutionResult ConstraintSystem::salvage() { // Solve the system. solveImpl(viable); + // Before removing any "fixed" solutions, let's check + // if ambiguity is caused by fixes and diagnose if possible. + if (diagnoseAmbiguityWithFixes(viable)) + return SolutionResult::forAmbiguous(viable); + // Check whether we have a best solution; this can happen if we found // a series of fixes that worked. if (auto best = findBestSolution(viable, /*minimize=*/true)) { @@ -2728,11 +2733,6 @@ SolutionResult ConstraintSystem::salvage() { return SolutionResult::forSolved(std::move(viable[0])); } - // Before removing any "fixed" solutions, let's check - // if ambiguity is caused by fixes and diagnose if possible. - if (diagnoseAmbiguityWithFixes(viable)) - return SolutionResult::forAmbiguous(viable); - // FIXME: If we were able to actually fix things along the way, // we may have to hunt for the best solution. For now, we don't care. @@ -3071,7 +3071,7 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes( if (diagnoseConflictingGenericArguments(*this, solutionDiff, solutions)) return true; - + if (auto bestScore = solverState->BestScore) { solutions.erase(llvm::remove_if(solutions, [&](const Solution &solution) { @@ -3087,6 +3087,9 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes( return false; } + if (solutions.size() < 2) + return false; + if (diagnoseAmbiguityWithEphemeralPointers(*this, solutions)) return true; From a8885189acb2aee5185d890883ed1b7980361b35 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 4 May 2020 14:55:52 -0700 Subject: [PATCH 02/22] [ConstraintSystem] Encapsulate a way to diagnose ambiguity for aggregate fixes --- lib/Sema/ConstraintSystem.cpp | 124 ++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 35300f3adff77..e9ad71d986f2c 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -3062,6 +3062,130 @@ diagnoseAmbiguityWithEphemeralPointers(ConstraintSystem &cs, return cs.diagnoseAmbiguity(solutions); } +static bool diagnoseAmbiguity( + ConstraintSystem &cs, + ArrayRef> aggregateFix, + SolutionDiff &solutionDiff, ArrayRef solutions) { + auto anchor = aggregateFix.front().second->getAnchor(); + + // Assignment failures are all about the source expression, because + // they treat destination as a contextual type. + if (auto *assignExpr = getAsExpr(anchor)) + anchor = assignExpr->getSrc(); + + if (auto *callExpr = getAsExpr(anchor)) { + if (!isa(callExpr->getDirectCallee())) + anchor = callExpr->getDirectCallee(); + } else if (auto *applyExpr = getAsExpr(anchor)) { + anchor = applyExpr->getFn(); + } + + auto ambiguity = + llvm::find_if(solutionDiff.overloads, + [&anchor](const SolutionDiff::OverloadDiff &diff) -> bool { + return diff.locator->getAnchor() == anchor; + }); + + if (ambiguity == solutionDiff.overloads.end()) { + auto &fix = aggregateFix.front(); + return aggregateFix.size() == 1 + ? fix.second->diagnose(*fix.first, /*asNote=*/false) + : fix.second->diagnoseForAmbiguity(aggregateFix); + } + + auto &DE = cs.getASTContext().Diags; + + auto *decl = ambiguity->choices.front().getDeclOrNull(); + if (!decl) + return false; + + auto *commonCalleeLocator = ambiguity->locator; + + bool diagnosed = true; + { + DiagnosticTransaction transaction(DE); + + auto commonAnchor = commonCalleeLocator->getAnchor(); + if (auto *callExpr = getAsExpr(commonAnchor)) + commonAnchor = callExpr->getDirectCallee(); + + const auto name = decl->getName(); + + // Emit an error message for the ambiguity. + if (name.isOperator()) { + auto *anchor = castToExpr(commonCalleeLocator->getAnchor()); + + // If operator is "applied" e.g. `1 + 2` there are tailored + // diagnostics in case of ambiguity, but if it's referenced + // e.g. `arr.sort(by: <)` it's better to produce generic error + // and a note per candidate. + if (auto *parentExpr = cs.getParentExpr(anchor)) { + if (isa(parentExpr)) { + diagnoseOperatorAmbiguity(cs, name.getBaseIdentifier(), solutions, + commonCalleeLocator); + return true; + } + } + + DE.diagnose(anchor->getLoc(), diag::no_overloads_match_exactly_in_call, + /*isApplication=*/false, decl->getDescriptiveKind(), + name.isSpecial(), name.getBaseName()); + } else { + bool isApplication = + llvm::any_of(cs.ArgumentInfos, [&](const auto &argInfo) { + return argInfo.first->getAnchor() == commonAnchor; + }); + + DE.diagnose(getLoc(commonAnchor), + diag::no_overloads_match_exactly_in_call, isApplication, + decl->getDescriptiveKind(), name.isSpecial(), + name.getBaseName()); + } + + // Produce candidate notes + SmallPtrSet distinctChoices; + llvm::SmallSet candidateTypes; + for (const auto &solution : solutions) { + auto overload = solution.getOverloadChoice(commonCalleeLocator); + auto *decl = overload.choice.getDecl(); + auto type = solution.simplifyType(overload.openedType); + // Skip if we've already produced a note for this overload + if (!distinctChoices.insert(decl).second) + continue; + + if (solution.Fixes.size() == 1) { + diagnosed &= + solution.Fixes.front()->diagnose(solution, /*asNote*/ true); + } else if (llvm::all_of(solution.Fixes, [&](ConstraintFix *fix) { + return fix->getLocator() + ->findLast() + .hasValue(); + })) { + // All fixes have to do with arguments, so let's show the parameter + // lists. + auto *fn = type->getAs(); + assert(fn); + DE.diagnose(decl->getLoc(), diag::candidate_partial_match, + fn->getParamListAsString(fn->getParams())); + } else { + // Emit a general "found candidate" note + if (decl->getLoc().isInvalid()) { + if (candidateTypes.insert(type->getCanonicalType()).second) + DE.diagnose(getLoc(commonAnchor), diag::found_candidate_type, type); + } else { + DE.diagnose(decl->getLoc(), diag::found_candidate); + } + } + } + + // If not all of the fixes produced a note, we can't diagnose this. + if (!diagnosed) + transaction.abort(); + } + + return diagnosed; +} + bool ConstraintSystem::diagnoseAmbiguityWithFixes( SmallVectorImpl &solutions) { if (solutions.empty()) From 7d3f5e3775680e5032643a68c6be147fe08e6874 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 11 May 2020 13:39:24 -0700 Subject: [PATCH 03/22] [ConstraintSystem] Overhaul ambiguity diagnostics Refactor `diagnoseAmbiguityWithFixes` as follows: - Aggregate all of the available fixes based on callee locator; - For each ambiguous overload match aggregated fixes and diagnose; - Discard all of the fixes which have been already considered as part of overload diagnostics; - Diagnose remaining (uniqued based on kind + locator) fixes iff they appear in all of the solutions. --- lib/Sema/ConstraintSystem.cpp | 209 +++++++++------------------------- 1 file changed, 55 insertions(+), 154 deletions(-) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index e9ad71d986f2c..f91c463bcc1d9 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -3063,43 +3063,19 @@ diagnoseAmbiguityWithEphemeralPointers(ConstraintSystem &cs, } static bool diagnoseAmbiguity( - ConstraintSystem &cs, + ConstraintSystem &cs, const SolutionDiff::OverloadDiff &ambiguity, ArrayRef> aggregateFix, - SolutionDiff &solutionDiff, ArrayRef solutions) { + ArrayRef solutions) { + auto *locator = aggregateFix.front().second->getLocator(); auto anchor = aggregateFix.front().second->getAnchor(); - // Assignment failures are all about the source expression, because - // they treat destination as a contextual type. - if (auto *assignExpr = getAsExpr(anchor)) - anchor = assignExpr->getSrc(); - - if (auto *callExpr = getAsExpr(anchor)) { - if (!isa(callExpr->getDirectCallee())) - anchor = callExpr->getDirectCallee(); - } else if (auto *applyExpr = getAsExpr(anchor)) { - anchor = applyExpr->getFn(); - } - - auto ambiguity = - llvm::find_if(solutionDiff.overloads, - [&anchor](const SolutionDiff::OverloadDiff &diff) -> bool { - return diff.locator->getAnchor() == anchor; - }); - - if (ambiguity == solutionDiff.overloads.end()) { - auto &fix = aggregateFix.front(); - return aggregateFix.size() == 1 - ? fix.second->diagnose(*fix.first, /*asNote=*/false) - : fix.second->diagnoseForAmbiguity(aggregateFix); - } - auto &DE = cs.getASTContext().Diags; - auto *decl = ambiguity->choices.front().getDeclOrNull(); + auto *decl = ambiguity.choices.front().getDeclOrNull(); if (!decl) return false; - auto *commonCalleeLocator = ambiguity->locator; + auto *commonCalleeLocator = ambiguity.locator; bool diagnosed = true; { @@ -3112,7 +3088,11 @@ static bool diagnoseAmbiguity( const auto name = decl->getName(); // Emit an error message for the ambiguity. - if (name.isOperator()) { + if (locator->isForContextualType()) { + auto baseName = name.getBaseName(); + DE.diagnose(getLoc(commonAnchor), diag::no_candidates_match_result_type, + baseName.userFacingName(), cs.getContextualType(anchor)); + } else if (name.isOperator()) { auto *anchor = castToExpr(commonCalleeLocator->getAnchor()); // If operator is "applied" e.g. `1 + 2` there are tailored @@ -3217,145 +3197,66 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes( if (diagnoseAmbiguityWithEphemeralPointers(*this, solutions)) return true; - // Collect aggregated fixes from all solutions - using LocatorAndKind = std::pair; - using SolutionAndFix = std::pair; - llvm::SmallMapVector, 4> - aggregatedFixes; - for (const auto &solution : solutions) { - for (const auto *fix : solution.Fixes) { - LocatorAndKind key(fix->getLocator(), fix->getKind()); - aggregatedFixes[key].emplace_back(&solution, fix); - } - } + using Fix = std::pair; - // If there is an overload difference, let's see if there's a common callee - // locator for all of the fixes. - auto ambiguousOverload = llvm::find_if(solutionDiff.overloads, - [&](const auto &overloadDiff) { - return llvm::all_of(aggregatedFixes, [&](const auto &aggregatedFix) { - auto *locator = aggregatedFix.first.first; - auto anchor = locator->getAnchor(); - // Assignment failures are all about the source expression, because - // they treat destination as a contextual type. - if (auto *assignExpr = getAsExpr(anchor)) - anchor = assignExpr->getSrc(); - - if (auto *callExpr = getAsExpr(anchor)) { - if (!isa(callExpr->getDirectCallee())) - anchor = callExpr->getDirectCallee(); - } else if (auto *applyExpr = getAsExpr(anchor)) { - anchor = applyExpr->getFn(); - } + llvm::SmallSetVector fixes; + for (auto &solution : solutions) { + for (auto *fix : solution.Fixes) + fixes.insert({&solution, fix}); + } - return overloadDiff.locator->getAnchor() == anchor; - }); - }); + llvm::MapVector> fixesByCallee; - // If we didn't find an ambiguous overload, diagnose the common fixes. - if (ambiguousOverload == solutionDiff.overloads.end()) { - bool diagnosed = false; - for (auto fixes: aggregatedFixes) { - // A common fix must appear in all solutions - auto &commonFixes = fixes.second; - if (commonFixes.size() != solutions.size()) continue; + for (const auto &entry : fixes) { + const auto &solution = *entry.first; + const auto *fix = entry.second; + auto *calleeLocator = solution.getCalleeLocator(fix->getLocator()); - auto *firstFix = commonFixes.front().second; - diagnosed |= firstFix->diagnoseForAmbiguity(commonFixes); - } - return diagnosed; + fixesByCallee[calleeLocator].push_back({&solution, fix}); } - auto *commonCalleeLocator = ambiguousOverload->locator; - auto *decl = ambiguousOverload->choices.front().getDecl(); - assert(solverState); + bool diagnosed = false; - bool diagnosed = true; - { - DiagnosticTransaction transaction(getASTContext().Diags); + // All of the fixes which have been considered already. + llvm::SmallSetVector consideredFixes; - auto commonAnchor = commonCalleeLocator->getAnchor(); - if (auto *callExpr = getAsExpr(commonAnchor)) - commonAnchor = callExpr->getDirectCallee(); - auto &DE = getASTContext().Diags; - const auto name = decl->getName(); + for (const auto &ambiguity : solutionDiff.overloads) { + auto fixes = fixesByCallee.find(ambiguity.locator); + if (fixes == fixesByCallee.end()) + continue; - // Emit an error message for the ambiguity. - if (aggregatedFixes.size() == 1 && - aggregatedFixes.front().first.first->isForContextualType()) { - auto anchor = aggregatedFixes.front().first.first->getAnchor(); - auto baseName = name.getBaseName(); - DE.diagnose(getLoc(commonAnchor), diag::no_candidates_match_result_type, - baseName.userFacingName(), getContextualType(anchor)); - } else if (name.isOperator()) { - auto *anchor = castToExpr(commonCalleeLocator->getAnchor()); + auto aggregate = fixes->second; + diagnosed |= ::diagnoseAmbiguity(*this, ambiguity, aggregate, solutions); - // If operator is "applied" e.g. `1 + 2` there are tailored - // diagnostics in case of ambiguity, but if it's referenced - // e.g. `arr.sort(by: <)` it's better to produce generic error - // and a note per candidate. - if (auto *parentExpr = getParentExpr(anchor)) { - if (isa(parentExpr)) { - diagnoseOperatorAmbiguity(*this, name.getBaseIdentifier(), solutions, - commonCalleeLocator); - return true; - } - } + consideredFixes.insert(aggregate.begin(), aggregate.end()); + } - DE.diagnose(anchor->getLoc(), diag::no_overloads_match_exactly_in_call, - /*isApplication=*/false, decl->getDescriptiveKind(), - name.isSpecial(), name.getBaseName()); - } else { - bool isApplication = - llvm::any_of(ArgumentInfos, [&](const auto &argInfo) { - return argInfo.first->getAnchor() == commonAnchor; - }); + // Remove all of the fixes which have been attached to ambiguous + // overload choices. + fixes.set_subtract(consideredFixes); - DE.diagnose(getLoc(commonAnchor), - diag::no_overloads_match_exactly_in_call, isApplication, - decl->getDescriptiveKind(), name.isSpecial(), - name.getBaseName()); - } + llvm::MapVector, SmallVector> + fixesByKind; - // Produce candidate notes - SmallPtrSet distinctChoices; - llvm::SmallSet candidateTypes; - for (const auto &solution: solutions) { - auto overload = solution.getOverloadChoice(commonCalleeLocator); - auto *decl = overload.choice.getDecl(); - auto type = solution.simplifyType(overload.openedType); - // Skip if we've already produced a note for this overload - if (!distinctChoices.insert(decl).second) - continue; + for (const auto &entry : fixes) { + const auto *fix = entry.second; + fixesByKind[{fix->getKind(), fix->getLocator()}].push_back( + {entry.first, fix}); + } - if (solution.Fixes.size() == 1) { - diagnosed &= - solution.Fixes.front()->diagnose(solution, /*asNote*/ true); - } else if (llvm::all_of(solution.Fixes, - [&](ConstraintFix *fix) { - return fix->getLocator() - ->findLast().hasValue(); - })) { - // All fixes have to do with arguments, so let's show the parameter lists. - auto *fn = type->getAs(); - assert(fn); - DE.diagnose(decl->getLoc(), - diag::candidate_partial_match, - fn->getParamListAsString(fn->getParams())); - } else { - // Emit a general "found candidate" note - if (decl->getLoc().isInvalid()) { - if (candidateTypes.insert(type->getCanonicalType()).second) - DE.diagnose(getLoc(commonAnchor), diag::found_candidate_type, type); - } else { - DE.diagnose(decl->getLoc(), diag::found_candidate); - } - } + // If leftover fix is contained in all of the solutions let's + // diagnose it as ambiguity. + for (const auto &entry : fixesByKind) { + if (llvm::all_of(solutions, [&](const Solution &solution) -> bool { + return llvm::any_of( + solution.Fixes, [&](const ConstraintFix *fix) -> bool { + return std::make_pair(fix->getKind(), fix->getLocator()) == + entry.first; + }); + })) { + auto &aggregate = entry.second; + diagnosed |= aggregate.front().second->diagnoseForAmbiguity(aggregate); } - - // If not all of the fixes produced a note, we can't diagnose this. - if (!diagnosed) - transaction.abort(); } return diagnosed; From cf3f52c94dd3eda9262d02a777d33cb361f439cb Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 11 May 2020 13:53:12 -0700 Subject: [PATCH 04/22] [ConstraintSystem] NFC: Leave notes on the algorithm used by `diagnoseAmbiguityWithFixes` --- lib/Sema/ConstraintSystem.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index f91c463bcc1d9..cdef4c5c7399f 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -3197,6 +3197,16 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes( if (diagnoseAmbiguityWithEphemeralPointers(*this, solutions)) return true; + + // Algorithm is as follows: + // + // a. Aggregate all of the available fixes based on callee locator; + // b. For each ambiguous overload match aggregated fixes and diagnose; + // c. Discard all of the fixes which have been already considered + // as part of overload diagnostics; + // d. Diagnose remaining (uniqued based on kind + locator) fixes + // iff they appear in all of the solutions. + using Fix = std::pair; llvm::SmallSetVector fixes; From d9594c712a03782d9f83ea479e0983066e83f3f0 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 13 May 2020 19:42:23 -0700 Subject: [PATCH 05/22] [TypeChecker] NFC: Adjust tests improved by new approach for ambiguity diagnosis --- .../Sema/differentiable_func_type.swift | 14 +- test/ClangImporter/objc_factory_method.swift | 2 +- test/ClangImporter/objc_implicit_with.swift | 2 +- test/Constraints/argument_matching.swift | 165 +----------------- test/Constraints/closures.swift | 3 +- test/Constraints/diagnostics.swift | 12 +- test/Constraints/dynamic_lookup.swift | 2 +- test/Constraints/fixes.swift | 6 +- test/Constraints/function.swift | 6 +- test/Constraints/rdar42678836.swift | 3 +- test/Constraints/rdar44770297.swift | 7 +- test/Constraints/tuple.swift | 2 +- test/Misc/misc_diagnostics.swift | 6 +- test/Sema/diag_ambiguous_overloads.swift | 6 +- test/Serialization/builtin.swift | 2 +- test/decl/protocol/req/recursion.swift | 2 +- test/stdlib/UnsafePointerDiagnostics.swift | 12 +- test/stmt/foreach.swift | 3 +- 18 files changed, 47 insertions(+), 208 deletions(-) diff --git a/test/AutoDiff/Sema/differentiable_func_type.swift b/test/AutoDiff/Sema/differentiable_func_type.swift index 77a2b8f71bc75..b02d99b64393e 100644 --- a/test/AutoDiff/Sema/differentiable_func_type.swift +++ b/test/AutoDiff/Sema/differentiable_func_type.swift @@ -175,8 +175,10 @@ extension Vector: Differentiable where T: Differentiable { mutating func move(along direction: TangentVector) { fatalError() } } +// expected-note@+1 2 {{candidate requires that 'Int' conform to 'Differentiable' (requirement specified as 'T' == 'Differentiable')}} func inferredConformancesGeneric(_: @differentiable (Vector) -> Vector) {} +// expected-note @+5 2 {{candidate requires that 'Int' conform to 'Differentiable' (requirement specified as 'T' == 'Differentiable')}} // expected-error @+4 {{generic signature requires types 'Vector' and 'Vector.TangentVector' to be the same}} // expected-error @+3 {{generic signature requires types 'Vector' and 'Vector.TangentVector' to be the same}} // expected-error @+2 {{parameter type 'Vector' does not conform to 'Differentiable' and satisfy 'Vector == Vector.TangentVector', but the enclosing function type is '@differentiable(linear)'}} @@ -184,9 +186,9 @@ func inferredConformancesGeneric(_: @differentiable (Vector) -> Vector< func inferredConformancesGenericLinear(_: @differentiable(linear) (Vector) -> Vector) {} func nondiff(x: Vector) -> Vector {} -// expected-error @+1 {{global function 'inferredConformancesGeneric' requires that 'Int' conform to 'Differentiable}} +// expected-error @+1 {{no exact matches in call to global function 'inferredConformancesGeneric'}} inferredConformancesGeneric(nondiff) -// expected-error @+1 {{global function 'inferredConformancesGenericLinear' requires that 'Int' conform to 'Differentiable}} +// expected-error @+1 {{no exact matches in call to global function 'inferredConformancesGenericLinear'}} inferredConformancesGenericLinear(nondiff) func diff(x: Vector) -> Vector {} @@ -208,16 +210,16 @@ extension Linear: Differentiable where T: Differentiable, T == T.TangentVector { typealias TangentVector = Self } -// expected-note @+1 2 {{where 'T' = 'Int'}} +// expected-note @+1 2 {{candidate requires that 'Int' conform to 'Differentiable' (requirement specified as 'T' == 'Differentiable')}} func inferredConformancesGeneric(_: @differentiable (Linear) -> Linear) {} -// expected-note @+1 2 {{where 'T' = 'Int'}} +// expected-note @+1 2 {{candidate requires that 'Int' conform to 'Differentiable' (requirement specified as 'T' == 'Differentiable')}} func inferredConformancesGenericLinear(_: @differentiable(linear) (Linear) -> Linear) {} func nondiff(x: Linear) -> Linear {} -// expected-error @+1 {{global function 'inferredConformancesGeneric' requires that 'Int' conform to 'Differentiable}} +// expected-error @+1 {{no exact matches in call to global function 'inferredConformancesGeneric'}} inferredConformancesGeneric(nondiff) -// expected-error @+1 {{global function 'inferredConformancesGenericLinear' requires that 'Int' conform to 'Differentiable}} +// expected-error @+1 {{no exact matches in call to global function 'inferredConformancesGenericLinear'}} inferredConformancesGenericLinear(nondiff) func diff(x: Linear) -> Linear {} diff --git a/test/ClangImporter/objc_factory_method.swift b/test/ClangImporter/objc_factory_method.swift index cef3cae8707a2..bd873f512bb0b 100644 --- a/test/ClangImporter/objc_factory_method.swift +++ b/test/ClangImporter/objc_factory_method.swift @@ -75,7 +75,7 @@ func testNSErrorFactoryMethod(_ path: String) throws { } func testNonInstanceTypeFactoryMethod(_ s: String) { - _ = NSObjectFactory(string: s) // expected-error{{argument passed to call that takes no arguments}} + _ = NSObjectFactory(string: s) // expected-error{{no exact matches in call to initializer}} } func testUseOfFactoryMethod(_ queen: Bee) { diff --git a/test/ClangImporter/objc_implicit_with.swift b/test/ClangImporter/objc_implicit_with.swift index ec5702c83bd4f..449b9162a2ae8 100644 --- a/test/ClangImporter/objc_implicit_with.swift +++ b/test/ClangImporter/objc_implicit_with.swift @@ -43,7 +43,7 @@ func testNSErrorFactoryMethod(_ path: String) throws { } func testNonInstanceTypeFactoryMethod(_ s: String) { - _ = NSObjectFactory(string: s) // expected-error{{argument passed to call that takes no arguments}} + _ = NSObjectFactory(string: s) // expected-error{{no exact matches in call to initializer}} } func testUseOfFactoryMethod(_ queen: Bee) { diff --git a/test/Constraints/argument_matching.swift b/test/Constraints/argument_matching.swift index f316c06dab41a..8d6c1a197eb62 100644 --- a/test/Constraints/argument_matching.swift +++ b/test/Constraints/argument_matching.swift @@ -1465,167 +1465,8 @@ _ = acceptTuple2(tuple1) _ = acceptTuple2((1, "hello", 3.14159)) -func generic_and_missing_label(x: Int) {} -func generic_and_missing_label(x: T) {} +func generic_and_missing_label(x: Int) {} // expected-note {{incorrect labels for candidate (have: '(_:)', expected: '(x:)')}} +func generic_and_missing_label(x: T) {} // expected-note {{incorrect labels for candidate (have: '(_:)', expected: '(x:)')}} generic_and_missing_label(42) -// expected-error@-1 {{missing argument label 'x:' in call}} {{27-27=x: }} - -// ------------------------------------------- -// Curried functions -// ------------------------------------------- - -func f7(_ a: Int) -> (_ b: Int) -> Int { - return { b in a+b } -} - -_ = f7(1)(1) -f7(1.0)(2) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} - -f7(1)(1.0) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} -f7(1)(b: 1.0) // expected-error{{extraneous argument label 'b:' in call}} -// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Int'}} - -let f10 = f7(2) -_ = f10(1) -f10(10) // expected-warning {{result of call to function returning 'Int' is unused}} -f10(1.0) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} -f10(b: 1.0) // expected-error {{extraneous argument label 'b:' in call}} -// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Int'}} - - -class CurriedClass { - func method1() {} - func method2(_ a: Int) -> (_ b : Int) -> () { return { b in () } } - func method3(_ a: Int, b : Int) {} // expected-note 3 {{'method3(_:b:)' declared here}} -} - -let c = CurriedClass() -_ = c.method1 -c.method1(1) // expected-error {{argument passed to call that takes no arguments}} -_ = c.method2(1) -_ = c.method2(1.0) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} -c.method2(1)(2) -c.method2(1)(c: 2) // expected-error {{extraneous argument label 'c:' in call}} -c.method2(1)(c: 2.0) // expected-error {{extraneous argument label 'c:' in call}} -// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Int'}} -c.method2(1)(2.0) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} -c.method2(1.0)(2) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} -c.method2(1.0)(2.0) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} -// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Int'}} - -CurriedClass.method1(c)() -_ = CurriedClass.method1(c) -CurriedClass.method1(c)(1) // expected-error {{argument passed to call that takes no arguments}} -CurriedClass.method1(2.0)(1) // expected-error {{cannot convert value of type 'Double' to expected argument type 'CurriedClass'}} -// expected-error@-1:27 {{argument passed to call that takes no arguments}} - -CurriedClass.method2(c)(32)(b: 1) // expected-error{{extraneous argument label 'b:' in call}} -_ = CurriedClass.method2(c) -_ = CurriedClass.method2(c)(32) -_ = CurriedClass.method2(1,2) // expected-error {{extra argument in call}} -// expected-error@-1 {{instance member 'method2' cannot be used on type 'CurriedClass'; did you mean to use a value of this type instead?}} -CurriedClass.method2(c)(1.0)(b: 1) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} -// expected-error@-1 {{extraneous argument label 'b:' in call}} -CurriedClass.method2(c)(1)(1.0) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} -CurriedClass.method2(c)(2)(c: 1.0) // expected-error {{extraneous argument label 'c:'}} -// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Int'}} - -CurriedClass.method3(c)(32, b: 1) -_ = CurriedClass.method3(c) -_ = CurriedClass.method3(c)(1, 2) // expected-error {{missing argument label 'b:' in call}} {{32-32=b: }} -_ = CurriedClass.method3(c)(1, b: 2)(32) // expected-error {{cannot call value of non-function type '()'}} -_ = CurriedClass.method3(1, 2) // expected-error {{instance member 'method3' cannot be used on type 'CurriedClass'; did you mean to use a value of this type instead?}} -// expected-error@-1 {{missing argument label 'b:' in call}} -CurriedClass.method3(c)(1.0, b: 1) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} -CurriedClass.method3(c)(1) // expected-error {{missing argument for parameter 'b' in call}} -CurriedClass.method3(c)(c: 1.0) // expected-error {{incorrect argument labels in call (have 'c:', expected '_:b:')}} -// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Int'}} -// expected-error@-2 {{missing argument for parameter #1 in call}} - - -extension CurriedClass { - func f() { - method3(1, b: 2) - method3() // expected-error {{missing arguments for parameters #1, 'b' in call}} {{13-13=<#Int#>, b: <#Int#>}} - method3(42) // expected-error {{missing argument for parameter 'b' in call}} - method3(self) - // expected-error@-1:13 {{cannot convert value of type 'CurriedClass' to expected argument type 'Int'}} - // expected-error@-2:17 {{missing argument for parameter 'b' in call}} {{17-17=, b: <#Int#>}} - } -} - -extension CurriedClass { - func m1(_ a : Int, b : Int) {} - - func m2(_ a : Int) {} -} - -// QoI: "Extra argument" error when accidentally currying a method -CurriedClass.m1(2, b: 42) // expected-error {{instance member 'm1' cannot be used on type 'CurriedClass'; did you mean to use a value of this type instead?}} - - -// QoI: Confusing error message when calling an instance method as a class method -CurriedClass.m2(12) // expected-error {{instance member 'm2' cannot be used on type 'CurriedClass'; did you mean to use a value of this type instead?}} - -// ------------------------------------------- -// Multiple label errors -// ------------------------------------------- - -func testLabelErrorsBasic() { - func f(_ aa: Int, _ bb: Int, cc: Int, dd: Int, ee: Int, ff: Int) {} - - // 1 wrong - f(0, 1, ccx: 2, dd: 3, ee: 4, ff: 5) - // expected-error@-1 {{incorrect argument label in call (have '_:_:ccx:dd:ee:ff:', expected '_:_:cc:dd:ee:ff:')}} {{11-14=cc}} {{none}} - - // 1 missing - f(0, 1, 2, dd: 3, ee: 4, ff: 5) - // expected-error@-1 {{missing argument label 'cc:' in call}} {{11-11=cc: }} {{none}} - - // 1 extra - f(aa: 0, 1, cc: 2, dd: 3, ee: 4, ff: 5) - // expected-error@-1 {{extraneous argument label 'aa:' in call}} {{5-9=}} {{none}} - - // 1 ooo - f(0, 1, dd: 3, cc: 2, ee: 4, ff: 5) - // expected-error@-1 {{argument 'cc' must precede argument 'dd'}} {{16-23=}} {{11-11=cc: 2, }} {{none}} - - // 2 wrong - f(0, 1, ccx: 2, ddx: 3, ee: 4, ff: 5) - // expected-error@-1 {{incorrect argument labels in call (have '_:_:ccx:ddx:ee:ff:', expected '_:_:cc:dd:ee:ff:')}} {{11-14=cc}} {{19-22=dd}} {{none}} - - // 2 missing - f(0, 1, 2, 3, ee: 4, ff: 5) - // expected-error@-1 {{missing argument labels 'cc:dd:' in call}} {{11-11=cc: }} {{14-14=dd: }} {{none}} - - // 2 extra - f(aa: 0, bb: 1, cc: 2, dd: 3, ee: 4, ff: 5) - // expected-error@-1 {{extraneous argument labels 'aa:bb:' in call}} {{5-9=}} {{12-16=}} {{none}} - - // 2 ooo - f(0, 1, dd: 3, cc: 2, ff: 5, ee: 4) - // expected-error@-1 {{argument 'cc' must precede argument 'dd'}} {{16-23=}} {{11-11=cc: 2, }} {{none}} - - // 1 wrong + 1 missing - f(0, 1, ccx: 2, 3, ee: 4, ff: 5) - // expected-error@-1 {{incorrect argument labels in call (have '_:_:ccx:_:ee:ff:', expected '_:_:cc:dd:ee:ff:')}} {{11-14=cc}} {{19-19=dd: }} {{none}} - - // 1 wrong + 1 extra - f(aa: 0, 1, ccx: 2, dd: 3, ee: 4, ff: 5) - // expected-error@-1 {{incorrect argument labels in call (have 'aa:_:ccx:dd:ee:ff:', expected '_:_:cc:dd:ee:ff:')}} {{5-9=}} {{15-18=cc}} {{none}} - - // 1 wrong + 1 ooo - f(0, 1, ccx: 2, dd: 3, ff: 5, ee: 4) - // expected-error@-1 {{incorrect argument labels in call (have '_:_:ccx:dd:ff:ee:', expected '_:_:cc:dd:ee:ff:')}} {{11-14=cc}} {{26-28=ee}} {{33-35=ff}} {{none}} -} - -struct DiagnoseAllLabels { - func f(aa: Int, bb: Int, cc: Int..., dd: Int, ee: Int = 0, ff: Int = 0) {} - - func test() { - f(aax: 0, bbx: 1, cc: 21, 22, 23, dd: 3, ff: 5) // expected-error {{incorrect argument labels in call (have 'aax:bbx:cc:_:_:dd:ff:', expected 'aa:bb:cc:_:_:dd:ff:')}} {{7-10=aa}} {{15-18=bb}} {{none}} - - f(aax: 0, bbx: 1, dd: 3, ff: 5) // expected-error {{incorrect argument labels in call (have 'aax:bbx:dd:ff:', expected 'aa:bb:dd:ff:')}} {{7-10=aa}} {{15-18=bb}} {{none}} - } -} +// expected-error@-1 {{no exact matches in call to global function 'generic_and_missing_label'}} diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift index 1b290fb44ca1e..29104fa24b268 100644 --- a/test/Constraints/closures.swift +++ b/test/Constraints/closures.swift @@ -562,7 +562,6 @@ r32432145 { _,_ in // rdar://problem/30106822 - Swift ignores type error in closure and presents a bogus error about the caller [1, 2].first { $0.foo = 3 } // expected-error@-1 {{value of type 'Int' has no member 'foo'}} -// expected-error@-2 {{cannot convert value of type '()' to closure result type 'Bool'}} // rdar://problem/32433193, SR-5030 - Higher-order function diagnostic mentions the wrong contextual type conversion problem protocol A_SR_5030 { @@ -827,7 +826,7 @@ func rdar_40537960() { } var arr: [S] = [] - _ = A(arr, fn: { L($0.v) }) // expected-error {{cannot convert value of type 'L' to closure result type 'R

'}} + _ = A(arr, fn: { L($0.v) }) // expected-error@-1 {{generic parameter 'P' could not be inferred}} // expected-note@-2 {{explicitly specify the generic arguments to fix this issue}} {{8-8=<[S], <#P: P_40537960#>>}} } diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index 0cda84772d554..021d4461a480b 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -407,8 +407,9 @@ enum Color { static var svar: Color { return .Red } } -let _: (Int, Color) = [1,2].map({ ($0, .Unknown("")) }) // expected-error {{cannot convert value of type 'Array<(Int, _)>' to specified type '(Int, Color)'}} -// expected-error@-1 {{cannot infer contextual base in reference to member 'Unknown'}} +let _: (Int, Color) = [1,2].map({ ($0, .Unknown("")) }) +// expected-error@-1 {{no 'map' candidates produce the expected contextual result type '(Int, Color)'}} +// expected-note@-2 {{found candidate with type '((Int) throws -> (Int, _)) throws -> Array<(Int, _)>'}} let _: [(Int, Color)] = [1,2].map({ ($0, .Unknown("")) })// expected-error {{missing argument label 'description:' in call}} @@ -1248,10 +1249,9 @@ func f11(_ n: Int) {} func f11(_ n: T, _ f: @escaping (T) -> T) {} // expected-note {{where 'T' = 'Int'}} f11(3, f4) // expected-error {{global function 'f11' requires that 'Int' conform to 'P2'}} -// FIXME: Arguably we should also prefer the conformance failure in this case. -let f12: (Int) -> Void = { _ in } -func f12(_ n: T, _ f: @escaping (T) -> T) {} -f12(3, f4)// expected-error {{extra argument in call}} +let f12: (Int) -> Void = { _ in } // expected-note {{candidate '(Int) -> Void' requires 1 argument, but 2 were provided}} +func f12(_ n: T, _ f: @escaping (T) -> T) {} // expected-note {{candidate requires that 'Int' conform to 'P2' (requirement specified as 'T' == 'P2')}} +f12(3, f4)// expected-error {{no exact matches in call to global function 'f12'}} // SR-12242 struct SR_12242_R {} diff --git a/test/Constraints/dynamic_lookup.swift b/test/Constraints/dynamic_lookup.swift index ce4398116c275..cea5680ae5e0b 100644 --- a/test/Constraints/dynamic_lookup.swift +++ b/test/Constraints/dynamic_lookup.swift @@ -338,7 +338,7 @@ func testOverloadedWithUnavailable(ao: AnyObject) { func dynamicInitCrash(ao: AnyObject.Type) { let sdk = ao.init(blahblah: ()) - // expected-error@-1 {{incorrect argument label in call (have 'blahblah:', expected 'toMemory:')}} + // expected-error@-1 {{no exact matches in call to initializer}} } // Test that we correctly diagnose ambiguity for different typed members available diff --git a/test/Constraints/fixes.swift b/test/Constraints/fixes.swift index 8a8aeb82c55ba..4abb3c747420b 100644 --- a/test/Constraints/fixes.swift +++ b/test/Constraints/fixes.swift @@ -358,8 +358,6 @@ func testKeyPathSubscriptArgFixes(_ fn: @escaping () -> Int) { } func sr12426(a: Any, _ str: String?) { - a == str // expected-error {{cannot convert value of type 'Any' to expected argument type 'String'}} - // expected-error@-1 {{value of optional type 'String?' must be unwrapped to a value of type 'String'}} - // expected-note@-2 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} - // expected-note@-3 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} + a == str // expected-error {{binary operator '==' cannot be applied to operands of type 'Any' and 'String?'}} + // expected-note@-1 {{overloads for '==' exist with these partially matching parameter lists: (String, String)}} } diff --git a/test/Constraints/function.swift b/test/Constraints/function.swift index 16d0bf2455fce..429b4dc865ee4 100644 --- a/test/Constraints/function.swift +++ b/test/Constraints/function.swift @@ -62,12 +62,12 @@ func test() { // QoI: argument label mismatches produce not-great diagnostic class A { - func a(_ text:String) { + func a(_ text:String) { // expected-note {{incorrect labels for candidate (have: '(text:)', expected: '(_:)')}} } - func a(_ text:String, something:Int?=nil) { + func a(_ text:String, something:Int?=nil) { // expected-note {{incorrect labels for candidate (have: '(text:)', expected: '(_:)')}} } } -A().a(text:"sometext") // expected-error{{extraneous argument label 'text:' in call}}{{7-12=}} +A().a(text:"sometext") // expected-error{{no exact matches in call to instance method 'a'}} // QoI: incorrect diagnostic when argument to print has the wrong type diff --git a/test/Constraints/rdar42678836.swift b/test/Constraints/rdar42678836.swift index ff9ebe2d9b1cc..016c0cc56896f 100644 --- a/test/Constraints/rdar42678836.swift +++ b/test/Constraints/rdar42678836.swift @@ -1,5 +1,6 @@ // RUN: %target-typecheck-verify-swift func foo(chr: Character) -> String { - return String(repeating: String(chr)) // expected-error {{missing argument for parameter 'count' in call}} {{39-39=, count: <#Int#>}} + return String(repeating: String(chr)) // expected-error {{no exact matches in call to initializer}} + // expected-note@-1 {{candidate has partially matching parameter list (repeating: String, count: Int)}} } diff --git a/test/Constraints/rdar44770297.swift b/test/Constraints/rdar44770297.swift index 82d96f7459112..664413a00a40b 100644 --- a/test/Constraints/rdar44770297.swift +++ b/test/Constraints/rdar44770297.swift @@ -4,11 +4,8 @@ protocol P { associatedtype A } -func foo(_: () throws -> T) -> T.A? { // expected-note {{where 'T' = 'Never'}} +func foo(_: () throws -> T) -> T.A? { fatalError() } -let _ = foo() {fatalError()} & nil // expected-error {{global function 'foo' requires that 'Never' conform to 'P'}} -// expected-error@-1 {{value of optional type 'Never.A?' must be unwrapped to a value of type 'Never.A'}} -// expected-note@-2 {{force-unwrap}} -// expected-note@-3 {{coalesce using '??'}} +let _ = foo() {fatalError()} & nil // expected-error {{binary operator '&' cannot be applied to operands of type 'Never.A?' and '_'}} diff --git a/test/Constraints/tuple.swift b/test/Constraints/tuple.swift index c452ea7b2b335..ec557012b835a 100644 --- a/test/Constraints/tuple.swift +++ b/test/Constraints/tuple.swift @@ -181,7 +181,7 @@ variadicWithTrailingClosure(fn: +) func gcd_23700031(_ a: T, b: T) { var a = a var b = b - (a, b) = (b, a % b) // expected-error {{referencing operator function '%' on 'BinaryInteger' requires that 'T' conform to 'BinaryInteger'}} + (a, b) = (b, a % b) // expected-error {{binary operator '%' cannot be applied to two 'T' operands}} } // diff --git a/test/Misc/misc_diagnostics.swift b/test/Misc/misc_diagnostics.swift index b8f2e27b18b32..00de8f07aa469 100644 --- a/test/Misc/misc_diagnostics.swift +++ b/test/Misc/misc_diagnostics.swift @@ -114,11 +114,11 @@ func test17875634() { var col = 2 var coord = (row, col) - match += (1, 2) // expected-error{{cannot convert value of type '(Int, Int)' to expected argument type 'Array<(Int, Int)>'}} + match += (1, 2) // expected-error{{binary operator '+=' cannot be applied to operands of type '[(Int, Int)]' and '(Int, Int)'}} - match += (row, col) // expected-error{{cannot convert value of type '(Int, Int)' to expected argument type 'Array<(Int, Int)>'}} + match += (row, col) // expected-error{{binary operator '+=' cannot be applied to operands of type '[(Int, Int)]' and '(Int, Int)'}} - match += coord // expected-error{{cannot convert value of type '(Int, Int)' to expected argument type 'Array<(Int, Int)>'}} + match += coord // expected-error{{binary operator '+=' cannot be applied to operands of type '[(Int, Int)]' and '(Int, Int)'}} match.append(row, col) // expected-error {{instance method 'append' expects a single parameter of type '(Int, Int)'}} {{16-16=(}} {{24-24=)}} diff --git a/test/Sema/diag_ambiguous_overloads.swift b/test/Sema/diag_ambiguous_overloads.swift index 10712fc3531c3..1869bdf55120b 100644 --- a/test/Sema/diag_ambiguous_overloads.swift +++ b/test/Sema/diag_ambiguous_overloads.swift @@ -51,10 +51,10 @@ func testDiagnoseForAmbiguityCrash(schools: [School]) { class DefaultValue { static func foo(_ a: Int) {} - static func foo(_ a: Int, _ b: Int = 1) {} - static func foo(_ a: Int, _ b: Int = 1, _ c: Int = 2) {} + static func foo(_ a: Int, _ b: Int = 1) {} // expected-note {{candidate expects value of type 'Int' for parameter #1}} + static func foo(_ a: Int, _ b: Int = 1, _ c: Int = 2) {} // expected-note {{candidate expects value of type 'Int' for parameter #1}} } -DefaultValue.foo(1.0, 1) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} +DefaultValue.foo(1.0, 1) // expected-error {{no exact matches in call to static method 'foo'}} class Variadic { diff --git a/test/Serialization/builtin.swift b/test/Serialization/builtin.swift index 3dc709ca2cef3..cce143203088b 100644 --- a/test/Serialization/builtin.swift +++ b/test/Serialization/builtin.swift @@ -11,4 +11,4 @@ var a : TheBuiltinInt64 // Check that it really is Builtin.Int64. var wrapped = Int64(a) // okay -var badWrapped = Int32(a) // expected-error{{initializer 'init(_:)' requires that 'TheBuiltinInt64' conform to 'BinaryInteger'}} +var badWrapped = Int32(a) // expected-error{{no exact matches in call to initializer}} diff --git a/test/decl/protocol/req/recursion.swift b/test/decl/protocol/req/recursion.swift index f9d9761ee5077..e6194f834759e 100644 --- a/test/decl/protocol/req/recursion.swift +++ b/test/decl/protocol/req/recursion.swift @@ -54,7 +54,7 @@ public struct S where A.T == S { // expected-error {{circular reference func g(a: S) { f(a: id(t: a)) - // expected-error@-1 {{cannot convert value of type 'S' to expected argument type 'A.T'}} + // expected-error@-1 {{conflicting arguments to generic parameter 'T' ('S' vs. 'A.T' (associated type of protocol 'P'))}} _ = S.self } diff --git a/test/stdlib/UnsafePointerDiagnostics.swift b/test/stdlib/UnsafePointerDiagnostics.swift index 7b654dcfdcc77..b41e5401218af 100644 --- a/test/stdlib/UnsafePointerDiagnostics.swift +++ b/test/stdlib/UnsafePointerDiagnostics.swift @@ -67,8 +67,8 @@ func unsafePointerConversionAvailability( _ = UnsafeMutablePointer(umpi) // expected-warning {{UnsafeMutablePointer has been replaced by UnsafeMutableRawPointer}} _ = UnsafeMutablePointer(umps) // expected-warning {{UnsafeMutablePointer has been replaced by UnsafeMutableRawPointer}} - _ = UnsafePointer(rp) // expected-error {{cannot convert value of type 'UnsafeRawPointer' to expected argument type 'Builtin.RawPointer'}} expected-warning {{UnsafePointer has been replaced by UnsafeRawPointer}} - _ = UnsafePointer(mrp) // expected-error {{cannot convert value of type 'UnsafeMutableRawPointer' to expected argument type 'Builtin.RawPointer'}} expected-warning {{UnsafePointer has been replaced by UnsafeRawPointer}} + _ = UnsafePointer(rp) // expected-error {{no exact matches in call to initializer}} expected-warning {{UnsafePointer has been replaced by UnsafeRawPointer}} + _ = UnsafePointer(mrp) // expected-error {{no exact matches in call to initializer}} expected-warning {{UnsafePointer has been replaced by UnsafeRawPointer}} _ = UnsafePointer(umpv) // expected-warning {{UnsafePointer has been replaced by UnsafeRawPointer}} _ = UnsafePointer(upv) // expected-warning {{UnsafePointer has been replaced by UnsafeRawPointer}} _ = UnsafePointer(umpi) // expected-warning {{UnsafePointer has been replaced by UnsafeRawPointer}} @@ -81,10 +81,10 @@ func unsafePointerConversionAvailability( _ = UnsafeMutablePointer(orp) // expected-error {{no exact matches in call to initializer}} _ = UnsafeMutablePointer(omrp) // expected-error {{no exact matches in call to initializer}} - _ = UnsafePointer(rp) // expected-error {{cannot convert value of type 'UnsafeRawPointer' to expected argument type 'Builtin.RawPointer'}} - _ = UnsafePointer(mrp) // expected-error {{cannot convert value of type 'UnsafeMutableRawPointer' to expected argument type 'Builtin.RawPointer'}} - _ = UnsafePointer(orp) // expected-error {{cannot convert value of type 'UnsafeRawPointer?' to expected argument type 'Builtin.RawPointer'}} - _ = UnsafePointer(omrp) // expected-error {{cannot convert value of type 'UnsafeMutableRawPointer?' to expected argument type 'Builtin.RawPointer'}} + _ = UnsafePointer(rp) // expected-error {{no exact matches in call to initializer}} + _ = UnsafePointer(mrp) // expected-error {{no exact matches in call to initializer}} + _ = UnsafePointer(orp) // expected-error {{no exact matches in call to initializer}} + _ = UnsafePointer(omrp) // expected-error {{no exact matches in call to initializer}} _ = UnsafePointer(ups) // expected-error {{cannot convert value of type 'UnsafePointer' to expected argument type 'UnsafePointer'}} // expected-note@-1 {{arguments to generic parameter 'Pointee' ('String' and 'Int') are expected to be equal}} diff --git a/test/stmt/foreach.swift b/test/stmt/foreach.swift index 8b7b8d0cea18d..2fe40f5d8aabc 100644 --- a/test/stmt/foreach.swift +++ b/test/stmt/foreach.swift @@ -68,7 +68,8 @@ func patterns(gir: GoodRange, gtr: GoodTupleIterator) { for (i, f) in gtr { sum = sum + i sumf = sumf + f - sum = sum + f // expected-error {{cannot convert value of type 'Float' to expected argument type 'Int'}} + sum = sum + f // expected-error {{binary operator '+' cannot be applied to operands of type 'Int' and 'Float'}} + // expected-note@-1 {{overloads for '+' exist with}} } for (i, _) : (Int, Float) in gtr { sum = sum + i } From 7641d9c6c89e91e98b238489750fa1df4c8c92f5 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 19 May 2020 18:43:21 -0700 Subject: [PATCH 06/22] [CSFix] Make it possible to diagnose r-value -> l-value fix for ambiguity --- lib/Sema/CSFix.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index 191bfd7170dcf..5a3692d23fdc1 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -369,6 +369,10 @@ class TreatRValueAsLValue final : public ConstraintFix { bool diagnose(const Solution &solution, bool asNote = false) const override; + bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { + return diagnose(*commonFixes.front().first); + } + static TreatRValueAsLValue *create(ConstraintSystem &cs, ConstraintLocator *locator); }; From ac2305e7f115a118bb8b701bf0153ea8a100383e Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 20 May 2020 18:05:57 -0700 Subject: [PATCH 07/22] [ConstraintSystem] Increase impact of fixes for some conditional requirements If there is a conditional requirement failure associated with member/function reference used in a call let's increase a score of a fix for such failure because it renders member/function unreachable in current context or with a given set of arguments. --- lib/Sema/CSSimplify.cpp | 14 ++++++++++++++ test/Constraints/bridging.swift | 2 +- test/Constraints/operator.swift | 2 +- test/Generics/conditional_conformances.swift | 4 ++-- test/Parse/pointer_conversion.swift.gyb | 2 +- test/stdlib/ArrayDiagnostics.swift | 2 +- 6 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index bea9edfe9a55b..8b85a2ca92692 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -1449,6 +1449,20 @@ assessRequirementFailureImpact(ConstraintSystem &cs, Type requirementType, if (!anchor) return impact; + // If this is a conditional requirement failure associated with a + // call, let's increase impact of the fix to show that such failure + // makes member/function unreachable in current context or with + // given arguments. + if (auto last = locator.last()) { + if (last->isConditionalRequirement()) { + if (auto *expr = getAsExpr(anchor)) { + auto *parent = cs.getParentExpr(expr); + if (parent && isa(parent)) + return 5; + } + } + } + // If this requirement is associated with a member reference and it // was possible to check it before overload choice is bound, that means // types came from the context (most likely Self, or associated type(s)) diff --git a/test/Constraints/bridging.swift b/test/Constraints/bridging.swift index e9424798d3c4f..5dcb206a1fc0d 100644 --- a/test/Constraints/bridging.swift +++ b/test/Constraints/bridging.swift @@ -180,7 +180,7 @@ func dictionaryToNSDictionary() { // In this case, we should not implicitly convert Dictionary to NSDictionary. struct NotEquatable {} func notEquatableError(_ d: Dictionary) -> Bool { - return d == d // expected-error{{operator function '==' requires that 'NotEquatable' conform to 'Equatable'}} + return d == d // expected-error{{referencing operator function '==' on 'Dictionary' requires that 'NotEquatable' conform to 'Equatable'}} } // NSString -> String diff --git a/test/Constraints/operator.swift b/test/Constraints/operator.swift index 6b2ffe10644c4..8c19035d5a8d2 100644 --- a/test/Constraints/operator.swift +++ b/test/Constraints/operator.swift @@ -220,7 +220,7 @@ func rdar46459603() { // expected-error@-1 {{referencing operator function '==' on 'Equatable' requires that 'Dictionary.Values' conform to 'Equatable'}} // expected-error@-2 {{cannot convert value of type '[E]' to expected argument type 'Dictionary.Values'}} _ = [arr.values] == [[e]] - // expected-error@-1 {{operator function '==' requires that 'Dictionary.Values' conform to 'Equatable'}} + // expected-error@-1 {{referencing operator function '==' on 'Array' requires that 'Dictionary.Values' conform to 'Equatable'}} // expected-error@-2 {{cannot convert value of type '[E]' to expected element type 'Dictionary.Values'}} } diff --git a/test/Generics/conditional_conformances.swift b/test/Generics/conditional_conformances.swift index 7aa6f7497ba1e..791d1a4b3ffff 100644 --- a/test/Generics/conditional_conformances.swift +++ b/test/Generics/conditional_conformances.swift @@ -413,9 +413,9 @@ extension Foo: P where Bar: P { extension BinaryInteger { var foo: Self { return self <= 1 - ? 1 + ? 1 // expected-error {{cannot convert return expression of type 'Int' to return type 'Self'}} : (2...self).reduce(1, *) - // expected-error@-1 {{referencing instance method 'reduce' on 'ClosedRange' requires that 'Self.Stride' conform to 'SignedInteger'}} + // expected-error@-1 {{cannot convert value of type 'Self' to expected argument type 'Int'}} {{20-20=Int(}} {{24-24=)}} } } diff --git a/test/Parse/pointer_conversion.swift.gyb b/test/Parse/pointer_conversion.swift.gyb index d2c8137b7f18e..cdc4a29901729 100644 --- a/test/Parse/pointer_conversion.swift.gyb +++ b/test/Parse/pointer_conversion.swift.gyb @@ -307,7 +307,7 @@ struct NotEquatable {} func arrayComparison(_ x: [NotEquatable], y: [NotEquatable], p: UnsafeMutablePointer) { var x = x // Don't allow implicit array-to-pointer conversions in operators. - let a: Bool = x == y // expected-error{{operator function '==' requires that 'NotEquatable' conform to 'Equatable'}} + let a: Bool = x == y // expected-error{{referencing operator function '==' on 'Array' requires that 'NotEquatable' conform to 'Equatable'}} let _: Bool = p == &x // Allowed! } diff --git a/test/stdlib/ArrayDiagnostics.swift b/test/stdlib/ArrayDiagnostics.swift index 2b6cf254d6c63..a13948e7f4b18 100644 --- a/test/stdlib/ArrayDiagnostics.swift +++ b/test/stdlib/ArrayDiagnostics.swift @@ -4,5 +4,5 @@ class NotEquatable {} func test_ArrayOfNotEquatableIsNotEquatable() { var a = [ NotEquatable(), NotEquatable() ] - if a == a {} // expected-error {{operator function '==' requires that 'NotEquatable' conform to 'Equatable'}} + if a == a {} // expected-error {{referencing operator function '==' on 'Array' requires that 'NotEquatable' conform to 'Equatable'}} } From 9067ed23cad79db9ad3ec4d35972f14bdbf96653 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 20 May 2020 20:12:43 -0700 Subject: [PATCH 08/22] [ConstraintSystem] Specialize diagnostic for `~=` to talk about expression pattern use --- lib/Sema/ConstraintSystem.cpp | 3 +++ test/Parse/switch.swift | 1 + 2 files changed, 4 insertions(+) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index cdef4c5c7399f..25947a7129189 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -2814,6 +2814,9 @@ static void diagnoseOperatorAmbiguity(ConstraintSystem &cs, operatorName.str()); return; } + } else if (operatorName.is("~=")) { + DE.diagnose(anchor->getLoc(), diag::cannot_match_expr_pattern_with_value, + lhsType, rhsType); } else { DE.diagnose(anchor->getLoc(), diag::cannot_apply_binop_to_args, operatorName.str(), lhsType, rhsType) diff --git a/test/Parse/switch.swift b/test/Parse/switch.swift index 6e0c190288d64..2b42e837965c8 100644 --- a/test/Parse/switch.swift +++ b/test/Parse/switch.swift @@ -336,6 +336,7 @@ func f1(x: String, y: Whichever) { case Whichever.buzz: // expected-error {{type 'Whichever' has no member 'buzz'}} break case Whichever.alias: // expected-error {{expression pattern of type 'Whichever' cannot match values of type 'String'}} + // expected-note@-1 {{overloads for '~=' exist with these partially matching parameter lists: (Substring, String)}} break default: break From b9aa70bc4fc79aff56bb4d76b3d6f9a5949268ac Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 8 Jun 2020 12:34:35 -0700 Subject: [PATCH 09/22] [ConstraintSystem] NFC/Debug: Log solutions before attempting to diagnose ambiguity with fixes --- lib/Sema/ConstraintSystem.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 25947a7129189..91026371376a5 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -3200,6 +3200,17 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes( if (diagnoseAmbiguityWithEphemeralPointers(*this, solutions)) return true; + if (isDebugMode()) { + auto &log = llvm::errs(); + log << "--- Ambiguity: Considering #" << solutions.size() + << " solutions with fixes ---\n"; + int i = 0; + for (auto &solution : solutions) { + log << "--- Solution #" << i++ << "---\n"; + solution.dump(log); + log << "\n"; + } + } // Algorithm is as follows: // From 7bbf9fe2793317a77f61de53ebe9d5f2ad7d3330 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 8 Jun 2020 13:04:58 -0700 Subject: [PATCH 10/22] [Diagnostics] If aggregate fix consists of identical fixes diagnose it specially If aggregate fix (based on callee locator) differs only in picked overload choices, let's diagnose that via `diagnoseForAmbiguity` associated with a particular fix kind all solutions share, that would produce a tailored diagnostic instead of the most general one. --- lib/Sema/CSFix.h | 12 ++++++++---- lib/Sema/ConstraintSystem.cpp | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index 5a3692d23fdc1..a0584f2c723f5 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -562,6 +562,10 @@ class ForceOptional final : public ContextualMismatch { bool diagnose(const Solution &solution, bool asNote = false) const override; + bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { + return diagnose(*commonFixes.front().first); + } + static ForceOptional *create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator); }; @@ -671,6 +675,10 @@ class GenericArgumentsMismatch final bool diagnose(const Solution &solution, bool asNote = false) const override; + bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { + return diagnose(*commonFixes.front().first); + } + static GenericArgumentsMismatch *create(ConstraintSystem &cs, Type actual, Type required, llvm::ArrayRef mismatches, @@ -1531,10 +1539,6 @@ class IgnoreContextualType : public ContextualMismatch { bool diagnose(const Solution &solution, bool asNote = false) const override; - bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { - return diagnose(*commonFixes.front().first); - } - static IgnoreContextualType *create(ConstraintSystem &cs, Type resultTy, Type specifiedTy, ConstraintLocator *locator); diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 91026371376a5..de6ebf0c2a53f 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -3074,6 +3074,20 @@ static bool diagnoseAmbiguity( auto &DE = cs.getASTContext().Diags; + { + auto fixKind = aggregateFix.front().second->getKind(); + if (llvm::all_of( + aggregateFix, [&](const std::pair &entry) { + auto &fix = entry.second; + return fix->getKind() == fixKind && fix->getLocator() == locator; + })) { + auto *primaryFix = aggregateFix.front().second; + if (primaryFix->diagnoseForAmbiguity(aggregateFix)) + return true; + } + } + auto *decl = ambiguity.choices.front().getDeclOrNull(); if (!decl) return false; @@ -3234,6 +3248,7 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes( for (const auto &entry : fixes) { const auto &solution = *entry.first; const auto *fix = entry.second; + auto *calleeLocator = solution.getCalleeLocator(fix->getLocator()); fixesByCallee[calleeLocator].push_back({&solution, fix}); From b0070f57397f519d2f4f1fb668aa80f6f7ded086 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 9 Jun 2020 16:33:54 -0700 Subject: [PATCH 11/22] [Diagnostics] Check whether all contextual mismatches has the same type before diagnosing ambiguity Instead of requiring sub-classes of `ContextualMismatch` to implement `diagnoseForAmbiguity` let's implement it directly on `ContextualMismatch` itself and check whether all of the aggregated fixes have same types on both sides and if so, diagnose as-if it was a single fix. --- lib/Sema/CSFix.cpp | 27 ++++++++++++++++++++ lib/Sema/CSFix.h | 10 ++------ test/ClangImporter/objc_factory_method.swift | 2 +- test/ClangImporter/objc_implicit_with.swift | 2 +- test/Constraints/diagnostics.swift | 3 +-- test/Constraints/optional.swift | 3 +-- test/Constraints/patterns.swift | 4 +-- test/Constraints/rdar42678836.swift | 3 +-- test/Constraints/rdar44770297.swift | 4 ++- test/Sema/diag_ambiguous_overloads.swift | 6 ++--- test/attr/attr_dynamic_member_lookup.swift | 4 +-- test/decl/subscript/subscripting.swift | 12 ++++----- test/expr/expressions.swift | 1 - test/expr/unary/keypath/keypath.swift | 2 +- test/stmt/foreach.swift | 3 +-- test/type/types.swift | 9 +------ 16 files changed, 50 insertions(+), 45 deletions(-) diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index d638fb8c9e10d..814e84f5cc1d6 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -252,6 +252,33 @@ bool ContextualMismatch::diagnose(const Solution &solution, bool asNote) const { return failure.diagnose(asNote); } +bool ContextualMismatch::diagnoseForAmbiguity( + CommonFixesArray commonFixes) const { + auto getTypes = + [&](const std::pair &entry) + -> std::pair { + auto &solution = *entry.first; + auto *fix = static_cast(entry.second); + + return {solution.simplifyType(fix->getFromType()), + solution.simplifyType(fix->getToType())}; + }; + + auto etalonTypes = getTypes(commonFixes.front()); + if (llvm::all_of( + commonFixes, + [&](const std::pair &entry) { + auto types = getTypes(entry); + return etalonTypes.first->isEqual(types.first) && + etalonTypes.second->isEqual(types.second); + })) { + const auto &primary = commonFixes.front(); + return primary.second->diagnose(*primary.first, /*aNote=*/false); + } + + return false; +} + ContextualMismatch *ContextualMismatch::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) { diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index a0584f2c723f5..c34e53a74ad46 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -526,6 +526,8 @@ class ContextualMismatch : public ConstraintFix { bool diagnose(const Solution &solution, bool asNote = false) const override; + bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override; + static ContextualMismatch *create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator); }; @@ -562,10 +564,6 @@ class ForceOptional final : public ContextualMismatch { bool diagnose(const Solution &solution, bool asNote = false) const override; - bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { - return diagnose(*commonFixes.front().first); - } - static ForceOptional *create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator); }; @@ -675,10 +673,6 @@ class GenericArgumentsMismatch final bool diagnose(const Solution &solution, bool asNote = false) const override; - bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { - return diagnose(*commonFixes.front().first); - } - static GenericArgumentsMismatch *create(ConstraintSystem &cs, Type actual, Type required, llvm::ArrayRef mismatches, diff --git a/test/ClangImporter/objc_factory_method.swift b/test/ClangImporter/objc_factory_method.swift index bd873f512bb0b..cef3cae8707a2 100644 --- a/test/ClangImporter/objc_factory_method.swift +++ b/test/ClangImporter/objc_factory_method.swift @@ -75,7 +75,7 @@ func testNSErrorFactoryMethod(_ path: String) throws { } func testNonInstanceTypeFactoryMethod(_ s: String) { - _ = NSObjectFactory(string: s) // expected-error{{no exact matches in call to initializer}} + _ = NSObjectFactory(string: s) // expected-error{{argument passed to call that takes no arguments}} } func testUseOfFactoryMethod(_ queen: Bee) { diff --git a/test/ClangImporter/objc_implicit_with.swift b/test/ClangImporter/objc_implicit_with.swift index 449b9162a2ae8..ec5702c83bd4f 100644 --- a/test/ClangImporter/objc_implicit_with.swift +++ b/test/ClangImporter/objc_implicit_with.swift @@ -43,7 +43,7 @@ func testNSErrorFactoryMethod(_ path: String) throws { } func testNonInstanceTypeFactoryMethod(_ s: String) { - _ = NSObjectFactory(string: s) // expected-error{{no exact matches in call to initializer}} + _ = NSObjectFactory(string: s) // expected-error{{argument passed to call that takes no arguments}} } func testUseOfFactoryMethod(_ queen: Bee) { diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index 021d4461a480b..243c199483d02 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -408,8 +408,7 @@ enum Color { } let _: (Int, Color) = [1,2].map({ ($0, .Unknown("")) }) -// expected-error@-1 {{no 'map' candidates produce the expected contextual result type '(Int, Color)'}} -// expected-note@-2 {{found candidate with type '((Int) throws -> (Int, _)) throws -> Array<(Int, _)>'}} +// expected-error@-1 {{cannot convert value of type 'Array<(Int, _)>' to specified type '(Int, Color)'}} let _: [(Int, Color)] = [1,2].map({ ($0, .Unknown("")) })// expected-error {{missing argument label 'description:' in call}} diff --git a/test/Constraints/optional.swift b/test/Constraints/optional.swift index d3bf1c65a1121..5e21951a8ed74 100644 --- a/test/Constraints/optional.swift +++ b/test/Constraints/optional.swift @@ -424,8 +424,7 @@ func test_force_unwrap_not_being_too_eager() { // rdar://problem/57097401 func invalidOptionalChaining(a: Any) { a == "="? // expected-error {{cannot use optional chaining on non-optional value of type 'String'}} - // expected-error@-1 {{value of protocol type 'Any' cannot conform to 'Equatable'; only struct/enum/class types can conform to protocols}} - // expected-note@-2 {{requirement from conditional conformance of 'Any?' to 'Equatable'}} + // expected-error@-1 {{cannot convert value of type 'Any' to expected argument type 'Any.Type?'}} } // SR-12309 - Force unwrapping 'nil' compiles without warning diff --git a/test/Constraints/patterns.swift b/test/Constraints/patterns.swift index d0ca8f7582397..5468e620f0827 100644 --- a/test/Constraints/patterns.swift +++ b/test/Constraints/patterns.swift @@ -274,9 +274,7 @@ struct StaticMembers: Equatable { static var optProp: Optional = StaticMembers() static func method(_: Int) -> StaticMembers { return prop } - // expected-note@-1 {{found candidate with type '(Int) -> StaticMembers'}} static func method(withLabel: Int) -> StaticMembers { return prop } - // expected-note@-1 {{found candidate with type '(Int) -> StaticMembers'}} static func optMethod(_: Int) -> StaticMembers? { return optProp } static func ==(x: StaticMembers, y: StaticMembers) -> Bool { return true } @@ -301,7 +299,7 @@ switch staticMembers { // TODO: repeated error message case .optProp: break // expected-error* {{not unwrapped}} - case .method: break // expected-error{{no exact matches in reference to static method 'method'}} + case .method: break // expected-error{{member 'method' expects argument of type 'Int'}} case .method(0): break case .method(_): break // expected-error{{'_' can only appear in a pattern}} case .method(let x): break // expected-error{{cannot appear in an expression}} diff --git a/test/Constraints/rdar42678836.swift b/test/Constraints/rdar42678836.swift index 016c0cc56896f..ff9ebe2d9b1cc 100644 --- a/test/Constraints/rdar42678836.swift +++ b/test/Constraints/rdar42678836.swift @@ -1,6 +1,5 @@ // RUN: %target-typecheck-verify-swift func foo(chr: Character) -> String { - return String(repeating: String(chr)) // expected-error {{no exact matches in call to initializer}} - // expected-note@-1 {{candidate has partially matching parameter list (repeating: String, count: Int)}} + return String(repeating: String(chr)) // expected-error {{missing argument for parameter 'count' in call}} {{39-39=, count: <#Int#>}} } diff --git a/test/Constraints/rdar44770297.swift b/test/Constraints/rdar44770297.swift index 664413a00a40b..8d0b128b9e136 100644 --- a/test/Constraints/rdar44770297.swift +++ b/test/Constraints/rdar44770297.swift @@ -8,4 +8,6 @@ func foo(_: () throws -> T) -> T.A? { fatalError() } -let _ = foo() {fatalError()} & nil // expected-error {{binary operator '&' cannot be applied to operands of type 'Never.A?' and '_'}} +let _ = foo() {fatalError()} & nil // expected-error {{value of optional type 'Never.A?' must be unwrapped to a value of type 'Never.A'}} +// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} +// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} diff --git a/test/Sema/diag_ambiguous_overloads.swift b/test/Sema/diag_ambiguous_overloads.swift index 1869bdf55120b..10712fc3531c3 100644 --- a/test/Sema/diag_ambiguous_overloads.swift +++ b/test/Sema/diag_ambiguous_overloads.swift @@ -51,10 +51,10 @@ func testDiagnoseForAmbiguityCrash(schools: [School]) { class DefaultValue { static func foo(_ a: Int) {} - static func foo(_ a: Int, _ b: Int = 1) {} // expected-note {{candidate expects value of type 'Int' for parameter #1}} - static func foo(_ a: Int, _ b: Int = 1, _ c: Int = 2) {} // expected-note {{candidate expects value of type 'Int' for parameter #1}} + static func foo(_ a: Int, _ b: Int = 1) {} + static func foo(_ a: Int, _ b: Int = 1, _ c: Int = 2) {} } -DefaultValue.foo(1.0, 1) // expected-error {{no exact matches in call to static method 'foo'}} +DefaultValue.foo(1.0, 1) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} class Variadic { diff --git a/test/attr/attr_dynamic_member_lookup.swift b/test/attr/attr_dynamic_member_lookup.swift index 06c810448855d..f13c6913c7a4b 100644 --- a/test/attr/attr_dynamic_member_lookup.swift +++ b/test/attr/attr_dynamic_member_lookup.swift @@ -600,9 +600,7 @@ func keypath_with_subscripts(_ arr: SubscriptLens<[Int]>, func keypath_with_incorrect_return_type(_ arr: Lens>) { for idx in 0..' conform to 'Strideable'}} - // expected-error@-2 {{cannot convert value of type 'Int' to expected argument type 'Lens'}} - // expected-error@-3 {{referencing operator function '..<' on 'Comparable' requires that 'Lens' conform to 'Comparable'}} + // expected-error@-1 {{cannot convert value of type 'Int' to expected argument type 'Lens'}} let _ = arr[idx] } } diff --git a/test/decl/subscript/subscripting.swift b/test/decl/subscript/subscripting.swift index 170b8fc9baea3..667f8e511ca42 100644 --- a/test/decl/subscript/subscripting.swift +++ b/test/decl/subscript/subscripting.swift @@ -349,9 +349,9 @@ func testUnresolvedMemberSubscriptFixit(_ s0: GenSubscriptFixitTest) { struct SubscriptTest1 { subscript(keyword:String) -> Bool { return true } - // expected-note@-1 5 {{found this candidate}} expected-note@-1 {{found candidate with type 'Bool'}} + // expected-note@-1 5 {{found this candidate}} expected-note@-1 {{'subscript(_:)' produces 'Bool', not the expected contextual result type 'Int'}} subscript(keyword:String) -> String? {return nil } - // expected-note@-1 5 {{found this candidate}} expected-note@-1 {{found candidate with type 'String?'}} + // expected-note@-1 5 {{found this candidate}} expected-note@-1 {{'subscript(_:)' produces 'String?', not the expected contextual result type 'Int'}} subscript(arg: SubClass) -> Bool { return true } // expected-note {{declared here}} // expected-note@-1 2 {{found this candidate}} @@ -397,14 +397,12 @@ func testSubscript1(_ s1 : SubscriptTest1) { struct SubscriptTest2 { subscript(a : String, b : Int) -> Int { return 0 } // expected-note {{candidate expects value of type 'Int' for parameter #2}} - // expected-note@-1 {{declared here}} - // expected-note@-2 {{candidate has partially matching parameter list (String, Int)}} - subscript(a : String, b : String) -> Int { return 0 } // expected-note {{candidate expects value of type 'String' for parameter #2}} - // expected-note@-1 {{candidate has partially matching parameter list (String, String)}} + // expected-note@-1 2 {{declared here}} + subscript(a : String, b : String) -> Int { return 0 } // expected-note {{candidate expects value of type 'String' for parameter #2}} } func testSubscript1(_ s2 : SubscriptTest2) { - _ = s2["foo"] // expected-error {{no exact matches in call to subscript}} + _ = s2["foo"] // expected-error {{missing argument for parameter #2 in call}} let a = s2["foo", 1.0] // expected-error {{no exact matches in call to subscript}} diff --git a/test/expr/expressions.swift b/test/expr/expressions.swift index f6aa38a7c39c4..819d681894bec 100644 --- a/test/expr/expressions.swift +++ b/test/expr/expressions.swift @@ -791,7 +791,6 @@ func testNilCoalescePrecedence(cond: Bool, a: Int?, r: ClosedRange?) { // ?? should have lower precedence than range and arithmetic operators. let r1 = r ?? (0...42) // ok let r2 = (r ?? 0)...42 // not ok: expected-error 2 {{cannot convert value of type 'Int' to expected argument type 'ClosedRange'}} - // expected-error@-1 {{referencing operator function '...' on 'Comparable' requires that 'ClosedRange' conform to 'Comparable'}} let r3 = r ?? 0...42 // parses as the first one, not the second. diff --git a/test/expr/unary/keypath/keypath.swift b/test/expr/unary/keypath/keypath.swift index 449876f2c8b98..4495b4a6249fc 100644 --- a/test/expr/unary/keypath/keypath.swift +++ b/test/expr/unary/keypath/keypath.swift @@ -507,7 +507,7 @@ func testLabeledSubscript() { let k = \AA.[labeled: 0] // TODO: These ought to work without errors. - let _ = \AA.[keyPath: k] // expected-error {{extraneous argument label 'keyPath:' in call}} + let _ = \AA.[keyPath: k] // expected-error@-1 {{cannot convert value of type 'KeyPath' to expected argument type 'Int'}} let _ = \AA.[keyPath: \AA.[labeled: 0]] // expected-error {{extraneous argument label 'keyPath:' in call}} diff --git a/test/stmt/foreach.swift b/test/stmt/foreach.swift index 2fe40f5d8aabc..07441ed39f079 100644 --- a/test/stmt/foreach.swift +++ b/test/stmt/foreach.swift @@ -68,8 +68,7 @@ func patterns(gir: GoodRange, gtr: GoodTupleIterator) { for (i, f) in gtr { sum = sum + i sumf = sumf + f - sum = sum + f // expected-error {{binary operator '+' cannot be applied to operands of type 'Int' and 'Float'}} - // expected-note@-1 {{overloads for '+' exist with}} + sum = sum + f // expected-error {{cannot convert value of type 'Float' to expected argument type 'Int'}} {{17-17=Int(}} {{18-18=)}} } for (i, _) : (Int, Float) in gtr { sum = sum + i } diff --git a/test/type/types.swift b/test/type/types.swift index 7716a1582c3cf..135607476d43f 100644 --- a/test/type/types.swift +++ b/test/type/types.swift @@ -20,14 +20,7 @@ var d4 : () -> Int = { d2 } // expected-error{{function produces expected type if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) { var e0 : [Int] - e0[] // expected-error {{no exact matches in call to subscript}} - // expected-note@-1 {{candidate has partially matching parameter list (Int)}} - // expected-note@-2 {{candidate has partially matching parameter list (Range)}} - // expected-note@-3 {{candidate has partially matching parameter list ((UnboundedRange_) -> ())}} - // expected-note@-4 {{candidate has partially matching parameter list (RangeSet.Index>)}} - // expected-note@-5 {{candidate has partially matching parameter list (Range.Index>)}} - // expected-note@-6 {{candidate has partially matching parameter list ((UnboundedRange_) -> ())}} - // expected-note@-7 {{candidate has partially matching parameter list (RangeSet.Index>)}} + e0[] // expected-error {{missing argument for parameter #1 in call}} {{6-6=<#Int#>}} } var f0 : [Float] From 13b4fcc5e7c7131b41e0bed741cf4c8b6f65228f Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 10 Jun 2020 09:41:51 -0700 Subject: [PATCH 12/22] [Diagnostics] Diagnose ambiguity related to contextual type specifically --- lib/Sema/ConstraintSystem.cpp | 92 ++++++++++++++++++++++++++++++- test/Constraints/members.swift | 13 +++-- test/Constraints/overload.swift | 7 ++- test/Generics/function_defs.swift | 16 +++--- test/Parse/recovery.swift | 2 + 5 files changed, 111 insertions(+), 19 deletions(-) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index de6ebf0c2a53f..bcc664c3c11e1 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -3065,6 +3065,85 @@ diagnoseAmbiguityWithEphemeralPointers(ConstraintSystem &cs, return cs.diagnoseAmbiguity(solutions); } +static bool diagnoseAmbiguityWithContextualType( + ConstraintSystem &cs, SolutionDiff &solutionDiff, + ArrayRef> aggregateFix, + ArrayRef solutions) { + // Diagnose only if contextual failure is associated with every solution. + if (aggregateFix.size() < solutions.size()) + return false; + + auto getResultType = + [](const std::pair &entry) + -> Type { + auto &solution = *entry.first; + auto anchor = entry.second->getLocator()->getAnchor(); + return solution.simplifyType(solution.getType(anchor)); + }; + + auto resultType = getResultType(aggregateFix.front()); + // If right-hand side of the conversion (result of the the AST node) + // is the same across all of the solutions let's diagnose it as if + // it it as a single failure. + if (llvm::all_of( + aggregateFix, + [&](const std::pair &entry) { + return resultType->isEqual(getResultType(entry)); + })) { + auto &fix = aggregateFix.front(); + return fix.second->diagnose(*fix.first, /*asNote=*/false); + } + + // If result types are different it could only mean that this is an attempt + // to convert a reference to, or call of overloaded declaration to a + // particular type. + + auto &solution = *aggregateFix.front().first; + auto *locator = aggregateFix.front().second->getLocator(); + auto *calleeLocator = solution.getCalleeLocator(locator); + + auto result = + llvm::find_if(solutionDiff.overloads, + [&calleeLocator](const SolutionDiff::OverloadDiff &entry) { + return entry.locator == calleeLocator; + }); + + if (result == solutionDiff.overloads.end()) + return false; + + auto &DE = cs.getASTContext().Diags; + + auto anchor = locator->getAnchor(); + auto name = result->choices.front().getName(); + DE.diagnose(getLoc(anchor), diag::no_candidates_match_result_type, + name.getBaseName().userFacingName(), + cs.getContextualType(anchor)); + + for (const auto &solution : solutions) { + auto overload = solution.getOverloadChoice(calleeLocator); + if (auto *decl = overload.choice.getDeclOrNull()) { + auto loc = decl->getLoc(); + if (loc.isInvalid()) + continue; + + auto type = solution.simplifyType(overload.boundType); + + if (isExpr(anchor) || isExpr(anchor) || + (isExpr(anchor) && + castToExpr(anchor)->hasArguments())) { + auto fnType = type->castTo(); + DE.diagnose( + loc, diag::cannot_convert_candidate_result_to_contextual_type, + decl->getName(), fnType->getResult(), cs.getContextualType(anchor)); + } else { + DE.diagnose(loc, diag::found_candidate_type, type); + } + } + } + + return true; +} + static bool diagnoseAmbiguity( ConstraintSystem &cs, const SolutionDiff::OverloadDiff &ambiguity, ArrayRef> aggregateFix, @@ -3244,13 +3323,18 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes( } llvm::MapVector> fixesByCallee; + llvm::SmallVector contextualFixes; for (const auto &entry : fixes) { const auto &solution = *entry.first; const auto *fix = entry.second; - auto *calleeLocator = solution.getCalleeLocator(fix->getLocator()); + if (fix->getLocator()->isForContextualType()) { + contextualFixes.push_back({&solution, fix}); + continue; + } + auto *calleeLocator = solution.getCalleeLocator(fix->getLocator()); fixesByCallee[calleeLocator].push_back({&solution, fix}); } @@ -3270,6 +3354,12 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes( consideredFixes.insert(aggregate.begin(), aggregate.end()); } + if (diagnoseAmbiguityWithContextualType(*this, solutionDiff, contextualFixes, + solutions)) { + consideredFixes.insert(contextualFixes.begin(), contextualFixes.end()); + diagnosed |= true; + } + // Remove all of the fixes which have been attached to ambiguous // overload choices. fixes.set_subtract(consideredFixes); diff --git a/test/Constraints/members.swift b/test/Constraints/members.swift index 54763e96a9c8b..3f35c02bf6b01 100644 --- a/test/Constraints/members.swift +++ b/test/Constraints/members.swift @@ -617,12 +617,13 @@ func rdar50679161() { func rdar_50467583_and_50909555() { if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) { // rdar://problem/50467583 - let _: Set = [Int][] // expected-error {{no exact matches in call to subscript}} - // expected-note@-1 {{found candidate with type '(Int) -> Int'}} - // expected-note@-2 {{found candidate with type '(Range) -> ArraySlice'}} - // expected-note@-3 {{found candidate with type '((UnboundedRange_) -> ()) -> ArraySlice'}} - // expected-note@-4 {{found candidate with type '(RangeSet.Index>) -> DiscontiguousSlice<[Int]>' (aka '(RangeSet) -> DiscontiguousSlice>')}} - // expected-note@-5 {{found candidate with type '(Range.Index>) -> Slice<[Int]>' (aka '(Range) -> Slice>')}} + let _: Set = [Int][] // expected-error {{no 'subscript' candidates produce the expected contextual result type 'Set'}} + // expected-error@-1 {{no exact matches in call to subscript}} + // expected-note@-2 {{found candidate with type '(Int) -> Int'}} + // expected-note@-3 {{found candidate with type '(Range) -> ArraySlice'}} + // expected-note@-4 {{found candidate with type '((UnboundedRange_) -> ()) -> ArraySlice'}} + // expected-note@-5 {{found candidate with type '(RangeSet.Index>) -> DiscontiguousSlice<[Int]>' (aka '(RangeSet) -> DiscontiguousSlice>')}} + // expected-note@-6 {{found candidate with type '(Range.Index>) -> Slice<[Int]>' (aka '(Range) -> Slice>')}} } // rdar://problem/50909555 diff --git a/test/Constraints/overload.swift b/test/Constraints/overload.swift index 9877c41ec0ab8..b1fe98112c989 100644 --- a/test/Constraints/overload.swift +++ b/test/Constraints/overload.swift @@ -127,11 +127,12 @@ func test20886179(_ handlers: [(Int) -> Void], buttonIndex: Int) { // The problem here is that the call has a contextual result type incompatible // with *all* overload set candidates. This is not an ambiguity. -func overloaded_identity(_ a : Int) -> Int {} // expected-note {{found this candidate}} -func overloaded_identity(_ b : Float) -> Float {} // expected-note {{found this candidate}} +func overloaded_identity(_ a : Int) -> Int {} // expected-note {{'overloaded_identity' produces 'Int', not the expected contextual result type '()'}} expected-note {{'overloaded_identity' declared her}} +func overloaded_identity(_ b : Float) -> Float {} // expected-note {{'overloaded_identity' produces 'Float', not the expected contextual result type '()'}} func test_contextual_result_1() { - return overloaded_identity() // expected-error {{no exact matches in call to global function 'overloaded_identity'}} + return overloaded_identity() // expected-error {{missing argument for parameter #1 in call}} + // expected-error@-1 {{no 'overloaded_identity' candidates produce the expected contextual result type '()'}} } func test_contextual_result_2() { diff --git a/test/Generics/function_defs.swift b/test/Generics/function_defs.swift index db836e2641733..0a271eec4f2ae 100644 --- a/test/Generics/function_defs.swift +++ b/test/Generics/function_defs.swift @@ -78,9 +78,9 @@ protocol Overload { func f1(_: B) -> B // expected-note {{candidate expects value of type 'OtherOvl.B' for parameter #1}} func f2(_: Int) -> A // expected-note{{found this candidate}} func f2(_: Int) -> B // expected-note{{found this candidate}} - func f3(_: Int) -> Int // expected-note {{found this candidate}} - func f3(_: Float) -> Float // expected-note {{found this candidate}} - func f3(_: Self) -> Self // expected-note {{found this candidate}} + func f3(_: Int) -> Int // expected-note {{found candidate with type '(Int) -> Int'}} + func f3(_: Float) -> Float // expected-note {{found candidate with type '(Float) -> Float'}} + func f3(_: Self) -> Self // expected-note {{found candidate with type '(OtherOvl) -> OtherOvl'}} var prop : Self { get } } @@ -112,7 +112,7 @@ func testOverload(_ ovl: Ovl, ovl2: Ovl, var f3f : (Float) -> Float = ovl.f3 var f3ovl_1 : (Ovl) -> Ovl = ovl.f3 var f3ovl_2 : (Ovl) -> Ovl = ovl2.f3 - var f3ovl_3 : (Ovl) -> Ovl = other.f3 // expected-error{{no exact matches in reference to instance method 'f3'}} + var f3ovl_3 : (Ovl) -> Ovl = other.f3 // expected-error{{no 'f3' candidates produce the expected contextual result type '(Ovl) -> Ovl'}} var f3i_unbound : (Ovl) -> (Int) -> Int = Ovl.f3 var f3f_unbound : (Ovl) -> (Float) -> Float = Ovl.f3 @@ -131,7 +131,7 @@ protocol Subscriptable { func getIndex() -> Index func getValue() -> Value - subscript (index : Index) -> Value { get set } + subscript (index : Index) -> Value { get set } // expected-note {{found this candidate}} } protocol IntSubscriptable { @@ -139,7 +139,7 @@ protocol IntSubscriptable { func getElement() -> ElementType - subscript (index : Int) -> ElementType { get } + subscript (index : Int) -> ElementType { get } // expected-note {{found this candidate}} } func subscripting(_ t: T) { @@ -152,9 +152,7 @@ func subscripting(_ t: T) { element = t[17] t[42] = element // expected-error{{cannot assign through subscript: subscript is get-only}} - // Suggests the Int form because we prefer concrete matches to generic matches in diagnosis. - t[value] = 17 // expected-error{{cannot convert value of type 'T.Value' to expected argument type 'Int'}} - // expected-error@-1 {{cannot assign value of type 'Int' to subscript of type 'T.ElementType'}} + t[value] = 17 // expected-error{{no exact matches in call to subscript}} } //===----------------------------------------------------------------------===// diff --git a/test/Parse/recovery.swift b/test/Parse/recovery.swift index 4613e471ca9da..cac7706052ded 100644 --- a/test/Parse/recovery.swift +++ b/test/Parse/recovery.swift @@ -10,12 +10,14 @@ func garbage() -> () { var a : Int ) this line is invalid, but we will stop at the keyword below... // expected-error{{expected expression}} return a + "a" // expected-error{{binary operator '+' cannot be applied to operands of type 'Int' and 'String'}} expected-note {{overloads for '+' exist with these partially matching parameter lists: (Int, Int), (String, String)}} + // expected-error@-1 {{no '+' candidates produce the expected contextual result type '()'}} } func moreGarbage() -> () { ) this line is invalid, but we will stop at the declaration... // expected-error{{expected expression}} func a() -> Int { return 4 } return a() + "a" // expected-error{{binary operator '+' cannot be applied to operands of type 'Int' and 'String'}} expected-note {{overloads for '+' exist with these partially matching parameter lists: (Int, Int), (String, String)}} + // expected-error@-1 {{no '+' candidates produce the expected contextual result type '()'}} } From e2e57ada1be258751c1948b05b83a97e1bfc5f3c Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 10 Jun 2020 11:25:20 -0700 Subject: [PATCH 13/22] [ConstraintSystem] Turn 'omit ' into a contextual mismatch it is --- lib/Sema/CSFix.cpp | 9 +++++++-- lib/Sema/CSFix.h | 8 ++++---- lib/Sema/CSSimplify.cpp | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 814e84f5cc1d6..9f193e1e539c8 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -894,14 +894,19 @@ RemoveAddressOf *RemoveAddressOf::create(ConstraintSystem &cs, Type lhs, Type rh return new (cs.getAllocator()) RemoveAddressOf(cs, lhs, rhs, locator); } +RemoveReturn::RemoveReturn(ConstraintSystem &cs, Type resultTy, + ConstraintLocator *locator) + : ContextualMismatch(cs, FixKind::RemoveReturn, resultTy, + cs.getASTContext().TheEmptyTupleType, locator) {} + bool RemoveReturn::diagnose(const Solution &solution, bool asNote) const { ExtraneousReturnFailure failure(solution, getLocator()); return failure.diagnose(asNote); } -RemoveReturn *RemoveReturn::create(ConstraintSystem &cs, +RemoveReturn *RemoveReturn::create(ConstraintSystem &cs, Type resultTy, ConstraintLocator *locator) { - return new (cs.getAllocator()) RemoveReturn(cs, locator); + return new (cs.getAllocator()) RemoveReturn(cs, resultTy, locator); } bool CollectionElementContextualMismatch::diagnose(const Solution &solution, diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index c34e53a74ad46..5fd734bea71ac 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -1405,16 +1405,16 @@ class AllowInvalidRefInKeyPath final : public ConstraintFix { ConstraintLocator *locator); }; -class RemoveReturn final : public ConstraintFix { - RemoveReturn(ConstraintSystem &cs, ConstraintLocator *locator) - : ConstraintFix(cs, FixKind::RemoveReturn, locator) {} +class RemoveReturn final : public ContextualMismatch { + RemoveReturn(ConstraintSystem &cs, Type resultTy, ConstraintLocator *locator); public: std::string getName() const override { return "remove or omit return type"; } bool diagnose(const Solution &solution, bool asNote = false) const override; - static RemoveReturn *create(ConstraintSystem &cs, ConstraintLocator *locator); + static RemoveReturn *create(ConstraintSystem &cs, Type resultTy, + ConstraintLocator *locator); }; class CollectionElementContextualMismatch final : public ContextualMismatch { diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 8b85a2ca92692..979aefc069c87 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -3881,7 +3881,7 @@ bool ConstraintSystem::repairFailures( if (rhs->isVoid() && (purpose == CTP_ReturnStmt || purpose == CTP_ReturnSingleExpr)) { conversionsOrFixes.push_back( - RemoveReturn::create(*this, getConstraintLocator(locator))); + RemoveReturn::create(*this, lhs, getConstraintLocator(locator))); return true; } From b407f7cd68f34d2910deeefcbabce1e1ea649f81 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 10 Jun 2020 11:43:05 -0700 Subject: [PATCH 14/22] [ConstraintSystem] Avoid recording duplicate fixes for contextual type mismatch --- lib/Sema/CSSimplify.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 979aefc069c87..74f3f281a670c 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -3877,6 +3877,11 @@ bool ConstraintSystem::repairFailures( if (lhs->isTypeVariableOrMember() || rhs->isTypeVariableOrMember()) break; + // If there is already a fix for contextual failure, let's not + // record a duplicate one. + if (hasFixFor(getConstraintLocator(locator))) + return true; + auto purpose = getContextualTypePurpose(anchor); if (rhs->isVoid() && (purpose == CTP_ReturnStmt || purpose == CTP_ReturnSingleExpr)) { From d23b938331f797bf7d2e1e51b2ec55c434a3251d Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 11 Jun 2020 00:21:11 -0700 Subject: [PATCH 15/22] [Diagnostics] Implement `IgnoreAssignmentDestinationType::diagnoseForAmbiguity` For cases like this: ```swift struct X {} struct Y {} func overloaded(_ value: T) -> T { value } func overloaded(_ value: T) -> Int { 0 } func test(x: inout X, y: Y) { x = overloaded(y) } ``` Solver would record a `IgnoreAssignmentDestinationType` fix per overload, `diagnoseForAmbiguity` could be used to properly diagnose ambiguity cases like that. --- lib/Sema/CSFix.cpp | 37 +++++++++++++++++++ lib/Sema/CSFix.h | 2 + test/Generics/deduction.swift | 4 +- .../Inputs/opaque-result-types-client.swift | 6 +-- 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 9f193e1e539c8..84d13b6063ca4 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -1111,6 +1111,43 @@ bool IgnoreAssignmentDestinationType::diagnose(const Solution &solution, return failure.diagnose(asNote); } +bool IgnoreAssignmentDestinationType::diagnoseForAmbiguity( + CommonFixesArray commonFixes) const { + auto &cs = getConstraintSystem(); + + // If all of the types are the same let's try to diagnose + // this as if there is no ambiguity. + if (ContextualMismatch::diagnoseForAmbiguity(commonFixes)) + return true; + + auto *commonLocator = getLocator(); + auto *assignment = castToExpr(commonLocator->getAnchor()); + + auto &solution = *commonFixes.front().first; + auto *calleeLocator = solution.getCalleeLocator( + solution.getConstraintLocator(assignment->getSrc())); + auto overload = solution.getOverloadChoiceIfAvailable(calleeLocator); + if (!overload) + return false; + + auto memberName = overload->choice.getName().getBaseName(); + auto destType = solution.getType(assignment->getDest()); + + auto &DE = cs.getASTContext().Diags; + // TODO(diagnostics): It might be good to add a tailored diagnostic + // for cases like this instead of using "contextual" one. + DE.diagnose(assignment->getSrc()->getLoc(), + diag::no_candidates_match_result_type, + memberName.userFacingName(), + solution.simplifyType(destType)->getRValueType()); + + for (auto &entry : commonFixes) { + entry.second->diagnose(*entry.first, /*asNote=*/true); + } + + return true; +} + IgnoreAssignmentDestinationType * IgnoreAssignmentDestinationType::create(ConstraintSystem &cs, Type sourceTy, Type destTy, diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index 5fd734bea71ac..b160c45de367a 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -1550,6 +1550,8 @@ class IgnoreAssignmentDestinationType final : public ContextualMismatch { bool diagnose(const Solution &solution, bool asNote = false) const override; + bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override; + static IgnoreAssignmentDestinationType *create(ConstraintSystem &cs, Type sourceTy, Type destTy, ConstraintLocator *locator); diff --git a/test/Generics/deduction.swift b/test/Generics/deduction.swift index f3e4d4b70cfa2..1a90faddc21a8 100644 --- a/test/Generics/deduction.swift +++ b/test/Generics/deduction.swift @@ -25,7 +25,7 @@ func useIdentity(_ x: Int, y: Float, i32: Int32) { // Deduction where the result type and input type can get different results var xx : X, yy : Y xx = identity(yy) // expected-error{{cannot assign value of type 'Y' to type 'X'}} - xx = identity2(yy) // expected-error{{no exact matches in call to global function 'identity2'}} + xx = identity2(yy) // expected-error{{no 'identity2' candidates produce the expected contextual result type 'X'}} } func twoIdentical(_ x: T, _ y: T) -> T {} @@ -89,7 +89,7 @@ func testReturnTuple(_ x: Int, y: Float) { var _ : (Float, Float) = returnTuple(y) // QoI: Propagate contextual information in a call to operands - var _ : (Int, Float) = returnTuple(y) // expected-error{{cannot convert value of type 'Float' to expected argument type 'Int'}} + var _ : (Int, Float) = returnTuple(y) // expected-error{{conflicting arguments to generic parameter 'T' ('Float' vs. 'Int')}} } diff --git a/test/ModuleInterface/Inputs/opaque-result-types-client.swift b/test/ModuleInterface/Inputs/opaque-result-types-client.swift index 88671bd7cc6c6..8258bc3f8bb13 100644 --- a/test/ModuleInterface/Inputs/opaque-result-types-client.swift +++ b/test/ModuleInterface/Inputs/opaque-result-types-client.swift @@ -20,7 +20,7 @@ func someTypeIsTheSame() { a = foo("") // expected-error{{cannot assign value of type 'some Foo' (result of 'foo') to type 'some Foo' (result of 'foo')}} var b = foo("") - b = foo(0) // expected-error{{cannot assign value of type 'some Foo' (result of 'foo') to type 'some Foo' (result of 'foo')}} + b = foo(0) // expected-error{{no 'foo' candidates produce the expected contextual result type 'some Foo'}} b = foo("") var c = foo(MyFoo()) @@ -33,7 +33,7 @@ func someTypeIsTheSame() { var d = barInt.foo(0) d = barInt.foo(0) - d = barString.foo(0) // expected-error{{cannot assign}} + d = barString.foo(0) // expected-error{{no 'foo' candidates produce the expected contextual result type 'some Foo'}} d = getAssocType(barInt) d = getAssocType(barString) // expected-error{{cannot assign}} @@ -50,7 +50,7 @@ func someTypeIsTheSame() { d3 = getAssocSubscriptType(barString) // expected-error{{cannot assign}} var e = barString.foo(0) - e = barInt.foo(0) // expected-error{{cannot assign}} + e = barInt.foo(0) // expected-error{{no 'foo' candidates produce the expected contextual result type 'some Foo'}} e = barString.foo(0) e = getAssocType(barInt) // expected-error{{cannot assign}} e = getAssocType(barString) From 3ebf633e669690fb081333454254317a011f95b6 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 11 Jun 2020 09:54:04 -0700 Subject: [PATCH 16/22] [ConstraintSystem] Increase impact of conformance failure associated with a known foundation type Just like we already do for stdlib types, extend impact of missing conformances on _known_ foundation types because it's unlikely to be a valid suggestion to extend a foundation type with a new conformance. --- lib/Sema/CSSimplify.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 74f3f281a670c..8c7f818476d1d 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -1489,9 +1489,12 @@ assessRequirementFailureImpact(ConstraintSystem &cs, Type requirementType, return 10; } - // Increase the impact of a conformance fix for a standard library type, - // as it's unlikely to be a good suggestion. Also do the same for the builtin - // compiler types Any and AnyObject, which cannot conform to protocols. + // Increase the impact of a conformance fix for a standard library + // or foundation type, as it's unlikely to be a good suggestion. + // + // Also do the same for the builtin compiler types Any and AnyObject, + // which cannot conform to protocols. + // // FIXME: We ought not to have the is() condition here, but // removing it currently regresses the diagnostic for the test case for // rdar://60727310. Once we better handle the separation of conformance fixes @@ -1499,7 +1502,8 @@ assessRequirementFailureImpact(ConstraintSystem &cs, Type requirementType, // remove it from the condition. auto resolvedTy = cs.simplifyType(requirementType); if ((requirementType->is() && resolvedTy->isStdlibType()) || - resolvedTy->isAny() || resolvedTy->isAnyObject()) { + resolvedTy->isAny() || resolvedTy->isAnyObject() || + getKnownFoundationEntity(resolvedTy->getString())) { if (auto last = locator.last()) { if (auto requirement = last->getAs()) { auto kind = requirement->getRequirementKind(); From 0af9a287acb11837ce8f96a64111a512acdcbd5d Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 11 Jun 2020 13:28:59 -0700 Subject: [PATCH 17/22] [Diagnostics] Allow property wrapper fixes to be diagnosed as ambiguity --- lib/Sema/CSFix.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index b160c45de367a..1652f2c1739c9 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -804,6 +804,10 @@ class UsePropertyWrapper final : public ConstraintFix { bool diagnose(const Solution &solution, bool asNote = false) const override; + bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { + return diagnose(*commonFixes.front().first); + } + static UsePropertyWrapper *create(ConstraintSystem &cs, VarDecl *wrapped, bool usingStorageWrapper, Type base, Type wrapper, ConstraintLocator *locator); @@ -831,6 +835,10 @@ class UseWrappedValue final : public ConstraintFix { bool diagnose(const Solution &solution, bool asNote = false) const override; + bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { + return diagnose(*commonFixes.front().first); + } + static UseWrappedValue *create(ConstraintSystem &cs, VarDecl *propertyWrapper, Type base, Type wrapper, ConstraintLocator *locator); From 82fcee7bc7d534269eb08f6f9c7161bbf6e9d765 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 12 Jun 2020 13:13:27 -0700 Subject: [PATCH 18/22] [Diagnostics] NFC: Adjust diagnostic test-cases improved by new ambiguity diagnosis --- test/Constraints/diagnostics.swift | 4 +++- test/Constraints/sr12964.swift | 3 +-- test/Constraints/tuple_arguments.swift | 4 ++-- .../import-resolution-overload.swift | 2 +- test/Misc/misc_diagnostics.swift | 5 +++-- test/Sema/enum_raw_representable.swift | 21 ++++++++++++------- test/decl/protocol/req/recursion.swift | 2 +- .../salvage-with-other-type-errors.swift | 2 +- test/stdlib/KeyPathAppending.swift | 10 ++++----- test/stdlib/StringDiagnostics.swift | 1 + test/stdlib/UnicodeScalarDiagnostics.swift | 6 +++--- test/type/protocol_composition.swift | 4 ++++ .../type_checker_perf/slow/rdar53589951.swift | 1 + 13 files changed, 38 insertions(+), 27 deletions(-) diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index 243c199483d02..28fe4a0f7b114 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -1117,8 +1117,10 @@ func platypus(a: [T]) { // Another case of the above. func badTypes() { let sequence:AnySequence<[Int]> = AnySequence() { AnyIterator() { [3] }} + // Notes, attached to declarations, explain that there is a difference between Array.init(_:) and + // RangeReplaceableCollection.init(_:) which are both applicable in this case. let array = [Int](sequence) - // expected-error@-1 {{initializer 'init(_:)' requires the types 'Int' and '[Int]' be equivalent}} + // expected-error@-1 {{no exact matches in call to initializer}} } // rdar://34357545 diff --git a/test/Constraints/sr12964.swift b/test/Constraints/sr12964.swift index 27d48299b144d..b18de10a36f30 100644 --- a/test/Constraints/sr12964.swift +++ b/test/Constraints/sr12964.swift @@ -3,5 +3,4 @@ protocol P {} typealias T = (P) -> Void let x: T! = [1, 2, 3].reversed().reduce() -// expected-error@-1 {{no exact matches in call to instance method 'reduce'}} -// expected-note@-2 2{{candidate has partially matching parameter list}} +// expected-error@-1 {{missing arguments for parameters #1, #2 in call}} diff --git a/test/Constraints/tuple_arguments.swift b/test/Constraints/tuple_arguments.swift index 7b31d6d897e99..c8be9ace19776 100644 --- a/test/Constraints/tuple_arguments.swift +++ b/test/Constraints/tuple_arguments.swift @@ -1702,8 +1702,8 @@ x.map { (_: ()) in () } // https://bugs.swift.org/browse/SR-9470 do { func f(_: Int...) {} - let _ = [(1, 2, 3)].map(f) // expected-error {{cannot convert value of type '(Int...) -> ()' to expected argument type '((Int, Int, Int)) throws -> T'}} - // expected-error@-1 {{generic parameter 'T' could not be inferred}} + let _ = [(1, 2, 3)].map(f) // expected-error {{no exact matches in call to instance method 'map'}} + // expected-note@-1 {{found candidate with type '(((Int, Int, Int)) throws -> _) throws -> Array<_>'}} } // rdar://problem/48443263 - cannot convert value of type '() -> Void' to expected argument type '(_) -> Void' diff --git a/test/ImportResolution/import-resolution-overload.swift b/test/ImportResolution/import-resolution-overload.swift index ce9c493560811..e19ef173eb9e5 100644 --- a/test/ImportResolution/import-resolution-overload.swift +++ b/test/ImportResolution/import-resolution-overload.swift @@ -46,7 +46,7 @@ scopedFunction = 42 // FIXME: Should be an error -- a type name and a function cannot overload. var _ : Int = TypeNameWins(42) -TypeNameWins = 42 // expected-error {{no exact matches in reference to global function 'TypeNameWins'}} +TypeNameWins = 42 // expected-error {{cannot assign to immutable expression of type 'Int'}} var _ : TypeNameWins // no-warning // rdar://problem/21739333 diff --git a/test/Misc/misc_diagnostics.swift b/test/Misc/misc_diagnostics.swift index 00de8f07aa469..557b1beec9021 100644 --- a/test/Misc/misc_diagnostics.swift +++ b/test/Misc/misc_diagnostics.swift @@ -54,8 +54,9 @@ struct MyArray {} // expected-note {{'Element' declared as parameter to class A { var a: MyArray init() { - a = MyArray.Type' and 'Int.Type'}} + // expected-error@-2 {{cannot assign value of type 'Bool' to type 'MyArray'}} } } diff --git a/test/Sema/enum_raw_representable.swift b/test/Sema/enum_raw_representable.swift index 39e89779ddf0d..59323fbb591d3 100644 --- a/test/Sema/enum_raw_representable.swift +++ b/test/Sema/enum_raw_representable.swift @@ -135,19 +135,23 @@ rdar32431165_2(E_32431165.bar) rdar32431165_2(42, E_32431165.bar) // expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String'}} {{34-34=.rawValue}} -E_32431165.bar == "bar" -// expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String}} {{15-15=.rawValue}} - -"bar" == E_32431165.bar -// expected-error@-1 {{cannot convert value of type 'E_32431165' to expected argument type 'String}} {{24-24=.rawValue}} +// TODO: In following two examples it's possible to fix a problem by either using `.rawValue` on first argument +// or constructing raw representable type from second, both ways are valid. +do { + E_32431165.bar == "bar" + // expected-error@-1 {{binary operator '==' cannot be applied to operands of type 'E_32431165' and 'String'}} expected-note@-1 {{partially matching parameter lists: (String, String)}} + + "bar" == E_32431165.bar + // expected-error@-1 {{binary operator '==' cannot be applied to operands of type 'String' and 'E_32431165'}} expected-note@-1 {{partially matching parameter lists: (String, String)}} +} -func rdar32431165_overloaded() -> Int { 42 } // expected-note {{found candidate with type 'Int'}} +func rdar32431165_overloaded() -> Int { 42 } // expected-note {{'rdar32431165_overloaded()' produces 'Int', not the expected contextual result type 'E_32431165'}} func rdar32431165_overloaded() -> String { "A" } // expected-note {{'rdar32431165_overloaded()' produces 'String', not the expected contextual result type 'E_32431165'}} func test_candidate_diagnostic() { func test_argument(_: E_32431165) {} - let _: E_32431165 = rdar32431165_overloaded() // expected-error {{no exact matches in call to global function 'rdar32431165_overloaded'}} + let _: E_32431165 = rdar32431165_overloaded() // expected-error {{no 'rdar32431165_overloaded' candidates produce the expected contextual result type 'E_32431165'}} test_argument(rdar32431165_overloaded()) // expected-error {{cannot convert value of type 'String' to expected argument type 'E_32431165'}} {{17-17=E_32431165(rawValue: }} {{42-42=) ?? <#default value#>}} } @@ -197,7 +201,8 @@ func sr8150_mutable(obj: SR8150Box) { sr8150_helper1(opt) // expected-error@-1 {{cannot convert value of type 'Bar?' to expected argument type 'Double'}} {{23-23=?.rawValue ?? <#default value#>}} sr8150_helper1(opt ?? Bar.a) - // expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{20-20=(}} {{32-32=).rawValue}} + // expected-error@-1 {{no exact matches in call to global function 'sr8150_helper1'}} + // expected-note@-2 {{candidate expects value of type 'Bar' for parameter #0}} {{20-20=(}} {{32-32=).rawValue}} let _: Double? = opt // expected-error@-1 {{cannot convert value of type 'Bar?' to specified type 'Double?'}} {{25-25=?.rawValue}} } diff --git a/test/decl/protocol/req/recursion.swift b/test/decl/protocol/req/recursion.swift index e6194f834759e..f9d9761ee5077 100644 --- a/test/decl/protocol/req/recursion.swift +++ b/test/decl/protocol/req/recursion.swift @@ -54,7 +54,7 @@ public struct S where A.T == S { // expected-error {{circular reference func g(a: S) { f(a: id(t: a)) - // expected-error@-1 {{conflicting arguments to generic parameter 'T' ('S' vs. 'A.T' (associated type of protocol 'P'))}} + // expected-error@-1 {{cannot convert value of type 'S' to expected argument type 'A.T'}} _ = S.self } diff --git a/test/expr/unary/keypath/salvage-with-other-type-errors.swift b/test/expr/unary/keypath/salvage-with-other-type-errors.swift index 56aeeb10982e9..f36b32cb46cad 100644 --- a/test/expr/unary/keypath/salvage-with-other-type-errors.swift +++ b/test/expr/unary/keypath/salvage-with-other-type-errors.swift @@ -52,7 +52,7 @@ protocol Bindable: class { } extension Bindable { func test(to targetKeyPath: ReferenceWritableKeyPath, change: Value?) { if self[keyPath:targetKeyPath] != change { - // expected-error@-1 {{operator function '!=' requires that 'Value' conform to 'Equatable'}} + // expected-error@-1 {{binary operator '!=' cannot be applied to operands of type 'Value' and 'Value?'}} self[keyPath: targetKeyPath] = change! } } diff --git a/test/stdlib/KeyPathAppending.swift b/test/stdlib/KeyPathAppending.swift index a4c4f3217d143..a416e3c7cebc1 100644 --- a/test/stdlib/KeyPathAppending.swift +++ b/test/stdlib/KeyPathAppending.swift @@ -58,22 +58,20 @@ func mismatchedAppends(readOnlyLeft: KeyPath, // expected-note@-2 {{arguments to generic parameter 'Root' ('T' and 'V') are expected to be equal}} _ = readOnlyRight.appending(path: referenceLeft) - // expected-error@-1 {{cannot convert value of type 'ReferenceWritableKeyPath' to expected argument type 'ReferenceWritableKeyPath'}} - // expected-note@-2 {{arguments to generic parameter 'Root' ('T' and 'V') are expected to be equal}} + // expected-error@-1 {{no exact matches in call to instance method 'appending'}} _ = writableRight.appending(path: readOnlyLeft) - // expected-error@-1 {{instance method 'appending(path:)' requires that 'KeyPath' inherit from 'KeyPath'}} + // expected-error@-1 {{no exact matches in call to instance method 'appending'}} _ = writableRight.appending(path: writableLeft) // expected-error@-1 {{cannot convert value of type 'WritableKeyPath' to expected argument type 'WritableKeyPath'}} // expected-note@-2 {{arguments to generic parameter 'Root' ('T' and 'V') are expected to be equal}} _ = writableRight.appending(path: referenceLeft) - // expected-error@-1 {{cannot convert value of type 'ReferenceWritableKeyPath' to expected argument type 'ReferenceWritableKeyPath'}} - // expected-note@-2 {{arguments to generic parameter 'Root' ('T' and 'V') are expected to be equal}} + // expected-error@-1 {{no exact matches in call to instance method 'appending'}} _ = referenceRight.appending(path: readOnlyLeft) - // expected-error@-1 {{instance method 'appending(path:)' requires that 'KeyPath' inherit from 'KeyPath'}} + // expected-error@-1 {{no exact matches in call to instance method 'appending'}} _ = referenceRight.appending(path: writableLeft) // expected-error@-1 {{cannot convert value of type 'WritableKeyPath' to expected argument type 'WritableKeyPath'}} diff --git a/test/stdlib/StringDiagnostics.swift b/test/stdlib/StringDiagnostics.swift index 3a53a26c69ee0..c3fde8ff884f5 100644 --- a/test/stdlib/StringDiagnostics.swift +++ b/test/stdlib/StringDiagnostics.swift @@ -48,6 +48,7 @@ func testAmbiguousStringComparisons(s: String) { // Shouldn't suggest 'as' in a pattern-matching context, as opposed to all these other situations if case nsString = "" {} // expected-error{{expression pattern of type 'NSString' cannot match values of type 'String'}} + // expected-note@-1 {{overloads for '~=' exist with these partially matching parameter lists: (Substring, String)}} } func testStringDeprecation(hello: String) { diff --git a/test/stdlib/UnicodeScalarDiagnostics.swift b/test/stdlib/UnicodeScalarDiagnostics.swift index 6446f3e7155bb..6e30489484d22 100644 --- a/test/stdlib/UnicodeScalarDiagnostics.swift +++ b/test/stdlib/UnicodeScalarDiagnostics.swift @@ -13,9 +13,9 @@ func test_UnicodeScalarDoesNotImplementArithmetic(_ us: UnicodeScalar, i: Int) { let a4 = "a" / "b" // expected-error {{binary operator '/' cannot be applied to two 'String' operands}} let b1 = us + us // expected-error {{referencing operator function '+' on 'RangeReplaceableCollection' requires that 'UnicodeScalar' (aka 'Unicode.Scalar') conform to 'RangeReplaceableCollection'}} - let b2 = us - us // expected-error {{referencing operator function '-' on 'FloatingPoint' requires that 'UnicodeScalar' (aka 'Unicode.Scalar') conform to 'FloatingPoint'}} - let b3 = us * us // expected-error {{referencing operator function '*' on 'FloatingPoint' requires that 'UnicodeScalar' (aka 'Unicode.Scalar') conform to 'FloatingPoint'}} - let b4 = us / us // expected-error {{referencing operator function '/' on 'FloatingPoint' requires that 'UnicodeScalar' (aka 'Unicode.Scalar') conform to 'FloatingPoint'}} + let b2 = us - us // expected-error {{binary operator '-' cannot be applied to two 'UnicodeScalar' (aka 'Unicode.Scalar') operands}} + let b3 = us * us // expected-error {{binary operator '*' cannot be applied to two 'UnicodeScalar' (aka 'Unicode.Scalar') operands}} + let b4 = us / us // expected-error {{binary operator '/' cannot be applied to two 'UnicodeScalar' (aka 'Unicode.Scalar') operands}} let c1 = us + i // expected-error {{cannot convert value of type 'UnicodeScalar' (aka 'Unicode.Scalar') to expected argument type 'Int'}} let c2 = us - i // expected-error {{cannot convert value of type 'UnicodeScalar' (aka 'Unicode.Scalar') to expected argument type 'Int'}} diff --git a/test/type/protocol_composition.swift b/test/type/protocol_composition.swift index c6ec77766eb01..f6df6bdc94d18 100644 --- a/test/type/protocol_composition.swift +++ b/test/type/protocol_composition.swift @@ -174,6 +174,10 @@ takesP1AndP2([AnyObject & protocol_composition.P1 & P2]()) takesP1AndP2([AnyObject & P1 & protocol_composition.P2]()) takesP1AndP2([DoesNotExist & P1 & P2]()) // expected-error {{cannot find 'DoesNotExist' in scope}} takesP1AndP2([Swift.DoesNotExist & P1 & P2]()) // expected-error {{module 'Swift' has no member named 'DoesNotExist'}} +// expected-error@-1 {{binary operator '&' cannot be applied to operands of type 'UInt8' and 'P1.Protocol'}} +// expected-error@-2 {{binary operator '&' cannot be applied to operands of type 'UInt8' and 'P2.Protocol'}} +// expected-note@-3 2 {{overloads for '&' exist with these partially matching parameter lists}} + typealias T08 = P1 & inout P2 // expected-error {{'inout' may only be used on parameters}} typealias T09 = P1 & __shared P2 // expected-error {{'__shared' may only be used on parameters}} diff --git a/validation-test/Sema/type_checker_perf/slow/rdar53589951.swift b/validation-test/Sema/type_checker_perf/slow/rdar53589951.swift index 702c92ee62ea9..b2bc3356a2986 100644 --- a/validation-test/Sema/type_checker_perf/slow/rdar53589951.swift +++ b/validation-test/Sema/type_checker_perf/slow/rdar53589951.swift @@ -1,5 +1,6 @@ // RUN: %target-typecheck-verify-swift -solver-expression-time-threshold=1 // REQUIRES: tools-release,no_asan +// REQUIRES: rdar36854536 class Color { init(hue: Double, saturation: Double, brightness: Double, alpha: Double) {} From f854cc666cd3c30bda5e7211c0d0da0db5f8f54c Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 12 Jun 2020 13:37:30 -0700 Subject: [PATCH 19/22] [ConstraintSystem] Attach candidate notes either to decl (if it has valid loc) or AST node --- lib/Sema/ConstraintSystem.cpp | 17 ++++++++++++++--- test/Constraints/diagnostics.swift | 4 ++-- test/Constraints/super_constructor.swift | 8 ++++---- test/expr/postfix/dot/init_ref_delegation.swift | 6 +++--- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index bcc664c3c11e1..30063320ad8e8 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -3229,6 +3229,9 @@ static bool diagnoseAmbiguity( if (!distinctChoices.insert(decl).second) continue; + auto noteLoc = + decl->getLoc().isInvalid() ? getLoc(commonAnchor) : decl->getLoc(); + if (solution.Fixes.size() == 1) { diagnosed &= solution.Fixes.front()->diagnose(solution, /*asNote*/ true); @@ -3241,15 +3244,23 @@ static bool diagnoseAmbiguity( // lists. auto *fn = type->getAs(); assert(fn); - DE.diagnose(decl->getLoc(), diag::candidate_partial_match, - fn->getParamListAsString(fn->getParams())); + + if (fn->getNumParams() == 1) { + const auto ¶m = fn->getParams()[0]; + DE.diagnose(noteLoc, diag::candidate_has_invalid_argument_at_position, + solution.simplifyType(param.getPlainType()), + /*position=*/1, param.isInOut()); + } else { + DE.diagnose(noteLoc, diag::candidate_partial_match, + fn->getParamListAsString(fn->getParams())); + } } else { // Emit a general "found candidate" note if (decl->getLoc().isInvalid()) { if (candidateTypes.insert(type->getCanonicalType()).second) DE.diagnose(getLoc(commonAnchor), diag::found_candidate_type, type); } else { - DE.diagnose(decl->getLoc(), diag::found_candidate); + DE.diagnose(noteLoc, diag::found_candidate); } } } diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index 28fe4a0f7b114..ab063ed2dcfbc 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -399,9 +399,9 @@ enum Color { static func rainbow() -> Color {} static func overload(a : Int) -> Color {} // expected-note {{incorrect labels for candidate (have: '(_:)', expected: '(a:)')}} - // expected-note@-1 {{candidate has partially matching parameter list (a: Int)}} + // expected-note@-1 {{candidate expects value of type 'Int' for parameter #1}} static func overload(b : Int) -> Color {} // expected-note {{incorrect labels for candidate (have: '(_:)', expected: '(b:)')}} - // expected-note@-1 {{candidate has partially matching parameter list (b: Int)}} + // expected-note@-1 {{candidate expects value of type 'Int' for parameter #1}} static func frob(_ a : Int, b : inout Int) -> Color {} static var svar: Color { return .Red } diff --git a/test/Constraints/super_constructor.swift b/test/Constraints/super_constructor.swift index 01e15a2990432..d6976b7ec010f 100644 --- a/test/Constraints/super_constructor.swift +++ b/test/Constraints/super_constructor.swift @@ -39,15 +39,15 @@ class B { init() { } - init(x:Int) { // expected-note{{candidate has partially matching parameter list (x: Int)}} + init(x:Int) { // expected-note{{candidate expects value of type 'Int' for parameter #1}} } - init(a:UnicodeScalar) { // expected-note {{candidate has partially matching parameter list (a: UnicodeScalar)}} + init(a:UnicodeScalar) { // expected-note {{candidate expects value of type 'UnicodeScalar' (aka 'Unicode.Scalar') for parameter #1}} } - init(b:UnicodeScalar) { // expected-note{{candidate has partially matching parameter list (b: UnicodeScalar)}} + init(b:UnicodeScalar) { // expected-note {{candidate expects value of type 'UnicodeScalar' (aka 'Unicode.Scalar') for parameter #1}} } - init(z:Float) { // expected-note{{candidate has partially matching parameter list (z: Float)}} + init(z:Float) { // expected-note{{candidate expects value of type 'Float' for parameter #1}} super.init() // expected-error{{'super' members cannot be referenced in a root class}} } } diff --git a/test/expr/postfix/dot/init_ref_delegation.swift b/test/expr/postfix/dot/init_ref_delegation.swift index 7acf0d033477c..e5ffb0be4d804 100644 --- a/test/expr/postfix/dot/init_ref_delegation.swift +++ b/test/expr/postfix/dot/init_ref_delegation.swift @@ -323,12 +323,12 @@ class TestOverloadSets { self.init(5, 5) // expected-error{{extra argument in call}} } - convenience init(a : Z0) { // expected-note{{candidate has partially matching parameter list (a: Z0)}} + convenience init(a : Z0) { // expected-note{{candidate expects value of type 'Z0' for parameter #1}} self.init(42 as Int8) // expected-error{{no exact matches in call to initializer}} } - init(value: Int) { /* ... */ } // expected-note{{candidate has partially matching parameter list (value: Int)}} - init(value: Double) { /* ... */ } // expected-note{{candidate has partially matching parameter list (value: Double)}} + init(value: Int) { /* ... */ } // expected-note{{candidate expects value of type 'Int' for parameter #1}} + init(value: Double) { /* ... */ } // expected-note{{candidate expects value of type 'Double' for parameter #1}} } class TestNestedExpr { From 2c0b8ca76a6d888801947536e2a0c5a58f1b6eed Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 12 Jun 2020 15:01:38 -0700 Subject: [PATCH 20/22] [Diagnostics] Add a tailored diagnostic for function mismatch in argument positions If parameter has a function type and no argument overload choices match let's diagnose that specifically. Resolves: [SR-12689](https://bugs.swift.org/browse/SR-12689) Resolves: rdar://problem/62481592 --- include/swift/AST/DiagnosticsSema.def | 4 ++ lib/Sema/CSFix.cpp | 51 ++++++++++++++++++++++++ lib/Sema/CSFix.h | 2 + test/Sema/diag_ambiguous_overloads.swift | 34 ++++++++++++++++ 4 files changed, 91 insertions(+) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index d12b61b251394..6a0ec73300919 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -253,6 +253,10 @@ ERROR(no_candidates_match_result_type,none, "no '%0' candidates produce the expected contextual result type %1", (StringRef, Type)) +ERROR(no_candidates_match_argument_type,none, + "no '%0' candidates produce the expected type %1 for parameter #%2", + (StringRef, Type, unsigned)) + ERROR(cannot_infer_closure_parameter_type,none, "unable to infer type of a closure parameter %0 in the current context", (StringRef)) diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 84d13b6063ca4..51477716aa36a 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -408,6 +408,57 @@ bool AllowFunctionTypeMismatch::diagnose(const Solution &solution, return coalesceAndDiagnose(solution, {}, asNote); } +bool AllowFunctionTypeMismatch::diagnoseForAmbiguity( + CommonFixesArray commonFixes) const { + if (ContextualMismatch::diagnoseForAmbiguity(commonFixes)) + return true; + + auto *locator = getLocator(); + // If this is a mismatch between two function types at argument + // position, there is a tailored diagnostic for that. + if (auto argConv = + locator->getLastElementAs()) { + auto &cs = getConstraintSystem(); + auto &DE = cs.getASTContext().Diags; + auto &solution = *commonFixes[0].first; + + auto info = getStructuralTypeContext(solution, locator); + if (!info) + return false; + + auto *argLoc = cs.getConstraintLocator(simplifyLocatorToAnchor(locator)); + + auto overload = solution.getOverloadChoiceIfAvailable( + solution.getCalleeLocator(argLoc)); + if (!overload) + return false; + + auto name = overload->choice.getName().getBaseName(); + DE.diagnose(getLoc(getAnchor()), diag::no_candidates_match_argument_type, + name.userFacingName(), std::get<2>(*info), + argConv->getParamIdx()); + + for (auto &entry : commonFixes) { + auto &solution = *entry.first; + auto overload = solution.getOverloadChoiceIfAvailable( + solution.getCalleeLocator(argLoc)); + + if (!(overload && overload->choice.isDecl())) + continue; + + auto *decl = overload->choice.getDecl(); + if (decl->getLoc().isValid()) { + DE.diagnose(decl, diag::found_candidate_type, + solution.simplifyType(overload->openedType)); + } + } + + return true; + } + + return false; +} + AllowFunctionTypeMismatch * AllowFunctionTypeMismatch::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator, unsigned index) { diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index 1652f2c1739c9..bd3cdf8233c5a 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -1117,6 +1117,8 @@ class AllowFunctionTypeMismatch final : public ContextualMismatch { bool asNote = false) const override; bool diagnose(const Solution &solution, bool asNote = false) const override; + + bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override; }; diff --git a/test/Sema/diag_ambiguous_overloads.swift b/test/Sema/diag_ambiguous_overloads.swift index 10712fc3531c3..f76457697e6d5 100644 --- a/test/Sema/diag_ambiguous_overloads.swift +++ b/test/Sema/diag_ambiguous_overloads.swift @@ -126,3 +126,37 @@ func getCounts(_ scheduler: sr5154_Scheduler, _ handler: @escaping ([Count]) -> }) } +// SR-12689 +func SR12689(_ u: UnsafeBufferPointer) {} + +let array : [UInt16] = [1, 2] + +array.withUnsafeBufferPointer { + SR12689(UnsafeRawPointer($0).bindMemory(to: UInt16.self, capacity: 1)) // expected-error {{cannot convert value of type 'UnsafePointer' to expected argument type 'UnsafeBufferPointer'}} + // expected-error@-1 {{no exact matches in call to initializer}} + // expected-note@-2 {{candidate expects value of type 'UnsafeRawPointer' for parameter #1}} + // expected-note@-3 {{candidate expects value of type 'UnsafeMutableRawPointer' for parameter #1}} + // expected-note@-4 {{candidate expects value of type 'OpaquePointer' for parameter #1}} + // expected-note@-5 {{candidate expects value of type 'Builtin.RawPointer' for parameter #1}} + + UnsafeRawPointer($0) as UnsafeBufferPointer // expected-error {{cannot convert value of type 'UnsafeRawPointer' to type 'UnsafeBufferPointer' in coercion}} + // expected-error@-1 {{no exact matches in call to initializer}} + // expected-note@-2 {{found candidate with type '(UnsafeRawPointer) -> UnsafeRawPointer'}} + // expected-note@-3 {{found candidate with type '(Builtin.RawPointer) -> UnsafeRawPointer'}} + // expected-note@-4 {{found candidate with type '(OpaquePointer) -> UnsafeRawPointer'}} + // expected-note@-5 {{found candidate with type '(UnsafeMutableRawPointer) -> UnsafeRawPointer'}} +} + +func SR12689_1(_ u: Int) -> String { "" } // expected-note {{found this candidate}} expected-note {{candidate expects value of type 'Int' for parameter #1}} +func SR12689_1(_ u: String) -> Double { 0 } // expected-note {{found this candidate}} expected-note {{candidate expects value of type 'String' for parameter #1}} +func SR12689_2(_ u: Int) {} + +SR12689_2(SR12689_1(1 as Double)) // expected-error {{no exact matches in call to global function 'SR12689_1'}} +SR12689_1(1 as Double) as Int // expected-error {{no exact matches in call to global function 'SR12689_1'}} + +// Ambiguos OverloadRefExpr +func SR12689_O(_ p: Int) {} // expected-note {{found candidate with type '(Int) -> ()'}} +func SR12689_O(_ p: Double) {} // expected-note {{found candidate with type '(Double) -> ()'}} +func SR12689_3(_ param: (String)-> Void) {} + +SR12689_3(SR12689_O) // expected-error {{no 'SR12689_O' candidates produce the expected type '(String) -> Void' for parameter #0}} From c0840fdcd3729f231d5afd1a55c589dc3744dff9 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 12 Jun 2020 15:07:32 -0700 Subject: [PATCH 21/22] [TypeChecker] NFC: Restore test-cases removed by incorrect merge --- test/Constraints/argument_matching.swift | 137 +++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/test/Constraints/argument_matching.swift b/test/Constraints/argument_matching.swift index 8d6c1a197eb62..1a8a1984faf1a 100644 --- a/test/Constraints/argument_matching.swift +++ b/test/Constraints/argument_matching.swift @@ -1470,3 +1470,140 @@ func generic_and_missing_label(x: T) {} // expected-note {{incorrect labels f generic_and_missing_label(42) // expected-error@-1 {{no exact matches in call to global function 'generic_and_missing_label'}} + +// ------------------------------------------- +// Curried functions +// ------------------------------------------- +func f7(_ a: Int) -> (_ b: Int) -> Int { + return { b in a+b } +} + +_ = f7(1)(1) +f7(1.0)(2) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} +f7(1)(1.0) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} +f7(1)(b: 1.0) // expected-error{{extraneous argument label 'b:' in call}} +// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Int'}} +let f10 = f7(2) +_ = f10(1) +f10(10) // expected-warning {{result of call to function returning 'Int' is unused}} +f10(1.0) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} +f10(b: 1.0) // expected-error {{extraneous argument label 'b:' in call}} +// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Int'}} + +class CurriedClass { + func method1() {} + func method2(_ a: Int) -> (_ b : Int) -> () { return { b in () } } + func method3(_ a: Int, b : Int) {} // expected-note 3 {{'method3(_:b:)' declared here}} +} + +let c = CurriedClass() +_ = c.method1 +c.method1(1) // expected-error {{argument passed to call that takes no arguments}} +_ = c.method2(1) +_ = c.method2(1.0) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} +c.method2(1)(2) +c.method2(1)(c: 2) // expected-error {{extraneous argument label 'c:' in call}} +c.method2(1)(c: 2.0) // expected-error {{extraneous argument label 'c:' in call}} +// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Int'}} +c.method2(1)(2.0) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} +c.method2(1.0)(2) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} +c.method2(1.0)(2.0) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} +// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Int'}} +CurriedClass.method1(c)() +_ = CurriedClass.method1(c) +CurriedClass.method1(c)(1) // expected-error {{argument passed to call that takes no arguments}} +CurriedClass.method1(2.0)(1) // expected-error {{cannot convert value of type 'Double' to expected argument type 'CurriedClass'}} +// expected-error@-1:27 {{argument passed to call that takes no arguments}} +CurriedClass.method2(c)(32)(b: 1) // expected-error{{extraneous argument label 'b:' in call}} +_ = CurriedClass.method2(c) +_ = CurriedClass.method2(c)(32) +_ = CurriedClass.method2(1,2) // expected-error {{extra argument in call}} +// expected-error@-1 {{instance member 'method2' cannot be used on type 'CurriedClass'; did you mean to use a value of this type instead?}} +CurriedClass.method2(c)(1.0)(b: 1) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} +// expected-error@-1 {{extraneous argument label 'b:' in call}} +CurriedClass.method2(c)(1)(1.0) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} +CurriedClass.method2(c)(2)(c: 1.0) // expected-error {{extraneous argument label 'c:'}} +// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Int'}} +CurriedClass.method3(c)(32, b: 1) +_ = CurriedClass.method3(c) +_ = CurriedClass.method3(c)(1, 2) // expected-error {{missing argument label 'b:' in call}} {{32-32=b: }} +_ = CurriedClass.method3(c)(1, b: 2)(32) // expected-error {{cannot call value of non-function type '()'}} +_ = CurriedClass.method3(1, 2) // expected-error {{instance member 'method3' cannot be used on type 'CurriedClass'; did you mean to use a value of this type instead?}} +// expected-error@-1 {{missing argument label 'b:' in call}} +CurriedClass.method3(c)(1.0, b: 1) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} +CurriedClass.method3(c)(1) // expected-error {{missing argument for parameter 'b' in call}} +CurriedClass.method3(c)(c: 1.0) // expected-error {{incorrect argument labels in call (have 'c:', expected '_:b:')}} +// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Int'}} +// expected-error@-2 {{missing argument for parameter #1 in call}} + +extension CurriedClass { + func f() { + method3(1, b: 2) + method3() // expected-error {{missing arguments for parameters #1, 'b' in call}} {{13-13=<#Int#>, b: <#Int#>}} + method3(42) // expected-error {{missing argument for parameter 'b' in call}} + method3(self) + // expected-error@-1:13 {{cannot convert value of type 'CurriedClass' to expected argument type 'Int'}} + // expected-error@-2:17 {{missing argument for parameter 'b' in call}} {{17-17=, b: <#Int#>}} + } +} + +extension CurriedClass { + func m1(_ a : Int, b : Int) {} + + func m2(_ a : Int) {} +} + +// QoI: "Extra argument" error when accidentally currying a method +CurriedClass.m1(2, b: 42) // expected-error {{instance member 'm1' cannot be used on type 'CurriedClass'; did you mean to use a value of this type instead?}} + +// QoI: Confusing error message when calling an instance method as a class method +CurriedClass.m2(12) // expected-error {{instance member 'm2' cannot be used on type 'CurriedClass'; did you mean to use a value of this type instead?}} +// ------------------------------------------- +// Multiple label errors +// ------------------------------------------- +func testLabelErrorsBasic() { + func f(_ aa: Int, _ bb: Int, cc: Int, dd: Int, ee: Int, ff: Int) {} + + // 1 wrong + f(0, 1, ccx: 2, dd: 3, ee: 4, ff: 5) + // expected-error@-1 {{incorrect argument label in call (have '_:_:ccx:dd:ee:ff:', expected '_:_:cc:dd:ee:ff:')}} {{11-14=cc}} {{none}} + // 1 missing + f(0, 1, 2, dd: 3, ee: 4, ff: 5) + // expected-error@-1 {{missing argument label 'cc:' in call}} {{11-11=cc: }} {{none}} + // 1 extra + f(aa: 0, 1, cc: 2, dd: 3, ee: 4, ff: 5) + // expected-error@-1 {{extraneous argument label 'aa:' in call}} {{5-9=}} {{none}} + // 1 ooo + f(0, 1, dd: 3, cc: 2, ee: 4, ff: 5) + // expected-error@-1 {{argument 'cc' must precede argument 'dd'}} {{16-23=}} {{11-11=cc: 2, }} {{none}} + // 2 wrong + f(0, 1, ccx: 2, ddx: 3, ee: 4, ff: 5) + // expected-error@-1 {{incorrect argument labels in call (have '_:_:ccx:ddx:ee:ff:', expected '_:_:cc:dd:ee:ff:')}} {{11-14=cc}} {{19-22=dd}} {{none}} + // 2 missing + f(0, 1, 2, 3, ee: 4, ff: 5) + // expected-error@-1 {{missing argument labels 'cc:dd:' in call}} {{11-11=cc: }} {{14-14=dd: }} {{none}} + // 2 extra + f(aa: 0, bb: 1, cc: 2, dd: 3, ee: 4, ff: 5) + // expected-error@-1 {{extraneous argument labels 'aa:bb:' in call}} {{5-9=}} {{12-16=}} {{none}} + // 2 ooo + f(0, 1, dd: 3, cc: 2, ff: 5, ee: 4) + // expected-error@-1 {{argument 'cc' must precede argument 'dd'}} {{16-23=}} {{11-11=cc: 2, }} {{none}} + // 1 wrong + 1 missing + f(0, 1, ccx: 2, 3, ee: 4, ff: 5) + // expected-error@-1 {{incorrect argument labels in call (have '_:_:ccx:_:ee:ff:', expected '_:_:cc:dd:ee:ff:')}} {{11-14=cc}} {{19-19=dd: }} {{none}} + // 1 wrong + 1 extra + f(aa: 0, 1, ccx: 2, dd: 3, ee: 4, ff: 5) + // expected-error@-1 {{incorrect argument labels in call (have 'aa:_:ccx:dd:ee:ff:', expected '_:_:cc:dd:ee:ff:')}} {{5-9=}} {{15-18=cc}} {{none}} + // 1 wrong + 1 ooo + f(0, 1, ccx: 2, dd: 3, ff: 5, ee: 4) + // expected-error@-1 {{incorrect argument labels in call (have '_:_:ccx:dd:ff:ee:', expected '_:_:cc:dd:ee:ff:')}} {{11-14=cc}} {{26-28=ee}} {{33-35=ff}} {{none}} +} + +struct DiagnoseAllLabels { + func f(aa: Int, bb: Int, cc: Int..., dd: Int, ee: Int = 0, ff: Int = 0) {} + + func test() { + f(aax: 0, bbx: 1, cc: 21, 22, 23, dd: 3, ff: 5) // expected-error {{incorrect argument labels in call (have 'aax:bbx:cc:_:_:dd:ff:', expected 'aa:bb:cc:_:_:dd:ff:')}} {{7-10=aa}} {{15-18=bb}} {{none}} + f(aax: 0, bbx: 1, dd: 3, ff: 5) // expected-error {{incorrect argument labels in call (have 'aax:bbx:dd:ff:', expected 'aa:bb:dd:ff:')}} {{7-10=aa}} {{15-18=bb}} {{none}} + } +} From 73667cdc7e4726161072611f5055ff50877f19cd Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 15 Jun 2020 11:57:48 -0700 Subject: [PATCH 22/22] [Diagnostics] Use `Id_MatchOperator` to check whether given operator is pattern match --- lib/Sema/CSFix.cpp | 2 +- lib/Sema/ConstraintSystem.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 51477716aa36a..409cd6129f40b 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -273,7 +273,7 @@ bool ContextualMismatch::diagnoseForAmbiguity( etalonTypes.second->isEqual(types.second); })) { const auto &primary = commonFixes.front(); - return primary.second->diagnose(*primary.first, /*aNote=*/false); + return primary.second->diagnose(*primary.first, /*asNote=*/false); } return false; diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 30063320ad8e8..f00bf468baddc 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -2775,7 +2775,8 @@ static void diagnoseOperatorAmbiguity(ConstraintSystem &cs, Identifier operatorName, ArrayRef solutions, ConstraintLocator *locator) { - auto &DE = cs.getASTContext().Diags; + auto &ctx = cs.getASTContext(); + auto &DE = ctx.Diags; auto *anchor = castToExpr(locator->getAnchor()); auto *applyExpr = cast(cs.getParentExpr(anchor)); @@ -2814,7 +2815,7 @@ static void diagnoseOperatorAmbiguity(ConstraintSystem &cs, operatorName.str()); return; } - } else if (operatorName.is("~=")) { + } else if (operatorName == ctx.Id_MatchOperator) { DE.diagnose(anchor->getLoc(), diag::cannot_match_expr_pattern_with_value, lhsType, rhsType); } else {