Skip to content

Commit 54706ba

Browse files
hborlaxedin
authored andcommitted
[Diagnostics] Simplify diagnoseAmbiguityWithFixes by removing AmbiguityKind.
1 parent 607c298 commit 54706ba

File tree

3 files changed

+64
-134
lines changed

3 files changed

+64
-134
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 61 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -2801,45 +2801,7 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes(
28012801
if (ambiguousOverload == solutionDiff.overloads.end())
28022802
return false;
28032803

2804-
ConstraintLocator* commonCalleeLocator = ambiguousOverload->locator;
2805-
SmallPtrSet<ValueDecl *, 4> distinctChoices;
2806-
SmallVector<const Solution *, 4> viableSolutions;
2807-
assert(ambiguousOverload->choices.size() == solutions.size());
2808-
for (unsigned i = 0; i < solutions.size(); ++i) {
2809-
if (distinctChoices.insert(ambiguousOverload->choices[i].getDecl()).second)
2810-
viableSolutions.push_back(&solutions[i]);
2811-
}
2812-
2813-
enum class AmbiguityKind {
2814-
/// There is exactly one fix associated with each candidate.
2815-
CloseMatch,
2816-
/// Solution is ambiguous because all candidates had partially matching
2817-
/// parameter lists.
2818-
ParameterList,
2819-
/// General ambiguity failure.
2820-
General,
2821-
/// Argument mismatch ambiguity where each solution has the same
2822-
/// argument mismatch fixes for the same call.
2823-
ArgumentMismatch
2824-
};
2825-
auto ambiguityKind = AmbiguityKind::CloseMatch;
2826-
2827-
// FIXME: Can this be re-written in a cleaner way?
2828-
for (const auto &solution: solutions) {
2829-
if (solution.Fixes.empty())
2830-
return false;
2831-
2832-
if (solution.Fixes.size() > 1) {
2833-
ambiguityKind = (ambiguityKind == AmbiguityKind::CloseMatch ||
2834-
ambiguityKind == AmbiguityKind::ParameterList) &&
2835-
llvm::all_of(solution.Fixes, [](const ConstraintFix *fix) -> bool {
2836-
auto *locator = fix->getLocator();
2837-
return locator->findLast<LocatorPathElt::ApplyArgument>().hasValue();
2838-
}) ? AmbiguityKind::ParameterList
2839-
: AmbiguityKind::General;
2840-
}
2841-
}
2842-
2804+
auto *commonCalleeLocator = ambiguousOverload->locator;
28432805
auto *decl = ambiguousOverload->choices.front().getDecl();
28442806
assert(solverState);
28452807

@@ -2851,110 +2813,78 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes(
28512813
auto &DE = getASTContext().Diags;
28522814
auto name = decl->getFullName();
28532815

2854-
auto emitGeneralAmbiguityFailure = [&]() {
2855-
// Three choices here:
2856-
// 1. If this is a special name avoid printing it because
2857-
// printing kind is sufficient;
2858-
// 2. If all of the labels match, print a full name;
2859-
// 3. If labels in different choices are different, it means
2860-
// that we can only print a base name.
2861-
if (name.isSpecial()) {
2862-
DE.diagnose(commonAnchor->getLoc(),
2863-
diag::no_overloads_match_exactly_in_call_special,
2864-
decl->getDescriptiveKind());
2865-
} else if (name.isOperator()) {
2866-
auto operatorId = name.getBaseIdentifier();
2867-
diagnoseOperatorAmbiguity(*this, operatorId, solutions,
2868-
commonCalleeLocator);
2869-
} else if (llvm::all_of(distinctChoices,
2870-
[&name](const ValueDecl *choice) {
2871-
return choice->getFullName() == name;
2872-
})) {
2873-
DE.diagnose(commonAnchor->getLoc(),
2874-
diag::no_overloads_match_exactly_in_call,
2875-
decl->getDescriptiveKind(), name);
2876-
} else {
2877-
DE.diagnose(commonAnchor->getLoc(),
2878-
diag::no_overloads_match_exactly_in_call_no_labels,
2879-
decl->getDescriptiveKind(), name.getBaseName());
2880-
}
2881-
};
2816+
if (name.isOperator()) {
2817+
diagnoseOperatorAmbiguity(*this, name.getBaseIdentifier(), solutions,
2818+
commonCalleeLocator);
2819+
return true;
2820+
}
28822821

2883-
switch (ambiguityKind) {
2884-
case AmbiguityKind::ArgumentMismatch:
2885-
case AmbiguityKind::CloseMatch:
2886-
// Handled below
2887-
break;
2888-
case AmbiguityKind::ParameterList: {
2889-
emitGeneralAmbiguityFailure();
2822+
// Emit an error message for the ambiguity.
2823+
if (aggregatedFixes.size() == 1 &&
2824+
aggregatedFixes.front().first.first
2825+
->getLastElementAs<LocatorPathElt::ContextualType>()) {
2826+
auto *anchor = aggregatedFixes.front().first.first->getAnchor();
2827+
auto baseName = name.getBaseName();
2828+
DE.diagnose(commonAnchor->getLoc(), diag::no_candidates_match_result_type,
2829+
baseName.userFacingName(), getContextualType(anchor));
2830+
} else if (name.isSpecial()) {
2831+
// If this is a special name, avoid printing it because printing the
2832+
// decl kind is sufficient.
2833+
DE.diagnose(commonAnchor->getLoc(),
2834+
diag::no_overloads_match_exactly_in_call_special,
2835+
decl->getDescriptiveKind());
2836+
} else if (llvm::all_of(ambiguousOverload->choices,
2837+
[&name](const OverloadChoice &choice) {
2838+
return choice.getDecl()->getFullName() == name;
2839+
})) {
2840+
// If the labels match in each overload, print a full name.
2841+
DE.diagnose(commonAnchor->getLoc(),
2842+
diag::no_overloads_match_exactly_in_call,
2843+
decl->getDescriptiveKind(), name);
2844+
} else {
2845+
// If the labels are different, we can only print a base name.
2846+
DE.diagnose(commonAnchor->getLoc(),
2847+
diag::no_overloads_match_exactly_in_call_no_labels,
2848+
decl->getDescriptiveKind(), name.getBaseName());
2849+
}
2850+
2851+
// Produce candidate notes
2852+
SmallPtrSet<ValueDecl *, 4> distinctChoices;
2853+
llvm::SmallSet<CanType, 4> candidateTypes;
2854+
for (const auto &solution: solutions) {
2855+
auto overload = solution.getOverloadChoice(commonCalleeLocator);
2856+
auto *decl = overload.choice.getDecl();
2857+
auto type = solution.simplifyType(overload.openedType);
2858+
// Skip if we've already produced a note for this overload
2859+
if (!distinctChoices.insert(decl).second)
2860+
continue;
28902861

2891-
for (const auto &viable: viableSolutions) {
2892-
auto overload = viable->getOverloadChoice(commonCalleeLocator);
2893-
auto *fn = overload.openedType->getAs<AnyFunctionType>();
2862+
if (solution.Fixes.size() == 1) {
2863+
// Create scope so each applied solution is rolled back.
2864+
ConstraintSystem::SolverScope scope(*this);
2865+
applySolution(solution);
2866+
// All of the solutions supposed to produce a "candidate" note.
2867+
diagnosed &= solution.Fixes.front()->diagnose(/*asNote*/ true);
2868+
} else if (llvm::all_of(solution.Fixes,
2869+
[&](ConstraintFix *fix) {
2870+
return fix->getLocator()
2871+
->findLast<LocatorPathElt::ApplyArgument>().hasValue();
2872+
})) {
2873+
// All fixes have to do with arguments, so let's show the parameter lists.
2874+
auto *fn = type->getAs<AnyFunctionType>();
28942875
assert(fn);
2895-
DE.diagnose(overload.choice.getDecl()->getLoc(),
2876+
DE.diagnose(decl->getLoc(),
28962877
diag::candidate_partial_match,
28972878
fn->getParamListAsString(fn->getParams()));
2898-
}
2899-
2900-
return true;
2901-
}
2902-
case AmbiguityKind::General: {
2903-
emitGeneralAmbiguityFailure();
2904-
2905-
// Notes for operators are diagnosed through emitGeneralAmbiguityFailure
2906-
if (name.isOperator())
2907-
return true;
2908-
2909-
llvm::SmallSet<CanType, 4> candidateTypes;
2910-
for (const auto &viable: viableSolutions) {
2911-
auto overload = viable->getOverloadChoice(commonCalleeLocator);
2912-
auto *decl = overload.choice.getDecl();
2913-
auto type = viable->simplifyType(overload.openedType);
2879+
} else {
2880+
// Emit a general "found candidate" note
29142881
if (decl->getLoc().isInvalid()) {
29152882
if (candidateTypes.insert(type->getCanonicalType()).second)
29162883
DE.diagnose(commonAnchor->getLoc(), diag::found_candidate_type, type);
29172884
} else {
29182885
DE.diagnose(decl->getLoc(), diag::found_candidate);
29192886
}
29202887
}
2921-
2922-
return true;
2923-
}
2924-
}
2925-
2926-
auto *fix = viableSolutions.front()->Fixes.front();
2927-
if (fix->getKind() == FixKind::UseSubscriptOperator) {
2928-
auto *UDE = cast<UnresolvedDotExpr>(commonAnchor);
2929-
DE.diagnose(commonAnchor->getLoc(),
2930-
diag::could_not_find_subscript_member_did_you_mean,
2931-
getType(UDE->getBase()));
2932-
} else if (fix->getKind() == FixKind::TreatRValueAsLValue) {
2933-
DE.diagnose(commonAnchor->getLoc(),
2934-
diag::no_overloads_match_exactly_in_assignment,
2935-
decl->getBaseName());
2936-
} else if (llvm::all_of(
2937-
viableSolutions,
2938-
[](const Solution *viable) {
2939-
auto *locator = viable->Fixes.front()->getLocator();
2940-
return locator
2941-
->isLastElement<LocatorPathElt::ContextualType>();
2942-
})) {
2943-
auto anchor =
2944-
viableSolutions.front()->Fixes.front()->getLocator()->getAnchor();
2945-
auto baseName = name.getBaseName();
2946-
DE.diagnose(commonAnchor->getLoc(), diag::no_candidates_match_result_type,
2947-
baseName.userFacingName(), getContextualType(anchor));
2948-
} else {
2949-
emitGeneralAmbiguityFailure();
2950-
}
2951-
2952-
for (const auto &viable : viableSolutions) {
2953-
// Create scope so each applied solution is rolled back.
2954-
ConstraintSystem::SolverScope scope(*this);
2955-
applySolution(*viable);
2956-
// All of the solutions supposed to produce a "candidate" note.
2957-
diagnosed &= viable->Fixes.front()->diagnose(/*asNote*/ true);
29582888
}
29592889

29602890
// If not all of the fixes produced a note, we can't diagnose this.

test/Constraints/diagnostics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1085,7 +1085,7 @@ func SR_6272_c() {
10851085
struct SR_6272_D: ExpressibleByIntegerLiteral {
10861086
typealias IntegerLiteralType = Int
10871087
init(integerLiteral: Int) {}
1088-
static func +(lhs: SR_6272_D, rhs: Int) -> Float { return 42.0 } // expected-note 2 {{candidate expects value of type 'Int' for parameter #2}}
1088+
static func +(lhs: SR_6272_D, rhs: Int) -> Float { return 42.0 }
10891089
}
10901090

10911091
func SR_6272_d() {

test/decl/subscript/subscripting.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,9 +385,9 @@ func testSubscript1(_ s1 : SubscriptTest1) {
385385
_ = s1.subscript(SuperClass())
386386
// expected-error@-1 {{no exact matches in call to subscript}}
387387
_ = s1.subscript("hello")
388-
// expected-error@-1 {{value of type 'SubscriptTest1' has no property or method named 'subscript'; did you mean to use the subscript operator?}}
388+
// expected-error@-1 {{no exact matches in call to subscript}}
389389
_ = s1.subscript("hello"
390-
// expected-error@-1 {{value of type 'SubscriptTest1' has no property or method named 'subscript'; did you mean to use the subscript operator?}}
390+
// expected-error@-1 {{no exact matches in call to subscript}}
391391
// expected-note@-2 {{to match this opening '('}}
392392

393393
let _ = s1["hello"]

0 commit comments

Comments
 (0)