Skip to content

Commit bd1653e

Browse files
committed
[Concurrency] Split up the non-Sendable result diagnostics and improve
wording.
1 parent 933f8eb commit bd1653e

10 files changed

+88
-46
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5656,18 +5656,31 @@ ERROR(non_sendable_param_in_objc,none,
56565656
"boundary",
56575657
(Type, const ValueDecl *, ActorIsolation))
56585658

5659-
ERROR(non_sendable_result_type,none,
5660-
"non-sendable type %0 returned by %select{call to %3 %kind2|"
5661-
"call from %4 context to nonisolated %kind2|"
5662-
"implicitly asynchronous call to %3 %kind2|"
5663-
"%3 %kind2 satisfying protocol requirement|"
5664-
"%3 overriding %kind2|"
5665-
"%3 '@objc' %kind2}1 cannot cross actor boundary",
5666-
(Type, unsigned, const ValueDecl *, ActorIsolation))
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+
56675680
ERROR(non_sendable_call_result_type,none,
5668-
"non-sendable type %0 returned by %select{|implicitly async }1"
5669-
"call to %2 function cannot cross actor boundary",
5670-
(Type, bool, ActorIsolation))
5681+
"non-sendable result type %0 cannot be sent from %1 context in call "
5682+
"to async function",
5683+
(Type, ActorIsolation))
56715684
ERROR(non_sendable_property_type,none,
56725685
"non-sendable type %0 in %select{"
56735686
"%select{asynchronous access to %4 %kind1|"

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,28 @@ getSendableParamDiag(SendableCheckReason refKind) {
11431143
}
11441144
}
11451145

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+
11461168
bool swift::diagnoseNonSendableTypesInReference(
11471169
Expr *base, ConcreteDeclRef declRef, const DeclContext *fromDC,
11481170
SourceLoc refLoc, SendableCheckReason refKind,
@@ -1207,8 +1229,8 @@ bool swift::diagnoseNonSendableTypesInReference(
12071229
if (diagnoseNonSendableTypes(
12081230
resultType, fromDC, derivedConformanceType,
12091231
refLoc, diagnoseLoc.isInvalid() ? refLoc : diagnoseLoc,
1210-
diag::non_sendable_result_type,
1211-
(unsigned)refKind, func, getActorIsolation()))
1232+
getSendableResultDiag(refKind),
1233+
func, getActorIsolation()))
12121234
return true;
12131235
}
12141236
}
@@ -1251,8 +1273,8 @@ bool swift::diagnoseNonSendableTypesInReference(
12511273
if (diagnoseNonSendableTypes(
12521274
resultType, fromDC, derivedConformanceType,
12531275
refLoc, diagnoseLoc.isInvalid() ? refLoc : diagnoseLoc,
1254-
diag::non_sendable_result_type,
1255-
(unsigned)refKind, subscript, getActorIsolation()))
1276+
getSendableResultDiag(refKind),
1277+
subscript, getActorIsolation()))
12561278
return true;
12571279
}
12581280

@@ -3871,14 +3893,21 @@ namespace {
38713893
fnType->getResult().getPointer();
38723894
};
38733895

3874-
if (!willDoubleError() &&
3875-
diagnoseNonSendableTypes(fnType->getResult(), getDeclContext(),
3876-
/*inDerivedConformance*/ Type(),
3877-
apply->getLoc(),
3878-
diag::non_sendable_call_result_type,
3879-
apply->isImplicitlyAsync().has_value(),
3880-
*unsatisfiedIsolation)) {
3881-
return true;
3896+
if (!willDoubleError()) {
3897+
if (calleeDecl) {
3898+
return diagnoseNonSendableTypes(fnType->getResult(), getDeclContext(),
3899+
/*inDerivedConformance*/ Type(),
3900+
apply->getLoc(),
3901+
diag::non_sendable_result_into_actor,
3902+
calleeDecl,
3903+
*unsatisfiedIsolation);
3904+
}
3905+
3906+
return diagnoseNonSendableTypes(fnType->getResult(), getDeclContext(),
3907+
/*inDerivedConformance*/ Type(),
3908+
apply->getLoc(),
3909+
diag::non_sendable_call_result_type,
3910+
*unsatisfiedIsolation);
38823911
}
38833912
}
38843913

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: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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/concurrent_value_checking.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ extension A1 {
102102
_ = other.localLet // expected-warning{{non-sendable type 'NotConcurrent' in implicitly asynchronous access to actor-isolated property 'localLet' cannot cross actor boundary}}
103103
// expected-warning@-1 {{expression is 'async' but is not marked with 'await'}}
104104
// expected-note@-2 {{property access is 'async'}}
105-
_ = await other.synchronous() // expected-warning{{non-sendable type 'NotConcurrent?' returned by implicitly async call to actor-isolated function cannot cross actor boundary}}
105+
_ = await other.synchronous() // expected-warning{{non-sendable result type 'NotConcurrent?' cannot be sent from actor-isolated context in call to instance method 'synchronous()'}}
106106
_ = await other.asynchronous(nil)
107107
}
108108
}
@@ -182,10 +182,10 @@ func globalTestMain(nc: NotConcurrent) async {
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}}
184184
_ = await ClassWithGlobalActorInits(nc)
185-
// expected-warning @-1 {{non-sendable type 'ClassWithGlobalActorInits' returned by implicitly async call to global actor 'SomeGlobalActor'-isolated function cannot cross actor boundary}}
185+
// expected-warning @-1 {{non-sendable result type 'ClassWithGlobalActorInits' cannot be sent from global actor 'SomeGlobalActor'-isolated context in call to initializer 'init(_:)'}}
186186
// expected-tns-warning @-2 {{sending 'nc' risks causing data races}}
187187
// expected-tns-note @-3 {{sending main actor-isolated 'nc' to global actor 'SomeGlobalActor'-isolated initializer 'init(_:)' risks causing data races between global actor 'SomeGlobalActor'-isolated and main actor-isolated uses}}
188-
_ = await ClassWithGlobalActorInits() // expected-warning{{non-sendable type 'ClassWithGlobalActorInits' returned by implicitly async call to global actor 'SomeGlobalActor'-isolated function cannot cross actor boundary}}
188+
_ = await ClassWithGlobalActorInits() // expected-warning{{non-sendable result type 'ClassWithGlobalActorInits' cannot be sent from global actor 'SomeGlobalActor'-isolated context in call to initializer 'init()'}}
189189
}
190190

