@@ -981,100 +981,128 @@ bool AssignmentFailure::diagnoseAsError() {
981
981
// we find a node in the lvalue path that is problematic, this returns it.
982
982
auto immInfo = resolveImmutableBase (destExpr);
983
983
984
- // Otherwise, we cannot resolve this because the available setter candidates
985
- // are all mutating and the base must be mutating. If we dug out a
986
- // problematic decl, we can produce a nice tailored diagnostic.
987
- if (auto *VD = dyn_cast_or_null<VarDecl>(immInfo.second )) {
988
- std::string message = " '" ;
989
- message += VD->getName ().str ().str ();
990
- message += " '" ;
991
-
992
- auto type = getType (immInfo.first );
993
- auto bgt = type ? type->getAs <BoundGenericType>() : nullptr ;
994
-
995
- if (bgt && bgt->getDecl () == getASTContext ().getKeyPathDecl ())
996
- message += " is a read-only key path" ;
997
- else if (VD->isCaptureList ())
998
- message += " is an immutable capture" ;
999
- else if (VD->isImplicit ())
1000
- message += " is immutable" ;
1001
- else if (VD->isLet ())
1002
- message += " is a 'let' constant" ;
1003
- else if (!VD->isSettable (DC))
1004
- message += " is a get-only property" ;
1005
- else if (!VD->isSetterAccessibleFrom (DC))
1006
- message += " setter is inaccessible" ;
1007
- else {
1008
- message += " is immutable" ;
1009
- }
1010
-
1011
- emitDiagnostic (Loc, DeclDiagnostic, message)
1012
- .highlight (immInfo.first ->getSourceRange ());
1013
-
1014
- // If there is a masked instance variable of the same type, emit a
1015
- // note to fixit prepend a 'self.'.
1016
- if (auto typeContext = DC->getInnermostTypeContext ()) {
1017
- UnqualifiedLookup lookup (VD->getFullName (), typeContext,
1018
- getASTContext ().getLazyResolver ());
1019
- for (auto &result : lookup.Results ) {
1020
- const VarDecl *typeVar = dyn_cast<VarDecl>(result.getValueDecl ());
1021
- if (typeVar && typeVar != VD && typeVar->isSettable (DC) &&
1022
- typeVar->isSetterAccessibleFrom (DC) &&
1023
- typeVar->getType ()->isEqual (VD->getType ())) {
1024
- // But not in its own accessor.
1025
- auto AD =
1026
- dyn_cast_or_null<AccessorDecl>(DC->getInnermostMethodContext ());
1027
- if (!AD || AD->getStorage () != typeVar) {
1028
- emitDiagnostic (Loc, diag::masked_instance_variable,
1029
- typeContext->getSelfTypeInContext ())
1030
- .fixItInsert (Loc, " self." );
984
+ Optional<OverloadChoice> choice = immInfo.second ;
985
+
986
+ // Attempt diagnostics based on the overload choice.
987
+ if (choice.hasValue ()) {
988
+
989
+ if (!choice->isDecl ()) {
990
+ if (choice->getKind () == OverloadChoiceKind::KeyPathApplication &&
991
+ !isa<ApplyExpr>(immInfo.first )) {
992
+ std::string message = " the key path" ;
993
+ if (auto *SE = dyn_cast<SubscriptExpr>(immInfo.first )) {
994
+ if (auto *tupleExpr = dyn_cast<TupleExpr>(SE->getIndex ())) {
995
+ if (auto *DRE = dyn_cast<DeclRefExpr>(tupleExpr->getElement (0 ))) {
996
+ auto identifier = DRE->getDecl ()->getBaseName ().getIdentifier ();
997
+ message = " '" + identifier.str ().str () + " '" ;
998
+ }
1031
999
}
1032
1000
}
1001
+ emitDiagnostic (Loc, DeclDiagnostic, message + " is a read-only key path" )
1002
+ .highlight (immInfo.first ->getSourceRange ());
1003
+ return true ;
1004
+ }
1005
+ return false ;
1006
+ }
1007
+
1008
+ // Otherwise, we cannot resolve this because the available setter candidates
1009
+ // are all mutating and the base must be mutating. If we dug out a
1010
+ // problematic decl, we can produce a nice tailored diagnostic.
1011
+ if (auto *VD = dyn_cast_or_null<VarDecl>(choice->getDecl ())) {
1012
+ std::string message = " '" ;
1013
+ message += VD->getName ().str ().str ();
1014
+ message += " '" ;
1015
+
1016
+ auto type = getType (immInfo.first );
1017
+
1018
+ if (isKnownKeyPathType (type))
1019
+ message += " is a read-only key path" ;
1020
+ else if (VD->isCaptureList ())
1021
+ message += " is an immutable capture" ;
1022
+ else if (VD->isImplicit ())
1023
+ message += " is immutable" ;
1024
+ else if (VD->isLet ())
1025
+ message += " is a 'let' constant" ;
1026
+ else if (!VD->isSettable (DC))
1027
+ message += " is a get-only property" ;
1028
+ else if (!VD->isSetterAccessibleFrom (DC))
1029
+ message += " setter is inaccessible" ;
1030
+ else {
1031
+ message += " is immutable" ;
1033
1032
}
1034
- }
1035
1033
1036
- // If this is a simple variable marked with a 'let', emit a note to fixit
1037
- // hint it to 'var'.
1038
- VD->emitLetToVarNoteIfSimple (DC);
1039
- return true ;
1040
- }
1034
+ emitDiagnostic (Loc, DeclDiagnostic, message)
1035
+ .highlight (immInfo.first ->getSourceRange ());
1036
+
1037
+ // If there is a masked instance variable of the same type, emit a
1038
+ // note to fixit prepend a 'self.'.
1039
+ if (auto typeContext = DC->getInnermostTypeContext ()) {
1040
+ UnqualifiedLookup lookup (VD->getFullName (), typeContext,
1041
+ getASTContext ().getLazyResolver ());
1042
+ for (auto &result : lookup.Results ) {
1043
+ const VarDecl *typeVar = dyn_cast<VarDecl>(result.getValueDecl ());
1044
+ if (typeVar && typeVar != VD && typeVar->isSettable (DC) &&
1045
+ typeVar->isSetterAccessibleFrom (DC) &&
1046
+ typeVar->getType ()->isEqual (VD->getType ())) {
1047
+ // But not in its own accessor.
1048
+ auto AD =
1049
+ dyn_cast_or_null<AccessorDecl>(DC->getInnermostMethodContext ());
1050
+ if (!AD || AD->getStorage () != typeVar) {
1051
+ emitDiagnostic (Loc, diag::masked_instance_variable,
1052
+ typeContext->getSelfTypeInContext ())
1053
+ .fixItInsert (Loc, " self." );
1054
+ }
1055
+ }
1056
+ }
1057
+ }
1041
1058
1042
- // If the underlying expression was a read-only subscript, diagnose that.
1043
- if (auto *SD = dyn_cast_or_null<SubscriptDecl>(immInfo.second )) {
1044
- StringRef message;
1045
- if (!SD->isSettable ())
1046
- message = " subscript is get-only" ;
1047
- else if (!SD->isSetterAccessibleFrom (DC))
1048
- message = " subscript setter is inaccessible" ;
1049
- else
1050
- message = " subscript is immutable" ;
1059
+ // If this is a simple variable marked with a 'let', emit a note to fixit
1060
+ // hint it to 'var'.
1061
+ VD->emitLetToVarNoteIfSimple (DC);
1062
+ return true ;
1063
+ }
1051
1064
1052
- emitDiagnostic (Loc, DeclDiagnostic, message)
1053
- .highlight (immInfo.first ->getSourceRange ());
1054
- return true ;
1055
- }
1065
+ // If the underlying expression was a read-only subscript, diagnose that.
1066
+ if (auto *SD = dyn_cast_or_null<SubscriptDecl>(choice->getDecl ())) {
1067
+ StringRef message;
1068
+ if (!SD->isSettable ())
1069
+ message = " subscript is get-only" ;
1070
+ else if (!SD->isSetterAccessibleFrom (DC))
1071
+ message = " subscript setter is inaccessible" ;
1072
+ else
1073
+ message = " subscript is immutable" ;
1056
1074
1057
- // If we're trying to set an unapplied method, say that.
1058
- if (auto *VD = immInfo.second ) {
1059
- std::string message = " '" ;
1060
- message += VD->getBaseName ().getIdentifier ().str ();
1061
- message += " '" ;
1075
+ emitDiagnostic (Loc, DeclDiagnostic, message)
1076
+ .highlight (immInfo.first ->getSourceRange ());
1077
+ return true ;
1078
+ }
1062
1079
1063
- auto diagID = DeclDiagnostic;
1064
- if (auto *AFD = dyn_cast<AbstractFunctionDecl>(VD)) {
1065
- if (AFD->hasImplicitSelfDecl ()) {
1066
- message += " is a method" ;
1067
- diagID = diag::assignment_lhs_is_immutable_variable;
1068
- } else {
1069
- message += " is a function" ;
1070
- }
1071
- } else
1072
- message += " is not settable" ;
1080
+ // If we're trying to set an unapplied method, say that.
1081
+ if (auto *VD = choice->getDecl ()) {
1082
+ std::string message = " '" ;
1083
+ message += VD->getBaseName ().getIdentifier ().str ();
1084
+ message += " '" ;
1085
+
1086
+ auto diagID = DeclDiagnostic;
1087
+ if (auto *AFD = dyn_cast<AbstractFunctionDecl>(VD)) {
1088
+ if (AFD->hasImplicitSelfDecl ()) {
1089
+ message += " is a method" ;
1090
+ diagID = diag::assignment_lhs_is_immutable_variable;
1091
+ } else {
1092
+ message += " is a function" ;
1093
+ }
1094
+ } else
1095
+ message += " is not settable" ;
1073
1096
1074
- emitDiagnostic (Loc, diagID, message)
1075
- .highlight (immInfo.first ->getSourceRange ());
1076
- return true ;
1097
+ emitDiagnostic (Loc, diagID, message)
1098
+ .highlight (immInfo.first ->getSourceRange ());
1099
+ return true ;
1100
+ }
1101
+
1077
1102
}
1103
+
1104
+ // Fall back to producing diagnostics based on the expression since we
1105
+ // couldn't determine anything from the OverloadChoice.
1078
1106
1079
1107
// If a keypath was the problem but wasn't resolved into a vardecl
1080
1108
// it is ambiguous or unable to be used for setting.
@@ -1227,40 +1255,63 @@ void AssignmentFailure::fixItChangeInoutArgType(const Expr *arg,
1227
1255
.fixItReplaceChars (startLoc, endLoc, scratch);
1228
1256
}
1229
1257
1230
- std::pair<Expr *, ValueDecl * >
1258
+ std::pair<Expr *, Optional<OverloadChoice> >
1231
1259
AssignmentFailure::resolveImmutableBase (Expr *expr) const {
1232
1260
auto &cs = getConstraintSystem ();
1233
1261
auto *DC = getDC ();
1234
1262
expr = expr->getValueProvidingExpr ();
1235
1263
1264
+ auto isImmutable = [&](ValueDecl *decl) {
1265
+ if (auto *storage = dyn_cast<AbstractStorageDecl>(decl))
1266
+ return !storage->isSettable (nullptr ) ||
1267
+ !storage->isSetterAccessibleFrom (DC);
1268
+
1269
+ return false ;
1270
+ };
1271
+
1236
1272
// Provide specific diagnostics for assignment to subscripts whose base expr
1237
1273
// is known to be an rvalue.
1238
1274
if (auto *SE = dyn_cast<SubscriptExpr>(expr)) {
1275
+
1239
1276
// If we found a decl for the subscript, check to see if it is a set-only
1240
1277
// subscript decl.
1241
- SubscriptDecl *member = nullptr ;
1242
- if ( SE->hasDecl ())
1243
- member = dyn_cast_or_null<SubscriptDecl>(SE-> getDecl (). getDecl ());
1244
-
1245
- if (!member) {
1246
- auto loc =
1247
- cs. getConstraintLocator (SE, ConstraintLocator::SubscriptMember) ;
1248
- member = dyn_cast_or_null<SubscriptDecl>( getMemberRef (loc));
1278
+ if (SE-> hasDecl ()) {
1279
+ const auto &declRef = SE->getDecl ();
1280
+ if ( auto *subscript =
1281
+ dyn_cast_or_null<SubscriptDecl>(declRef. getDecl ())) {
1282
+ if (isImmutable (subscript))
1283
+ return {expr, OverloadChoice ( getType (SE-> getBase ()), subscript,
1284
+ FunctionRefKind::DoubleApply)} ;
1285
+ }
1249
1286
}
1250
1287
1288
+ Optional<OverloadChoice> member;
1289
+
1290
+ auto loc = cs.getConstraintLocator (SE, ConstraintLocator::SubscriptMember);
1291
+ member = getMemberRef (loc);
1292
+
1251
1293
// If it isn't settable, return it.
1252
1294
if (member) {
1253
- if (! member->isSettable () || ! member->isSetterAccessibleFrom (DC ))
1295
+ if (member->isDecl () && isImmutable ( member->getDecl () ))
1254
1296
return {expr, member};
1255
- }
1256
1297
1257
- if (auto tupleExpr = dyn_cast<TupleExpr>(SE->getIndex ())) {
1258
- if (tupleExpr->getNumElements () == 1 &&
1259
- tupleExpr->getElementName (0 ).str () == " keyPath" ) {
1260
- auto indexType = getType (tupleExpr->getElement (0 ));
1298
+ // We still have a choice, the choice is not a decl
1299
+ if (!member->isDecl ()) {
1300
+ // This must be a keypath application
1301
+ assert (member->getKind () == OverloadChoiceKind::KeyPathApplication);
1302
+
1303
+ auto *argType = getType (SE->getIndex ())->castTo <TupleType>();
1304
+ assert (argType->getNumElements () == 1 );
1305
+
1306
+ auto indexType = resolveType (argType->getElementType (0 ));
1307
+
1261
1308
if (auto bgt = indexType->getAs <BoundGenericType>()) {
1262
- if (bgt->getDecl () == getASTContext ().getKeyPathDecl ())
1263
- return resolveImmutableBase (tupleExpr->getElement (0 ));
1309
+ // In Swift versions lower than 5, this check will fail as read only
1310
+ // key paths can masquerade as writable for compatibilty reasons.
1311
+ // This is fine as in this case we just fall back on old diagnostics.
1312
+ if (bgt->getDecl () == getASTContext ().getKeyPathDecl ()) {
1313
+ return {expr, member};
1314
+ }
1264
1315
}
1265
1316
}
1266
1317
}
@@ -1274,18 +1325,12 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const {
1274
1325
// If we found a decl for the UDE, check it.
1275
1326
auto loc = cs.getConstraintLocator (UDE, ConstraintLocator::Member);
1276
1327
1277
- auto *member = getMemberRef (loc);
1328
+ auto member = getMemberRef (loc);
1329
+
1278
1330
// If we can resolve a member, we can determine whether it is settable in
1279
1331
// this context.
1280
- if (member) {
1281
- auto *memberVD = dyn_cast<VarDecl>(member);
1282
-
1283
- // If the member isn't a vardecl (e.g. its a funcdecl), or it isn't
1284
- // settable, then it is the problem: return it.
1285
- if (!memberVD || !member->isSettable (nullptr ) ||
1286
- !memberVD->isSetterAccessibleFrom (DC))
1287
- return {expr, member};
1288
- }
1332
+ if (member && member->isDecl () && isImmutable (member->getDecl ()))
1333
+ return {expr, member};
1289
1334
1290
1335
// If we weren't able to resolve a member or if it is mutable, then the
1291
1336
// problem must be with the base, recurse.
@@ -1295,16 +1340,18 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const {
1295
1340
if (auto *MRE = dyn_cast<MemberRefExpr>(expr)) {
1296
1341
// If the member isn't settable, then it is the problem: return it.
1297
1342
if (auto member = dyn_cast<AbstractStorageDecl>(MRE->getMember ().getDecl ()))
1298
- if (!member->isSettable (nullptr ) || !member->isSetterAccessibleFrom (DC))
1299
- return {expr, member};
1343
+ if (isImmutable (member))
1344
+ return {expr, OverloadChoice (getType (MRE->getBase ()), member,
1345
+ FunctionRefKind::SingleApply)};
1300
1346
1301
1347
// If we weren't able to resolve a member or if it is mutable, then the
1302
1348
// problem must be with the base, recurse.
1303
1349
return resolveImmutableBase (MRE->getBase ());
1304
1350
}
1305
1351
1306
1352
if (auto *DRE = dyn_cast<DeclRefExpr>(expr))
1307
- return {expr, DRE->getDecl ()};
1353
+ return {expr,
1354
+ OverloadChoice (Type (), DRE->getDecl (), FunctionRefKind::Unapplied)};
1308
1355
1309
1356
// Look through x!
1310
1357
if (auto *FVE = dyn_cast<ForceValueExpr>(expr))
@@ -1322,13 +1369,17 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const {
1322
1369
if (auto *SAE = dyn_cast<SelfApplyExpr>(expr))
1323
1370
return resolveImmutableBase (SAE->getFn ());
1324
1371
1325
- return {expr, nullptr };
1372
+ return {expr, None };
1326
1373
}
1327
1374
1328
- ValueDecl *AssignmentFailure::getMemberRef (ConstraintLocator *locator) const {
1375
+ Optional<OverloadChoice>
1376
+ AssignmentFailure::getMemberRef (ConstraintLocator *locator) const {
1329
1377
auto member = getOverloadChoiceIfAvailable (locator);
1330
- if (!member || !member->choice .isDecl ())
1331
- return nullptr ;
1378
+ if (!member)
1379
+ return None;
1380
+
1381
+ if (!member->choice .isDecl ())
1382
+ return member->choice ;
1332
1383
1333
1384
auto *DC = getDC ();
1334
1385
auto &TC = getTypeChecker ();
@@ -1352,14 +1403,14 @@ ValueDecl *AssignmentFailure::getMemberRef(ConstraintLocator *locator) const {
1352
1403
locator, LocatorPathElt::getKeyPathDynamicMember (keyPath));
1353
1404
1354
1405
auto memberRef = getOverloadChoiceIfAvailable (memberLoc);
1355
- return memberRef ? memberRef->choice . getDecl ( ) : nullptr ;
1406
+ return memberRef ? Optional<OverloadChoice>( memberRef->choice ) : None ;
1356
1407
}
1357
1408
1358
1409
// If this is a string based dynamic lookup, there is no member declaration.
1359
- return nullptr ;
1410
+ return None ;
1360
1411
}
1361
1412
1362
- return decl ;
1413
+ return member-> choice ;
1363
1414
}
1364
1415
1365
1416
Diag<StringRef> AssignmentFailure::findDeclDiagonstic (ASTContext &ctx,
0 commit comments