From 84b212cc23372609c92e8492f6905884a0437d4f Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 18 May 2023 17:02:59 -0700 Subject: [PATCH 1/2] [ConstraintSytem] NFC: Remove unnecessary checking/counting from `countDistinctOverloads` --- lib/Sema/ConstraintSystem.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index ea05b94ee1999..f93d4787d3975 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -5302,12 +5302,10 @@ 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(); } /// Determine the name of the overload in a set of overload choices. From f12e24e85c5932052e5cfaf16363335831b18b83 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 19 May 2023 09:35:48 -0700 Subject: [PATCH 2/2] [Diagnostics] Skip overloaded locations where all solutions have the same type If there are multiple overloads, let's skip locations that produce the same type across all of the solutions, such location is most likely a consequence of ambiguity and not its source. Resolves: rdar://109245375 --- lib/Sema/ConstraintSystem.cpp | 27 +++++++++++ test/Constraints/ambiguity_diagnostics.swift | 50 ++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 test/Constraints/ambiguity_diagnostics.swift diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index f93d4787d3975..f0090d1b4230a 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -5308,6 +5308,14 @@ static unsigned countDistinctOverloads(ArrayRef choices) { 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. static DeclName getOverloadChoiceName(ArrayRef choices) { DeclName name; @@ -5387,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()'}} +}