191191
@SomeGlobalActor

test/Concurrency/sendable_checking.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public actor MyActor: MyProto {
9696
await nonisolatedAsyncFunc1(ns1)
9797
// expected-tns-warning @-1 {{sending 'ns1' risks causing data races}}
9898
// expected-tns-note @-2 {{sending 'self'-isolated 'ns1' to nonisolated global function 'nonisolatedAsyncFunc1' risks causing data races between nonisolated and 'self'-isolated uses}}
99-
_ = await nonisolatedAsyncFunc2() // expected-warning{{non-sendable type 'NS1' returned by call to nonisolated function cannot cross actor boundary}}
99+
_ = await nonisolatedAsyncFunc2() // expected-warning{{non-sendable result type 'NS1' cannot be sent from nonisolated context in call to global function 'nonisolatedAsyncFunc2()'}}
100100
}
101101
}
102102

test/Concurrency/sendable_conformance_checking.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ actor A2: IsolatedWithNotSendableRequirements {
3838
nonisolated var prop: NotSendable { NotSendable() }
3939

4040
nonisolated func fAsync() async -> NotSendable { NotSendable() }
41-
// expected-warning@-1{{non-sendable type 'NotSendable' returned by nonisolated instance method 'fAsync()' satisfying protocol requirement cannot cross actor boundary}}
41+
// expected-warning@-1{{non-sendable type 'NotSendable' cannot be returned from nonisolated implementation to caller of protocol requirement 'fAsync()'}}
4242
}
4343

