Skip to content

Commit 68418cd

Browse files
committed
[SE-0302] Crank up Sendable to also diagnose in-module missing conformances.
Extend the diagnostics for `Sendable` conformances to always diagnose missing `Sendable` conformances for nominal types that are within the same module. The intuition here is that if the type is in the same module, it can be updated and evaluated at the same time as code requiring the `Sendable` conformance is introduced. Another part of rdar://78269348.
1 parent 42c0658 commit 68418cd

14 files changed

+58
-30
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1939,6 +1939,9 @@ NOTE(nonsendable_function_type,none,
19391939
NOTE(nonsendable_tuple_type,none,
19401940
"a tuple type must be composed of 'Sendable' elements to conform to "
19411941
"'Sendable'", ())
1942+
NOTE(non_sendable_nominal,none,
1943+
"%0 %1 does not conform to the `Sendable` protocol",
1944+
(DescriptiveDeclKind, DeclName))
19421945
NOTE(add_nominal_sendable_conformance,none,
19431946
"consider making %0 %1 conform to the 'Sendable' protocol",
19441947
(DescriptiveDeclKind, DeclName))

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -583,30 +583,26 @@ static bool diagnoseSingleNonSendableType(
583583

584584
if (langOpts.isSwiftVersionAtLeast(6)) {
585585
// In Swift 6, error when the nominal type comes from a module that
586-
// had the concurrency checks consistently applied. Otherwise,
587-
// warn only when requested (via -warn-concurrency) and leave a safety
588-
// hole otherwise.
589-
if (nominalModule->isConcurrencyChecked())
586+
// had the concurrency checks consistently applied or from this module.
587+
// Otherwise, warn.
588+
if (nominalModule->isConcurrencyChecked() || nominalModule == module)
590589
behavior = DiagnosticBehavior::Unspecified;
591-
else if (langOpts.WarnConcurrency)
592-
behavior = DiagnosticBehavior::Warning;
593590
else
594-
behavior = DiagnosticBehavior::Ignore;
591+
behavior = DiagnosticBehavior::Warning;
595592
} else {
596593
// In Swift 5, warn if either the imported or importing model is
597-
// checking for concurrency. Otherwise, leave a safety hole.
598-
if (nominalModule->isConcurrencyChecked() || langOpts.WarnConcurrency)
594+
// checking for concurrency, or if the nominal type comes from this
595+
// module. Otherwise, leave a safety hole.
596+
if (nominalModule->isConcurrencyChecked() ||
597+
nominalModule == module ||
598+
langOpts.WarnConcurrency)
599599
behavior = DiagnosticBehavior::Warning;
600600
else
601601
behavior = DiagnosticBehavior::Ignore;
602602
}
603603
} else if (!langOpts.isSwiftVersionAtLeast(6)) {
604-
// In Swift 5, warn if the current module requested warnings. Otherwise,
605-
// leave a safety hole.
606-
if (langOpts.WarnConcurrency)
607-
behavior = DiagnosticBehavior::Warning;
608-
else
609-
behavior = DiagnosticBehavior::Ignore;
604+
// Always warn in Swift 5.
605+
behavior = DiagnosticBehavior::Warning;
610606
}
611607

612608
bool wasError = diagnose(type, behavior);
@@ -626,6 +622,10 @@ static bool diagnoseSingleNonSendableType(
626622
fixItLoc = Lexer::getLocForEndOfToken(ctx.SourceMgr, fixItLoc);
627623
note.fixItInsert(fixItLoc, ", Sendable");
628624
}
625+
} else if (nominal) {
626+
nominal->diagnose(
627+
diag::non_sendable_nominal, nominal->getDescriptiveKind(),
628+
nominal->getName());
629629
}
630630

