Skip to content

Commit 9319102

Browse files
authored
Merge pull request #75687 from hborla/sendable-param-diagnostics
[Concurrency] Split up the non-`Sendable` diagnostics and improve wording.
2 parents 8ce7456 + 7dbec84 commit 9319102

18 files changed

+236
-129
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 66 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5635,36 +5635,73 @@ NOTE(in_derived_conformance, none,
56355635
NOTE(in_derived_witness, none,
56365636
"in %0 %1 for derived conformance to %2",
56375637
(DescriptiveDeclKind, DeclName, Type))
5638-
ERROR(non_sendable_param_type,none,
5639-
"non-sendable type %0 %select{passed in call to %3 %kind2|"
5640-
"exiting %3 context in call to nonisolated %kind2|"
5641-
"passed in implicitly asynchronous call to %3 %kind2|"
5642-
"in parameter of the protocol requirement satisfied by %3 %kind2|"
5643-
"in parameter of superclass method overridden by %3 %kind2|"
5644-
"in parameter of %3 '@objc' %kind2}1 cannot cross actor boundary",
5645-
(Type, unsigned, const ValueDecl *, ActorIsolation))
5646-
ERROR(non_sendable_result_type,none,
5647-
"non-sendable type %0 returned by %select{call to %3 %kind2|"
5648-
"call from %4 context to nonisolated %kind2|"
5649-
"implicitly asynchronous call to %3 %kind2|"
5650-
"%3 %kind2 satisfying protocol requirement|"
5651-
"%3 overriding %kind2|"
5652-
"%3 '@objc' %kind2}1 cannot cross actor boundary",
5653-
(Type, unsigned, const ValueDecl *, ActorIsolation))
5638+
5639+
ERROR(non_sendable_arg_into_actor,none,
5640+
"non-sendable type %0 cannot be sent into %2 context in call to %kind1",
5641+
(Type, const ValueDecl *, ActorIsolation))
5642+
ERROR(non_sendable_arg_exits_actor,none,
5643+
"non-sendable type %0 cannot exit %2 context in call to nonisolated "
5644+
"%kind1",
5645+
(Type, const ValueDecl *, ActorIsolation))
5646+
ERROR(non_sendable_param_in_witness,none,
5647+
"non-sendable parameter type %0 cannot be sent from caller of "
5648+
"protocol requirement %1 into %2 implementation",
5649+
(Type, const ValueDecl *, ActorIsolation))
5650+
ERROR(non_sendable_param_in_override,none,
5651+
"non-sendable parameter type %0 cannot be sent from caller of "
5652+
"superclass %kind1 into %2 override",
5653+
(Type, const ValueDecl *, ActorIsolation))
5654+
ERROR(non_sendable_param_in_objc,none,
5655+
"non-sendable parameter type %0 of %2 '@objc' %kind1 cannot cross actor "
5656+
"boundary",
5657+
(Type, const ValueDecl *, ActorIsolation))
5658+
5659+
ERROR(non_sendable_result_into_actor,none,
5660+
"non-sendable result type %0 cannot be sent from %2 context in call "
5661+
"to %kind1",
5662+
(Type, const ValueDecl *, ActorIsolation))
5663+
ERROR(non_sendable_result_exits_actor,none,
5664+
"non-sendable result type %0 cannot exit %2 context in call to "
5665+
"nonisolated %kind1",
5666+
(Type, const ValueDecl *, ActorIsolation))
5667+
ERROR(non_sendable_result_in_witness,none,
5668+
"non-sendable type %0 cannot be returned from %2 implementation "
5669+
"to caller of protocol requirement %1",
5670+
(Type, const ValueDecl *, ActorIsolation))
5671+
ERROR(non_sendable_result_in_override,none,
5672+
"non-sendable type %0 cannot be returned from %2 override to "
5673+
"caller of superclass %kind1",
5674+
(Type, const ValueDecl *, ActorIsolation))
5675+
ERROR(non_sendable_result_in_objc,none,
5676+
"non-sendable type %0 returned by %2 '@objc' %kind1 cannot cross "
5677+
"actor boundary",
5678+
(Type, const ValueDecl *, ActorIsolation))
5679+
56545680
ERROR(non_sendable_call_result_type,none,
5655-
"non-sendable type %0 returned by %select{|implicitly async }1"
5656-
"call to %2 function cannot cross actor boundary",
5657-
(Type, bool, ActorIsolation))
5658-
ERROR(non_sendable_property_type,none,
5659-
"non-sendable type %0 in %select{"
5660-
"%select{asynchronous access to %4 %kind1|"
5661-
"asynchronous access from %4 context to nonisolated %kind1|"
5662-
"implicitly asynchronous access to %4 %kind1|"
5663-
"conformance of %4 %kind1 to protocol requirement|"
5664-
"%4 overriding %kind1|"
5665-
"%4 '@objc' %kind1}3|captured local %1}2 cannot "
5666-
"cross %select{actor|task}2 boundary",
5667-
(Type, const ValueDecl *, bool, unsigned, ActorIsolation))
5681+
"non-sendable result type %0 cannot be sent from %1 context in call "
5682+
"to async function",
5683+
(Type, 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+
56685705
ERROR(non_sendable_keypath_capture,none,
56695706
"cannot form key path that captures non-sendable type %0",
56705707
(Type))

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 93 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,72 @@ bool swift::diagnoseNonSendableTypes(
11211121
return anyMissing;
11221122
}
11231123

1124+
static
1125+
Diag<Type, const ValueDecl *, ActorIsolation>
1126+
getSendableParamDiag(SendableCheckReason refKind) {
1127+
switch (refKind) {
1128+
case SendableCheckReason::CrossActor:
1129+
case SendableCheckReason::SynchronousAsAsync:
1130+
return diag::non_sendable_arg_into_actor;
1131+
1132+
case SendableCheckReason::ExitingActor:
1133+
return diag::non_sendable_arg_exits_actor;
1134+
1135+
case SendableCheckReason::Conformance:
1136+
return diag::non_sendable_param_in_witness;
1137+
1138+
case SendableCheckReason::Override:
1139+
return diag::non_sendable_param_in_override;
1140+
1141+
case SendableCheckReason::ObjC:
1142+
return diag::non_sendable_param_in_objc;
1143+
}
1144+
}
1145+
1146+
static
1147+
Diag<Type, const ValueDecl *, ActorIsolation>
1148+
getSendableResultDiag(SendableCheckReason refKind) {
1149+
switch (refKind) {
1150+
case SendableCheckReason::CrossActor:
1151+
case SendableCheckReason::SynchronousAsAsync:
1152+
return diag::non_sendable_result_into_actor;
1153+
1154+
case SendableCheckReason::ExitingActor:
1155+
return diag::non_sendable_result_exits_actor;
1156+
1157+
case SendableCheckReason::Conformance:
1158+
return diag::non_sendable_result_in_witness;
1159+
1160+
case SendableCheckReason::Override:
1161+
return diag::non_sendable_result_in_override;
1162+
1163+
case SendableCheckReason::ObjC:
1164+
return diag::non_sendable_result_in_objc;
1165+
}
1166+
}
1167+
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+
11241190
bool swift::diagnoseNonSendableTypesInReference(
11251191
Expr *base, ConcreteDeclRef declRef, const DeclContext *fromDC,
11261192
SourceLoc refLoc, SendableCheckReason refKind,
@@ -1155,8 +1221,8 @@ bool swift::diagnoseNonSendableTypesInReference(
11551221
base->getType(),
11561222
fromDC, derivedConformanceType,
11571223
base->getStartLoc(),
1158-
diag::non_sendable_param_type,
1159-
(unsigned)refKind, declRef.getDecl(),
1224+
getSendableParamDiag(refKind),
1225+
declRef.getDecl(),
11601226
getActorIsolation()))
11611227
return true;
11621228
}
@@ -1171,8 +1237,8 @@ bool swift::diagnoseNonSendableTypesInReference(
11711237
if (diagnoseNonSendableTypes(
11721238
paramType, fromDC, derivedConformanceType,
11731239
refLoc, diagnoseLoc.isInvalid() ? refLoc : diagnoseLoc,
1174-
diag::non_sendable_param_type,
1175-
(unsigned)refKind, function, getActorIsolation()))
1240+
getSendableParamDiag(refKind),
1241+
function, getActorIsolation()))
11761242
return true;
11771243
}
11781244
}
@@ -1185,8 +1251,8 @@ bool swift::diagnoseNonSendableTypesInReference(
11851251
if (diagnoseNonSendableTypes(
11861252
resultType, fromDC, derivedConformanceType,
11871253
refLoc, diagnoseLoc.isInvalid() ? refLoc : diagnoseLoc,
1188-
diag::non_sendable_result_type,
1189-
(unsigned)refKind, func, getActorIsolation()))
1254+
getSendableResultDiag(refKind),
1255+
func, getActorIsolation()))
11901256
return true;
11911257
}
11921258
}
@@ -1201,11 +1267,8 @@ bool swift::diagnoseNonSendableTypesInReference(
12011267
if (diagnoseNonSendableTypes(
12021268
propertyType, fromDC,
12031269
derivedConformanceType, refLoc,
1204-
diag::non_sendable_property_type,
1205-
var,
1206-
var->isLocalCapture(),
1207-
(unsigned)refKind,
1208-
getActorIsolation()))
1270+
getSendablePropertyDiag(refKind),
1271+
var, getActorIsolation()))
12091272
return true;
12101273
}
12111274

