Skip to content

Commit ee84ecf

Browse files
authored
Merge pull request #16467 from rudkx/rdar39802797-4.2
Allowing forming WritableKeyPath to read-only value in Swift 3/4.
2 parents 91e07e9 + be80028 commit ee84ecf

File tree

5 files changed

+46
-4
lines changed

5 files changed

+46
-4
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4036,8 +4036,19 @@ ConstraintSystem::simplifyKeyPathConstraint(Type keyPathTy,
40364036
// get any special power from being formed in certain contexts, such
40374037
// as the ability to assign to `let`s in initialization contexts, so
40384038
// we pass null for the DC to `isSettable` here.)
4039-
if (!storage->isSettable(nullptr)
4040-
|| !storage->isSetterAccessibleFrom(DC)) {
4039+
if (!getASTContext().isSwiftVersionAtLeast(5)) {
4040+
// As a source-compatibility measure, continue to allow
4041+
// WritableKeyPaths to be formed in the same conditions we did
4042+
// in previous releases even if we should not be able to set
4043+
// the value in this context.
4044+
if (!storage->isSettable(DC)) {
4045+
// A non-settable component makes the key path read-only, unless
4046+
// a reference-writable component shows up later.
4047+
capability = ReadOnly;
4048+
continue;
4049+
}
4050+
} else if (!storage->isSettable(nullptr)
4051+
|| !storage->isSetterAccessibleFrom(DC)) {
40414052
// A non-settable component makes the key path read-only, unless
40424053
// a reference-writable component shows up later.
40434054
capability = ReadOnly;

test/Constraints/Inputs/keypath.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class C {
2+
fileprivate(set) var i = 0
3+
}

test/Constraints/keypath.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %target-typecheck-verify-swift %S/Inputs/keypath.swift -primary-file %s
2+
3+
struct S {
4+
let i: Int
5+
6+
init() {
7+
let _: WritableKeyPath<S, Int> = \.i // no error for Swift 3/4
8+
}
9+
}
10+
11+
func test() {
12+
let _: WritableKeyPath<C, Int> = \.i // no error for Swift 3/4
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %target-typecheck-verify-swift %S/Inputs/keypath.swift -primary-file %s -swift-version 5
2+
3+
struct S {
4+
let i: Int
5+
6+
init() {
7+
let _: WritableKeyPath<S, Int> = \.i // expected-error {{type of expression is ambiguous without more context}}
8+
}
9+
}
10+
11+
func test() {
12+
let _: WritableKeyPath<C, Int> = \.i // expected-error {{type of expression is ambiguous without more context}}
13+
}

test/expr/unary/keypath/keypath.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -514,8 +514,9 @@ struct VisibilityTesting {
514514
toHaveType: Exactly<WritableKeyPath<VisibilityTesting, Int>>.self)
515515
expect(&yRef,
516516
toHaveType: Exactly<WritableKeyPath<VisibilityTesting, Int>>.self)
517+
// Allow WritableKeyPath for Swift 3/4 only.
517518
expect(&zRef,
518-
toHaveType: Exactly<KeyPath<VisibilityTesting, Int>>.self)
519+
toHaveType: Exactly<WritableKeyPath<VisibilityTesting, Int>>.self)
519520
}
520521

521522
func inPrivateContext() {
@@ -536,8 +537,9 @@ struct VisibilityTesting2 {
536537
var xRef = \VisibilityTesting.x
537538
var yRef = \VisibilityTesting.y
538539
var zRef = \VisibilityTesting.z
540+
// Allow WritableKeyPath for Swift 3/4 only.
539541
expect(&xRef,
540-
toHaveType: Exactly<KeyPath<VisibilityTesting, Int>>.self)
542+
toHaveType: Exactly<WritableKeyPath<VisibilityTesting, Int>>.self)
541543
expect(&yRef,
542544
toHaveType: Exactly<WritableKeyPath<VisibilityTesting, Int>>.self)
543545
expect(&zRef,

0 commit comments

Comments
 (0)