Skip to content

Commit 976d921

Browse files
committed
[Concurrency] Split up the non-Sendable property diagnostics and improve
wording.
1 parent 9f0b2ec commit 976d921

8 files changed

+74
-44
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5681,16 +5681,27 @@ ERROR(non_sendable_call_result_type,none,
56815681
"non-sendable result type %0 cannot be sent from %1 context in call "
56825682
"to async function",
56835683
(Type, ActorIsolation))
5684-
ERROR(non_sendable_property_type,none,
5685-
"non-sendable type %0 in %select{"
5686-
"%select{asynchronous access to %4 %kind1|"
5687-
"asynchronous access from %4 context to nonisolated %kind1|"
5688-
"implicitly asynchronous access to %4 %kind1|"
5689-
"conformance of %4 %kind1 to protocol requirement|"
5690-
"%4 overriding %kind1|"
5691-
"%4 '@objc' %kind1}3|captured local %1}2 cannot "
5692-
"cross %select{actor|task}2 boundary",
5693-
(Type, const ValueDecl *, bool, unsigned, ActorIsolation))
5684+
5685+
ERROR(non_sendable_property_exits_actor,none,
5686+
"non-sendable type %0 of %kind1 cannot exit %2 context",
5687+
(Type, const ValueDecl *, ActorIsolation))
5688+
ERROR(non_sendable_property_into_actor,none,
5689+
"non-sendable type %0 of nonisolated %kind1 cannot be sent to "
5690+
"%2 context",
5691+
(Type, const ValueDecl *, ActorIsolation))
5692+
ERROR(non_sendable_property_in_witness,none,
5693+
"non-sendable type %0 cannot be returned from %2 implementation "
5694+
"to caller of protocol requirement %1",
5695+
(Type, const ValueDecl *, ActorIsolation))
5696+
ERROR(non_sendable_property_in_override,none,
5697+
"non-sendable type %0 cannot be returned from %2 override to "
5698+
"caller of superclass %kind1",
5699+
(Type, const ValueDecl *, ActorIsolation))
5700+
ERROR(non_sendable_property_in_objc,none,
5701+
"non-sendable type %0 returned by %2 '@objc' %kind1 cannot cross "
5702+
"actor boundary",
5703+
(Type, const ValueDecl *, ActorIsolation))
5704+
56945705
ERROR(non_sendable_keypath_capture,none,
56955706
"cannot form key path that captures non-sendable type %0",
56965707
(Type))

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,28 @@ getSendableResultDiag(SendableCheckReason refKind) {
11651165
}
11661166
}
11671167

1168+
static
1169+
Diag<Type, const ValueDecl *, ActorIsolation>
1170+
getSendablePropertyDiag(SendableCheckReason refKind) {
1171+
switch (refKind) {
1172+
case SendableCheckReason::CrossActor:
1173+
case SendableCheckReason::SynchronousAsAsync:
1174+
return diag::non_sendable_property_exits_actor;
1175+
1176+
case SendableCheckReason::ExitingActor:
1177+
return diag::non_sendable_property_into_actor;
1178+
1179+
case SendableCheckReason::Conformance:
1180+
return diag::non_sendable_property_in_witness;
1181+
1182+
case SendableCheckReason::Override:
1183+
return diag::non_sendable_property_in_override;
1184+
1185+
case SendableCheckReason::ObjC:
1186+
return diag::non_sendable_property_in_objc;
1187+
}
1188+
}
1189+
11681190
bool swift::diagnoseNonSendableTypesInReference(
11691191
Expr *base, ConcreteDeclRef declRef, const DeclContext *fromDC,
11701192
SourceLoc refLoc, SendableCheckReason refKind,
@@ -1245,11 +1267,8 @@ bool swift::diagnoseNonSendableTypesInReference(
12451267
if (diagnoseNonSendableTypes(
12461268
propertyType, fromDC,
12471269
derivedConformanceType, refLoc,
1248-
diag::non_sendable_property_type,
1249-
var,
1250-
var->isLocalCapture(),
1251-
(unsigned)refKind,
1252-
getActorIsolation()))
1270+
getSendablePropertyDiag(refKind),
1271+
var, getActorIsolation()))
12531272
return true;
12541273
}
12551274

