Skip to content

Commit 22a3ec0

Browse files
authored
Merge pull request #78601 from stzn/fix-sending-typecheck
[Sema]Skip Sendable conformance check when `sending` are added to parameters or return types of an actor-isolated function
2 parents 642a6ca + 55e8d55 commit 22a3ec0

File tree

3 files changed

+153
-47
lines changed

3 files changed

+153
-47
lines changed

lib/Sema/TypeCheckConcurrency.cpp

+32-47
Original file line numberDiff line numberDiff line change
@@ -1173,34 +1173,47 @@ bool swift::diagnoseNonSendableTypesInReference(
11731173
return true;
11741174
}
11751175

1176-
// For functions, check the parameter and result types.
1176+
// For functions or subscripts, check the parameter and result types.
11771177
SubstitutionMap subs = declRef.getSubstitutions();
1178-
if (auto function = dyn_cast<AbstractFunctionDecl>(declRef.getDecl())) {
1178+
auto decl = declRef.getDecl();
1179+
if (isa<AbstractFunctionDecl>(decl) || isa<SubscriptDecl>(decl)) {
11791180
if (funcCheckOptions.contains(FunctionCheckKind::Params)) {
11801181
// only check params if funcCheckKind specifies so
1181-
for (auto param : *function->getParameters()) {
1182+
ParameterList *paramList = nullptr;
1183+
if (auto function = dyn_cast<AbstractFunctionDecl>(decl)) {
1184+
paramList = function->getParameters();
1185+
} else if (auto subscript = dyn_cast<SubscriptDecl>(decl)) {
1186+
paramList = subscript->getIndices();
1187+
}
1188+
1189+
// Check params of this function or subscript override for sendability
1190+
for (auto param : *paramList) {
11821191
Type paramType = param->getInterfaceType().subst(subs);
1183-
if (diagnoseNonSendableTypes(
1184-
paramType, fromDC, derivedConformanceType,
1185-
refLoc, diagnoseLoc.isInvalid() ? refLoc : diagnoseLoc,
1186-
getSendableParamDiag(refKind),
1187-
function, getActorIsolation()))
1192+
if (diagnoseNonSendableTypesWithSendingCheck(
1193+
param, paramType, fromDC, derivedConformanceType, refLoc,
1194+
diagnoseLoc.isInvalid() ? refLoc : diagnoseLoc,
1195+
getSendableParamDiag(refKind), decl, getActorIsolation()))
11881196
return true;
11891197
}
11901198
}
11911199

1192-
// Check the result type of a function.
1193-
if (auto func = dyn_cast<FuncDecl>(function)) {
1194-
if (funcCheckOptions.contains(FunctionCheckKind::Results)) {
1195-
// only check results if funcCheckKind specifies so
1196-
Type resultType = func->getResultInterfaceType().subst(subs);
1197-
if (diagnoseNonSendableTypes(
1198-
resultType, fromDC, derivedConformanceType,
1199-
refLoc, diagnoseLoc.isInvalid() ? refLoc : diagnoseLoc,
1200-
getSendableResultDiag(refKind),
1201-
func, getActorIsolation()))
1202-
return true;
1200+
// Check the result type of a function or subscript.
1201+
if (funcCheckOptions.contains(FunctionCheckKind::Results)) {
1202+
Type resultType;
1203+
if (auto func = dyn_cast<FuncDecl>(decl)) {
1204+
resultType = func->getResultInterfaceType().subst(subs);
1205+
decl = func;
1206+
} else if (auto subscript = dyn_cast<SubscriptDecl>(decl)) {
1207+
resultType = subscript->getElementInterfaceType().subst(subs);
1208+
}
1209+
if (!resultType) {
1210+
return false;
12031211
}
1212+
if (diagnoseNonSendableTypesWithSendingCheck(
1213+
decl, resultType, fromDC, derivedConformanceType, refLoc,
1214+
diagnoseLoc.isInvalid() ? refLoc : diagnoseLoc,
1215+
getSendableResultDiag(refKind), decl, getActorIsolation()))
1216+
return true;
12041217
}
12051218

12061219
return false;
@@ -1218,34 +1231,6 @@ bool swift::diagnoseNonSendableTypesInReference(
12181231
return true;
12191232
}
12201233

1221-
if (auto subscript = dyn_cast<SubscriptDecl>(declRef.getDecl())) {
1222-
for (auto param : *subscript->getIndices()) {
1223-
if (funcCheckOptions.contains(FunctionCheckKind::Params)) {
1224-
// Check params of this subscript override for sendability
1225-
Type paramType = param->getInterfaceType().subst(subs);
1226-
if (diagnoseNonSendableTypes(
1227-
paramType, fromDC, derivedConformanceType,
1228-
refLoc, diagnoseLoc.isInvalid() ? refLoc : diagnoseLoc,
1229-
getSendableParamDiag(refKind),
1230-
subscript, getActorIsolation()))
1231-
return true;
1232-
}
1233-
}
1234-
1235-
if (funcCheckOptions.contains(FunctionCheckKind::Results)) {
1236-
// Check the element type of a subscript.
1237-
Type resultType = subscript->getElementInterfaceType().subst(subs);
1238-
if (diagnoseNonSendableTypes(
1239-
resultType, fromDC, derivedConformanceType,
1240-
refLoc, diagnoseLoc.isInvalid() ? refLoc : diagnoseLoc,
1241-
getSendableResultDiag(refKind),
1242-
subscript, getActorIsolation()))
1243-
return true;
1244-
}
1245-
1246-
return false;
1247-
}
1248-
12491234
return false;
12501235
}
12511236

lib/Sema/TypeCheckConcurrency.h

+32
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "swift/AST/Expr.h"
2424
#include "swift/AST/Module.h"
2525
#include "swift/AST/Type.h"
26+
#include "swift/AST/TypeRepr.h"
2627
#include "swift/Sema/Concurrency.h"
2728

2829
#include <cassert>
@@ -444,6 +445,37 @@ namespace detail {
444445
};
445446
}
446447

448+
/// Diagnose any non-Sendable types that occur within the given type, using
449+
/// the given diagnostic.
450+
///
451+
/// \returns \c true if any errors were produced, \c false if no diagnostics or
452+
/// only warnings and notes were produced or if a decl contains a sending
453+
/// parameter or result
454+
template <typename... DiagArgs>
455+
bool diagnoseNonSendableTypesWithSendingCheck(
456+
ValueDecl *decl, Type type, SendableCheckContext fromContext,
457+
Type derivedConformance, SourceLoc typeLoc, SourceLoc diagnoseLoc,
458+
Diag<Type, DiagArgs...> diag,
459+
typename detail::Identity<DiagArgs>::type... diagArgs) {
460+
if (auto param = dyn_cast<ParamDecl>(decl)) {
461+
if (param->isSending()) {
462+
return false;
463+
}
464+
}
465+
if (auto *func = dyn_cast<FuncDecl>(decl)) {
466+
if (func->hasSendingResult())
467+
return false;
468+
}
469+
if (auto *subscript = dyn_cast<SubscriptDecl>(decl)) {
470+
if (isa_and_nonnull<SendingTypeRepr>(subscript->getResultTypeRepr()))
471+
return false;
472+
}
473+
474+
return diagnoseNonSendableTypes(
475+
type, fromContext, derivedConformance, typeLoc, diagnoseLoc, diag,
476+
std::forward<decltype(diagArgs)>(diagArgs)...);
477+
}
478+
447479
/// Diagnose any non-Sendable types that occur within the given type, using
448480
/// the given diagnostic.
449481
///
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// RUN: %target-typecheck-verify-swift -swift-version 6
2+
3+
// https://github.com/swiftlang/swift/issues/76710
4+
5+
class NonSendableKlass1 {}
6+
7+
protocol P1 {
8+
func bar(_ a: sending NonSendableKlass1) async -> sending NonSendableKlass1
9+
}
10+
11+
@MainActor
12+
class P1Class: P1 {
13+
func bar(_ a: sending NonSendableKlass1) async -> sending NonSendableKlass1 { a }
14+
}
15+
16+
class NonSendableKlass2 {}
17+
// expected-note@-1 2{{class 'NonSendableKlass2' does not conform to the 'Sendable' protocol}}
18+
19+
protocol P2 {
20+
func bar(_ a: NonSendableKlass2) async -> NonSendableKlass2
21+
}
22+
23+
@MainActor
24+
class P2Class: P2 {
25+
func bar(_ a: NonSendableKlass2) async -> NonSendableKlass2 { a }
26+
// expected-error@-1 {{non-sendable type 'NonSendableKlass2' cannot be returned from main actor-isolated implementation to caller of protocol requirement 'bar'}}
27+
// expected-error@-2 {{non-sendable parameter type 'NonSendableKlass2' cannot be sent from caller of protocol requirement 'bar' into main actor-isolated implementation}}
28+
}
29+
30+
class NonSendableKlass3 {}
31+
32+
protocol P3 {
33+
func bar(_ a: sending NonSendableKlass3) async -> sending NonSendableKlass3
34+
}
35+
36+
actor P3Actor: P3 {
37+
func bar(_ a: sending NonSendableKlass3) async -> sending NonSendableKlass3 { NonSendableKlass3() }
38+
}
39+
40+
class NonSendableKlass4 {}
41+
// expected-note@-1 2{{class 'NonSendableKlass4' does not conform to the 'Sendable' protocol}}
42+
43+
protocol P4 {
44+
func bar(_ a: NonSendableKlass4) async -> NonSendableKlass4
45+
}
46+
47+
actor P4Actor: P4 {
48+
func bar(_ a: NonSendableKlass4) async -> NonSendableKlass4 { NonSendableKlass4() }
49+
// expected-error@-1 {{non-sendable type 'NonSendableKlass4' cannot be returned from actor-isolated implementation to caller of protocol requirement 'bar'}}
50+
// expected-error@-2 {{non-sendable parameter type 'NonSendableKlass4' cannot be sent from caller of protocol requirement 'bar' into actor-isolated implementation}}
51+
}
52+
53+
class NonSendableKlass5 {}
54+
// expected-note@-1 {{class 'NonSendableKlass5' does not conform to the 'Sendable' protocol}}
55+
56+
57+
protocol P5 {
58+
func bar(_ a: sending NonSendableKlass5, _ b: NonSendableKlass5) async -> sending NonSendableKlass5
59+
}
60+
61+
@MainActor
62+
class P5Class: P5 {
63+
func bar(_ a: sending NonSendableKlass5, _ b: NonSendableKlass5) async -> sending NonSendableKlass5 { a }
64+
// expected-error@-1 {{non-sendable parameter type 'NonSendableKlass5' cannot be sent from caller of protocol requirement 'bar' into main actor-isolated implementation}}
65+
}
66+
67+
class NonSendableKlass6 {}
68+
69+
protocol P6 {
70+
func bar(_ a: sending NonSendableKlass6, _ b: sending NonSendableKlass6) async -> sending NonSendableKlass6
71+
}
72+
73+
@MainActor
74+
class P6Class: P6 {
75+
func bar(_ a: sending NonSendableKlass6, _ b: sending NonSendableKlass6) async -> sending NonSendableKlass6 { a }
76+
}
77+
78+
class NonSendableKlass7 {}
79+
80+
protocol P7 {
81+
subscript(_: sending NonSendableKlass7) -> sending NonSendableKlass7 { get async }
82+
}
83+
84+
@MainActor
85+
struct S: P7 {
86+
subscript(_: sending NonSendableKlass7) -> sending NonSendableKlass7 {
87+
get async { NonSendableKlass7() }
88+
}
89+
}

0 commit comments

Comments
 (0)