mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Sema] Expand ~Sendable annotation checking and diagnostics
Diagnose incorrect conformance + suppression uses, make sure that adding `Sendable` is not suggested is type is using `~Sendable`.
This commit is contained in:
@@ -8950,6 +8950,13 @@ ERROR(tilde_sendable_requires_feature_flag,none,
|
|||||||
"'~Sendable' requires -enable-experimental-feature TildeSendable",
|
"'~Sendable' requires -enable-experimental-feature TildeSendable",
|
||||||
())
|
())
|
||||||
|
|
||||||
|
NOTE(sendable_conformance_is_suppressed, none,
|
||||||
|
"%kind0 explicitly suppresses conformance to 'Sendable' protocol",
|
||||||
|
(const NominalTypeDecl *))
|
||||||
|
|
||||||
|
ERROR(non_sendable_type_suppressed,none,
|
||||||
|
"cannot both conform to and suppress conformance to 'Sendable'", ())
|
||||||
|
|
||||||
ERROR(conformance_repression_only_on_struct_class_enum,none,
|
ERROR(conformance_repression_only_on_struct_class_enum,none,
|
||||||
"conformance to %0 can only be suppressed on structs, classes, and enums",
|
"conformance to %0 can only be suppressed on structs, classes, and enums",
|
||||||
(const ProtocolDecl *))
|
(const ProtocolDecl *))
|
||||||
|
|||||||
@@ -1016,12 +1016,15 @@ static bool diagnoseSingleNonSendableType(
|
|||||||
|
|
||||||
if (type->is<FunctionType>()) {
|
if (type->is<FunctionType>()) {
|
||||||
ctx.Diags.diagnose(loc, diag::nonsendable_function_type);
|
ctx.Diags.diagnose(loc, diag::nonsendable_function_type);
|
||||||
|
} else if (nominal &&
|
||||||
|
nominal->suppressesConformance(KnownProtocolKind::Sendable)) {
|
||||||
|
nominal->diagnose(diag::sendable_conformance_is_suppressed, nominal);
|
||||||
} else if (nominal && nominal->getParentModule() == module) {
|
} else if (nominal && nominal->getParentModule() == module) {
|
||||||
// If the nominal type is in the current module, suggest adding
|
// If the nominal type is in the current module, suggest adding
|
||||||
// `Sendable` if it might make sense. Otherwise, just complain.
|
// `Sendable` if it might make sense. Otherwise, just complain.
|
||||||
if (isa<StructDecl>(nominal) || isa<EnumDecl>(nominal)) {
|
if (isa<StructDecl>(nominal) || isa<EnumDecl>(nominal)) {
|
||||||
auto note = nominal->diagnose(
|
auto note =
|
||||||
diag::add_nominal_sendable_conformance, nominal);
|
nominal->diagnose(diag::add_nominal_sendable_conformance, nominal);
|
||||||
addSendableFixIt(nominal, note, /*unchecked=*/false);
|
addSendableFixIt(nominal, note, /*unchecked=*/false);
|
||||||
} else {
|
} else {
|
||||||
nominal->diagnose(diag::non_sendable_nominal, nominal);
|
nominal->diagnose(diag::non_sendable_nominal, nominal);
|
||||||
@@ -1302,6 +1305,9 @@ inferSendableFromInstanceStorage(NominalTypeDecl *nominal,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nominal->suppressesConformance(KnownProtocolKind::Sendable))
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
class Visitor : public StorageVisitor {
|
class Visitor : public StorageVisitor {
|
||||||
public:
|
public:
|
||||||
NominalTypeDecl *nominal;
|
NominalTypeDecl *nominal;
|
||||||
@@ -1395,6 +1401,10 @@ void swift::diagnoseMissingExplicitSendable(NominalTypeDecl *nominal) {
|
|||||||
/*treatUsableFromInlineAsPublic=*/true).isPublic())
|
/*treatUsableFromInlineAsPublic=*/true).isPublic())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// If `Sendable` conformance is explicitly suppressed, do nothing.
|
||||||
|
if (nominal->suppressesConformance(KnownProtocolKind::Sendable))
|
||||||
|
return;
|
||||||
|
|
||||||
// If the conformance is explicitly stated, do nothing.
|
// If the conformance is explicitly stated, do nothing.
|
||||||
if (hasExplicitSendableConformance(nominal, /*applyModuleDefault=*/false))
|
if (hasExplicitSendableConformance(nominal, /*applyModuleDefault=*/false))
|
||||||
return;
|
return;
|
||||||
@@ -7173,6 +7183,14 @@ static bool checkSendableInstanceStorage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nominal->suppressesConformance(KnownProtocolKind::Sendable)) {
|
||||||
|
auto *conformanceDecl = dc->getAsDecl() ? dc->getAsDecl() : nominal;
|
||||||
|
if (!isImplicitSendableCheck(check)) {
|
||||||
|
conformanceDecl->diagnose(diag::non_sendable_type_suppressed);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Stored properties of structs and classes must have
|
// Stored properties of structs and classes must have
|
||||||
// Sendable-conforming types.
|
// Sendable-conforming types.
|
||||||
class Visitor: public StorageVisitor {
|
class Visitor: public StorageVisitor {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// RUN: %target-typecheck-verify-swift -enable-experimental-feature TildeSendable
|
// RUN: %target-typecheck-verify-swift -strict-concurrency=complete -swift-version 5 -enable-experimental-feature TildeSendable
|
||||||
|
|
||||||
// REQUIRES: swift_feature_TildeSendable
|
// REQUIRES: swift_feature_TildeSendable
|
||||||
|
|
||||||
@@ -15,6 +15,7 @@ class B: ~Sendable {}
|
|||||||
enum C: ~Sendable {}
|
enum C: ~Sendable {}
|
||||||
|
|
||||||
struct E1: Sendable, ~Sendable {}
|
struct E1: Sendable, ~Sendable {}
|
||||||
|
// expected-error@-1 {{cannot both conform to and suppress conformance to 'Sendable'}}
|
||||||
|
|
||||||
enum E2: ~Sendable, ~Sendable {} // expected-warning {{already suppressed conformance to 'Sendable'}}
|
enum E2: ~Sendable, ~Sendable {} // expected-warning {{already suppressed conformance to 'Sendable'}}
|
||||||
|
|
||||||
@@ -32,3 +33,22 @@ struct Generic<T: ~Sendable> { // expected-error {{conformance to 'Sendable' can
|
|||||||
|
|
||||||
var x: some BinaryInteger & ~Sendable // expected-error {{type 'Sendable' cannot be suppressed}}
|
var x: some BinaryInteger & ~Sendable // expected-error {{type 'Sendable' cannot be suppressed}}
|
||||||
|
|
||||||
|
protocol W: Sendable {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that inference is suppressed by the annotation.
|
||||||
|
do {
|
||||||
|
struct NonSendable: ~Sendable {
|
||||||
|
// expected-note@-1 {{struct 'NonSendable' explicitly suppresses conformance to 'Sendable' protocol}}
|
||||||
|
let x: Int = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NoInference: W, ~Sendable {
|
||||||
|
// expected-error@-1 {{cannot both conform to and suppress conformance to 'Sendable'}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func check<T: Sendable>(_: T) {}
|
||||||
|
|
||||||
|
check(NonSendable()) // expected-warning {{type 'NonSendable' does not conform to the 'Sendable' protocol}}
|
||||||
|
check(NoInference()) // Ok
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user