Skip to content

Commit ed3eaef

Browse files
committed
Sema / Test: Revert the error for assignment through read-only key path
This updates the error message so that in the case where we can find a Decl, it gives the error "cannot assign through subscript: 'name' is a read-only key path", and in the case where there's no associated Decl, gives the error message "cannot assign through subscript: key path is read-only". Additionally updates tests with the new error messages and formats all changes.
1 parent 44c6ad6 commit ed3eaef

File tree

3 files changed

+26
-29
lines changed

3 files changed

+26
-29
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -995,19 +995,20 @@ bool AssignmentFailure::diagnoseAsError() {
995995
if (!choice->isDecl()) {
996996
if (choice->getKind() == OverloadChoiceKind::KeyPathApplication &&
997997
!isa<ApplyExpr>(immInfo.first)) {
998-
std::string message = "";
998+
std::string message = "key path is read-only";
999999
if (auto *SE = dyn_cast<SubscriptExpr>(immInfo.first)) {
10001000
if (auto *DRE = dyn_cast<DeclRefExpr>(getKeyPathArgument(SE))) {
10011001
auto identifier = DRE->getDecl()->getBaseName().getIdentifier();
1002-
message = "'" + identifier.str().str() + "' ";
1002+
message =
1003+
"'" + identifier.str().str() + "' is a read-only key path";
10031004
}
10041005
}
1005-
emitDiagnostic(Loc, DeclDiagnostic, message + "is read-only")
1006+
emitDiagnostic(Loc, DeclDiagnostic, message)
10061007
.highlight(immInfo.first->getSourceRange());
10071008
return true;
10081009
}
10091010
return false;
1010-
}
1011+
}
10111012

