Skip to content

Commit 902721a

Browse files
committed
Sema: Diagnose availability of accessors in chained assignments.
In the following example, the writeback via the property `b` should be diagnosed since `b`'s setter is unavailable: ``` struct A { struct B { var x: Int = 0 } private var _b: B = B() var b: B { get { _b } @available(*, unavailable) set { _b = newValue } } } var a = A() a.b.x = 1 ``` Resolves rdar://125019717
1 parent acf0dcf commit 902721a

File tree

2 files changed

+26
-16
lines changed

2 files changed

+26
-16
lines changed

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3537,10 +3537,20 @@ class ExprAvailabilityWalker : public ASTWalker {
35373537

35383538
/// Walk a member reference expression, checking for availability.
35393539
void walkMemberRef(MemberRefExpr *E) {
3540-
// Walk the base in a getter context.
3541-
// FIXME: We may need to look at the setter too, if we're going to do
3542-
// writeback. The AST should have this information.
3543-
walkInContext(E, E->getBase(), MemberAccessContext::Getter);
3540+
// Walk the base. If the access context is currently `Setter`, then we must
3541+
// be diagnosing the destination of an assignment. When recursing, diagnose
3542+
// any remaining member refs as if they were in an InOutExpr, since there is
3543+
// a writeback occurring through them as a result of the assignment.
3544+
//
3545+
// someVar.x.y = 1
3546+
// │ ╰─ MemberAccessContext::Setter
3547+
// ╰─── MemberAccessContext::InOut
3548+
//
3549+
MemberAccessContext accessContext =
3550+
(AccessContext == MemberAccessContext::Setter)
3551+
? MemberAccessContext::InOut
3552+
: AccessContext;
3553+
walkInContext(E, E->getBase(), accessContext);
35443554

35453555
ConcreteDeclRef DR = E->getMember();
35463556
// Diagnose for the member declaration itself.

test/Sema/availability_accessors.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@ struct BaseStruct {
4141
var unavailableSetter: Value {
4242
get { .defaultValue }
4343
@available(*, unavailable)
44-
set { fatalError() } // expected-note 16 {{setter for 'unavailableSetter' has been explicitly marked unavailable here}}
44+
set { fatalError() } // expected-note 21 {{setter for 'unavailableSetter' has been explicitly marked unavailable here}}
4545
}
4646

4747
var unavailableGetterAndSetter: Value {
4848
@available(*, unavailable)
4949
get { fatalError() } // expected-note 28 {{getter for 'unavailableGetterAndSetter' has been explicitly marked unavailable here}}
5050
@available(*, unavailable)
51-
set { fatalError() } // expected-note 16 {{setter for 'unavailableGetterAndSetter' has been explicitly marked unavailable here}}
51+
set { fatalError() } // expected-note 21 {{setter for 'unavailableGetterAndSetter' has been explicitly marked unavailable here}}
5252
}
5353
}
5454

@@ -96,12 +96,12 @@ func testLValueAssignments() {
9696
x.unavailableGetter[0].b = 1 // expected-error {{getter for 'unavailableGetter' is unavailable}}
9797

9898
x.unavailableSetter = someValue // expected-error {{setter for 'unavailableSetter' is unavailable}}
99-
x.unavailableSetter.a = someValue.a // FIXME: missing diagnostic for setter
99+
x.unavailableSetter.a = someValue.a // expected-error {{setter for 'unavailableSetter' is unavailable}}
100100
x.unavailableSetter[0] = someValue.a // expected-error {{setter for 'unavailableSetter' is unavailable}}
101101
x.unavailableSetter[0].b = 1 // expected-error {{setter for 'unavailableSetter' is unavailable}}
102102

103103
x.unavailableGetterAndSetter = someValue // expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
104-
x.unavailableGetterAndSetter.a = someValue.a // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} FIXME: missing diagnostic for setter
104+
x.unavailableGetterAndSetter.a = someValue.a // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
105105
x.unavailableGetterAndSetter[0] = someValue.a // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
106106
x.unavailableGetterAndSetter[0].b = 1 // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
107107
}
@@ -128,14 +128,14 @@ func testKeyPathLoads() {
128128
_ = x[keyPath: \.unavailableSetter.a]
129129
_ = x[keyPath: \.unavailableSetter[0]]
130130
_ = x[keyPath: \.unavailableSetter[0].b]
131-
_ = a[keyPath: \.[takesIntInOut(&x.unavailableSetter.a.b)]] // FIXME: missing diagnostic for setter
131+
_ = a[keyPath: \.[takesIntInOut(&x.unavailableSetter.a.b)]] // expected-error {{setter for 'unavailableSetter' is unavailable}}
132132
_ = a[keyPath: \.[takesIntInOut(&x.unavailableSetter[0].b)]] // expected-error {{setter for 'unavailableSetter' is unavailable}}
133133

134134
_ = x[keyPath: \.unavailableGetterAndSetter] // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}}
135135
_ = x[keyPath: \.unavailableGetterAndSetter.a] // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}}
136136
_ = x[keyPath: \.unavailableGetterAndSetter[0]] // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}}
137137
_ = x[keyPath: \.unavailableGetterAndSetter[0].b] // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}}
138-
_ = a[keyPath: \.[takesIntInOut(&x.unavailableGetterAndSetter.a.b)]] // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} FIXME: missing diagnostic for setter
138+
_ = a[keyPath: \.[takesIntInOut(&x.unavailableGetterAndSetter.a.b)]] // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} // expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
139139
_ = a[keyPath: \.[takesIntInOut(&x.unavailableGetterAndSetter[0].b)]] // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
140140
}
141141

@@ -162,14 +162,14 @@ func testKeyPathAssignments() {
162162
x[keyPath: \.unavailableSetter.a] = someValue.a // expected-error {{setter for 'unavailableSetter' is unavailable}}
163163
x[keyPath: \.unavailableSetter[0]] = someValue.a // expected-error {{setter for 'unavailableSetter' is unavailable}}
164164
x[keyPath: \.unavailableSetter[0].b] = 1 // expected-error {{setter for 'unavailableSetter' is unavailable}}
165-
a[keyPath: \.[takesIntInOut(&x.unavailableSetter.a.b)]] = 0 // FIXME: missing diagnostic for setter
165+
a[keyPath: \.[takesIntInOut(&x.unavailableSetter.a.b)]] = 0 // expected-error {{setter for 'unavailableSetter' is unavailable}}
166166
a[keyPath: \.[takesIntInOut(&x.unavailableSetter[0].b)]] = 0 // expected-error {{setter for 'unavailableSetter' is unavailable}}
167167

168168
x[keyPath: \.unavailableGetterAndSetter] = someValue // expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
169169
x[keyPath: \.unavailableGetterAndSetter.a] = someValue.a // expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
170170
x[keyPath: \.unavailableGetterAndSetter[0]] = someValue.a // expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
171171
x[keyPath: \.unavailableGetterAndSetter[0].b] = 1 // expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
172-
a[keyPath: \.[takesIntInOut(&x.unavailableGetterAndSetter.a.b)]] = 0 // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} FIXME: missing diagnostic for setter
172+
a[keyPath: \.[takesIntInOut(&x.unavailableGetterAndSetter.a.b)]] = 0 // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
173173
a[keyPath: \.[takesIntInOut(&x.unavailableGetterAndSetter[0].b)]] = 0 // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
174174
}
175175

@@ -192,13 +192,13 @@ func testMutatingMember() {
192192
x.unavailableSetter.setToZero() // expected-error {{setter for 'unavailableSetter' is unavailable}}
193193
x.unavailableSetter[0].setToZero() // expected-error {{setter for 'unavailableSetter' is unavailable}}
194194
_ = a[x.unavailableSetter.setToZero()] // expected-error {{setter for 'unavailableSetter' is unavailable}}
195-
_ = a[x.unavailableSetter.a.setToZero()] // FIXME: missing diagnostic for setter
195+
_ = a[x.unavailableSetter.a.setToZero()] // expected-error {{setter for 'unavailableSetter' is unavailable}}
196196
_ = a[x.unavailableSetter[0].setToZero()] // expected-error {{setter for 'unavailableSetter' is unavailable}}
197197

198198
x.unavailableGetterAndSetter.setToZero() // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
199199
x.unavailableGetterAndSetter[0].setToZero() // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
200200
_ = a[x.unavailableGetterAndSetter.setToZero()] // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
201-
_ = a[x.unavailableGetterAndSetter.a.setToZero()] // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} FIXME: should diagnose setter
201+
_ = a[x.unavailableGetterAndSetter.a.setToZero()] // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
202202
_ = a[x.unavailableGetterAndSetter[0].setToZero()] // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
203203
}
204204

@@ -218,12 +218,12 @@ func testPassAsInOutParameter() {
218218
takesInOut(&x.unavailableGetter[0].b) // expected-error {{getter for 'unavailableGetter' is unavailable}}
219219

220220
takesInOut(&x.unavailableSetter) // expected-error {{setter for 'unavailableSetter' is unavailable}}
221-
takesInOut(&x.unavailableSetter.a) //
221+
takesInOut(&x.unavailableSetter.a) // expected-error {{setter for 'unavailableSetter' is unavailable}}
222222
takesInOut(&x.unavailableSetter[0]) // expected-error {{setter for 'unavailableSetter' is unavailable}}
223223
takesInOut(&x.unavailableSetter[0].b) // expected-error {{setter for 'unavailableSetter' is unavailable}}
224224

225225
takesInOut(&x.unavailableGetterAndSetter) // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
226-
takesInOut(&x.unavailableGetterAndSetter.a) // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} FIXME: missing diagnostic for setter
226+
takesInOut(&x.unavailableGetterAndSetter.a) // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
227227
takesInOut(&x.unavailableGetterAndSetter[0]) // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
228228
takesInOut(&x.unavailableGetterAndSetter[0].b) // expected-error {{getter for 'unavailableGetterAndSetter' is unavailable}} expected-error {{setter for 'unavailableGetterAndSetter' is unavailable}}
229229
}

0 commit comments

Comments
 (0)