@@ -1217,8 +1280,8 @@ bool swift::diagnoseNonSendableTypesInReference(
12171280
if (diagnoseNonSendableTypes(
12181281
paramType, fromDC, derivedConformanceType,
12191282
refLoc, diagnoseLoc.isInvalid() ? refLoc : diagnoseLoc,
1220-
diag::non_sendable_param_type,
1221-
(unsigned)refKind, subscript, getActorIsolation()))
1283+
getSendableParamDiag(refKind),
1284+
subscript, getActorIsolation()))
12221285
return true;
12231286
}
12241287
}
@@ -1229,8 +1292,8 @@ bool swift::diagnoseNonSendableTypesInReference(
12291292
if (diagnoseNonSendableTypes(
12301293
resultType, fromDC, derivedConformanceType,
12311294
refLoc, diagnoseLoc.isInvalid() ? refLoc : diagnoseLoc,
1232-
diag::non_sendable_result_type,
1233-
(unsigned)refKind, subscript, getActorIsolation()))
1295+
getSendableResultDiag(refKind),
1296+
subscript, getActorIsolation()))
12341297
return true;
12351298
}
12361299

@@ -3849,14 +3912,21 @@ namespace {
38493912
fnType->getResult().getPointer();
38503913
};
38513914

3852-
if (!willDoubleError() &&
3853-
diagnoseNonSendableTypes(fnType->getResult(), getDeclContext(),
3854-
/*inDerivedConformance*/ Type(),
3855-
apply->getLoc(),
3856-
diag::non_sendable_call_result_type,
3857-
apply->isImplicitlyAsync().has_value(),
3858-
*unsatisfiedIsolation)) {
3859-
return true;
3915+
if (!willDoubleError()) {
3916+
if (calleeDecl) {
3917+
return diagnoseNonSendableTypes(fnType->getResult(), getDeclContext(),
3918+
/*inDerivedConformance*/ Type(),
3919+
apply->getLoc(),
3920+
diag::non_sendable_result_into_actor,
3921+
calleeDecl,
3922+
*unsatisfiedIsolation);
3923+
}
3924+
3925+
return diagnoseNonSendableTypes(fnType->getResult(), getDeclContext(),
3926+
/*inDerivedConformance*/ Type(),
3927+
apply->getLoc(),
3928+
diag::non_sendable_call_result_type,
3929+
*unsatisfiedIsolation);
38603930
}
38613931
}
38623932

