Skip to content

Commit d7c6c00

Browse files
authored
Merge pull request #34614 from xedin/improvements-to-ambiguity-diags
[Diagnostic] Improve diagnostics for situations with ambiguity caused by conformance requirements
2 parents b40aa54 + 66fbdce commit d7c6c00

File tree

10 files changed

+41
-34
lines changed

10 files changed

+41
-34
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,20 +1672,6 @@ assessRequirementFailureImpact(ConstraintSystem &cs, Type requirementType,
16721672
if (!anchor)
16731673
return impact;
16741674

1675-
// If this is a conditional requirement failure associated with a
1676-
// call, let's increase impact of the fix to show that such failure
1677-
// makes member/function unreachable in current context or with
1678-
// given arguments.
1679-
if (auto last = locator.last()) {
1680-
if (last->isConditionalRequirement()) {
1681-
if (auto *expr = getAsExpr(anchor)) {
1682-
auto *parent = cs.getParentExpr(expr);
1683-
if (parent && isa<ApplyExpr>(parent))
1684-
return 5;
1685-
}
1686-
}
1687-
}
1688-
16891675
// If this requirement is associated with a member reference and it
16901676
// was possible to check it before overload choice is bound, that means
16911677
// types came from the context (most likely Self, or associated type(s))

lib/Sema/ConstraintSystem.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3399,6 +3399,30 @@ static bool diagnoseAmbiguity(
33993399

34003400
auto &DE = cs.getASTContext().Diags;
34013401

3402+
llvm::SmallPtrSet<ValueDecl *, 4> localAmbiguity;
3403+
{
3404+
for (auto &entry : aggregateFix) {
3405+
const auto &solution = entry.first;
3406+
const auto &overload = solution->getOverloadChoice(ambiguity.locator);
3407+
auto *choice = overload.choice.getDeclOrNull();
3408+
3409+
// It's not possible to diagnose different kinds of overload choices.
3410+
if (!choice)
3411+
return false;
3412+
3413+
localAmbiguity.insert(choice);
3414+
}
3415+
}
3416+
3417+
if (localAmbiguity.empty())
3418+
return false;
3419+
3420+
// If all of the fixes are rooted in the same choice.
3421+
if (localAmbiguity.size() == 1) {
3422+
auto &primaryFix = aggregateFix.front();
3423+
return primaryFix.second->diagnose(*primaryFix.first);
3424+
}
3425+
34023426
{
34033427
auto fixKind = aggregateFix.front().second->getKind();
34043428
if (llvm::all_of(
@@ -3413,10 +3437,7 @@ static bool diagnoseAmbiguity(
34133437
}
34143438
}
34153439

3416-
auto *decl = ambiguity.choices.front().getDeclOrNull();
3417-
if (!decl)
3418-
return false;
3419-
3440+
auto *decl = *localAmbiguity.begin();
34203441
auto *commonCalleeLocator = ambiguity.locator;
34213442

34223443
bool diagnosed = true;

test/Constraints/bridging.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ func dictionaryToNSDictionary() {
180180
// In this case, we should not implicitly convert Dictionary to NSDictionary.
181181
struct NotEquatable {}
182182
func notEquatableError(_ d: Dictionary<Int, NotEquatable>) -> Bool {
183-
return d == d // expected-error{{referencing operator function '==' on 'Dictionary' requires that 'NotEquatable' conform to 'Equatable'}}
183+
// There is a note attached to a requirement `requirement from conditional conformance of 'Dictionary<Int, NotEquatable>' to 'Equatable'`
184+
return d == d // expected-error{{operator function '==' requires that 'NotEquatable' conform to 'Equatable'}}
184185
}
185186

186187
// NSString -> String

test/Constraints/operator.swift

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -216,14 +216,11 @@ func rdar46459603() {
216216
let e = E.foo(value: "String")
217217
var arr = ["key": e]
218218

219-
// FIXME(rdar://problem/64844584) - on iOS simulator this diagnostic is flaky,
220-
// either `referencing operator function '==' on 'Equatable'` or `operator function '==' requires`
221219
_ = arr.values == [e]
222-
// expected-error@-1 {{requires that 'Dictionary<String, E>.Values' conform to 'Equatable'}}
223-
// expected-error@-2 {{cannot convert value of type '[E]' to expected argument type 'Dictionary<String, E>.Values'}}
220+
// expected-error@-1 {{binary operator '==' cannot be applied to operands of type 'Dictionary<String, E>.Values' and '[E]'}}
224221
_ = [arr.values] == [[e]]
225-
// expected-error@-1 {{requires that 'Dictionary<String, E>.Values' conform to 'Equatable'}}
226-
// expected-error@-2 {{cannot convert value of type '[E]' to expected element type 'Dictionary<String, E>.Values'}}
222+
// expected-error@-1 {{referencing operator function '==' on 'Array' requires that 'E' conform to 'Equatable'}} expected-note@-1 {{binary operator '==' cannot be synthesized for enums with associated values}}
223+
// expected-error@-2 {{cannot convert value of type 'Dictionary<String, E>.Values' to expected element type '[E]'}}
227224
}
228225

229226
// SR-10843

test/Generics/conditional_conformances.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -413,9 +413,9 @@ extension Foo: P where Bar: P {
413413
extension BinaryInteger {
414414
var foo: Self {
415415
return self <= 1
416-
? 1 // expected-error {{cannot convert return expression of type 'Int' to return type 'Self'}}
416+
? 1
417417
: (2...self).reduce(1, *)
418-
// expected-error@-1 {{cannot convert value of type 'Self' to expected argument type 'Int'}} {{20-20=Int(}} {{24-24=)}}
418+
// expected-error@-1 {{referencing instance method 'reduce' on 'ClosedRange' requires that 'Self.Stride' conform to 'SignedInteger'}}
419419
}
420420
}
421421

test/Parse/pointer_conversion.swift.gyb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,8 @@ struct NotEquatable {}
307307
func arrayComparison(_ x: [NotEquatable], y: [NotEquatable], p: UnsafeMutablePointer<NotEquatable>) {
308308
var x = x
309309
// Don't allow implicit array-to-pointer conversions in operators.
310-
let a: Bool = x == y // expected-error{{referencing operator function '==' on 'Array' requires that 'NotEquatable' conform to 'Equatable'}}
310+
// There is a note attached to declaration - requirement from conditional conformance of '[NotEquatable]' to 'Equatable'
311+
let a: Bool = x == y // expected-error{{operator function '==' requires that 'NotEquatable' conform to 'Equatable'}}
311312
let _: Bool = p == &x // Allowed!
312313
}
313314

test/Sema/enum_raw_representable.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,7 @@ func sr8150_mutable(obj: SR8150Box) {
204204
sr8150_helper1(opt)
205205
// expected-error@-1 {{cannot convert value of type 'Bar?' to expected argument type 'Double'}} {{23-23=?.rawValue ?? <#default value#>}}
206206
sr8150_helper1(opt ?? Bar.a)
207-
// expected-error@-1 {{no exact matches in call to global function 'sr8150_helper1'}}
208-
// expected-note@-2 {{candidate expects value of type 'Bar' for parameter #0}} {{20-20=(}} {{32-32=).rawValue}}
207+
// expected-error@-1 {{cannot convert value of type 'Bar' to expected argument type 'Double'}} {{20-20=(}} {{32-32=).rawValue}}
209208
let _: Double? = opt
210209
// expected-error@-1 {{cannot convert value of type 'Bar?' to specified type 'Double?'}} {{25-25=?.rawValue}}
211210
}

test/expr/unary/keypath/salvage-with-other-type-errors.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,9 @@ protocol Bindable: class { }
5353

5454
extension Bindable {
5555
func test<Value>(to targetKeyPath: ReferenceWritableKeyPath<Self, Value>, change: Value?) {
56+
// There is also a note attached to declaration - requirement from conditional conformance of 'Optional<Value>' to 'Equatable'
5657
if self[keyPath:targetKeyPath] != change {
57-
// expected-error@-1 {{binary operator '!=' cannot be applied to operands of type 'Value' and 'Value?'}}
58+
// expected-error@-1 {{operator function '!=' requires that 'Value' conform to 'Equatable'}}
5859
self[keyPath: targetKeyPath] = change!
5960
}
6061
}

test/stdlib/ArrayDiagnostics.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ class NotEquatable {}
44

55
func test_ArrayOfNotEquatableIsNotEquatable() {
66
var a = [ NotEquatable(), NotEquatable() ]
7-
if a == a {} // expected-error {{referencing operator function '==' on 'Array' requires that 'NotEquatable' conform to 'Equatable'}}
7+
// There is also a note attached to declaration - requirement from conditional conformance of '[NotEquatable]' to 'Equatable'
8+
if a == a {} // expected-error {{operator function '==' requires that 'NotEquatable' conform to 'Equatable'}}
89
}

test/stdlib/KeyPathAppending.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func mismatchedAppends<T, U, V>(readOnlyLeft: KeyPath<T, U>,
6161
// expected-error@-1 {{no exact matches in call to instance method 'appending'}}
6262

6363
_ = writableRight.appending(path: readOnlyLeft)
64-
// expected-error@-1 {{no exact matches in call to instance method 'appending'}}
64+
// expected-error@-1 {{instance method 'appending(path:)' requires that 'KeyPath<U, V>' inherit from 'KeyPath<U, T>'}}
6565

6666
_ = writableRight.appending(path: writableLeft)
6767
// expected-error@-1 {{cannot convert value of type 'WritableKeyPath<T, U>' to expected argument type 'WritableKeyPath<V, U>'}}
@@ -71,7 +71,7 @@ func mismatchedAppends<T, U, V>(readOnlyLeft: KeyPath<T, U>,
7171
// expected-error@-1 {{no exact matches in call to instance method 'appending'}}
7272

7373
_ = referenceRight.appending(path: readOnlyLeft)
74-
// expected-error@-1 {{no exact matches in call to instance method 'appending'}}
74+
// expected-error@-1 {{instance method 'appending(path:)' requires that 'KeyPath<U, V>' inherit from 'KeyPath<U, T>'}}
7575

7676
_ = referenceRight.appending(path: writableLeft)
7777
// expected-error@-1 {{cannot convert value of type 'WritableKeyPath<T, U>' to expected argument type 'WritableKeyPath<V, U>'}}

0 commit comments

Comments
 (0)