Skip to content

Commit 9db56da

Browse files
committed
Use an unavailable extension to suppress "missing explicit Sendable" warning
Becca noticed that one can already write an unavailable `Sendable` conformance in language: @available(*, unavailable) extension MyType: Sendable { ... } Add tests to verify that this suppresses the "missing Sendable annotation" warning (it does) and suggest this spelling in a Fix-It to help users find it.
1 parent bc4ae04 commit 9db56da

File tree

2 files changed

+66
-7
lines changed

2 files changed

+66
-7
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -756,8 +756,6 @@ void swift::diagnoseMissingExplicitSendable(NominalTypeDecl *nominal) {
756756
/*treatUsableFromInlineAsPublic=*/true).isPublic())
757757
return;
758758

759-
// FIXME: Check for explicit "do not conform to Sendable" marker.
760-
761759
// Look for any conformance to `Sendable`.
762760
auto proto = ctx.getProtocol(KnownProtocolKind::Sendable);
763761
if (!proto)
@@ -797,11 +795,16 @@ void swift::diagnoseMissingExplicitSendable(NominalTypeDecl *nominal) {
797795
}
798796

799797
// Note to disable the warning.
800-
nominal->diagnose(
801-
diag::explicit_disable_sendable, nominal->getDescriptiveKind(),
802-
nominal->getName())
803-
.fixItInsert(nominal->getAttributeInsertionLoc(/*forModifier=*/false),
804-
"@_nonSendable ");
798+
{
799+
auto note = nominal->diagnose(
800+
diag::explicit_disable_sendable, nominal->getDescriptiveKind(),
801+
nominal->getName());
802+
auto insertionLoc = nominal->getBraces().End;
803+
note.fixItInsertAfter(
804+
insertionLoc,
805+
("\n\n@available(*, unavailable)\nextension " + nominal->getName().str()
806+
+ ": Sendable { }\n").str());
807+
}
805808
}
806809

807810
/// Determine whether this is the main actor type.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// RUN: %target-typecheck-verify-swift -require-explicit-sendable
2+
3+
public protocol P { }
4+
5+
public struct S1 { // expected-warning{{public struct 'S1' does not specify whether it is 'Sendable' or not}}
6+
// expected-note@-1{{consider making struct 'S1' conform to the 'Sendable' protocol}}{{18-18=: Sendable}}
7+
// expected-note@-2{{make struct 'S1' explicitly non-Sendable to suppress this warning}}{{2-2=\n\n@available(*, unavailable)\nextension S1: Sendable { \}\n}}
8+
var str: String
9+
}
10+
11+
class C { }
12+
13+
public struct S2 { // expected-warning{{public struct 'S2' does not specify whether it is 'Sendable' or not}}
14+
// expected-note@-1{{add '@unchecked Sendable' conformance to struct 'S2' if this type manually implements concurrency safety}}{{18-18=: @unchecked Sendable}}
15+
// expected-note@-2{{make struct 'S2' explicitly non-Sendable to suppress this warning}}{{2-2=\n\n@available(*, unavailable)\nextension S2: Sendable { \}\n}}
16+
var c: C
17+
}
18+
19+
final public class C1: P { // expected-warning{{public class 'C1' does not specify whether it is 'Sendable' or not}}
20+
// expected-note@-1{{consider making class 'C1' conform to the 'Sendable' protocol}}{{25-25=, Sendable}}
21+
// expected-note@-2{{make class 'C1' explicitly non-Sendable to suppress this warning}}{{2-2=\n\n@available(*, unavailable)\nextension C1: Sendable { \}\n}}
22+
let str: String = ""
23+
}
24+
25+
public class C2 { // expected-warning{{public class 'C2' does not specify whether it is 'Sendable' or not}}
26+
// expected-note@-1{{add '@unchecked Sendable' conformance to class 'C2' if this type manually implements concurrency safety}}{{17-17=: @unchecked Sendable}}
27+
// expected-note@-2{{make class 'C2' explicitly non-Sendable to suppress this warning}}{{2-2=\n\n@available(*, unavailable)\nextension C2: Sendable { \}\n}}
28+
var str: String = ""
29+
}
30+
31+
public struct S3<T> { // expected-warning{{public generic struct 'S3' does not specify whether it is 'Sendable' or not}}
32+
// expected-note@-1{{add '@unchecked Sendable' conformance to generic struct 'S3' if this type manually implements concurrency safety}}{{21-21=: @unchecked Sendable}}
33+
// expected-note@-2{{make generic struct 'S3' explicitly non-Sendable to suppress this warning}}{{2-2=\n\n@available(*, unavailable)\nextension S3: Sendable { \}\n}}
34+
var t: T
35+
}
36+
37+
public struct S4<T> { // expected-warning{{public generic struct 'S4' does not specify whether it is 'Sendable' or not}}
38+
// expected-note@-1{{add '@unchecked Sendable' conformance to generic struct 'S4' if this type manually implements concurrency safety}}{{21-21=: @unchecked Sendable}}
39+
// expected-note@-2{{make generic struct 'S4' explicitly non-Sendable to suppress this warning}}{{2-2=\n\n@available(*, unavailable)\nextension S4: Sendable { \}\n}}
40+
var t: T
41+
var c: C
42+
}
43+
44+
public struct S5 { } // no diagnostic: S5 is not Sendable
45+
46+
@available(*, unavailable)
47+
extension S5: Sendable { }
48+
49+
// Public type with a conditional conformance, so don't complain
50+
public struct S6<T, U> {
51+
var t: T
52+
var u: U
53+
}
54+
55+
extension S6: Sendable where T: Sendable, U: Sendable { }
56+

0 commit comments

Comments
 (0)