Skip to content

Commit 13b4fcc

Browse files
committed
[Diagnostics] Diagnose ambiguity related to contextual type specifically
1 parent b0070f5 commit 13b4fcc

File tree

5 files changed

+111
-19
lines changed

5 files changed

+111
-19
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3065,6 +3065,85 @@ diagnoseAmbiguityWithEphemeralPointers(ConstraintSystem &cs,
30653065
return cs.diagnoseAmbiguity(solutions);
30663066
}
30673067

3068+
static bool diagnoseAmbiguityWithContextualType(
3069+
ConstraintSystem &cs, SolutionDiff &solutionDiff,
3070+
ArrayRef<std::pair<const Solution *, const ConstraintFix *>> aggregateFix,
3071+
ArrayRef<Solution> solutions) {
3072+
// Diagnose only if contextual failure is associated with every solution.
3073+
if (aggregateFix.size() < solutions.size())
3074+
return false;
3075+
3076+
auto getResultType =
3077+
[](const std::pair<const Solution *, const ConstraintFix *> &entry)
3078+
-> Type {
3079+
auto &solution = *entry.first;
3080+
auto anchor = entry.second->getLocator()->getAnchor();
3081+
return solution.simplifyType(solution.getType(anchor));
3082+
};
3083+
3084+
auto resultType = getResultType(aggregateFix.front());
3085+
// If right-hand side of the conversion (result of the the AST node)
3086+
// is the same across all of the solutions let's diagnose it as if
3087+
// it it as a single failure.
3088+
if (llvm::all_of(
3089+
aggregateFix,
3090+
[&](const std::pair<const Solution *, const ConstraintFix *> &entry) {
3091+
return resultType->isEqual(getResultType(entry));
3092+
})) {
3093+
auto &fix = aggregateFix.front();
3094+
return fix.second->diagnose(*fix.first, /*asNote=*/false);
3095+
}
3096+
3097+
// If result types are different it could only mean that this is an attempt
3098+
// to convert a reference to, or call of overloaded declaration to a
3099+
// particular type.
3100+
3101+
auto &solution = *aggregateFix.front().first;
3102+
auto *locator = aggregateFix.front().second->getLocator();
3103+
auto *calleeLocator = solution.getCalleeLocator(locator);
3104+
3105+
auto result =
3106+
llvm::find_if(solutionDiff.overloads,
3107+
[&calleeLocator](const SolutionDiff::OverloadDiff &entry) {
3108+
return entry.locator == calleeLocator;
3109+
});
3110+
3111+
if (result == solutionDiff.overloads.end())
3112+
return false;
3113+
3114+
auto &DE = cs.getASTContext().Diags;
3115+
3116+
auto anchor = locator->getAnchor();
3117+
auto name = result->choices.front().getName();
3118+
DE.diagnose(getLoc(anchor), diag::no_candidates_match_result_type,
3119+
name.getBaseName().userFacingName(),
3120+
cs.getContextualType(anchor));
3121+
3122+
for (const auto &solution : solutions) {
3123+
auto overload = solution.getOverloadChoice(calleeLocator);
3124+
if (auto *decl = overload.choice.getDeclOrNull()) {
3125+
auto loc = decl->getLoc();
3126+
if (loc.isInvalid())
3127+
continue;
3128+
3129+
auto type = solution.simplifyType(overload.boundType);
3130+
3131+
if (isExpr<ApplyExpr>(anchor) || isExpr<SubscriptExpr>(anchor) ||
3132+
(isExpr<UnresolvedMemberExpr>(anchor) &&
3133+
castToExpr<UnresolvedMemberExpr>(anchor)->hasArguments())) {
3134+
auto fnType = type->castTo<FunctionType>();
3135+
DE.diagnose(
3136+
loc, diag::cannot_convert_candidate_result_to_contextual_type,
3137+
decl->getName(), fnType->getResult(), cs.getContextualType(anchor));
3138+
} else {
3139+
DE.diagnose(loc, diag::found_candidate_type, type);
3140+
}
3141+
}
3142+
}
3143+
3144+
return true;
3145+
}
3146+
30683147
static bool diagnoseAmbiguity(
30693148
ConstraintSystem &cs, const SolutionDiff::OverloadDiff &ambiguity,
30703149
ArrayRef<std::pair<const Solution *, const ConstraintFix *>> aggregateFix,
@@ -3244,13 +3323,18 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes(
32443323
}
32453324

32463325
llvm::MapVector<ConstraintLocator *, SmallVector<Fix, 4>> fixesByCallee;
3326+
llvm::SmallVector<Fix, 4> contextualFixes;
32473327

32483328
for (const auto &entry : fixes) {
32493329
const auto &solution = *entry.first;
32503330
const auto *fix = entry.second;
32513331

3252-
auto *calleeLocator = solution.getCalleeLocator(fix->getLocator());
3332+
if (fix->getLocator()->isForContextualType()) {
3333+
contextualFixes.push_back({&solution, fix});
3334+
continue;
3335+
}
32533336

3337+
auto *calleeLocator = solution.getCalleeLocator(fix->getLocator());
32543338
fixesByCallee[calleeLocator].push_back({&solution, fix});
32553339
}
32563340

@@ -3270,6 +3354,12 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes(
32703354
consideredFixes.insert(aggregate.begin(), aggregate.end());
32713355
}
32723356

3357+
if (diagnoseAmbiguityWithContextualType(*this, solutionDiff, contextualFixes,
3358+
solutions)) {
3359+
consideredFixes.insert(contextualFixes.begin(), contextualFixes.end());
3360+
diagnosed |= true;
3361+
}
3362+
32733363
// Remove all of the fixes which have been attached to ambiguous
32743364
// overload choices.
32753365
fixes.set_subtract(consideredFixes);

test/Constraints/members.swift

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -617,12 +617,13 @@ func rdar50679161() {
617617
func rdar_50467583_and_50909555() {
618618
if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) {
619619
// rdar://problem/50467583
620-
let _: Set = [Int][] // expected-error {{no exact matches in call to subscript}}
621-
// expected-note@-1 {{found candidate with type '(Int) -> Int'}}
622-
// expected-note@-2 {{found candidate with type '(Range<Int>) -> ArraySlice<Int>'}}
623-
// expected-note@-3 {{found candidate with type '((UnboundedRange_) -> ()) -> ArraySlice<Int>'}}
624-
// expected-note@-4 {{found candidate with type '(RangeSet<Array<Int>.Index>) -> DiscontiguousSlice<[Int]>' (aka '(RangeSet<Int>) -> DiscontiguousSlice<Array<Int>>')}}
625-
// expected-note@-5 {{found candidate with type '(Range<Array<Int>.Index>) -> Slice<[Int]>' (aka '(Range<Int>) -> Slice<Array<Int>>')}}
620+
let _: Set = [Int][] // expected-error {{no 'subscript' candidates produce the expected contextual result type 'Set'}}
621+
// expected-error@-1 {{no exact matches in call to subscript}}
622+
// expected-note@-2 {{found candidate with type '(Int) -> Int'}}
623+
// expected-note@-3 {{found candidate with type '(Range<Int>) -> ArraySlice<Int>'}}
624+
// expected-note@-4 {{found candidate with type '((UnboundedRange_) -> ()) -> ArraySlice<Int>'}}
625+
// expected-note@-5 {{found candidate with type '(RangeSet<Array<Int>.Index>) -> DiscontiguousSlice<[Int]>' (aka '(RangeSet<Int>) -> DiscontiguousSlice<Array<Int>>')}}
626+
// expected-note@-6 {{found candidate with type '(Range<Array<Int>.Index>) -> Slice<[Int]>' (aka '(Range<Int>) -> Slice<Array<Int>>')}}
626627
}
627628

628629
// rdar://problem/50909555

test/Constraints/overload.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,12 @@ func test20886179(_ handlers: [(Int) -> Void], buttonIndex: Int) {
127127

128128
// The problem here is that the call has a contextual result type incompatible
129129
// with *all* overload set candidates. This is not an ambiguity.
130-
func overloaded_identity(_ a : Int) -> Int {} // expected-note {{found this candidate}}
131-
func overloaded_identity(_ b : Float) -> Float {} // expected-note {{found this candidate}}
130+
func overloaded_identity(_ a : Int) -> Int {} // expected-note {{'overloaded_identity' produces 'Int', not the expected contextual result type '()'}} expected-note {{'overloaded_identity' declared her}}
131+
func overloaded_identity(_ b : Float) -> Float {} // expected-note {{'overloaded_identity' produces 'Float', not the expected contextual result type '()'}}
132132

133133
func test_contextual_result_1() {
134-
return overloaded_identity() // expected-error {{no exact matches in call to global function 'overloaded_identity'}}
134+
return overloaded_identity() // expected-error {{missing argument for parameter #1 in call}}
135+
// expected-error@-1 {{no 'overloaded_identity' candidates produce the expected contextual result type '()'}}
135136
}
136137

137138
func test_contextual_result_2() {

test/Generics/function_defs.swift

Lines changed: 7 additions & 9 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{{no exact matches in reference to instance method '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
@@ -131,15 +131,15 @@ protocol Subscriptable {
131131
func getIndex() -> Index
132132
func getValue() -> Value
133133

134-
subscript (index : Index) -> Value { get set }
134+
subscript (index : Index) -> Value { get set } // expected-note {{found this candidate}}
135135
}
136136

137137
protocol IntSubscriptable {
138138
associatedtype ElementType
139139

140140
func getElement() -> ElementType
141141

142-
subscript (index : Int) -> ElementType { get }
142+
subscript (index : Int) -> ElementType { get } // expected-note {{found this candidate}}
143143
}
144144

145145
func subscripting<T : Subscriptable & IntSubscriptable>(_ t: T) {
@@ -152,9 +152,7 @@ func subscripting<T : Subscriptable & IntSubscriptable>(_ t: T) {
152152
element = t[17]
153153
t[42] = element // expected-error{{cannot assign through subscript: subscript is get-only}}
154154

155-
// Suggests the Int form because we prefer concrete matches to generic matches in diagnosis.
156-
t[value] = 17 // expected-error{{cannot convert value of type 'T.Value' to expected argument type 'Int'}}
157-
// expected-error@-1 {{cannot assign value of type 'Int' to subscript of type 'T.ElementType'}}
155+
t[value] = 17 // expected-error{{no exact matches in call to subscript}}
158156
}
159157

160158
//===----------------------------------------------------------------------===//

test/Parse/recovery.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ func garbage() -> () {
1010
var a : Int
1111
) this line is invalid, but we will stop at the keyword below... // expected-error{{expected expression}}
1212
return a + "a" // expected-error{{binary operator '+' cannot be applied to operands of type 'Int' and 'String'}} expected-note {{overloads for '+' exist with these partially matching parameter lists: (Int, Int), (String, String)}}
13+
// expected-error@-1 {{no '+' candidates produce the expected contextual result type '()'}}
1314
}
1415

1516
func moreGarbage() -> () {
1617
) this line is invalid, but we will stop at the declaration... // expected-error{{expected expression}}
1718
func a() -> Int { return 4 }
1819
return a() + "a" // expected-error{{binary operator '+' cannot be applied to operands of type 'Int' and 'String'}} expected-note {{overloads for '+' exist with these partially matching parameter lists: (Int, Int), (String, String)}}
20+
// expected-error@-1 {{no '+' candidates produce the expected contextual result type '()'}}
1921
}
2022

2123

0 commit comments

Comments
 (0)