Skip to content

Commit 7c47803

Browse files
committed
Improve sendable diagnostics for the arguments/parameters of functions
1 parent 11601c4 commit 7c47803

File tree

4 files changed

+53
-30
lines changed

4 files changed

+53
-30
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4570,10 +4570,18 @@ NOTE(protocol_isolated_to_global_actor_here,none,
45704570

45714571
ERROR(isolated_parameter_not_actor,none,
45724572
"'isolated' parameter has non-actor type %0", (Type))
4573-
4573+
45744574
WARNING(non_sendable_param_type,none,
4575-
"cannot pass argument of non-sendable type %0 across actors",
4576-
(Type))
4575+
"non-sendable type %0 %select{passed in call to %4 %2 %3|"
4576+
"passed in implicitly asynchronous call to %4 %2 %3|"
4577+
"in parameter of %4 %2 %3 satisfying non-isolated protocol "
4578+
"requirement|"
4579+
"in parameter of %4 '@objc' %2 %3}1 cannot cross actor boundary",
4580+
(Type, unsigned, DescriptiveDeclKind, DeclName, ActorIsolation))
4581+
WARNING(non_sendable_call_param_type,none,
4582+
"non-sendable type %0 passed in %select{implicitly asynchronous |}1"
4583+
"call to %2 function cannot cross actor boundary",
4584+
(Type, bool, ActorIsolation))
45774585
WARNING(non_sendable_result_type,none,
45784586
"non-sendable type %0 returned by %select{call to %4 %2 %3|"
45794587
"implicitly asynchronous call to %4 %2 %3|"

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,9 @@ bool swift::diagnoseNonSendableTypesInReference(
788788
for (auto param : *function->getParameters()) {
789789
Type paramType = param->getInterfaceType().subst(subs);
790790
if (diagnoseNonSendableTypes(
791-
paramType, fromDC, loc, diag::non_sendable_param_type))
791+
paramType, fromDC, loc, diag::non_sendable_param_type,
792+
(unsigned)reason, function->getDescriptiveKind(),
793+
function->getName(), getActorIsolation(function)))
792794
return true;
793795
}
794796

@@ -821,7 +823,9 @@ bool swift::diagnoseNonSendableTypesInReference(
821823
for (auto param : *subscript->getIndices()) {
822824
Type paramType = param->getInterfaceType().subst(subs);
823825
if (diagnoseNonSendableTypes(
824-
paramType, fromDC, loc, diag::non_sendable_param_type))
826+
paramType, fromDC, loc, diag::non_sendable_param_type,
827+
(unsigned)reason, subscript->getDescriptiveKind(),
828+
subscript->getName(), getActorIsolation(subscript)))
825829
return true;
826830
}
827831

@@ -2107,11 +2111,23 @@ namespace {
21072111
}
21082112

21092113
// Check for sendability of the parameter types.
2110-
for (const auto &param : fnType->getParams()) {
2111-
// FIXME: Dig out the locations of the corresponding arguments.
2114+
auto params = fnType->getParams();
2115+
for (unsigned paramIdx : indices(params)) {
2116+
const auto &param = params[paramIdx];
2117+
2118+
// Dig out the location of the argument.
2119+
SourceLoc argLoc = apply->getLoc();
2120+
if (auto argList = apply->getArgs()) {
2121+
auto arg = argList->get(paramIdx);
2122+
if (arg.getStartLoc().isValid())
2123+
argLoc = arg.getStartLoc();
2124+
}
2125+
21122126
if (diagnoseNonSendableTypes(
2113-
param.getParameterType(), getDeclContext(), apply->getLoc(),
2114-
diag::non_sendable_param_type))
2127+
param.getParameterType(), getDeclContext(), argLoc,
2128+
diag::non_sendable_call_param_type,
2129+
apply->isImplicitlyAsync().hasValue(),
2130+
*unsatisfiedIsolation))
21152131
return true;
21162132
}
21172133