631631
return wasError;
@@ -2047,7 +2047,8 @@ namespace {
20472047
if (auto varDecl = dyn_cast<VarDecl>(decl)) {
20482048
if (varDecl->isLet()) {
20492049
auto type = component.getComponentType();
2050-
if (diagnoseNonSendableTypes(
2050+
if (shouldDiagnoseExistingDataRaces(getDeclContext()) &&
2051+
diagnoseNonSendableTypes(
20512052
type, getParentModule(), component.getLoc(),
20522053
diag::non_sendable_keypath_access))
20532054
return true;
@@ -2113,6 +2114,7 @@ namespace {
21132114
if (auto indexExpr = component.getIndexExpr()) {
21142115
auto type = indexExpr->getType();
21152116
if (type &&
2117+
shouldDiagnoseExistingDataRaces(getDeclContext()) &&
21162118
diagnoseNonSendableTypes(
21172119
type, getParentModule(), component.getLoc(),
21182120
diag::non_sendable_keypath_capture))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
public class NonStrictClass { }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
public struct StrictStruct: Hashable { }

test/Concurrency/actor_call_implicitly_async.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ func rethrower(_ f : @autoclosure () throws -> Any) rethrows -> Any {
1313
func asAutoclosure(_ f : @autoclosure () -> Any) -> Any { return f() }
1414

1515
// not a concurrency-safe type
16-
class Box {
16+
class Box { // expected-note 4{{class 'Box' does not conform to the `Sendable` protocol}}
1717
var counter : Int = 0
1818
}
1919

test/Concurrency/actor_isolation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ actor MySuperActor {
4646
}
4747
}
4848

49-
class Point {
49+
class Point { // expected-note{{class 'Point' does not conform to the `Sendable` protocol}}
5050
var x : Int = 0
5151
var y : Int = 0
5252
}

test/Concurrency/actor_isolation_unsafe.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ struct S4_P1: P1 {
3434
}
3535

3636
@MainActor(unsafe)
37-
protocol P2 {
37+
protocol P2 { // expected-note{{protocol 'P2' does not conform to the `Sendable` protocol}}
3838
func f() // expected-note{{calls to instance method 'f()' from outside of its actor context are implicitly asynchronous}}
3939
nonisolated func g()
4040
}
@@ -44,6 +44,7 @@ struct S5_P2: P2 {
4444
func g() { }
4545
}
4646

47+
// expected-warning@+1{{cannot pass argument of non-sendable type 'P2' across actors}}
4748
nonisolated func testP2(x: S5_P2, p2: P2) {
4849
p2.f() // expected-error{{call to main actor-isolated instance method 'f()' in a synchronous nonisolated context}}
4950
p2.g() // OKAY

test/Concurrency/actor_keypath_isolation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: %target-typecheck-verify-swift -disable-availability-checking -warn-concurrency
22
// REQUIRES: concurrency
33

4-
class Box {
4+
class Box { // expected-note 3{{class 'Box' does not conform to the `Sendable` protocol}}
55
let size : Int = 0
66
}
77

test/Concurrency/concurrent_value_checking.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: %target-typecheck-verify-swift -disable-availability-checking -warn-concurrency
22
// REQUIRES: concurrency
33

4-
class NotConcurrent { }
4+
class NotConcurrent { } // expected-note 17{{class 'NotConcurrent' does not conform to the `Sendable` protocol}}
55

66
// ----------------------------------------------------------------------
77
// Sendable restriction on actor operations
@@ -77,7 +77,7 @@ struct HasSubscript {
7777
subscript (i: Int) -> NotConcurrent? { nil }
7878
}
7979

80-
class ClassWithGlobalActorInits {
80+
class ClassWithGlobalActorInits { // expected-note 2{{class 'ClassWithGlobalActorInits' does not conform to the `Sendable` protocol}}
8181
@SomeGlobalActor
8282
init(_: NotConcurrent) { }
8383

@@ -144,7 +144,7 @@ func testUnsafeSendableInAsync() async {
144144
// ----------------------------------------------------------------------
145145
// Sendable restriction on key paths.
146146
// ----------------------------------------------------------------------
147-
class NC: Hashable {
147+
class NC: Hashable { // expected-note 3{{class 'NC' does not conform to the `Sendable` protocol}}
148148
func hash(into: inout Hasher) { }
149149
static func==(_: NC, _: NC) -> Bool { true }
150150
}

test/Concurrency/concurrent_value_checking_objc.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ final class B: NSObject, Sendable {
1313
var x: Int = 5 // expected-error{{stored property 'x' of 'Sendable'-conforming class 'B' is mutable}}
1414
}
1515

16-
class C { }
16+
class C { } // expected-note{{class 'C' does not conform to the `Sendable` protocol}}
1717

1818
final class D: NSObject, Sendable {
1919
let c: C = C() // expected-error{{stored property 'c' of 'Sendable'-conforming class 'D' has non-sendable type 'C'}}

0 commit comments

Comments
 (0)