Skip to content

Commit 651c27b

Browse files
hborlaxedin
authored andcommitted
[Diagnostics] Add CSFix::diagnoseForAmbiguity for diagnosing common
fixes that appear in all solutions.
1 parent 54706ba commit 651c27b

File tree

7 files changed

+58
-25
lines changed

7 files changed

+58
-25
lines changed

lib/Sema/CSFix.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,24 @@ bool DefineMemberBasedOnUse::diagnose(bool asNote) const {
479479
return AlreadyDiagnosed || failure.diagnose(asNote);
480480
}
481481

482+
bool
483+
DefineMemberBasedOnUse::diagnoseForAmbiguity(ArrayRef<Solution> solutions) const {
484+
Type concreteBaseType;
485+
for (const auto &solution: solutions) {
486+
auto baseType = solution.simplifyType(BaseType);
487+
if (!concreteBaseType)
488+
concreteBaseType = baseType;
489+
490+
if (concreteBaseType->getCanonicalType() != baseType->getCanonicalType()) {
491+
getConstraintSystem().getASTContext().Diags.diagnose(getAnchor()->getLoc(),
492+
diag::unresolved_member_no_inference, Name);
493+
return true;
494+
}
495+
}
496+
497+
return diagnose();
498+
}
499+
482500
DefineMemberBasedOnUse *
483501
DefineMemberBasedOnUse::create(ConstraintSystem &cs, Type baseType,
484502
DeclNameRef member, bool alreadyDiagnosed,

lib/Sema/CSFix.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,8 @@ class ConstraintFix {
289289
/// Diagnose a failure associated with this fix.
290290
virtual bool diagnose(bool asNote = false) const = 0;
291291

292+
virtual bool diagnoseForAmbiguity(ArrayRef<Solution> solutions) const { return false; }
293+
292294
void print(llvm::raw_ostream &Out) const;
293295

294296
SWIFT_DEBUG_DUMP;
@@ -843,6 +845,8 @@ class DefineMemberBasedOnUse final : public ConstraintFix {
843845

844846
bool diagnose(bool asNote = false) const override;
845847

848+
bool diagnoseForAmbiguity(ArrayRef<Solution> solutions) const override;
849+
846850
static DefineMemberBasedOnUse *create(ConstraintSystem &cs, Type baseType,
847851
DeclNameRef member, bool alreadyDiagnosed,
848852
ConstraintLocator *locator);
@@ -1109,6 +1113,10 @@ class AddMissingArguments final
11091113

11101114
bool diagnose(bool asNote = false) const override;
11111115

1116+
bool diagnoseForAmbiguity(ArrayRef<Solution> solutions) const override {
1117+
return diagnose();
1118+
}
1119+
11121120
static AddMissingArguments *create(ConstraintSystem &cs,
11131121
llvm::ArrayRef<Param> synthesizedArgs,
11141122
ConstraintLocator *locator);
@@ -1149,6 +1157,10 @@ class RemoveExtraneousArguments final
11491157

11501158
bool diagnose(bool asNote = false) const override;
11511159

1160+
bool diagnoseForAmbiguity(ArrayRef<Solution> solutions) const override {
1161+
return diagnose();
1162+
}
1163+
11521164
/// FIXME(diagnostics): Once `resolveDeclRefExpr` is gone this
11531165
/// logic would be obsolete.
11541166
///
@@ -1349,6 +1361,10 @@ class DefaultGenericArgument final : public ConstraintFix {
13491361

13501362
bool diagnose(bool asNote = false) const override;
13511363

1364+
bool diagnoseForAmbiguity(ArrayRef<Solution> solutions) const override {
1365+
return diagnose();
1366+
}
1367+
13521368
static DefaultGenericArgument *create(ConstraintSystem &cs,
13531369
GenericTypeParamType *param,
13541370
ConstraintLocator *locator);
@@ -1420,6 +1436,10 @@ class IgnoreContextualType : public ContextualMismatch {
14201436

14211437
bool diagnose(bool asNote = false) const override;
14221438

1439+
bool diagnoseForAmbiguity(ArrayRef<Solution> solutions) const override {
1440+
return diagnose();
1441+
}
1442+
14231443
static IgnoreContextualType *create(ConstraintSystem &cs, Type resultTy,
14241444
Type specifiedTy,
14251445
ConstraintLocator *locator);

lib/Sema/ConstraintSystem.cpp

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2761,22 +2761,9 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes(
27612761
}
27622762
}
27632763

2764-
// If there are no overload differences, diagnose the common fixes.
2765-
SolutionDiff solutionDiff(solutions);
2766-
if (solutionDiff.overloads.size() == 0) {
2767-
bool diagnosed = false;
2768-
ConstraintSystem::SolverScope scope(*this);
2769-
applySolution(solutions.front());
2770-
for (auto fixes: aggregatedFixes) {
2771-
// A common fix must appear in all solutions
2772-
if (fixes.second.size() < solutions.size()) continue;
2773-
diagnosed |= fixes.second.front()->diagnose();
2774-
}
2775-
return diagnosed;
2776-
}
2777-
27782764
// If there is an overload difference, let's see if there's a common callee
27792765
// locator for all of the fixes.
2766+
SolutionDiff solutionDiff(solutions);
27802767
auto ambiguousOverload = llvm::find_if(solutionDiff.overloads,
27812768
[&](const auto &overloadDiff) {
27822769
return llvm::all_of(aggregatedFixes, [&](const auto &aggregatedFix) {
@@ -2798,8 +2785,18 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes(
27982785
});
27992786
});
28002787

2801-
if (ambiguousOverload == solutionDiff.overloads.end())
2802-
return false;
2788+
// If we didn't find an ambiguous overload, diagnose the common fixes.
2789+
if (ambiguousOverload == solutionDiff.overloads.end()) {
2790+
bool diagnosed = false;
2791+
ConstraintSystem::SolverScope scope(*this);
2792+
applySolution(solutions.front());
2793+
for (auto fixes: aggregatedFixes) {
2794+
// A common fix must appear in all solutions
2795+
if (fixes.second.size() < solutions.size()) continue;
2796+
diagnosed |= fixes.second.front()->diagnoseForAmbiguity(solutions);
2797+
}
2798+
return diagnosed;
2799+
}
28032800

28042801
auto *commonCalleeLocator = ambiguousOverload->locator;
28052802
auto *decl = ambiguousOverload->choices.front().getDecl();

test/Constraints/closures.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ func testMap() {
186186
}
187187

188188
// <rdar://problem/22414757> "UnresolvedDot" "in wrong phase" assertion from verifier
189-
[].reduce { $0 + $1 } // expected-error {{cannot invoke 'reduce' with an argument list of type '(_)'}}
189+
[].reduce { $0 + $1 } // expected-error {{missing argument for parameter #1 in call}}
190190

191191

192192

test/Misc/misc_diagnostics.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@ takesInt(noParams(1)) // expected-error{{argument passed to call that takes no a
4747
takesInt(takesAndReturnsInt("")) // expected-error{{cannot convert value of type 'String' to expected argument type 'Int'}}
4848

4949
// Test error recovery for type expressions.
50-
struct MyArray<Element> {}
50+
struct MyArray<Element> {} // expected-note {{'Element' declared as parameter to type 'MyArray'}}
5151
class A {
5252
var a: MyArray<Int>
5353
init() {
54-
a = MyArray<Int // expected-error{{binary operator '<' cannot be applied to operands of type 'MyArray<_>.Type' and 'Int.Type'}}
55-
// expected-note @-1 {{overloads for '<' exist with these partially matching parameter lists:}}
54+
a = MyArray<Int // expected-error {{generic parameter 'Element' could not be inferred}}
55+
// expected-note@-1 {{explicitly specify the generic arguments to fix this issue}}
5656
}
5757
}
5858

test/Sema/diag_ambiguous_overloads.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ func fe(_: Int, _: Int) {}
1212
fe(E.baz) // expected-error {{type 'E' has no member 'baz'; did you mean 'bar'?}}
1313
fe(.baz) // expected-error {{reference to member 'baz' cannot be resolved without a contextual type}}
1414

15-
// FIXME: maybe complain about .nope also?
16-
fe(.nope, .nyet) // expected-error {{reference to member 'nyet' cannot be resolved without a contextual type}}
15+
fe(.nope, .nyet) // expected-error {{type 'Int' has no member 'nope'}}
16+
// expected-error@-1 {{reference to member 'nyet' cannot be resolved without a contextual type}}
1717

1818
func fg<T>(_ f: (T) -> T) -> Void {} // expected-note {{in call to function 'fg'}}
1919
fg({x in x}) // expected-error {{generic parameter 'T' could not be inferred}}

test/type/protocol_composition.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,7 @@ takesP1AndP2([Swift.AnyObject & P1 & P2]())
173173
takesP1AndP2([AnyObject & protocol_composition.P1 & P2]())
174174
takesP1AndP2([AnyObject & P1 & protocol_composition.P2]())
175175
takesP1AndP2([DoesNotExist & P1 & P2]()) // expected-error {{use of unresolved identifier 'DoesNotExist'}}
176-
// TODO(diagnostics): The problem here is that `&` is interpreted as a binary operator, we need to re-think
177-
// how "missing member" fix is implemented because currently it finds N solutions with multiple fixes.
178-
takesP1AndP2([Swift.DoesNotExist & P1 & P2]()) // expected-error {{cannot invoke '' with no arguments}}
176+
takesP1AndP2([Swift.DoesNotExist & P1 & P2]()) // expected-error {{module 'Swift' has no member named 'DoesNotExist'}}
179177

180178
typealias T08 = P1 & inout P2 // expected-error {{'inout' may only be used on parameters}}
181179
typealias T09 = P1 & __shared P2 // expected-error {{'__shared' may only be used on parameters}}

0 commit comments

Comments
 (0)