Skip to content

Commit b0070f5

Browse files
committed
[Diagnostics] Check whether all contextual mismatches has the same type before diagnosing ambiguity
Instead of requiring sub-classes of `ContextualMismatch` to implement `diagnoseForAmbiguity` let's implement it directly on `ContextualMismatch` itself and check whether all of the aggregated fixes have same types on both sides and if so, diagnose as-if it was a single fix.
1 parent 7bbf9fe commit b0070f5

16 files changed

+50
-45
lines changed

lib/Sema/CSFix.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,33 @@ bool ContextualMismatch::diagnose(const Solution &solution, bool asNote) const {
252252
return failure.diagnose(asNote);
253253
}
254254

255+
bool ContextualMismatch::diagnoseForAmbiguity(
256+
CommonFixesArray commonFixes) const {
257+
auto getTypes =
258+
[&](const std::pair<const Solution *, const ConstraintFix *> &entry)
259+
-> std::pair<Type, Type> {
260+
auto &solution = *entry.first;
261+
auto *fix = static_cast<const ContextualMismatch *>(entry.second);
262+
263+
return {solution.simplifyType(fix->getFromType()),
264+
solution.simplifyType(fix->getToType())};
265+
};
266+
267+
auto etalonTypes = getTypes(commonFixes.front());
268+
if (llvm::all_of(
269+
commonFixes,
270+
[&](const std::pair<const Solution *, const ConstraintFix *> &entry) {
271+
auto types = getTypes(entry);
272+
return etalonTypes.first->isEqual(types.first) &&
273+
etalonTypes.second->isEqual(types.second);
274+
})) {
275+
const auto &primary = commonFixes.front();
276+
return primary.second->diagnose(*primary.first, /*aNote=*/false);
277+
}
278+
279+
return false;
280+
}
281+
255282
ContextualMismatch *ContextualMismatch::create(ConstraintSystem &cs, Type lhs,
256283
Type rhs,
257284
ConstraintLocator *locator) {

lib/Sema/CSFix.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,8 @@ class ContextualMismatch : public ConstraintFix {
526526

527527
bool diagnose(const Solution &solution, bool asNote = false) const override;
528528

529+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override;
530+
529531
static ContextualMismatch *create(ConstraintSystem &cs, Type lhs, Type rhs,
530532
ConstraintLocator *locator);
531533
};
@@ -562,10 +564,6 @@ class ForceOptional final : public ContextualMismatch {
562564

563565
bool diagnose(const Solution &solution, bool asNote = false) const override;
564566

565-
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
566-
return diagnose(*commonFixes.front().first);
567-
}
568-
569567
static ForceOptional *create(ConstraintSystem &cs, Type fromType, Type toType,
570568
ConstraintLocator *locator);
571569
};
@@ -675,10 +673,6 @@ class GenericArgumentsMismatch final
675673

676674
bool diagnose(const Solution &solution, bool asNote = false) const override;
677675

