@@ -987,6 +987,8 @@ class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{
987
987
bool diagnoseClosureExpr (ClosureExpr *closureExpr, Type contextualType,
988
988
std::function<bool (Type, Type)> resultTypeProcessor);
989
989
990
+ bool diagnoseSubscriptErrors (SubscriptExpr *SE, bool performingSet);
991
+
990
992
bool visitExpr (Expr *E);
991
993
bool visitIdentityExpr (IdentityExpr *E);
992
994
bool visitTryExpr (TryExpr *E);
@@ -4478,9 +4480,7 @@ bool FailureDiagnosis::diagnoseParameterErrors(CalleeCandidateInfo &CCI,
4478
4480
return false ;
4479
4481
}
4480
4482
4481
-
4482
-
4483
- bool FailureDiagnosis::visitSubscriptExpr (SubscriptExpr *SE) {
4483
+ bool FailureDiagnosis::diagnoseSubscriptErrors (SubscriptExpr *SE, bool inAssignmentDestination) {
4484
4484
auto baseExpr = typeCheckChildIndependently (SE->getBase ());
4485
4485
if (!baseExpr) return true ;
4486
4486
auto baseType = CS.getType (baseExpr);
@@ -4494,8 +4494,7 @@ bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) {
4494
4494
std::function<bool (ArrayRef<OverloadChoice>)> callback =
4495
4495
[&](ArrayRef<OverloadChoice> candidates) -> bool {
4496
4496
CalleeCandidateInfo calleeInfo (Type (), candidates, SE->hasTrailingClosure (),
4497
- CS,
4498
- /* selfAlreadyApplied*/ false );
4497
+ CS, /* selfAlreadyApplied*/ false );
4499
4498
4500
4499
// We're about to typecheck the index list, which needs to be processed with
4501
4500
// self already applied.
@@ -4522,7 +4521,9 @@ bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) {
4522
4521
calleeInfo.filterList (
4523
4522
[&](UncurriedCandidate cand) -> CalleeCandidateInfo::ClosenessResultTy {
4524
4523
// Classify how close this match is. Non-subscript decls don't match.
4525
- if (!dyn_cast_or_null<SubscriptDecl>(cand.getDecl ()))
4524
+ auto subscriptDecl = dyn_cast_or_null<SubscriptDecl>(cand.getDecl ());
4525
+ if (!subscriptDecl ||
4526
+ (inAssignmentDestination && !subscriptDecl->isSettable ()))
4526
4527
return {CC_GeneralMismatch, {}};
4527
4528
4528
4529
// Check whether the self type matches.
@@ -4544,8 +4545,7 @@ bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) {
4544
4545
});
4545
4546
4546
4547
// If the closest matches all mismatch on self, we either have something
4547
- // that
4548
- // cannot be subscripted, or an ambiguity.
4548
+ // that cannot be subscripted, or an ambiguity.
4549
4549
if (calleeInfo.closeness == CC_SelfMismatch) {
4550
4550
diagnose (SE->getLoc (), diag::cannot_subscript_base, baseType)
4551
4551
.highlight (SE->getBase ()->getSourceRange ());
@@ -4575,6 +4575,20 @@ bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) {
4575
4575
4576
4576
if (CS.TC .getTypeOfExpressionWithoutApplying (expr, CS.DC , decl))
4577
4577
return false ;
4578
+
4579
+ // If we are down to a single candidate but with an unresolved
4580
+ // index type, we can substitute in the base type to get a simpler
4581
+ // and more concrete expected type for this subscript decl, in order
4582
+ // to diagnose a better error.
4583
+ if (baseType && indexType->hasUnresolvedType ()) {
4584
+ UncurriedCandidate cand = calleeInfo.candidates [0 ];
4585
+ auto candType = baseType->getTypeOfMember (CS.DC ->getParentModule (),
4586
+ cand.getDecl (), nullptr );
4587
+ auto paramsType = candType->getAs <FunctionType>()->getInput ();
4588
+ if (!typeCheckChildIndependently (indexExpr, paramsType,
4589
+ CTP_CallArgument, TCC_ForceRecheck))
4590
+ return true ;
4591
+ }
4578
4592
}
4579
4593
4580
4594
diagnose (SE->getLoc (), message, baseType, indexType)
@@ -4599,6 +4613,12 @@ bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) {
4599
4613
if (calleeInfo.diagnoseSimpleErrors (SE))
4600
4614
return true ;
4601
4615
4616
+ // If we haven't found a diagnostic yet, and we are in an assignment's
4617
+ // destination, continue with diagnosing the assignment rather than giving
4618
+ // a last resort diagnostic here.
4619
+ if (inAssignmentDestination)
4620
+ return false ;
4621
+
4602
4622
diagnose (SE->getLoc (), diag::cannot_subscript_with_index, baseType,
4603
4623
indexType);
4604
4624
@@ -4615,6 +4635,9 @@ bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) {
4615
4635
callback);
4616
4636
}
4617
4637
4638
+ bool FailureDiagnosis::visitSubscriptExpr (SubscriptExpr *SE) {
4639
+ return diagnoseSubscriptErrors (SE, /* inAssignmentDestination = */ false );
4640
+ }
4618
4641
4619
4642
namespace {
4620
4643
// / Type checking listener for pattern binding initializers.
@@ -5833,6 +5856,14 @@ bool FailureDiagnosis::visitAssignExpr(AssignExpr *assignExpr) {
5833
5856
// If the result type is a non-lvalue, then we are failing because it is
5834
5857
// immutable and that's not a great thing to assign to.
5835
5858
if (!destType->hasLValueType ()) {
5859
+ // If the destination is a subscript, the problem may actually be that we
5860
+ // incorrectly decided on a get-only subscript overload, and we may be able
5861
+ // to come up with a better diagnosis by looking only at subscript candidates
5862
+ // that are set-able.
5863
+ if (auto subscriptExpr = dyn_cast<SubscriptExpr>(destExpr)) {
5864
+ if (diagnoseSubscriptErrors (subscriptExpr, /* inAssignmentDestination = */ true ))
5865
+ return true ;
5866
+ }
5836
5867
CS.diagnoseAssignmentFailure (destExpr, destType, assignExpr->getLoc ());
5837
5868
return true ;
5838
5869
}
0 commit comments