Skip to content

Commit 4076fa6

Browse files
committed
ConstraintSystem: Make key paths for properties with unavailable setters read-only.
Previously, only conditional unavailability was considered, but setters that are always unavailable must also make a keypath read-only. Resolves rdar://155832511.
1 parent 761c503 commit 4076fa6

File tree

3 files changed

+126
-38
lines changed

3 files changed

+126
-38
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5003,11 +5003,7 @@ bool ConstraintSystem::isReadOnlyKeyPathComponent(
50035003
// If the setter is unavailable, then the keypath ought to be read-only
50045004
// in this context.
50055005
if (auto setter = storage->getOpaqueAccessor(AccessorKind::Set)) {
5006-
// FIXME: [availability] Fully unavailable setters should cause the key path
5007-
// to be readonly too.
5008-
auto constraint =
5009-
getUnsatisfiedAvailabilityConstraint(setter, DC, referenceLoc);
5010-
if (constraint && constraint->isPotentiallyAvailable())
5006+
if (getUnsatisfiedAvailabilityConstraint(setter, DC, referenceLoc))
50115007
return true;
50125008
}
50135009

test/Availability/availability_accessors.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,14 @@ struct BaseStruct<T> {
6363
var unavailableSetter: T {
6464
get { fatalError() }
6565
@available(*, unavailable)
66-
set { fatalError() } // expected-note 38 {{setter for 'unavailableSetter' has been explicitly marked unavailable here}}
66+
set { fatalError() } // expected-note 33 {{setter for 'unavailableSetter' has been explicitly marked unavailable here}}
6767
}
6868

6969
var unavailableGetterAndSetter: T {
7070
@available(*, unavailable)
7171
get { fatalError() } // expected-note 67 {{getter for 'unavailableGetterAndSetter' has been explicitly marked unavailable here}}
7272
@available(*, unavailable)
73-
set { fatalError() } // expected-note 38 {{setter for 'unavailableGetterAndSetter' has been explicitly marked unavailable here}}
73+
set { fatalError() } // expected-note 33 {{setter for 'unavailableGetterAndSetter' has been explicitly marked unavailable here}}
7474
}
7575
}
7676

@@ -318,17 +318,17 @@ func testKeyPathAssignments_Struct(_ someValue: StructValue) {
318318
a[keyPath: \.[takesInOut(&x.unavailableGetter.a.b)]] = 0 // expected-error {{getter for 'unavailableGetter' is unavailable}}
319319
a[keyPath: \.[takesInOut(&x.unavailableGetter[0].b)]] = 0 // expected-error {{getter for 'unavailableGetter' is unavailable}}
320320

321-
x[keyPath: \.unavailableSetter] = someValue // expected-error {{setter for 'unavailableSetter' is unavailable}}
322-
x[keyPath: \.unavailableSetter.a] = someValue.a // expected-error {{setter for 'unavailableSetter' is unavailable}}
323-
x[keyPath: \.unavailableSetter[0]] = someValue.a // expected-error {{setter for 'unavailableSetter' is unavailable}}
324-
x[keyPath: \.unavailableSetter[0].b] = 1 // expected-error {{setter for 'unavailableSetter' is unavailable}}
321+
x[keyPath: \.unavailableSetter] = someValue // expected-error {{cannot assign through subscript: key path is read-only}}
322+
x[keyPath: \.unavailableSetter.a] = someValue.a // expected-error {{cannot assign through subscript: key path is read-only}}
323+
x[keyPath: \.unavailableSetter[0]] = someValue.a // expected-error {{cannot assign through subscript: key path is read-only}}
324+
x[keyPath: \.unavailableSetter[0].b] = 1 // expected-error {{cannot assign through subscript: key path is read-only}}
325325
a[keyPath: \.[takesInOut(&x.unavailableSetter.a.b)]] = 0 // expected-error {{setter for 'unavailableSetter' is unavailable}}
326326
a[keyPath: \.[takesInOut(&x.unavailableSetter[0].b)]] = 0 // expected-error {{setter for 'unavailableSetter' is unavailable}}
327327

328-
x[keyPath: \.unavailableGetterAndSetter] = someValue // expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
329-
x[keyPath: \.unavailableGetterAndSetter.a] = someValue.a // expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
330-
x[keyPath: \.unavailableGetterAndSetter[0]] = someValue.a // expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
331-
x[keyPath: \.unavailableGetterAndSetter[0].b] = 1 // expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
328+
x[keyPath: \.unavailableGetterAndSetter] = someValue // expected-error {{cannot assign through subscript: key path is read-only}}
329+
x[keyPath: \.unavailableGetterAndSetter.a] = someValue.a // expected-error {{cannot assign through subscript: key path is read-only}}
330+
x[keyPath: \.unavailableGetterAndSetter[0]] = someValue.a // expected-error {{cannot assign through subscript: key path is read-only}}
331+
x[keyPath: \.unavailableGetterAndSetter[0].b] = 1 // expected-error {{cannot assign through subscript: key path is read-only}}
332332
a[keyPath: \.[takesInOut(&x.unavailableGetterAndSetter.a.b)]] = 0 // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
333333
a[keyPath: \.[takesInOut(&x.unavailableGetterAndSetter[0].b)]] = 0 // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
334334
}
@@ -352,7 +352,7 @@ func testKeyPathAssignments_Class(_ someValue: ClassValue) {
352352
a[keyPath: \.[takesInOut(&x.unavailableGetter.a.b)]] = 0 // expected-error {{getter for 'unavailableGetter' is unavailable}}
353353
a[keyPath: \.[takesInOut(&x.unavailableGetter[0].b)]] = 0 // expected-error {{getter for 'unavailableGetter' is unavailable}}
354354

355-
x[keyPath: \.unavailableSetter] = someValue // expected-error {{setter for 'unavailableSetter' is unavailable}}
355+
x[keyPath: \.unavailableSetter] = someValue // expected-error {{cannot assign through subscript: key path is read-only}}
356356
// FIXME: spurious unavailable setter error
357357
x[keyPath: \.unavailableSetter.a] = someValue.a // expected-error {{setter for 'unavailableSetter' is unavailable}}
358358
// FIXME: spurious unavailable setter error
@@ -362,7 +362,7 @@ func testKeyPathAssignments_Class(_ someValue: ClassValue) {
362362
a[keyPath: \.[takesInOut(&x.unavailableSetter.a.b)]] = 0
363363
a[keyPath: \.[takesInOut(&x.unavailableSetter[0].b)]] = 0
364364

365-
x[keyPath: \.unavailableGetterAndSetter] = someValue // expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
365+
x[keyPath: \.unavailableGetterAndSetter] = someValue // expected-error {{cannot assign through subscript: key path is read-only}}
366366
x[keyPath: \.unavailableGetterAndSetter.a] = someValue.a // expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
367367
x[keyPath: \.unavailableGetterAndSetter[0]] = someValue.a // expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
368368
// FIXME: spurious unavailable setter error
Lines changed: 113 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,128 @@
1-
// RUN: %target-swift-frontend -target %target-cpu-apple-macosx10.9 -typecheck -verify %s
1+
// RUN: %target-swift-frontend -typecheck -verify %s
22
// REQUIRES: OS=macosx
33

44
struct Butt {
5-
var setter_conditionally_available: Int {
6-
get { fatalError() }
5+
var setter_conditionally_available: Int {
6+
get { fatalError() }
77

8-
@available(macOS 10.10, *)
9-
set { fatalError() }
10-
}
8+
@available(macOS 99, *)
9+
set { fatalError() }
10+
}
11+
12+
var setter_unavailable_on_macos: Int {
13+
get { fatalError() }
14+
15+
@available(macOS, unavailable)
16+
set { fatalError() }
17+
}
18+
19+
var setter_universally_unavailable: Int {
20+
get { fatalError() }
21+
22+
@available(*, unavailable)
23+
set { fatalError() }
24+
}
25+
}
26+
27+
@dynamicMemberLookup
28+
struct Lens<T> {
29+
var obj: T
30+
31+
init(_ obj: T) {
32+
self.obj = obj
33+
}
34+
35+
subscript<U>(dynamicMember member: KeyPath<T, U>) -> Lens<U> {
36+
get { return Lens<U>(obj[keyPath: member]) }
37+
}
38+
39+
subscript<U>(dynamicMember member: WritableKeyPath<T, U>) -> Lens<U> {
40+
get { return Lens<U>(obj[keyPath: member]) }
41+
set { obj[keyPath: member] = newValue.obj }
42+
}
1143
}
1244

1345
func assertExactType<T>(of _: inout T, is _: T.Type) {}
1446

1547
@available(macOS 10.9, *)
16-
public func unavailableSetterContext() {
17-
var kp = \Butt.setter_conditionally_available
18-
assertExactType(of: &kp, is: KeyPath<Butt, Int>.self)
48+
public func availableOnMacOS_10_9() {
49+
var kp = \Butt.setter_conditionally_available
50+
var lens = Lens(Butt())
51+
assertExactType(of: &kp, is: KeyPath<Butt, Int>.self)
52+
_ = lens.setter_conditionally_available
53+
lens.setter_conditionally_available = Lens(1) // expected-error {{cannot assign to property: 'lens' is immutable}}
54+
}
55+
56+
@available(macOS 99, *)
57+
public func availableOnMacOS_99() {
58+
var kp = \Butt.setter_conditionally_available
59+
var lens = Lens(Butt())
60+
assertExactType(of: &kp, is: WritableKeyPath<Butt, Int>.self)
61+
_ = lens.setter_conditionally_available
62+
lens.setter_conditionally_available = Lens(1)
1963
}
20-
@available(macOS 10.10, *)
21-
public func availableSetterContext() {
64+
65+
public func alwaysAvailableOnMacOS() {
66+
var lens = Lens(Butt())
67+
68+
if #available(macOS 99, *) {
2269
var kp = \Butt.setter_conditionally_available
2370
assertExactType(of: &kp, is: WritableKeyPath<Butt, Int>.self)
71+
_ = lens.setter_conditionally_available
72+
// FIXME: [availability] setter_conditionally_available should be writable in this branch
73+
lens.setter_conditionally_available = Lens(1) // expected-error {{cannot assign to property: 'lens' is immutable}}
74+
} else {
75+
var kp = \Butt.setter_conditionally_available
76+
assertExactType(of: &kp, is: KeyPath<Butt, Int>.self)
77+
_ = lens.setter_conditionally_available
78+
lens.setter_conditionally_available = Lens(1) // expected-error {{cannot assign to property: 'lens' is immutable}}
79+
}
80+
81+
var kp2 = \Butt.setter_unavailable_on_macos
82+
assertExactType(of: &kp2, is: KeyPath<Butt, Int>.self)
83+
_ = lens.setter_unavailable_on_macos
84+
lens.setter_unavailable_on_macos = Lens(1) // expected-error {{cannot assign to property: 'lens' is immutable}}
85+
86+
var kp3 = \Butt.setter_universally_unavailable
87+
assertExactType(of: &kp3, is: KeyPath<Butt, Int>.self)
88+
_ = lens.setter_universally_unavailable
89+
lens.setter_universally_unavailable = Lens(1) // expected-error {{cannot assign to property: 'lens' is immutable}}
2490
}
25-
@available(macOS 10.9, *)
26-
public func conditionalAvailableSetterContext() {
27-
if #available(macOS 10.10, *) {
28-
var kp = \Butt.setter_conditionally_available
29-
assertExactType(of: &kp, is: WritableKeyPath<Butt, Int>.self)
30-
} else {
31-
var kp = \Butt.setter_conditionally_available
32-
assertExactType(of: &kp, is: KeyPath<Butt, Int>.self)
33-
}
91+
92+
@available(macOS, unavailable)
93+
public func unvailableOnMacOS() {
94+
var lens = Lens(Butt())
95+
var kp = \Butt.setter_conditionally_available
96+
assertExactType(of: &kp, is: WritableKeyPath<Butt, Int>.self)
97+
_ = lens.setter_conditionally_available
98+
lens.setter_conditionally_available = Lens(1)
99+
100+
var kp2 = \Butt.setter_unavailable_on_macos
101+
assertExactType(of: &kp2, is: WritableKeyPath<Butt, Int>.self)
102+
_ = lens.setter_unavailable_on_macos
103+
lens.setter_unavailable_on_macos = Lens(1)
104+
105+
var kp3 = \Butt.setter_universally_unavailable
106+
assertExactType(of: &kp3, is: KeyPath<Butt, Int>.self)
107+
_ = lens.setter_universally_unavailable
108+
lens.setter_universally_unavailable = Lens(1) // expected-error {{cannot assign to property: 'lens' is immutable}}
34109
}
35110

36-
// FIXME: Check additional unavailability conditions
111+
@available(*, unavailable)
112+
public func universallyUnavailable() {
113+
var lens = Lens(Butt())
114+
var kp = \Butt.setter_conditionally_available
115+
assertExactType(of: &kp, is: WritableKeyPath<Butt, Int>.self)
116+
_ = lens.setter_conditionally_available
117+
lens.setter_conditionally_available = Lens(1)
118+
119+
var kp2 = \Butt.setter_unavailable_on_macos
120+
assertExactType(of: &kp2, is: WritableKeyPath<Butt, Int>.self)
121+
_ = lens.setter_unavailable_on_macos
122+
lens.setter_unavailable_on_macos = Lens(1)
123+
124+
var kp3 = \Butt.setter_universally_unavailable
125+
assertExactType(of: &kp3, is: KeyPath<Butt, Int>.self)
126+
_ = lens.setter_universally_unavailable
127+
lens.setter_universally_unavailable = Lens(1) // expected-error {{cannot assign to property: 'lens' is immutable}}
128+
}

0 commit comments

Comments
 (0)