Skip to content

Commit 16862e5

Browse files
authored
Merge pull request #31713 from xedin/no-ranking-with-ambiguous-with-fixes
[ConstraintSystem] Overhaul ambiguity diagnostics
2 parents aaa6b45 + 73667cd commit 16862e5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+597
-259
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,10 @@ ERROR(no_candidates_match_result_type,none,
253253
"no '%0' candidates produce the expected contextual result type %1",
254254
(StringRef, Type))
255255

256+
ERROR(no_candidates_match_argument_type,none,
257+
"no '%0' candidates produce the expected type %1 for parameter #%2",
258+
(StringRef, Type, unsigned))
259+
256260
ERROR(cannot_infer_closure_parameter_type,none,
257261
"unable to infer type of a closure parameter %0 in the current context",
258262
(StringRef))

lib/Sema/CSFix.cpp

Lines changed: 122 additions & 2 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, /*asNote=*/false);
277+
}
278+
279+
return false;
280+
}
281+
255282
ContextualMismatch *ContextualMismatch::create(ConstraintSystem &cs, Type lhs,
256283
Type rhs,
257284
ConstraintLocator *locator) {
@@ -381,6 +408,57 @@ bool AllowFunctionTypeMismatch::diagnose(const Solution &solution,
381408
return coalesceAndDiagnose(solution, {}, asNote);
382409
}
383410

411+
bool AllowFunctionTypeMismatch::diagnoseForAmbiguity(
412+
CommonFixesArray commonFixes) const {
413+
if (ContextualMismatch::diagnoseForAmbiguity(commonFixes))
414+
return true;
415+
416+
auto *locator = getLocator();
417+
// If this is a mismatch between two function types at argument
418+
// position, there is a tailored diagnostic for that.
419+
if (auto argConv =
420+
locator->getLastElementAs<LocatorPathElt::ApplyArgToParam>()) {
421+
auto &cs = getConstraintSystem();
422+
auto &DE = cs.getASTContext().Diags;
423+
auto &solution = *commonFixes[0].first;
424+
425+
auto info = getStructuralTypeContext(solution, locator);
426+
if (!info)
427+
return false;
428+
429+
auto *argLoc = cs.getConstraintLocator(simplifyLocatorToAnchor(locator));
430+
431+
auto overload = solution.getOverloadChoiceIfAvailable(
432+
solution.getCalleeLocator(argLoc));
433+
if (!overload)
434+
return false;
435+
436+
auto name = overload->choice.getName().getBaseName();
437+
DE.diagnose(getLoc(getAnchor()), diag::no_candidates_match_argument_type,
438+
name.userFacingName(), std::get<2>(*info),
439+
argConv->getParamIdx());
440+
441+
for (auto &entry : commonFixes) {
442+
auto &solution = *entry.first;
443+
auto overload = solution.getOverloadChoiceIfAvailable(
444+
solution.getCalleeLocator(argLoc));
445+
446+
if (!(overload && overload->choice.isDecl()))
447+
continue;
448+
449+
auto *decl = overload->choice.getDecl();
450+
if (decl->getLoc().isValid()) {
451+
DE.diagnose(decl, diag::found_candidate_type,
452+
solution.simplifyType(overload->openedType));
453+
}
454+
}
455+
456+
return true;
457+
}
458+
459+
return false;
460+
}
461+
384462
AllowFunctionTypeMismatch *
385463
AllowFunctionTypeMismatch::create(ConstraintSystem &cs, Type lhs, Type rhs,
386464
ConstraintLocator *locator, unsigned index) {
@@ -867,14 +945,19 @@ RemoveAddressOf *RemoveAddressOf::create(ConstraintSystem &cs, Type lhs, Type rh
867945
return new (cs.getAllocator()) RemoveAddressOf(cs, lhs, rhs, locator);
868946
}
869947

948+
RemoveReturn::RemoveReturn(ConstraintSystem &cs, Type resultTy,
949+
ConstraintLocator *locator)
950+
: ContextualMismatch(cs, FixKind::RemoveReturn, resultTy,
951+
cs.getASTContext().TheEmptyTupleType, locator) {}
952+
870953
bool RemoveReturn::diagnose(const Solution &solution, bool asNote) const {
871954
ExtraneousReturnFailure failure(solution, getLocator());
872955
return failure.diagnose(asNote);
873956
}
874957

875-
RemoveReturn *RemoveReturn::create(ConstraintSystem &cs,
958+
RemoveReturn *RemoveReturn::create(ConstraintSystem &cs, Type resultTy,
876959
ConstraintLocator *locator) {
877-
return new (cs.getAllocator()) RemoveReturn(cs, locator);
960+
return new (cs.getAllocator()) RemoveReturn(cs, resultTy, locator);
878961
}
879962

880963
bool CollectionElementContextualMismatch::diagnose(const Solution &solution,
@@ -1079,6 +1162,43 @@ bool IgnoreAssignmentDestinationType::diagnose(const Solution &solution,
10791162
return failure.diagnose(asNote);
10801163
}
10811164

1165+
bool IgnoreAssignmentDestinationType::diagnoseForAmbiguity(
1166+
CommonFixesArray commonFixes) const {
1167+
auto &cs = getConstraintSystem();
1168+
1169+
// If all of the types are the same let's try to diagnose
1170+
// this as if there is no ambiguity.
1171+
if (ContextualMismatch::diagnoseForAmbiguity(commonFixes))
1172+
return true;
1173+
1174+
auto *commonLocator = getLocator();
1175+
auto *assignment = castToExpr<AssignExpr>(commonLocator->getAnchor());
1176+
1177+
auto &solution = *commonFixes.front().first;
1178+
auto *calleeLocator = solution.getCalleeLocator(
1179+
solution.getConstraintLocator(assignment->getSrc()));
1180+
auto overload = solution.getOverloadChoiceIfAvailable(calleeLocator);
1181+
if (!overload)
1182+
return false;
1183+
1184+
auto memberName = overload->choice.getName().getBaseName();
1185+
auto destType = solution.getType(assignment->getDest());
1186+
1187+
auto &DE = cs.getASTContext().Diags;
1188+
// TODO(diagnostics): It might be good to add a tailored diagnostic
1189+
// for cases like this instead of using "contextual" one.
1190+
DE.diagnose(assignment->getSrc()->getLoc(),
1191+
diag::no_candidates_match_result_type,
1192+
memberName.userFacingName(),
1193+
solution.simplifyType(destType)->getRValueType());
1194+
1195+
for (auto &entry : commonFixes) {
1196+
entry.second->diagnose(*entry.first, /*asNote=*/true);
1197+
}
1198+
1199+
return true;
1200+
}
1201+
10821202
IgnoreAssignmentDestinationType *
10831203
IgnoreAssignmentDestinationType::create(ConstraintSystem &cs, Type sourceTy,
10841204
Type destTy,

lib/Sema/CSFix.h

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,10 @@ class TreatRValueAsLValue final : public ConstraintFix {
369369

370370
bool diagnose(const Solution &solution, bool asNote = false) const override;
371371

372+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
373+
return diagnose(*commonFixes.front().first);
374+
}
375+
372376
static TreatRValueAsLValue *create(ConstraintSystem &cs,
373377
ConstraintLocator *locator);
374378
};
@@ -522,6 +526,8 @@ class ContextualMismatch : public ConstraintFix {
522526

523527
bool diagnose(const Solution &solution, bool asNote = false) const override;
524528

529+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override;
530+
525531
static ContextualMismatch *create(ConstraintSystem &cs, Type lhs, Type rhs,
526532
ConstraintLocator *locator);
527533
};
@@ -798,6 +804,10 @@ class UsePropertyWrapper final : public ConstraintFix {
798804

799805
bool diagnose(const Solution &solution, bool asNote = false) const override;
800806

807+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
808+
return diagnose(*commonFixes.front().first);
809+
}
810+
801811
static UsePropertyWrapper *create(ConstraintSystem &cs, VarDecl *wrapped,
802812
bool usingStorageWrapper, Type base,
803813
Type wrapper, ConstraintLocator *locator);
@@ -825,6 +835,10 @@ class UseWrappedValue final : public ConstraintFix {
825835

826836
bool diagnose(const Solution &solution, bool asNote = false) const override;
827837

838+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
839+
return diagnose(*commonFixes.front().first);
840+
}
841+
828842
static UseWrappedValue *create(ConstraintSystem &cs, VarDecl *propertyWrapper,
829843
Type base, Type wrapper,
830844
ConstraintLocator *locator);
@@ -1103,6 +1117,8 @@ class AllowFunctionTypeMismatch final : public ContextualMismatch {
11031117
bool asNote = false) const override;
11041118

11051119
bool diagnose(const Solution &solution, bool asNote = false) const override;
1120+
1121+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override;
11061122
};
11071123

11081124

@@ -1399,16 +1415,16 @@ class AllowInvalidRefInKeyPath final : public ConstraintFix {
13991415
ConstraintLocator *locator);
14001416
};
14011417

1402-
class RemoveReturn final : public ConstraintFix {
1403-
RemoveReturn(ConstraintSystem &cs, ConstraintLocator *locator)
1404-
: ConstraintFix(cs, FixKind::RemoveReturn, locator) {}
1418+
class RemoveReturn final : public ContextualMismatch {
1419+
RemoveReturn(ConstraintSystem &cs, Type resultTy, ConstraintLocator *locator);
14051420

14061421
public:
14071422
std::string getName() const override { return "remove or omit return type"; }
14081423

14091424
bool diagnose(const Solution &solution, bool asNote = false) const override;
14101425

1411-
static RemoveReturn *create(ConstraintSystem &cs, ConstraintLocator *locator);
1426+
static RemoveReturn *create(ConstraintSystem &cs, Type resultTy,
1427+
ConstraintLocator *locator);
14121428
};
14131429

14141430
class CollectionElementContextualMismatch final : public ContextualMismatch {
@@ -1527,10 +1543,6 @@ class IgnoreContextualType : public ContextualMismatch {
15271543

15281544
bool diagnose(const Solution &solution, bool asNote = false) const override;
15291545

1530-
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
1531-
return diagnose(*commonFixes.front().first);
1532-
}
1533-
15341546
static IgnoreContextualType *create(ConstraintSystem &cs, Type resultTy,
15351547
Type specifiedTy,
15361548
ConstraintLocator *locator);
@@ -1548,6 +1560,8 @@ class IgnoreAssignmentDestinationType final : public ContextualMismatch {
15481560

15491561
bool diagnose(const Solution &solution, bool asNote = false) const override;
15501562

1563+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override;
1564+
15511565
static IgnoreAssignmentDestinationType *create(ConstraintSystem &cs,
15521566
Type sourceTy, Type destTy,
15531567
ConstraintLocator *locator);

lib/Sema/CSSimplify.cpp

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,6 +1482,20 @@ assessRequirementFailureImpact(ConstraintSystem &cs, Type requirementType,
14821482
if (!anchor)
14831483
return impact;
14841484

1485+
// If this is a conditional requirement failure associated with a
1486+
// call, let's increase impact of the fix to show that such failure
1487+
// makes member/function unreachable in current context or with
1488+
// given arguments.
1489+
if (auto last = locator.last()) {
1490+
if (last->isConditionalRequirement()) {
1491+
if (auto *expr = getAsExpr(anchor)) {
1492+
auto *parent = cs.getParentExpr(expr);
1493+
if (parent && isa<ApplyExpr>(parent))
1494+
return 5;
1495+
}
1496+
}
1497+
}
1498+
14851499
// If this requirement is associated with a member reference and it
14861500
// was possible to check it before overload choice is bound, that means
14871501
// types came from the context (most likely Self, or associated type(s))
@@ -1508,17 +1522,21 @@ assessRequirementFailureImpact(ConstraintSystem &cs, Type requirementType,
15081522
return 10;
15091523
}
15101524

1511-
// Increase the impact of a conformance fix for a standard library type,
1512-
// as it's unlikely to be a good suggestion. Also do the same for the builtin
1513-
// compiler types Any and AnyObject, which cannot conform to protocols.
1525+
// Increase the impact of a conformance fix for a standard library
1526+
// or foundation type, as it's unlikely to be a good suggestion.
1527+
//
1528+
// Also do the same for the builtin compiler types Any and AnyObject,
1529+
// which cannot conform to protocols.
1530+
//
15141531
// FIXME: We ought not to have the is<TypeVariableType>() condition here, but
15151532
// removing it currently regresses the diagnostic for the test case for
15161533
// rdar://60727310. Once we better handle the separation of conformance fixes
15171534
// from argument mismatches in cases like SR-12438, we should be able to
15181535
// remove it from the condition.
15191536
auto resolvedTy = cs.simplifyType(requirementType);
15201537
if ((requirementType->is<TypeVariableType>() && resolvedTy->isStdlibType()) ||
1521-
resolvedTy->isAny() || resolvedTy->isAnyObject()) {
1538+
resolvedTy->isAny() || resolvedTy->isAnyObject() ||
1539+
getKnownFoundationEntity(resolvedTy->getString())) {
15221540
if (auto last = locator.last()) {
15231541
if (auto requirement = last->getAs<LocatorPathElt::AnyRequirement>()) {
15241542
auto kind = requirement->getRequirementKind();
@@ -3896,11 +3914,16 @@ bool ConstraintSystem::repairFailures(
38963914
if (lhs->isTypeVariableOrMember() || rhs->isTypeVariableOrMember())
38973915
break;
38983916

3917+
// If there is already a fix for contextual failure, let's not
3918+
// record a duplicate one.
3919+
if (hasFixFor(getConstraintLocator(locator)))
3920+
return true;
3921+
38993922
auto purpose = getContextualTypePurpose(anchor);
39003923
if (rhs->isVoid() &&
39013924
(purpose == CTP_ReturnStmt || purpose == CTP_ReturnSingleExpr)) {
39023925
conversionsOrFixes.push_back(
3903-
RemoveReturn::create(*this, getConstraintLocator(locator)));
3926+
RemoveReturn::create(*this, lhs, getConstraintLocator(locator)));
39043927
return true;
39053928
}
39063929

0 commit comments

Comments
 (0)