diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index ea05b94ee1999..f0090d1b4230a 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -5302,12 +5302,18 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes( /// provided set. static unsigned countDistinctOverloads(ArrayRef choices) { llvm::SmallPtrSet uniqueChoices; - unsigned result = 0; for (auto choice : choices) { - if (uniqueChoices.insert(choice.getOpaqueChoiceSimple()).second) - ++result; + uniqueChoices.insert(choice.getOpaqueChoiceSimple()); } - return result; + return uniqueChoices.size(); +} + +static Type getOverloadChoiceType(ConstraintLocator *overloadLoc, + const Solution &solution) { + auto selectedOverload = solution.overloadChoices.find(overloadLoc); + if (selectedOverload == solution.overloadChoices.end()) + return Type(); + return solution.simplifyType(selectedOverload->second.adjustedOpenedType); } /// Determine the name of the overload in a set of overload choices. @@ -5389,6 +5395,25 @@ bool ConstraintSystem::diagnoseAmbiguity(ArrayRef solutions) { auto &overload = diff.overloads[i]; auto *locator = overload.locator; + // If there is only one overload difference, it's the best. + if (n == 1) { + bestOverload = i; + break; + } + + // If there are multiple overload sets involved, let's pick the + // one that has choices with different types, because that is + // most likely the source of ambiguity. + { + auto overloadTy = getOverloadChoiceType(locator, solutions.front()); + if (std::all_of(solutions.begin() + 1, solutions.end(), + [&](const Solution &solution) { + return overloadTy->isEqual( + getOverloadChoiceType(locator, solution)); + })) + continue; + } + ASTNode anchor; // Simplification of member locator would produce a base expression, diff --git a/test/Constraints/ambiguity_diagnostics.swift b/test/Constraints/ambiguity_diagnostics.swift new file mode 100644 index 0000000000000..b8d991529bc0e --- /dev/null +++ b/test/Constraints/ambiguity_diagnostics.swift @@ -0,0 +1,50 @@ +// RUN: %target-typecheck-verify-swift -swift-version 5 -disable-availability-checking + +protocol View { +} + +extension View { + func title(_ title: S) -> some View where S : StringProtocol { + EmptyView() + } + + func title(_ titleKey: LocalizedString) -> some View { + EmptyView() + } +} + +extension View { + func background(_: T) -> some View { + EmptyView() + } +} + +struct EmptyView : View {} + +struct Text : View { + init(_: String) {} +} + +protocol ShapeStyle { +} + +struct AnyShapeStyle : ShapeStyle {} +struct AnyGradient : ShapeStyle {} + +struct LocalizedString : ExpressibleByStringLiteral, ExpressibleByExtendedGraphemeClusterLiteral { + init(extendedGraphemeClusterLiteral value: String) {} + init(stringLiteral: String) {} +} + +func test() { + func __findValue(_: String, fallback: LocalizedString) -> LocalizedString { fatalError() } + func __findValue(_: String, fallback: T) -> T { fatalError() } + func __findValue(_: String, fallback: T) -> T { fatalError() } + + func ambiguitySource() -> AnyShapeStyle { fatalError() } // expected-note {{found this candidate}} + func ambiguitySource() -> AnyGradient { fatalError() } // expected-note {{found this candidate}} + + Text("Test") + .title(__findValue("someKey", fallback: "")) + .background(ambiguitySource()) // expected-error {{ambiguous use of 'ambiguitySource()'}} +}