Skip to content

Commit eaf1dc0

Browse files
committed
[Diagnostics] Diagnose use of member with mutating getter in key path
1 parent c33b726 commit eaf1dc0

File tree

4 files changed

+65
-2
lines changed

4 files changed

+65
-2
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2470,3 +2470,8 @@ bool InvalidStaticMemberRefInKeyPath::diagnoseAsError() {
24702470
emitDiagnostic(getLoc(), diag::expr_keypath_static_member, getName());
24712471
return true;
24722472
}
2473+
2474+
bool InvalidMemberWithMutatingGetterInKeyPath::diagnoseAsError() {
2475+
emitDiagnostic(getLoc(), diag::expr_keypath_mutating_getter, getName());
2476+
return true;
2477+
}

lib/Sema/CSDiagnostics.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,34 @@ class InvalidStaticMemberRefInKeyPath final : public InvalidMemberRefInKeyPath {
10701070
bool diagnoseAsError() override;
10711071
};
10721072

1073+
/// Diagnose an attempt to reference a member which has a mutating getter as a
1074+
/// key path component e.g.
1075+
///
1076+
/// ```swift
1077+
/// struct S {
1078+
/// var foo: Int {
1079+
/// mutating get { return 42 }
1080+
/// }
1081+
///
1082+
/// subscript(_: Int) -> Bool {
1083+
/// mutating get { return false }
1084+
/// }
1085+
/// }
1086+
///
1087+
/// _ = \S.foo
1088+
/// _ = \S.[42]
1089+
/// ```
1090+
class InvalidMemberWithMutatingGetterInKeyPath final
1091+
: public InvalidMemberRefInKeyPath {
1092+
public:
1093+
InvalidMemberWithMutatingGetterInKeyPath(Expr *root, ConstraintSystem &cs,
1094+
ValueDecl *member,
1095+
ConstraintLocator *locator)
1096+
: InvalidMemberRefInKeyPath(root, cs, member, locator) {}
1097+
1098+
bool diagnoseAsError() override;
1099+
};
1100+
10731101
} // end namespace constraints
10741102
} // end namespace swift
10751103

lib/Sema/CSFix.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,9 @@ bool AllowInvalidRefInKeyPath::diagnose(Expr *root, bool asNote) const {
432432
}
433433

434434
case RefKind::MutatingGetter: {
435-
return false;
435+
InvalidMemberWithMutatingGetterInKeyPath failure(
436+
root, getConstraintSystem(), Member, getLocator());
437+
return failure.diagnose(asNote);
436438
}
437439
}
438440
}

test/expr/unary/keypath/keypath.swift

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,7 @@ func test_keypath_with_static_members(_ p: P_With_Static_Members) {
732732
static var baz: Int = 42
733733
}
734734

735-
func foo(_ s: S) {
735+
func foo(_ s: S) {
736736
let _ = \S.Type.foo
737737
// expected-error@-1 {{key path cannot refer to static member 'foo'}}
738738
let _ = s[keyPath: \.foo]
@@ -748,6 +748,34 @@ func foo(_ s: S) {
748748
}
749749
}
750750

751+
func test_keypath_with_mutating_getter() {
752+
struct S {
753+
var foo: Int {
754+
mutating get { return 42 }
755+
}
756+
757+
subscript(_: Int) -> [Int] {
758+
mutating get { return [] }
759+
}
760+
}
761+
762+
_ = \S.foo
763+
// expected-error@-1 {{key path cannot refer to 'foo', which has a mutating getter}}
764+
let _: KeyPath<S, Int> = \.foo
765+
// expected-error@-1 {{key path cannot refer to 'foo', which has a mutating getter}}
766+
_ = \S.[0]
767+
// expected-error@-1 {{key path cannot refer to 'subscript(_:)', which has a mutating getter}}
768+
_ = \S.[0].count
769+
// expected-error@-1 {{key path cannot refer to 'subscript(_:)', which has a mutating getter}}
770+
771+
func test_via_subscript(_ s: S) {
772+
_ = s[keyPath: \.foo]
773+
// expected-error@-1 {{key path cannot refer to 'foo', which has a mutating getter}}
774+
_ = s[keyPath: \.[0].count]
775+
// expected-error@-1 {{key path cannot refer to 'subscript(_:)', which has a mutating getter}}
776+
}
777+
}
778+
751779
func testSyntaxErrors() { // expected-note{{}}
752780
_ = \. ; // expected-error{{expected member name following '.'}}
753781
_ = \.a ;

0 commit comments

Comments
 (0)