4444
@available(SwiftStdlib 5.1, *)
@@ -51,7 +51,7 @@ protocol AsyncProtocolWithNotSendable {
5151
// actor's domain.
5252
@available(SwiftStdlib 5.1, *)
5353
actor A3: AsyncProtocolWithNotSendable {
54-
func f() async -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' returned by actor-isolated instance method 'f()' satisfying protocol requirement cannot cross actor boundary}}
54+
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

5656
var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' in conformance of actor-isolated property 'prop' to protocol requirement cannot cross actor boundary}}
5757
get async {
@@ -64,7 +64,7 @@ actor A3: AsyncProtocolWithNotSendable {
6464
// actor's domain.
6565
@available(SwiftStdlib 5.1, *)
6666
actor A4: AsyncProtocolWithNotSendable {
67-
func f() -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' returned by actor-isolated instance method 'f()' satisfying protocol requirement cannot cross actor boundary}}
67+
func f() -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' cannot be returned from actor-isolated implementation to caller of protocol requirement 'f()'}}
6868

6969
var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' in conformance of actor-isolated property 'prop' to protocol requirement cannot cross actor boundary}}
7070
get {
@@ -109,7 +109,7 @@ protocol AsyncThrowingProtocolWithNotSendable {
109109
// actor's domain.
110110
@available(SwiftStdlib 5.1, *)
111111
actor A7: AsyncThrowingProtocolWithNotSendable {
112-
func f() async -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' returned by actor-isolated instance method 'f()' satisfying protocol requirement cannot cross actor boundary}}
112+
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

114114
var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' in conformance of actor-isolated property 'prop' to protocol requirement cannot cross actor boundary}}
115115
get async {
@@ -122,7 +122,7 @@ actor A7: AsyncThrowingProtocolWithNotSendable {
122122
// actor's domain.
123123
@available(SwiftStdlib 5.1, *)
124124
actor A8: AsyncThrowingProtocolWithNotSendable {
125-
func f() -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' returned by actor-isolated instance method 'f()' satisfying protocol requirement cannot cross actor boundary}}
125+
func f() -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' cannot be returned from actor-isolated implementation to caller of protocol requirement 'f()'}}
126126

127127
var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' in conformance of actor-isolated property 'prop' to protocol requirement cannot cross actor boundary}}
128128
get {

test/Concurrency/transfernonsendable_asynclet.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,7 @@ func asyncLetWithoutCapture() async {
722722
//
723723
// NOTE: Error below will go away in next commit.
724724
async let x: NonSendableKlass = await returnValueFromMain()
725-
// expected-warning @-1 {{non-sendable type 'NonSendableKlass' returned by call to main actor-isolated function cannot cross actor boundary}}
725+
// expected-warning @-1 {{non-sendable result type 'NonSendableKlass' cannot be sent from main actor-isolated context in call to global function 'returnValueFromMain()'}}
726726
let y = await x
727727
await transferToMain(y) // expected-warning {{sending 'y' risks causing data races}}
728728
// expected-note @-1 {{sending 'y' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
@@ -774,7 +774,7 @@ extension NonSendableStruct {
774774
async let subTask6: NonSendableStruct = self
775775
// expected-warning @-1 {{sending 'self' risks causing data races}}
776776
// expected-note @-2 {{sending 'actor'-isolated 'self' into async let risks causing data races between nonisolated and 'actor'-isolated uses}}
777-
// expected-warning @-3 {{non-sendable type 'NonSendableStruct' returned by call to nonisolated function cannot cross actor boundary}}
777+
// expected-warning @-3 {{non-sendable result type 'NonSendableStruct' cannot be sent from nonisolated context in call to async function}}
778778
_ = await subTask6
779779
}
780780
}

test/Concurrency/transfernonsendable_defer_and_typecheck_only.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func callActorFuncsFromNonisolated(a : A, ns : NonSendable) async {
3434
//deferred-warning@-1{{passing argument of non-sendable type 'NonSendable' into actor-isolated context may introduce data races}}
3535

3636
_ = await a.actorRetsNS()
37-
//expected-warning@-1{{non-sendable type 'NonSendable' returned by call to actor-isolated function cannot cross actor boundary}}
37+
//expected-warning@-1{{non-sendable result type 'NonSendable' cannot be sent from actor-isolated context in call to instance method 'actorRetsNS()'}}
3838
}
3939

4040
@available(SwiftStdlib 5.1, *)
@@ -52,7 +52,7 @@ actor A {
5252
//deferred-warning@-1{{passing argument of non-sendable type 'NonSendable' outside of actor-isolated context may introduce data races}}
5353

5454
_ = await retsNS()
55-
//expected-warning@-1{{non-sendable type 'NonSendable' returned by call to nonisolated function cannot cross actor boundary}}
55+
//expected-warning@-1{{non-sendable result type 'NonSendable' cannot be sent from nonisolated context in call to global function 'retsNS()'}}
5656
}
5757

5858
func callActorFuncsFromDiffActor(ns : NonSendable, a : A) async {
@@ -62,6 +62,6 @@ actor A {
6262
//deferred-warning@-1{{passing argument of non-sendable type 'NonSendable' into actor-isolated context may introduce data races}}
6363

6464
_ = await a.actorRetsNS()
65-
//expected-warning@-1{{non-sendable type 'NonSendable' returned by call to actor-isolated function cannot cross actor boundary}}
65+
//expected-warning@-1{{non-sendable result type 'NonSendable' cannot be sent from actor-isolated context in call to instance method 'actorRetsNS()'}}
6666
}
6767
}

test/Concurrency/transfernonsendable_sending_results.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ func asyncLetReabstractionThunkTest() async {
234234
func asyncLetReabstractionThunkTest2() async {
235235
// We emit the error here since we are returning a main actor isolated value.
236236
async let newValue: NonSendableKlass = await getMainActorValueAsync()
237-
// expected-warning @-1 {{non-sendable type 'NonSendableKlass' returned by call to main actor-isolated function cannot cross actor boundary}}
237+
// expected-warning @-1 {{non-sendable result type 'NonSendableKlass' cannot be sent from main actor-isolated context in call to global function 'getMainActorValueAsync()'}}
238238

239239
let _ = await newValue
240240

@@ -257,7 +257,7 @@ func asyncLetReabstractionThunkTest2() async {
257257
@MainActor func asyncLetReabstractionThunkTestGlobalActor2() async {
258258
// We emit the error here since we are returning a main actor isolated value.
259259
async let newValue: NonSendableKlass = await getMainActorValueAsync()
260-
// expected-warning @-1 {{non-sendable type 'NonSendableKlass' returned by call to main actor-isolated function cannot cross actor boundary}}
260+
// expected-warning @-1 {{non-sendable result type 'NonSendableKlass' cannot be sent from main actor-isolated context in call to global function 'getMainActorValueAsync()'}}
261261

262262
let _ = await newValue
263263

0 commit comments

Comments
 (0)