test/Concurrency/actor_call_implicitly_async.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -289,28 +289,28 @@ func blender(_ peeler : () -> Void) {
289289

290290

291291
await wisk({})
292-
// expected-warning@-1{{cannot pass argument of non-sendable type 'Any' across actors}}
292+
// expected-warning@-1{{non-sendable type 'Any' passed in call to global actor 'BananaActor'-isolated function cannot cross actor boundary}}
293293
await wisk(1)
294-
// expected-warning@-1{{cannot pass argument of non-sendable type 'Any' across actors}}
294+
// expected-warning@-1{{non-sendable type 'Any' passed in call to global actor 'BananaActor'-isolated function cannot cross actor boundary}}
295295
await (peelBanana)()
296296
await (((((peelBanana)))))()
297297
await (((wisk)))((wisk)((wisk)(1)))
298-
// expected-warning@-1 3{{cannot pass argument of non-sendable type 'Any' across actors}}
298+
// expected-warning@-1 3{{non-sendable type 'Any' passed in call to global actor 'BananaActor'-isolated function cannot cross actor boundary}}
299299

300300
blender((peelBanana))
301301
// expected-error@-1{{converting function value of type '@BananaActor () -> ()' to '() -> Void' loses global actor 'BananaActor'}}
302302
await wisk(peelBanana)
303-
// expected-warning@-1{{cannot pass argument of non-sendable type 'Any' across actors}}
303+
// expected-warning@-1{{non-sendable type 'Any' passed in call to global actor 'BananaActor'-isolated function cannot cross actor boundary}}
304304

305305
await wisk(wisk)
306-
// expected-warning@-1{{cannot pass argument of non-sendable type 'Any' across actors}}
306+
// expected-warning@-1{{non-sendable type 'Any' passed in call to global actor 'BananaActor'-isolated function cannot cross actor boundary}}
307307
await (((wisk)))(((wisk)))
308-
// expected-warning@-1{{cannot pass argument of non-sendable type 'Any' across actors}}
308+
// expected-warning@-1{{non-sendable type 'Any' passed in call to global actor 'BananaActor'-isolated function cannot cross actor boundary}}
309309

310-
// expected-warning@+1 {{cannot pass argument of non-sendable type 'Any' across actors}}
310+
// expected-warning@+1 {{non-sendable type 'Any' passed in call to global actor 'BananaActor'-isolated function cannot cross actor boundary}}
311311
await {wisk}()(1)
312312

313-
// expected-warning@+1 {{cannot pass argument of non-sendable type 'Any' across actors}}
313+
// expected-warning@+1 {{non-sendable type 'Any' passed in call to global actor 'BananaActor'-isolated function cannot cross actor boundary}}
314314
await (true ? wisk : {n in return})(1)
315315
}
316316

test/Concurrency/concurrent_value_checking.swift

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@ actor A2 {
2525
}
2626

2727
convenience init(delegatingSync value: NotConcurrent) {
28-
self.init(value: value) // expected-warning{{cannot pass argument of non-sendable type 'NotConcurrent' across actors}}
28+
self.init(value: value) // expected-warning{{non-sendable type 'NotConcurrent' passed in call to nonisolated initializer 'init(value:)' cannot cross actor boundary}}
2929
}
3030

3131
convenience init(delegatingAsync value: NotConcurrent) async {
32-
await self.init(valueAsync: value) // expected-warning{{cannot pass argument of non-sendable type 'NotConcurrent' across actors}}
32+
await self.init(valueAsync: value) // expected-warning{{non-sendable type 'NotConcurrent' passed in call to actor-isolated initializer 'init(valueAsync:)' cannot cross actor boundary}}
3333
}
3434
}
3535

3636
func testActorCreation(value: NotConcurrent) async {
37-
_ = A2(value: value) // expected-warning{{cannot pass argument of non-sendable type 'NotConcurrent' across actors}}
38-
_ = await A2(valueAsync: value) // expected-warning{{cannot pass argument of non-sendable type 'NotConcurrent' across actors}}
37+
_ = A2(value: value) // expected-warning{{non-sendable type 'NotConcurrent' passed in call to nonisolated initializer 'init(value:)' cannot cross actor boundary}}
38+
_ = await A2(valueAsync: value) // expected-warning{{non-sendable type 'NotConcurrent' passed in call to actor-isolated initializer 'init(valueAsync:)' cannot cross actor boundary}}
3939
}
4040

4141
extension A1 {
@@ -52,7 +52,7 @@ extension A1 {
5252
// Across to a different actor, so Sendable restriction is enforced.
5353
_ = other.localLet // expected-warning{{cannot use property 'localLet' with a non-sendable type 'NotConcurrent' across actors}}
5454
_ = await other.synchronous() // expected-warning{{non-sendable type 'NotConcurrent?' returned by implicitly asynchronous call to actor-isolated instance method 'synchronous()' cannot cross actor boundary}}
55-
_ = await other.asynchronous(nil) // expected-warning{{cannot pass argument of non-sendable type 'NotConcurrent?' across actors}}
55+
_ = await other.asynchronous(nil) // expected-warning{{non-sendable type 'NotConcurrent?' passed in call to actor-isolated instance method 'asynchronous' cannot cross actor boundary}}
5656
}
5757
}
5858