10121013
// Otherwise, we cannot resolve this because the available setter candidates
10131014
// are all mutating and the base must be mutating. If we dug out a
@@ -1042,7 +1043,7 @@ bool AssignmentFailure::diagnoseAsError() {
10421043
// note to fixit prepend a 'self.'.
10431044
if (auto typeContext = DC->getInnermostTypeContext()) {
10441045
UnqualifiedLookup lookup(VD->getFullName(), typeContext,
1045-
getASTContext().getLazyResolver());
1046+
getASTContext().getLazyResolver());
10461047
for (auto &result : lookup.Results) {
10471048
const VarDecl *typeVar = dyn_cast<VarDecl>(result.getValueDecl());
10481049
if (typeVar && typeVar != VD && typeVar->isSettable(DC) &&
@@ -1053,7 +1054,7 @@ bool AssignmentFailure::diagnoseAsError() {
10531054
dyn_cast_or_null<AccessorDecl>(DC->getInnermostMethodContext());
10541055
if (!AD || AD->getStorage() != typeVar) {
10551056
emitDiagnostic(Loc, diag::masked_instance_variable,
1056-
typeContext->getSelfTypeInContext())
1057+
typeContext->getSelfTypeInContext())
10571058
.fixItInsert(Loc, "self.");
10581059
}
10591060
}
@@ -1102,9 +1103,8 @@ bool AssignmentFailure::diagnoseAsError() {
11021103
.highlight(immInfo.first->getSourceRange());
11031104
return true;
11041105
}
1105-
11061106
}
1107-
1107+
11081108
// Fall back to producing diagnostics based on the expression since we
11091109
// couldn't determine anything from the OverloadChoice.
11101110

@@ -1265,7 +1265,7 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const {
12651265
auto *DC = getDC();
12661266
expr = expr->getValueProvidingExpr();
12671267

1268-
auto isImmutable = [&](ValueDecl *decl) {
1268+
auto isImmutable = [&DC](ValueDecl *decl) {
12691269
if (auto *storage = dyn_cast<AbstractStorageDecl>(decl))
12701270
return !storage->isSettable(nullptr) ||
12711271
!storage->isSetterAccessibleFrom(DC);
@@ -1276,7 +1276,6 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const {
12761276
// Provide specific diagnostics for assignment to subscripts whose base expr
12771277
// is known to be an rvalue.
12781278
if (auto *SE = dyn_cast<SubscriptExpr>(expr)) {
1279-
12801279
// If we found a decl for the subscript, check to see if it is a set-only
12811280
// subscript decl.
12821281
if (SE->hasDecl()) {
@@ -1289,10 +1288,8 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const {
12891288
}
12901289
}
12911290

1292-
Optional<OverloadChoice> member;
1293-
1294-
auto loc = cs.getConstraintLocator(SE, ConstraintLocator::SubscriptMember);
1295-
member = getMemberRef(loc);
1291+
Optional<OverloadChoice> member = getMemberRef(
1292+
cs.getConstraintLocator(SE, ConstraintLocator::SubscriptMember));
12961293

12971294
// If it isn't settable, return it.
12981295
if (member) {
@@ -1303,7 +1300,7 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const {
13031300
if (!member->isDecl()) {
13041301
// This must be a keypath application
13051302
assert(member->getKind() == OverloadChoiceKind::KeyPathApplication);
1306-
1303+
13071304
auto *argType = getType(SE->getIndex())->castTo<TupleType>();
13081305
assert(argType->getNumElements() == 1);
13091306

test/Constraints/keypath_swift_5.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,30 @@ struct S {
77
let _: WritableKeyPath<S, Int> = \.i // expected-error {{cannot convert value of type 'KeyPath<S, Int>' to specified type 'WritableKeyPath<S, Int>'}}
88

99
S()[keyPath: \.i] = 1
10-
// expected-error@-1 {{cannot assign through subscript: is read-only}}
10+
// expected-error@-1 {{cannot assign through subscript: key path is read-only}}
1111
}
1212
}
1313

1414
func test() {
1515
let _: WritableKeyPath<C, Int> = \.i // expected-error {{cannot convert value of type 'KeyPath<C, Int>' to specified type 'WritableKeyPath<C, Int>'}}
1616

1717
C()[keyPath: \.i] = 1
18-
// expected-error@-1 {{cannot assign through subscript: is read-only}}
18+
// expected-error@-1 {{cannot assign through subscript: key path is read-only}}
1919

2020
let _ = C()[keyPath: \.i] // no warning for a read
2121
}
2222

2323

2424
struct T {
25-
private(set) var a: Int
26-
init(a: Int) {
27-
self.a = a
28-
}
25+
private(set) var a: Int
26+
init(a: Int) {
27+
self.a = a
28+
}
2929
}
3030

3131
func testReadOnlyKeyPathDiagnostics() {
3232
let path = \T.a
3333
var t = T(a: 3)
34-
t[keyPath: path] = 4 // expected-error {{cannot assign through subscript: 'path' is read-only}}
35-
t[keyPath: \T.a] = 4 // expected-error {{cannot assign through subscript: is read-only}}
34+
t[keyPath: path] = 4 // expected-error {{cannot assign through subscript: 'path' is a read-only key path}}
35+
t[keyPath: \T.a] = 4 // expected-error {{cannot assign through subscript: key path is read-only}}
3636
}

test/expr/unary/keypath/keypath.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,8 @@ func testKeyPathSubscript(readonly: Z, writable: inout Z,
301301
sink = readonly[keyPath: rkp]
302302
sink = writable[keyPath: rkp]
303303

304-
readonly[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is read-only}}
305-
writable[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is read-only}}
304+
readonly[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is a read-only key path}}
305+
writable[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is a read-only key path}}
306306
readonly[keyPath: wkp] = sink // expected-error{{cannot assign through subscript: 'readonly' is a 'let' constant}}
307307
writable[keyPath: wkp] = sink
308308
readonly[keyPath: rkp] = sink
@@ -401,8 +401,8 @@ func testKeyPathSubscriptMetatype(readonly: Z.Type, writable: inout Z.Type,
401401
sink = readonly[keyPath: rkp]
402402
sink = writable[keyPath: rkp]
403403

404-
readonly[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is read-only}}
405-
writable[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is read-only}}
404+
readonly[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is a read-only key path}}
405+
writable[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is a read-only key path}}
406406
readonly[keyPath: wkp] = sink // expected-error{{cannot assign through subscript: 'readonly' is a 'let' constant}}
407407
writable[keyPath: wkp] = sink
408408
readonly[keyPath: rkp] = sink
@@ -421,8 +421,8 @@ func testKeyPathSubscriptTuple(readonly: (Z,Z), writable: inout (Z,Z),
421421
sink = readonly[keyPath: rkp]
422422
sink = writable[keyPath: rkp]
423423

424-
readonly[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is read-only}}
425-
writable[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is read-only}}
424+
readonly[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is a read-only key path}}
425+
writable[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is a read-only key path}}
426426
readonly[keyPath: wkp] = sink // expected-error{{cannot assign through subscript: 'readonly' is a 'let' constant}}
427427
writable[keyPath: wkp] = sink
428428
readonly[keyPath: rkp] = sink

0 commit comments

Comments
 (0)