test/ClangImporter/objc_async.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,12 +322,12 @@ func check() async {
322322
_ = await BarFrame()
323323
_ = await FooFrame()
324324
_ = await BazFrame()
325-
// expected-warning@-1 {{non-sendable type 'BazFrame' returned by implicitly async call to global actor 'SomeGlobalActor'-isolated function cannot cross actor boundary; this is an error in the Swift 6 language mode}}
325+
// expected-warning@-1 {{non-sendable result type 'BazFrame' cannot be sent from global actor 'SomeGlobalActor'-isolated context in call to initializer 'init()'; this is an error in the Swift 6 language mode}}
326326

327327
_ = await BarFrame(size: 0)
328328
_ = await FooFrame(size: 0)
329329
_ = await BazFrame(size: 0)
330-
// expected-warning@-1 {{non-sendable type 'BazFrame' returned by implicitly async call to global actor 'SomeGlobalActor'-isolated function cannot cross actor boundary; this is an error in the Swift 6 language mode}}
330+
// expected-warning@-1 {{non-sendable result type 'BazFrame' cannot be sent from global actor 'SomeGlobalActor'-isolated context in call to initializer 'init(size:)'; this is an error in the Swift 6 language mode}}
331331
}
332332

333333
@available(SwiftStdlib 5.5, *)

test/Concurrency/actor_call_implicitly_async.swift

