Skip to content

Commit ebdb5c7

Browse files
committed
[ConstraintSystem] Improve handling of ambiguities related to fixes
Solutions passed to `diagnoseAmbiguityWithFixes` aren't filtered so we need to remove all of the solutions with the score worse than overall "best". Also logic has to account for some fixes being "warnings".
1 parent 15c58d1 commit ebdb5c7

File tree

6 files changed

+45
-8
lines changed

6 files changed

+45
-8
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2583,6 +2583,18 @@ static void diagnoseOperatorAmbiguity(ConstraintSystem &cs,
25832583
if (!applyExpr)
25842584
return;
25852585

2586+
auto isNameOfStandardComparisonOperator = [](StringRef opName) -> bool {
2587+
return opName == "==" || opName == "!=" || opName == "===" ||
2588+
opName == "!==" || opName == "<" || opName == ">" ||
2589+
opName == "<=" || opName == ">=";
2590+
};
2591+
2592+
auto isEnumWithAssociatedValues = [](Type type) -> bool {
2593+
if (auto *enumType = type->getAs<EnumType>())
2594+
return !enumType->getDecl()->hasOnlyCasesWithoutAssociatedValues();
2595+
return false;
2596+
};
2597+
25862598
const auto &solution = solutions.front();
25872599
if (auto *binaryOp = dyn_cast<BinaryExpr>(applyExpr)) {
25882600
auto *lhs = binaryOp->getArg()->getElement(0);
@@ -2596,6 +2608,14 @@ static void diagnoseOperatorAmbiguity(ConstraintSystem &cs,
25962608
operatorName.str(), lhsType)
25972609
.highlight(lhs->getSourceRange())
25982610
.highlight(rhs->getSourceRange());
2611+
2612+
if (isNameOfStandardComparisonOperator(operatorName.str()) &&
2613+
isEnumWithAssociatedValues(lhsType)) {
2614+
DE.diagnose(applyExpr->getLoc(),
2615+
diag::no_binary_op_overload_for_enum_with_payload,
2616+
operatorName.str());
2617+
return;
2618+
}
25992619
} else {
26002620
DE.diagnose(anchor->getLoc(), diag::cannot_apply_binop_to_args,
26012621
operatorName.str(), lhsType, rhsType)
@@ -2624,16 +2644,35 @@ static void diagnoseOperatorAmbiguity(ConstraintSystem &cs,
26242644
FunctionType::getParamListAsString(fnType->getParams()));
26252645
}
26262646

2647+
// All of the overload choices had generic parameters like `Self`.
2648+
if (parameters.empty())
2649+
return;
2650+
26272651
DE.diagnose(anchor->getLoc(), diag::suggest_partial_overloads,
26282652
/*isResult=*/false, operatorName.str(),
26292653
llvm::join(parameters, ", "));
26302654
}
26312655

26322656
bool ConstraintSystem::diagnoseAmbiguityWithFixes(
2633-
ArrayRef<Solution> solutions) {
2657+
SmallVectorImpl<Solution> &solutions) {
26342658
if (solutions.empty())
26352659
return false;
26362660

2661+
if (auto bestScore = solverState->BestScore) {
2662+
solutions.erase(llvm::remove_if(solutions,
2663+
[&](const Solution &solution) {
2664+
return solution.getFixedScore() >
2665+
*bestScore;
2666+
}),
2667+
solutions.end());
2668+
2669+
if (llvm::all_of(solutions, [&](const Solution &solution) {
2670+
auto score = solution.getFixedScore();
2671+
return score.Data[SK_Fix] == 0 && solution.Fixes.empty();
2672+
}))
2673+
return false;
2674+
}
2675+
26372676
// Problems related to fixes forming ambiguous solution set
26382677
// could only be diagnosed (at the moment), if all of the fixes
26392678
// have the same callee locator, which means they fix different

lib/Sema/ConstraintSystem.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2147,7 +2147,7 @@ class ConstraintSystem {
21472147
void diagnoseFailureForExpr(Expr *expr);
21482148

21492149
bool diagnoseAmbiguity(ArrayRef<Solution> solutions);
2150-
bool diagnoseAmbiguityWithFixes(ArrayRef<Solution> solutions);
2150+
bool diagnoseAmbiguityWithFixes(SmallVectorImpl<Solution> &solutions);
21512151

21522152
/// Give the deprecation warning for referring to a global function
21532153
/// when there's a method from a conditional conformance in a smaller/closer

test/Constraints/closures.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ func rdar37790062() {
717717
}
718718

719719
// <rdar://problem/39489003>
720-
typealias KeyedItem<K, T> = (key: K, value: T) // expected-note {{'T' declared as parameter to type 'KeyedItem'}}
720+
typealias KeyedItem<K, T> = (key: K, value: T)
721721

722722
protocol Node {
723723
associatedtype T
@@ -731,7 +731,7 @@ extension Node {
731731
func getChild(for key:K)->(key: K, value: T) {
732732
return children.first(where: { (item:KeyedItem) -> Bool in
733733
return item.key == key
734-
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
734+
// expected-error@-1 {{binary operator '==' cannot be applied to two 'Self.K' operands}}
735735
})!
736736
}
737737
}

test/Generics/deduction.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
func identity<T>(_ value: T) -> T { return value }
88

99
func identity2<T>(_ value: T) -> T { return value }
10-
// expected-note@-1 {{candidate expects value of type 'X' for parameter #1}}
10+
// expected-note@-1 {{'identity2' produces 'Y', not the expected contextual result type 'X'}}
1111
func identity2<T>(_ value: T) -> Int { return 0 }
1212
// expected-note@-1 {{'identity2' produces 'Int', not the expected contextual result type 'X'}}
1313

test/Interpreter/SDK/misc_osx.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ import CoreServices
77
func testFSEventStreamRef(stream: FSEventStreamRef) {
88
// FIXME: These should be distinct types, constructible from one another.
99
_ = stream as ConstFSEventStreamRef // works by coincidence because both are currently OpaquePointer
10-
_ = ConstFSEventStreamRef(stream) // expected-error {{cannot invoke initializer for type 'ConstFSEventStreamRef' with an argument list of type '(FSEventStreamRef)'}}
11-
// expected-note @-1 {{overloads for 'ConstFSEventStreamRef' exist with these partially matching parameter lists:}}
10+
_ = ConstFSEventStreamRef(stream) // expected-error {{no exact matches in call to initializer}}
1211

1312
// This is not a CF object.
1413
FSEventStreamRetain(stream) // no-warning

test/Sema/struct_equatable_hashable.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ struct StructWithoutExplicitConformance {
115115

116116
func structWithoutExplicitConformance() {
117117
if StructWithoutExplicitConformance(a: 1, b: "b") == StructWithoutExplicitConformance(a: 2, b: "a") { } // expected-error{{binary operator '==' cannot be applied to two 'StructWithoutExplicitConformance' operands}}
118-
// expected-note @-1 {{overloads for '==' exist with these partially matching parameter lists: }}
119118
}
120119

121120
// Structs with non-hashable/equatable stored properties don't derive conformance.

0 commit comments

Comments
 (0)