678-
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
679-
return diagnose(*commonFixes.front().first);
680-
}
681-
682676
static GenericArgumentsMismatch *create(ConstraintSystem &cs, Type actual,
683677
Type required,
684678
llvm::ArrayRef<unsigned> mismatches,

test/ClangImporter/objc_factory_method.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func testNSErrorFactoryMethod(_ path: String) throws {
7575
}
7676

7777
func testNonInstanceTypeFactoryMethod(_ s: String) {
78-
_ = NSObjectFactory(string: s) // expected-error{{no exact matches in call to initializer}}
78+
_ = NSObjectFactory(string: s) // expected-error{{argument passed to call that takes no arguments}}
7979
}
8080

8181
func testUseOfFactoryMethod(_ queen: Bee) {

test/ClangImporter/objc_implicit_with.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func testNSErrorFactoryMethod(_ path: String) throws {
4343
}
4444

4545
func testNonInstanceTypeFactoryMethod(_ s: String) {
46-
_ = NSObjectFactory(string: s) // expected-error{{no exact matches in call to initializer}}
46+
_ = NSObjectFactory(string: s) // expected-error{{argument passed to call that takes no arguments}}
4747
}
4848

4949
func testUseOfFactoryMethod(_ queen: Bee) {

test/Constraints/diagnostics.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,8 +408,7 @@ enum Color {
408408
}
409409

410410
let _: (Int, Color) = [1,2].map({ ($0, .Unknown("")) })
411-
// expected-error@-1 {{no 'map' candidates produce the expected contextual result type '(Int, Color)'}}
412-
// expected-note@-2 {{found candidate with type '((Int) throws -> (Int, _)) throws -> Array<(Int, _)>'}}
411+
// expected-error@-1 {{cannot convert value of type 'Array<(Int, _)>' to specified type '(Int, Color)'}}
413412

414413
let _: [(Int, Color)] = [1,2].map({ ($0, .Unknown("")) })// expected-error {{missing argument label 'description:' in call}}
415414

test/Constraints/optional.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -424,8 +424,7 @@ func test_force_unwrap_not_being_too_eager() {
424424
// rdar://problem/57097401
425425
func invalidOptionalChaining(a: Any) {
426426
a == "="? // expected-error {{cannot use optional chaining on non-optional value of type 'String'}}
427-
// expected-error@-1 {{value of protocol type 'Any' cannot conform to 'Equatable'; only struct/enum/class types can conform to protocols}}
428-
// expected-note@-2 {{requirement from conditional conformance of 'Any?' to 'Equatable'}}
427+
// expected-error@-1 {{cannot convert value of type 'Any' to expected argument type 'Any.Type?'}}
429428
}
430429

431430
// SR-12309 - Force unwrapping 'nil' compiles without warning

test/Constraints/patterns.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,9 +274,7 @@ struct StaticMembers: Equatable {
274274
static var optProp: Optional = StaticMembers()
275275

276276
static func method(_: Int) -> StaticMembers { return prop }
277-
// expected-note@-1 {{found candidate with type '(Int) -> StaticMembers'}}
278277
static func method(withLabel: Int) -> StaticMembers { return prop }
279-
// expected-note@-1 {{found candidate with type '(Int) -> StaticMembers'}}
280278
static func optMethod(_: Int) -> StaticMembers? { return optProp }
281279

282280
static func ==(x: StaticMembers, y: StaticMembers) -> Bool { return true }
@@ -301,7 +299,7 @@ switch staticMembers {
301299
// TODO: repeated error message
302300
case .optProp: break // expected-error* {{not unwrapped}}
303301

304-
case .method: break // expected-error{{no exact matches in reference to static method 'method'}}
302+
case .method: break // expected-error{{member 'method' expects argument of type 'Int'}}
305303
case .method(0): break
306304
case .method(_): break // expected-error{{'_' can only appear in a pattern}}
307305
case .method(let x): break // expected-error{{cannot appear in an expression}}

test/Constraints/rdar42678836.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// RUN: %target-typecheck-verify-swift
22

33
func foo(chr: Character) -> String {
4-
return String(repeating: String(chr)) // expected-error {{no exact matches in call to initializer}}
5-
// expected-note@-1 {{candidate has partially matching parameter list (repeating: String, count: Int)}}
4+
return String(repeating: String(chr)) // expected-error {{missing argument for parameter 'count' in call}} {{39-39=, count: <#Int#>}}
65
}

test/Constraints/rdar44770297.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ func foo<T: P>(_: () throws -> T) -> T.A? {
88
fatalError()
99
}
1010

11-
let _ = foo() {fatalError()} & nil // expected-error {{binary operator '&' cannot be applied to operands of type 'Never.A?' and '_'}}
11+
let _ = foo() {fatalError()} & nil // expected-error {{value of optional type 'Never.A?' must be unwrapped to a value of type 'Never.A'}}
12+
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}}
13+
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}

test/Sema/diag_ambiguous_overloads.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ func testDiagnoseForAmbiguityCrash(schools: [School]) {
5151

5252
class DefaultValue {
5353
static func foo(_ a: Int) {}
54-
static func foo(_ a: Int, _ b: Int = 1) {} // expected-note {{candidate expects value of type 'Int' for parameter #1}}
55-
static func foo(_ a: Int, _ b: Int = 1, _ c: Int = 2) {} // expected-note {{candidate expects value of type 'Int' for parameter #1}}
54+
static func foo(_ a: Int, _ b: Int = 1) {}
55+
static func foo(_ a: Int, _ b: Int = 1, _ c: Int = 2) {}
5656
}
57-
DefaultValue.foo(1.0, 1) // expected-error {{no exact matches in call to static method 'foo'}}
57+
DefaultValue.foo(1.0, 1) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
5858

5959

6060
class Variadic {

0 commit comments

Comments
 (0)