Skip to content

Commit 34f5b52

Browse files
committed
[Diagnostics] Diagnose ambiguities related to contextual type mismatch
If none of the candidates produce expected contextual type, record all of the posibilities to produce a note per and diagnose this as contextual type mismatch instead of a reference ambiguity.
1 parent a9f1144 commit 34f5b52

File tree

6 files changed

+36
-12
lines changed

6 files changed

+36
-12
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2152,6 +2152,16 @@ bool ContextualFailure::diagnoseAsError() {
21522152
return true;
21532153
}
21542154

2155+
bool ContextualFailure::diagnoseAsNote() {
2156+
auto overload = getChoiceFor(getLocator());
2157+
if (!(overload && overload->choice.isDecl()))
2158+
return false;
2159+
2160+
auto *decl = overload->choice.getDecl();
2161+
emitDiagnostic(decl, diag::found_candidate_type, getFromType());
2162+
return true;
2163+
}
2164+
21552165
static Optional<Diag<Type>>
21562166
getContextualNilDiagnostic(ContextualTypePurpose CTP) {
21572167
switch (CTP) {

lib/Sema/CSDiagnostics.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,8 @@ class ContextualFailure : public FailureDiagnostic {
722722

723723
bool diagnoseAsError() override;
724724

725+
bool diagnoseAsNote() override;
726+
725727
/// If we're trying to convert something to `nil`.
726728
bool diagnoseConversionToNil() const;
727729

lib/Sema/ConstraintSystem.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2696,6 +2696,8 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes(
26962696
const auto *fix = viableSolutions.front().second;
26972697
auto *commonAnchor = commonCalleeLocator->getAnchor();
26982698
auto &DE = getASTContext().Diags;
2699+
auto name = decl->getFullName();
2700+
26992701
if (fix->getKind() == FixKind::UseSubscriptOperator) {
27002702
auto *UDE = cast<UnresolvedDotExpr>(commonAnchor);
27012703
DE.diagnose(commonAnchor->getLoc(),
@@ -2705,8 +2707,18 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes(
27052707
DE.diagnose(commonAnchor->getLoc(),
27062708
diag::no_overloads_match_exactly_in_assignment,
27072709
decl->getBaseName());
2710+
} else if (llvm::all_of(
2711+
viableSolutions,
2712+
[](const std::pair<const Solution *, const ConstraintFix *>
2713+
&fix) {
2714+
auto *locator = fix.second->getLocator();
2715+
return locator
2716+
->isLastElement<LocatorPathElt::ContextualType>();
2717+
})) {
2718+
auto baseName = name.getBaseName();
2719+
DE.diagnose(commonAnchor->getLoc(), diag::no_candidates_match_result_type,
2720+
baseName.userFacingName(), getContextualType());
27082721
} else {
2709-
auto name = decl->getFullName();
27102722
// Three choices here:
27112723
// 1. If this is a special name avoid printing it because
27122724
// printing kind is sufficient;

test/Generics/function_defs.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ protocol Overload {
7878
func f1(_: B) -> B // expected-note {{candidate expects value of type 'OtherOvl.B' for parameter #1}}
7979
func f2(_: Int) -> A // expected-note{{found this candidate}}
8080
func f2(_: Int) -> B // expected-note{{found this candidate}}
81-
func f3(_: Int) -> Int // expected-note {{found this candidate}}
82-
func f3(_: Float) -> Float // expected-note {{found this candidate}}
83-
func f3(_: Self) -> Self // expected-note {{found this candidate}}
81+
func f3(_: Int) -> Int // expected-note {{found candidate with type '(Int) -> Int'}}
82+
func f3(_: Float) -> Float // expected-note {{found candidate with type '(Float) -> Float'}}
83+
func f3(_: Self) -> Self // expected-note {{found candidate with type '(OtherOvl) -> OtherOvl'}}
8484

8585
var prop : Self { get }
8686
}
@@ -112,7 +112,7 @@ func testOverload<Ovl : Overload, OtherOvl : Overload>(_ ovl: Ovl, ovl2: Ovl,
112112
var f3f : (Float) -> Float = ovl.f3
113113
var f3ovl_1 : (Ovl) -> Ovl = ovl.f3
114114
var f3ovl_2 : (Ovl) -> Ovl = ovl2.f3
115-
var f3ovl_3 : (Ovl) -> Ovl = other.f3 // expected-error{{ambiguous reference to member 'f3'}}
115+
var f3ovl_3 : (Ovl) -> Ovl = other.f3 // expected-error{{no 'f3' candidates produce the expected contextual result type '(Ovl) -> Ovl'}}
116116

117117
var f3i_unbound : (Ovl) -> (Int) -> Int = Ovl.f3
118118
var f3f_unbound : (Ovl) -> (Float) -> Float = Ovl.f3

test/decl/subscript/subscripting.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -349,9 +349,9 @@ func testUnresolvedMemberSubscriptFixit(_ s0: GenSubscriptFixitTest) {
349349

350350
struct SubscriptTest1 {
351351
subscript(keyword:String) -> Bool { return true }
352-
// expected-note@-1 4 {{found this candidate}}
352+
// expected-note@-1 3 {{found this candidate}} expected-note@-1 {{found candidate with type 'Bool'}}
353353
subscript(keyword:String) -> String? {return nil }
354-
// expected-note@-1 4 {{found this candidate}}
354+
// expected-note@-1 3 {{found this candidate}} expected-note@-1 {{found candidate with type 'String?'}}
355355

356356
subscript(arg: SubClass) -> Bool { return true } // expected-note {{declared here}}
357357
subscript(arg: Protocol) -> Bool { return true } // expected-note 2 {{declared here}}
@@ -361,7 +361,7 @@ struct SubscriptTest1 {
361361
}
362362

363363
func testSubscript1(_ s1 : SubscriptTest1) {
364-
let _ : Int = s1["hello"] // expected-error {{ambiguous subscript with base type 'SubscriptTest1' and index type 'String'}}
364+
let _ : Int = s1["hello"] // expected-error {{no 'subscript' candidates produce the expected contextual result type 'Int'}}
365365

366366
if s1["hello"] {}
367367

validation-test/stdlib/FixedPointDiagnostics.swift.gyb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
// RUN: %line-directive %t/main.swift -- %target-swift-frontend -typecheck -verify -swift-version 4.2 %t/main.swift
44

55
func testUnaryMinusInUnsigned() {
6-
var a: UInt8 = -(1) // expected-error {{cannot convert value of type 'Int' to specified type 'UInt8'}} expected-note * {{}} expected-warning * {{}}
6+
var a: UInt8 = -(1) // expected-error {{no '-' candidates produce the expected contextual result type 'UInt8'}} expected-note * {{}} expected-warning * {{}}
77

8-
var b: UInt16 = -(1) // expected-error {{cannot convert value of type 'Int' to specified type 'UInt16'}} expected-note * {{}} expected-warning * {{}}
8+
var b: UInt16 = -(1) // expected-error {{no '-' candidates produce the expected contextual result type 'UInt16'}} expected-note * {{}} expected-warning * {{}}
99

10-
var c: UInt32 = -(1) // expected-error {{cannot convert value of type 'Int' to specified type 'UInt32'}} expected-note * {{}} expected-warning * {{}}
10+
var c: UInt32 = -(1) // expected-error {{no '-' candidates produce the expected contextual result type 'UInt32'}} expected-note * {{}} expected-warning * {{}}
1111

12-
var d: UInt64 = -(1) // expected-error {{cannot convert value of type 'Int' to specified type 'UInt64'}} expected-note * {{}} expected-warning * {{}}
12+
var d: UInt64 = -(1) // expected-error {{no '-' candidates produce the expected contextual result type 'UInt64'}} expected-note * {{}} expected-warning * {{}}
1313
}
1414

1515
// Int and UInt are not identical to any fixed-size integer type

0 commit comments

Comments
 (0)