test/Concurrency/actor_call_implicitly_async.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,11 @@ func someAsyncFunc() async {
176176
////////////
177177
// effectful properties from outside the actor instance
178178

179-
// expected-warning@+2 {{non-sendable type 'Box' in asynchronous access to actor-isolated property 'effPropA' cannot cross actor boundary}}
179+
// expected-warning@+2 {{non-sendable type 'Box' of property 'effPropA' cannot exit actor-isolated context}}
180180
// expected-error@+1{{expression is 'async' but is not marked with 'await'}} {{7-7=await }} expected-note@+1{{property access is 'async'}}
181181
_ = a.effPropA
182182

183-
// expected-warning@+3 {{non-sendable type 'Box' in implicitly asynchronous access to actor-isolated property 'effPropT' cannot cross actor boundary}}
183+
// expected-warning@+3 {{non-sendable type 'Box' of property 'effPropT' cannot exit actor-isolated context}}
184184
// expected-error@+2{{property access can throw, but it is not marked with 'try' and the error is not handled}}
185185
// expected-error@+1{{expression is 'async' but is not marked with 'await'}} {{7-7=await }} expected-note@+1{{property access is 'async'}}
186186
_ = a.effPropT
@@ -190,8 +190,8 @@ func someAsyncFunc() async {
190190
_ = a.effPropAT
191191

192192
// (mostly) corrected ones
193-
_ = await a.effPropA // expected-warning {{non-sendable type 'Box' in asynchronous access to actor-isolated property 'effPropA' cannot cross actor boundary}}
194-
_ = try! await a.effPropT // expected-warning {{non-sendable type 'Box' in implicitly asynchronous access to actor-isolated property 'effPropT' cannot cross actor boundary}}
193+
_ = await a.effPropA // expected-warning {{non-sendable type 'Box' of property 'effPropA' cannot exit actor-isolated context}}
194+
_ = try! await a.effPropT // expected-warning {{non-sendable type 'Box' of property 'effPropT' cannot exit actor-isolated context}}
195195
_ = try? await a.effPropAT
196196

197197
print("ok!")

test/Concurrency/actor_isolation.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func checkAsyncPropertyAccess() async {
111111

112112
act.text[0] += "hello" // expected-error{{actor-isolated property 'text' can not be mutated from a nonisolated context}}
113113

114-
_ = act.point // expected-warning{{non-sendable type 'Point' in implicitly asynchronous access to actor-isolated property 'point' cannot cross actor boundary}}
114+
_ = act.point // expected-warning{{non-sendable type 'Point' of property 'point' cannot exit actor-isolated context}}
115115
// expected-warning@-1 {{expression is 'async' but is not marked with 'await'}}
116116
// expected-note@-2 {{property access is 'async'}}
117117
}
@@ -151,8 +151,8 @@ func checkIsolationValueType(_ formance: InferredFromConformance,
151151
_ ext: InferredFromContext,
152152
_ anno: NoGlobalActorValueType) async {
153153
// these still do need an await in Swift 5
154-
_ = await ext.point // expected-warning {{non-sendable type 'Point' in implicitly asynchronous access to main actor-isolated property 'point' cannot cross actor boundary}}
155-
_ = await anno.point // expected-warning {{non-sendable type 'Point' in implicitly asynchronous access to global actor 'SomeGlobalActor'-isolated property 'point' cannot cross actor boundary}}
154+
_ = await ext.point // expected-warning {{non-sendable type 'Point' of property 'point' cannot exit main actor-isolated context}}
155+
_ = await anno.point // expected-warning {{non-sendable type 'Point' of property 'point' cannot exit global actor 'SomeGlobalActor'-isolated context}}
156156
// expected-warning@-1 {{non-sendable type 'NoGlobalActorValueType' cannot be sent into global actor 'SomeGlobalActor'-isolated context in call to property 'point'}}
157157

158158
_ = formance.counter
@@ -162,9 +162,9 @@ func checkIsolationValueType(_ formance: InferredFromConformance,
162162
_ = await (formance as MainCounter).counter // expected-warning {{non-sendable type 'any MainCounter' cannot be sent into main actor-isolated context in call to property 'counter'}}
163163
_ = await ext[1]
164164
_ = await formance.ticker
165-
_ = await ext.polygon // expected-warning {{non-sendable type '[Point]' in implicitly asynchronous access to main actor-isolated property 'polygon' cannot cross actor boundary}}
165+
_ = await ext.polygon // expected-warning {{non-sendable type '[Point]' of property 'polygon' cannot exit main actor-isolated context}}
166166
_ = await InferredFromContext.stuff
167-
_ = await NoGlobalActorValueType.polygon // expected-warning {{non-sendable type '[Point]' in implicitly asynchronous access to main actor-isolated static property 'polygon' cannot cross actor boundary}}
167+
_ = await NoGlobalActorValueType.polygon // expected-warning {{non-sendable type '[Point]' of static property 'polygon' cannot exit main actor-isolated context}}
168168
}
169169

170170
// expected-warning@+2 {{memberwise initializer for 'NoGlobalActorValueType' cannot be both nonisolated and global actor 'SomeGlobalActor'-isolated; this is an error in the Swift 6 language mode}}
@@ -1049,8 +1049,8 @@ func testCrossModuleLets(actor: OtherModuleActor) async {
10491049
_ = actor.b // okay
10501050
_ = actor.c // expected-error{{expression is 'async' but is not marked with 'await'}}
10511051
// expected-note@-1{{property access is 'async'}}
1052-
// expected-warning@-2{{non-sendable type 'SomeClass' in implicitly asynchronous access to actor-isolated property 'c' cannot cross actor boundary}}
1053-
_ = await actor.c // expected-warning{{non-sendable type 'SomeClass' in implicitly asynchronous access to actor-isolated property 'c' cannot cross actor boundary}}
1052+
// expected-warning@-2{{non-sendable type 'SomeClass' of property 'c' cannot exit actor-isolated context}}
1053+
_ = await actor.c // expected-warning{{non-sendable type 'SomeClass' of property 'c' cannot exit actor-isolated context}}
10541054
_ = await actor.d // okay
10551055
}
10561056

@@ -1085,8 +1085,8 @@ actor CrossModuleFromInitsActor {
10851085
_ = actor.b // okay
10861086
_ = actor.c // expected-error{{expression is 'async' but is not marked with 'await'}}
10871087
// expected-note@-1{{property access is 'async'}}
1088-
// expected-warning@-2{{non-sendable type 'SomeClass' in implicitly asynchronous access to actor-isolated property 'c' cannot cross actor boundary}}
1089-
_ = await actor.c // expected-warning{{non-sendable type 'SomeClass' in implicitly asynchronous access to actor-isolated property 'c' cannot cross actor boundary}}
1088+
// expected-warning@-2{{non-sendable type 'SomeClass' of property 'c' cannot exit actor-isolated context}}
1089+
_ = await actor.c // expected-warning{{non-sendable type 'SomeClass' of property 'c' cannot exit actor-isolated context}}
10901090
_ = await actor.d // okay
10911091
}
10921092
}
@@ -1613,7 +1613,7 @@ class ReferenceActor {
16131613
init() async {
16141614
self.a = ProtectNonSendable()
16151615

1616-
// expected-warning@+3 {{non-sendable type 'NonSendable' in implicitly asynchronous access to actor-isolated property 'ns' cannot cross actor boundary}}
1616+
// expected-warning@+3 {{non-sendable type 'NonSendable' of property 'ns' cannot exit actor-isolated context}}
16171617
// expected-warning@+2 {{expression is 'async' but is not marked with 'await'}}
16181618
// expected-note@+1 {{property access is 'async'}}
16191619
_ = a.ns

test/Concurrency/concurrent_value_checking.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ extension A1 {
9999
_ = await self.asynchronous(nil)
100100

101101
// Across to a different actor, so Sendable restriction is enforced.
102-
_ = other.localLet // expected-warning{{non-sendable type 'NotConcurrent' in implicitly asynchronous access to actor-isolated property 'localLet' cannot cross actor boundary}}
102+
_ = other.localLet // expected-warning{{non-sendable type 'NotConcurrent' of property 'localLet' cannot exit actor-isolated context}}
103103
// expected-warning@-1 {{expression is 'async' but is not marked with 'await'}}
104104
// expected-note@-2 {{property access is 'async'}}
105105
_ = await other.synchronous() // expected-warning{{non-sendable result type 'NotConcurrent?' cannot be sent from actor-isolated context in call to instance method 'synchronous()'}}
@@ -140,22 +140,22 @@ enum E {
140140
func globalTest() async {
141141
// expected-warning@+2 {{expression is 'async' but is not marked with 'await'}}
142142
// expected-note@+1 {{property access is 'async'}}
143-
let a = globalValue // expected-warning{{non-sendable type 'NotConcurrent?' in implicitly asynchronous access to global actor 'SomeGlobalActor'-isolated let 'globalValue' cannot cross actor boundary}}
143+
let a = globalValue // expected-warning{{non-sendable type 'NotConcurrent?' of let 'globalValue' cannot exit global actor 'SomeGlobalActor'-isolated context}}
144144
await globalAsync(a) // expected-tns-warning {{sending 'a' risks causing data races}}
145145
// expected-tns-note @-1 {{sending global actor 'SomeGlobalActor'-isolated 'a' to global actor 'SomeGlobalActor'-isolated global function 'globalAsync' risks causing data races between global actor 'SomeGlobalActor'-isolated and local nonisolated uses}}
146146
await globalSync(a) // expected-tns-note {{access can happen concurrently}}
147147

148148
// expected-warning@+2 {{expression is 'async' but is not marked with 'await'}}
149149
// expected-note@+1 {{property access is 'async'}}
150-
let _ = E.notSafe // expected-warning{{non-sendable type 'NotConcurrent?' in implicitly asynchronous access to global actor 'SomeGlobalActor'-isolated static property 'notSafe' cannot cross actor boundary}}
150+
let _ = E.notSafe // expected-warning{{non-sendable type 'NotConcurrent?' of static property 'notSafe' cannot exit global actor 'SomeGlobalActor'-isolated context}}
151151

152152
#if ALLOW_TYPECHECKER_ERRORS
153153
// expected-typechecker-error@+3 {{expression is 'async' but is not marked with 'await'}}
154154
// expected-typechecker-note@+2 {{call is 'async'}}
155155
// expected-typechecker-note@+1 {{property access is 'async'}}
156156
globalAsync(E.notSafe)
157157

158-
// expected-typechecker-warning@-2 {{non-sendable type 'NotConcurrent?' in implicitly asynchronous access to global actor 'SomeGlobalActor'-isolated static property 'notSafe' cannot cross actor boundary}}
158+
// expected-typechecker-warning@-2 {{non-sendable type 'NotConcurrent?' of static property 'notSafe' cannot exit global actor 'SomeGlobalActor'-isolated context}}
159159
#endif
160160
}
161161

@@ -177,7 +177,7 @@ class ClassWithGlobalActorInits { // expected-note 2{{class 'ClassWithGlobalActo
177177
func globalTestMain(nc: NotConcurrent) async {
178178
// expected-warning@+2 {{expression is 'async' but is not marked with 'await'}}
179179
// expected-note@+1 {{property access is 'async'}}
180-
let a = globalValue // expected-warning {{non-sendable type 'NotConcurrent?' in implicitly asynchronous access to global actor 'SomeGlobalActor'-isolated let 'globalValue' cannot cross actor boundary}}
180+
let a = globalValue // expected-warning {{non-sendable type 'NotConcurrent?' of let 'globalValue' cannot exit global actor 'SomeGlobalActor'-isolated context}}
181181
await globalAsync(a) // expected-tns-warning {{sending 'a' risks causing data races}}
182182
// expected-tns-note @-1 {{sending global actor 'SomeGlobalActor'-isolated 'a' to global actor 'SomeGlobalActor'-isolated global function 'globalAsync' risks causing data races between global actor 'SomeGlobalActor'-isolated and local main actor-isolated uses}}
183183
await globalSync(a) // expected-tns-note {{access can happen concurrently}}
@@ -259,7 +259,7 @@ actor ANI {
259259
}
260260

261261
func testANI(ani: ANI) async {
262-
_ = ani.nc // expected-warning{{non-sendable type 'NC' in asynchronous access to nonisolated property 'nc' cannot cross actor boundary}}
262+
_ = ani.nc // expected-warning{{non-sendable type 'NC' of property 'nc' cannot exit nonisolated context}}
263263
}
264264

265265
// ----------------------------------------------------------------------

test/Concurrency/sendable_checking.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ struct DowngradeForPreconcurrency {
443443
self.x
444444
// expected-warning@-1 {{expression is 'async' but is not marked with 'await'; this is an error in the Swift 6 language mode}}
445445
// expected-note@-2 {{property access is 'async'}}
446-
// expected-warning@-3 {{non-sendable type 'NonSendable' in implicitly asynchronous access to main actor-isolated property 'x' cannot cross actor boundary; this is an error in the Swift 6 language mode}}
446+
// expected-warning@-3 {{non-sendable type 'NonSendable' of property 'x' cannot exit main actor-isolated context; this is an error in the Swift 6 language mode}}
447447
}
448448
}
449449
}

test/Concurrency/sendable_conformance_checking.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ protocol AsyncProtocolWithNotSendable {
5353
actor A3: AsyncProtocolWithNotSendable {
5454
func f() async -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' cannot be returned from actor-isolated implementation to caller of protocol requirement 'f()'}}
5555

56-
var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' in conformance of actor-isolated property 'prop' to protocol requirement cannot cross actor boundary}}
56+
var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' cannot be returned from actor-isolated implementation to caller of protocol requirement 'prop'}}
5757
get async {
5858
NotSendable()
5959
}
@@ -66,7 +66,7 @@ actor A3: AsyncProtocolWithNotSendable {
6666
actor A4: AsyncProtocolWithNotSendable {
6767
func f() -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' cannot be returned from actor-isolated implementation to caller of protocol requirement 'f()'}}
6868

69-
var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' in conformance of actor-isolated property 'prop' to protocol requirement cannot cross actor boundary}}
69+
var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' cannot be returned from actor-isolated implementation to caller of protocol requirement 'prop'}}
7070
get {
7171
NotSendable()
7272
}
@@ -111,7 +111,7 @@ protocol AsyncThrowingProtocolWithNotSendable {
111111
actor A7: AsyncThrowingProtocolWithNotSendable {
112112
func f() async -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' cannot be returned from actor-isolated implementation to caller of protocol requirement 'f()'}}
113113

114-
var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' in conformance of actor-isolated property 'prop' to protocol requirement cannot cross actor boundary}}
114+
var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' cannot be returned from actor-isolated implementation to caller of protocol requirement 'prop'}}
115115
get async {
116116
NotSendable()
117117
}
@@ -124,7 +124,7 @@ actor A7: AsyncThrowingProtocolWithNotSendable {
124124
actor A8: AsyncThrowingProtocolWithNotSendable {
125125
func f() -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' cannot be returned from actor-isolated implementation to caller of protocol requirement 'f()'}}
126126

127-
var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' in conformance of actor-isolated property 'prop' to protocol requirement cannot cross actor boundary}}
127+
var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' cannot be returned from actor-isolated implementation to caller of protocol requirement 'prop'}}
128128
get {
129129
NotSendable()
130130
}

0 commit comments

Comments
 (0)