Skip to content

Commit 699e57b

Browse files
authored
[Concurrency] ban inheriting Actor explicitly by class (#38095)
1 parent 8cdd76e commit 699e57b

File tree

6 files changed

+42
-5
lines changed

6 files changed

+42
-5
lines changed

docs/Diagnostics.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Clang also has a kind of diagnostic called a "remark", which represents informat
5151
- "...to silence this warning"
5252
- "...here" (for a purely locational note)
5353

54+
- If possible, it is best to include the name of the type or function that has the error, e.g. "non-actor type 'Nope' cannot ..." is better than "non-actor type cannot ...". It helps developers relate the error message to the specific type the error is about, even if the error would highlight the appropriate line / function in other ways.
5455

5556
### Locations and Highlights ###
5657

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4366,6 +4366,10 @@ ERROR(async_objc_dynamic_self,none,
43664366
ERROR(actor_inheritance,none,
43674367
"actor types do not support inheritance", ())
43684368

4369+
ERROR(actor_protocol_illegal_inheritance,none,
4370+
"non-actor type %0 cannot conform to the 'Actor' protocol",
4371+
(DeclName))
4372+
43694373
// FIXME: This diagnostic was temporarily downgraded from an error because
43704374
// it spuriously triggers when building the Foundation module from its textual
43714375
// swiftinterface. (rdar://78932296)

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5778,6 +5778,15 @@ void TypeChecker::checkConformancesInContext(IterableDeclContext *idc) {
57785778
}
57795779
} else if (proto->isSpecificProtocol(KnownProtocolKind::Sendable)) {
57805780
SendableConformance = conformance;
5781+
} else if (proto->isSpecificProtocol(KnownProtocolKind::Actor)) {
5782+
if (auto classDecl = dyn_cast<ClassDecl>(nominal)) {
5783+
if (!classDecl->isExplicitActor()) {
5784+
dc->getSelfNominalTypeDecl()
5785+
->diagnose(diag::actor_protocol_illegal_inheritance,
5786+
dc->getSelfNominalTypeDecl()->getName())
5787+
.fixItReplace(nominal->getStartLoc(), "actor");
5788+
}
5789+
}
57815790
} else if (proto->isSpecificProtocol(
57825791
KnownProtocolKind::UnsafeSendable)) {
57835792
unsafeSendableConformance = conformance;

test/Concurrency/actor_isolation.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,20 @@ func outsideSomeClassWithInits() { // expected-note 3 {{add '@MainActor' to make
763763
// ----------------------------------------------------------------------
764764
// Actor protocols.
765765
// ----------------------------------------------------------------------
766+
767+
@available(SwiftStdlib 5.5, *)
768+
actor A: Actor { // ok
769+
}
770+
771+
@available(SwiftStdlib 5.5, *)
772+
class C: Actor, UnsafeSendable {
773+
// expected-error@-1{{non-actor type 'C' cannot conform to the 'Actor' protocol}}
774+
// expected-warning@-2{{'UnsafeSendable' is deprecated: Use @unchecked Sendable instead}}
775+
nonisolated var unownedExecutor: UnownedSerialExecutor {
776+
fatalError()
777+
}
778+
}
779+
766780
@available(SwiftStdlib 5.5, *)
767781
protocol P: Actor {
768782
func f()

test/decl/class/actor/basic.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
actor MyActor { }
66

7-
class MyActorSubclass1: MyActor { } // expected-error{{actor types do not support inheritance}}
8-
// expected-error@-1{{non-final class 'MyActorSubclass1' cannot conform to `Sendable`; use `UnsafeSendable`}}
7+
class MyActorSubclass1: MyActor { }
8+
// expected-error@-1{{actor types do not support inheritance}}
9+
// expected-error@-2{{type 'MyActorSubclass1' cannot conform to the 'Actor' protocol}}
10+
// expected-error@-3{{non-final class 'MyActorSubclass1' cannot conform to `Sendable`; use `UnsafeSendable`}}
911

1012
actor MyActorSubclass2: MyActor { } // expected-error{{actor types do not support inheritance}}
1113

test/decl/protocol/special/Actor.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,29 @@ actor A7 {
4242

4343
// A non-actor can conform to the Actor protocol, if it does it properly.
4444
@available(SwiftStdlib 5.5, *)
45-
class C1: Actor { // expected-error{{non-final class 'C1' cannot conform to `Sendable`; use `UnsafeSendable`}}
45+
class C1: Actor {
46+
// expected-error@-1{{non-actor type 'C1' cannot conform to the 'Actor' protocol}}
47+
// expected-error@-2{{non-final class 'C1' cannot conform to `Sendable`; use `UnsafeSendable`}}
4648
nonisolated var unownedExecutor: UnownedSerialExecutor {
4749
fatalError("")
4850
}
4951
}
5052

5153
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
52-
class C2: Actor { // expected-error{{non-final class 'C2' cannot conform to `Sendable`; use `UnsafeSendable`}}
54+
class C2: Actor {
55+
// expected-error@-1{{non-actor type 'C2' cannot conform to the 'Actor' protocol}}
56+
// expected-error@-2{{non-final class 'C2' cannot conform to `Sendable`; use `UnsafeSendable`}}
5357
// FIXME: this should be an isolation violation
5458
var unownedExecutor: UnownedSerialExecutor {
5559
fatalError("")
5660
}
5761
}
5862

5963
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
60-
class C3: Actor { // expected-error{{non-final class 'C3' cannot conform to `Sendable`; use `UnsafeSendable`}} expected-error {{type 'C3' does not conform to protocol 'Actor'}}
64+
class C3: Actor {
65+
// expected-error@-1{{type 'C3' does not conform to protocol 'Actor'}}
66+
// expected-error@-2{{non-actor type 'C3' cannot conform to the 'Actor' protocol}}
67+
// expected-error@-3{{non-final class 'C3' cannot conform to `Sendable`; use `UnsafeSendable`}}
6168
nonisolated func enqueue(_ job: UnownedJob) { }
6269
}
6370

0 commit comments

Comments
 (0)