Lines changed: 9 additions & 9 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!")
@@ -353,23 +353,23 @@ actor Calculator {
353353

354354
@OrangeActor func doSomething() async {
355355
let _ = (await bananaAdd(1))(2)
356-
// expected-warning@-1{{non-sendable type '(Int) -> Int' returned by implicitly async call to global actor 'BananaActor'-isolated function cannot cross actor boundary}}
356+
// expected-warning@-1{{non-sendable result type '(Int) -> Int' cannot be sent from global actor 'BananaActor'-isolated context in call to global function 'bananaAdd'}}
357357
// expected-note@-2{{a function type must be marked '@Sendable' to conform to 'Sendable'}}
358358
let _ = await (await bananaAdd(1))(2) // expected-warning{{no 'async' operations occur within 'await' expression}}
359-
// expected-warning@-1{{non-sendable type '(Int) -> Int' returned by implicitly async call to global actor 'BananaActor'-isolated function cannot cross actor boundary}}
359+
// expected-warning@-1{{non-sendable result type '(Int) -> Int' cannot be sent from global actor 'BananaActor'-isolated context in call to global function 'bananaAdd'}}
360360
// expected-note@-2{{a function type must be marked '@Sendable' to conform to 'Sendable'}}
361361

362362
let calc = Calculator()
363363

364364
let _ = (await calc.addCurried(1))(2)
365-
// expected-warning@-1{{non-sendable type '(Int) -> Int' returned by implicitly async call to actor-isolated function cannot cross actor boundary}}
365+
// expected-warning@-1{{non-sendable result type '(Int) -> Int' cannot be sent from actor-isolated context in call to instance method 'addCurried'}}
366366
// expected-note@-2{{a function type must be marked '@Sendable' to conform to 'Sendable'}}
367367
let _ = await (await calc.addCurried(1))(2) // expected-warning{{no 'async' operations occur within 'await' expression}}
368-
// expected-warning@-1{{non-sendable type '(Int) -> Int' returned by implicitly async call to actor-isolated function cannot cross actor boundary}}
368+
// expected-warning@-1{{non-sendable result type '(Int) -> Int' cannot be sent from actor-isolated context in call to instance method 'addCurried'}}
369369
// expected-note@-2{{a function type must be marked '@Sendable' to conform to 'Sendable'}}
370370

371371
let plusOne = await calc.addCurried(await calc.add(0, 1))
372-
// expected-warning@-1{{non-sendable type '(Int) -> Int' returned by implicitly async call to actor-isolated function cannot cross actor boundary}}
372+
// expected-warning@-1{{non-sendable result type '(Int) -> Int' cannot be sent from actor-isolated context in call to instance method 'addCurried'}}
373373
// expected-note@-2{{a function type must be marked '@Sendable' to conform to 'Sendable'}}
374374
let _ = plusOne(2)
375375
}

test/Concurrency/actor_inout_isolation.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ extension TestActor {
119119
func passStateIntoDifferentClassMethod() async {
120120
let other = NonAsyncClass()
121121
let otherCurry = other.modifyOtherAsync
122-
// expected-targeted-complete-tns-warning @-1 {{non-sendable type 'NonAsyncClass' exiting actor-isolated context in call to nonisolated instance method 'modifyOtherAsync' cannot cross actor boundary}}
122+
// expected-targeted-complete-tns-warning @-1 {{non-sendable type 'NonAsyncClass' cannot exit actor-isolated context in call to nonisolated instance method 'modifyOtherAsync'}}
123123
await other.modifyOtherAsync(&value2)
124124
// expected-error @-1 {{actor-isolated property 'value2' cannot be passed 'inout' to 'async' function call}}
125125

@@ -288,11 +288,11 @@ actor ProtectArray {
288288
func test() async {
289289
// FIXME: this is invalid too!
290290
_ = await array.mutateAsynchronously
291-
// expected-targeted-complete-tns-warning@-1 {{non-sendable type '@lvalue [Int]' exiting actor-isolated context in call to nonisolated property 'mutateAsynchronously' cannot cross actor boundary}}
291+
// expected-targeted-complete-tns-warning@-1 {{non-sendable type '@lvalue [Int]' cannot exit actor-isolated context in call to nonisolated property 'mutateAsynchronously'}}
292292

293293
_ = await array[mutateAsynchronously: 0]
294294
// expected-error@-1 {{actor-isolated property 'array' cannot be passed 'inout' to 'async' function call}}
295-
// expected-targeted-complete-tns-warning@-2 {{non-sendable type 'inout Array<Int>' exiting actor-isolated context in call to nonisolated subscript 'subscript(mutateAsynchronously:)' cannot cross actor boundary}}
295+
// expected-targeted-complete-tns-warning@-2 {{non-sendable type 'inout Array<Int>' cannot exit actor-isolated context in call to nonisolated subscript 'subscript(mutateAsynchronously:)'}}
296296

297297
await passToAsync(array[0])
298298

0 commit comments

Comments
 (0)