@@ -81,8 +81,8 @@ func globalAsync(_: NotConcurrent?) async {
8181

8282
func globalTest() async {
8383
let a = globalValue // expected-warning{{cannot use let 'globalValue' with a non-sendable type 'NotConcurrent?' across actors}}
84-
await globalAsync(a) // expected-warning{{cannot pass argument of non-sendable type 'NotConcurrent?' across actors}}
85-
await globalSync(a) // expected-warning{{cannot pass argument of non-sendable type 'NotConcurrent?' across actors}}
84+
await globalAsync(a) // expected-warning{{non-sendable type 'NotConcurrent?' passed in implicitly asynchronous call to global actor 'SomeGlobalActor'-isolated function cannot cross actor boundary}}
85+
await globalSync(a) // expected-warning{{non-sendable type 'NotConcurrent?' passed in call to global actor 'SomeGlobalActor'-isolated function cannot cross actor boundary}}
8686
}
8787

8888
struct HasSubscript {
@@ -102,9 +102,9 @@ class ClassWithGlobalActorInits { // expected-note 2{{class 'ClassWithGlobalActo
102102
@MainActor
103103
func globalTestMain(nc: NotConcurrent) async {
104104
let a = globalValue // expected-warning{{cannot use let 'globalValue' with a non-sendable type 'NotConcurrent?' across actors}}
105-
await globalAsync(a) // expected-warning{{cannot pass argument of non-sendable type 'NotConcurrent?' across actors}}
106-
await globalSync(a) // expected-warning{{cannot pass argument of non-sendable type 'NotConcurrent?' across actors}}
107-
_ = await ClassWithGlobalActorInits(nc) // expected-warning{{cannot pass argument of non-sendable type 'NotConcurrent' across actors}}
105+
await globalAsync(a) // expected-warning{{non-sendable type 'NotConcurrent?' passed in implicitly asynchronous call to global actor 'SomeGlobalActor'-isolated function cannot cross actor boundary}}
106+
await globalSync(a) // expected-warning{{non-sendable type 'NotConcurrent?' passed in call to global actor 'SomeGlobalActor'-isolated function cannot cross actor boundary}}
107+
_ = await ClassWithGlobalActorInits(nc) // expected-warning{{non-sendable type 'NotConcurrent' passed in call to global actor 'SomeGlobalActor'-isolated function cannot cross actor boundary}}
108108
// expected-warning@-1{{non-sendable type 'ClassWithGlobalActorInits' returned by call to global actor 'SomeGlobalActor'-isolated function cannot cross actor boundary}}
109109
_ = await ClassWithGlobalActorInits() // expected-warning{{non-sendable type 'ClassWithGlobalActorInits' returned by call to global actor 'SomeGlobalActor'-isolated function cannot cross actor boundary}}
110110
}
@@ -191,8 +191,7 @@ protocol AsyncProto {
191191
}
192192

193193
extension A1: AsyncProto {
194-
// FIXME: Poor diagnostic.
195-
func asyncMethod(_: NotConcurrent) async { } // expected-warning{{cannot pass argument of non-sendable type 'NotConcurrent' across actors}}
194+
func asyncMethod(_: NotConcurrent) async { } // expected-warning{{non-sendable type 'NotConcurrent' in parameter of actor-isolated instance method 'asyncMethod' satisfying non-isolated protocol requirement cannot cross actor boundary}}
196195
}
197196

198197
protocol MainActorProto {
@@ -201,7 +200,7 @@ protocol MainActorProto {
201200

202201
class SomeClass: MainActorProto {
203202
@SomeGlobalActor
204-
func asyncMainMethod(_: NotConcurrent) async { } // expected-warning{{cannot pass argument of non-sendable type 'NotConcurrent' across actors}}
203+
func asyncMainMethod(_: NotConcurrent) async { } // expected-warning{{non-sendable type 'NotConcurrent' in parameter of global actor 'SomeGlobalActor'-isolated instance method 'asyncMainMethod' satisfying non-isolated protocol requirement cannot cross actor boundary}}
205204
}
206205

207206
// ----------------------------------------------------------------------

0 commit comments

Comments
 (0)