Skip to content

[SE-0306] Disable actor inheritance. #37053

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -4351,8 +4351,8 @@ NOTE(objc_ambiguous_async_convention_candidate,none,
ERROR(async_objc_dynamic_self,none,
"asynchronous method returning 'Self' cannot be '@objc'", ())

ERROR(actor_with_nonactor_superclass,none,
"actor cannot inherit from non-actor class %0", (DeclName))
ERROR(actor_inheritance,none,
"actor types do not support inheritance", ())

ERROR(actor_isolated_non_self_reference,none,
"actor-isolated %0 %1 can only be %select{referenced|mutated|used 'inout'}3 "
Expand Down
43 changes: 2 additions & 41 deletions lib/Sema/TypeCheckConcurrency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,32 +270,8 @@ bool IsActorRequest::evaluate(
if (!classDecl)
return false;

bool isExplicitActor = classDecl->isExplicitActor() ||
classDecl->getAttrs().getAttribute<ActorAttr>();

// If there is a superclass, we can infer actor-ness from it.
if (auto superclassDecl = classDecl->getSuperclassDecl()) {
// The superclass is an actor, so we are, too.
if (superclassDecl->isActor())
return true;

// The superclass is 'NSObject', which is known to have no state and no
// superclass.
if (superclassDecl->isNSObject() && isExplicitActor)
return true;

// This class cannot be an actor; complain if the 'actor' modifier was
// provided.
if (isExplicitActor) {
classDecl->diagnose(diag::actor_with_nonactor_superclass,
superclassDecl->getName())
.highlight(classDecl->getStartLoc());
}

return false;
}

return isExplicitActor;
return classDecl->isExplicitActor() ||
classDecl->getAttrs().getAttribute<ActorAttr>();
}

bool IsDefaultActorRequest::evaluate(
Expand All @@ -305,21 +281,6 @@ bool IsDefaultActorRequest::evaluate(
if (!classDecl->isActor())
return false;

// If there is a superclass, and it's an actor, we defer
// the decision to it.
if (auto superclassDecl = classDecl->getSuperclassDecl()) {
// If the superclass is an actor, we inherit its default-actor-ness.
if (superclassDecl->isActor())
return superclassDecl->isDefaultActor();

// If the superclass is not an actor, it can only be
// a default actor if it's NSObject. (For now, other classes simply
// can't be actors at all.) We don't need to diagnose this; we
// should've done that already in isActor().
if (!superclassDecl->isNSObject())
return false;
}

// If the class is resilient from the perspective of the module
// module, it's not a default actor.
if (classDecl->isForeign() || classDecl->isResilient(M, expansion))
Expand Down
8 changes: 8 additions & 0 deletions lib/Sema/TypeCheckDeclPrimary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2314,6 +2314,14 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
// Check for circular inheritance.
(void)CD->getSuperclassDecl();

if (auto superclass = CD->getSuperclassDecl()) {
// Actors cannot have superclasses, nor can they be superclasses.
if (CD->isActor() && !superclass->isNSObject())
CD->diagnose(diag::actor_inheritance);
else if (superclass->isActor())
CD->diagnose(diag::actor_inheritance);
}

// Force lowering of stored properties.
(void) CD->getStoredProperties();

Expand Down
2 changes: 1 addition & 1 deletion test/Concurrency/actor_isolation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class Point {
}

@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
actor MyActor: MySuperActor {
actor MyActor: MySuperActor { // expected-error{{actor types do not support inheritance}}
nonisolated let immutable: Int = 17
// expected-note@+2 2{{property declared here}}
// expected-note@+1 6{{mutation of this property is only permitted within the actor}}
Expand Down
3 changes: 1 addition & 2 deletions test/Concurrency/async_initializer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ actor A {
}
}

// NOTE: actor inheritance is probably being removed soon, so just remove this def of B
actor B: A {
actor B: A { // expected-error{{actor types do not support inheritance}}
init(x : String) async {} // expected-error {{missing call to superclass's initializer; 'super.init' is 'async' and requires an explicit call}}
}

Expand Down
2 changes: 1 addition & 1 deletion test/Concurrency/global_actor_inference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ actor GenericSuper<T> {
@GenericGlobalActor<T> func method5() { }
}

actor GenericSub<T> : GenericSuper<[T]> {
actor GenericSub<T> : GenericSuper<[T]> { // expected-error{{actor types do not support inheritance}}
override func method() { } // expected-note {{calls to instance method 'method()' from outside of its actor context are implicitly asynchronous}}

@GenericGlobalActor<T> override func method2() { } // expected-error{{global actor 'GenericGlobalActor<T>'-isolated instance method 'method2()' has different actor isolation from global actor 'GenericGlobalActor<[T]>'-isolated overridden declaration}}
Expand Down
4 changes: 0 additions & 4 deletions test/IRGen/actor_class_forbid_objc_assoc_objects.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ final actor Actor {
actor Actor2 {
}

// CHECK: @_METACLASS_DATA__TtC37actor_class_forbid_objc_assoc_objects6Actor3 = internal constant { {{.*}} } { i32 [[METAFLAGS]],
// CHECK: @_DATA__TtC37actor_class_forbid_objc_assoc_objects6Actor3 = internal constant { {{.*}} } { i32 [[OBJECTFLAGS]],
class Actor3 : Actor2 {}

actor GenericActor<T> {
var state: T
init(state: T) { self.state = state }
Expand Down
5 changes: 0 additions & 5 deletions test/IRGen/async/Inputs/resilient_actor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@ open actor ResilientBaseActor {
public init() {}
}

@_fixed_layout
open actor FixedSubclassOfResilientBaseActor : ResilientBaseActor {
public override init() {}
}

@_fixed_layout
open actor FixedBaseActor {
public init() {}
Expand Down
30 changes: 0 additions & 30 deletions test/IRGen/async/default_actor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,40 +8,10 @@
// 0x81010050: the same, but using a singleton metadata initialization
// CHECK-SAME: i32 {{-2130706352|-2130640816}},

// CHECK: @"$s13default_actor1BCMn" = hidden constant
// 0x62010050: 0x02000000 IndirectTypeDescriptor + 0x01000000 IsDefaultActor
// CHECK-SAME: i32 1644232784,

// CHECK: @"$s13default_actor1CCMn" = hidden constant
// 0x62010050: 0x02000000 IndirectTypeDescriptor + 0x01000000 IsDefaultActor
// CHECK-SAME: i32 1644232784,

// CHECK: @"$s13default_actor1DCMn" = hidden constant
// 0x63010050: 0x02000000 IndirectTypeDescriptor + 0x01000000 IsDefaultActor
// CHECK-SAME: i32 1661010000,

import resilient_actor

// CHECK-LABEL: define hidden swiftcc void @"$s13default_actor1ACfD"(%T13default_actor1AC* swiftself %0)
// CHECK-NOT: ret void
// CHECK: call swiftcc void @swift_defaultActor_deallocate(
// CHECK: ret void
actor A {}

// CHECK-LABEL: define hidden swiftcc void @"$s13default_actor1BCfD"(%T13default_actor1BC* swiftself %0)
// CHECK-NOT: ret void
// CHECK: call swiftcc void @swift_defaultActor_deallocateResilient(
// CHECK: ret void
actor B : ResilientBaseActor {}

// CHECK-LABEL: define hidden swiftcc void @"$s13default_actor1CCfD"(%T13default_actor1CC* swiftself %0)
// CHECK-NOT: ret void
// CHECK: call swiftcc void @swift_defaultActor_deallocateResilient(
// CHECK: ret void
actor C : FixedSubclassOfResilientBaseActor {}

// CHECK-LABEL: define hidden swiftcc void @"$s13default_actor1DCfD"(%T13default_actor1DC* swiftself %0)
// CHECK-NOT: ret void
// CHECK: call swiftcc void @swift_defaultActor_deallocate(
// CHECK: ret void
actor D : FixedBaseActor {}
86 changes: 0 additions & 86 deletions test/Interpreter/actor_class_forbid_objc_assoc_objects.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,48 +44,6 @@ if #available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *) {
}
}

@available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *)
class Actor3 : Actor2 {}

if #available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *) {
Tests.test("non-final subclass crash when set assoc object")
.crashOutputMatches("objc_setAssociatedObject called on instance")
.code {
expectCrashLater()
let x = Actor3()
objc_setAssociatedObject(x, "myKey", "myValue", .OBJC_ASSOCIATION_RETAIN)
}
}

@available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *)
final class Actor3Final : Actor2 {}

if #available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *) {
Tests.test("final subclass crash when set assoc object")
.crashOutputMatches("objc_setAssociatedObject called on instance")
.code {
expectCrashLater()
let x = Actor3Final()
objc_setAssociatedObject(x, "myKey", "myValue", .OBJC_ASSOCIATION_RETAIN)
}
}

@available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *)
class Actor4<T> : Actor2 {
var state: T
init(state: T) { self.state = state }
}

if #available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *) {
Tests.test("generic subclass crash when set assoc object")
.crashOutputMatches("objc_setAssociatedObject called on instance")
.code {
expectCrashLater()
let x = Actor4(state: 5)
objc_setAssociatedObject(x, "myKey", "myValue", .OBJC_ASSOCIATION_RETAIN)
}
}

@available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *)
actor Actor5<T> {
var state: T
Expand All @@ -110,50 +68,6 @@ if #available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *) {
}
}

@available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *)
class Actor6<T> : Actor5<T> {
override init(state: T) { super.init(state: state) }
}

if #available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *) {
Tests.test("sub-generic class base generic class crash when set assoc object")
.crashOutputMatches("objc_setAssociatedObject called on instance")
.code {
expectCrashLater()
let x = Actor6(state: 5)
objc_setAssociatedObject(x, "myKey", "myValue", .OBJC_ASSOCIATION_RETAIN)
}
}

@available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *)
final class Actor6Final<T> : Actor5<T> {
override init(state: T) { super.init(state: state) }
}

if #available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *) {
Tests.test("final sub-generic class base generic class crash when set assoc object")
.crashOutputMatches("objc_setAssociatedObject called on instance")
.code {
expectCrashLater()
let x = Actor6Final(state: 5)
objc_setAssociatedObject(x, "myKey", "myValue", .OBJC_ASSOCIATION_RETAIN)
}

Tests.test("final sub-generic class base generic class crash when set assoc object2")
.code {
let x = Actor6Final(state: 5)
print(type(of: x))
}

Tests.test("final sub-generic class metatype, base generic class crash when set assoc object")
.crashOutputMatches("objc_setAssociatedObject called on instance")
.code {
expectCrashLater()
let x = Actor6Final<Int>.self
objc_setAssociatedObject(x, "myKey", "myValue", .OBJC_ASSOCIATION_RETAIN)
}
}

@available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *)
actor ActorNSObjectSubKlass : NSObject {}

Expand Down
20 changes: 0 additions & 20 deletions test/Interpreter/actor_subclass_metatypes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,3 @@ Tests.test("base generic class")
let x = Actor5(state: 5)
print(type(of: x))
}

class Actor6<T> : Actor5<T> {
override init(state: T) { super.init(state: state) }
}

Tests.test("non-final sub-generic class parent generic class crash")
.code {
let x = Actor6(state: 5)
print(type(of: x))
}

final class Actor6Final<T> : Actor5<T> {
override init(state: T) { super.init(state: state) }
}

Tests.test("final sub-generic class parent generic class crash")
.code {
let x = Actor6Final(state: 5)
print(type(of: x))
}
6 changes: 0 additions & 6 deletions test/ModuleInterface/actor_isolation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,3 @@ public class C2 { }

// CHECK: @{{(Test.)?}}SomeGlobalActor public class C2
public class C3: C2 { }

// CHECK: public actor SomeSubActor
// CHECK-NEXT: @actorIndependent public func maine()
public actor SomeSubActor: SomeActor {
override public func maine() { }
}
7 changes: 4 additions & 3 deletions test/decl/class/actor/basic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@

actor MyActor { }

class MyActorSubclass1: MyActor { }
class MyActorSubclass1: MyActor { } // expected-error{{actor types do not support inheritance}}
// expected-error@-1{{non-final class 'MyActorSubclass1' cannot conform to `Sendable`; use `UnsafeSendable`}}

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

// expected-warning@+1{{'actor class' has been renamed to 'actor'}}{{7-13=}}
actor class MyActorClass { }

class NonActor { }

actor NonActorSubclass : NonActor { } // expected-error{{actor cannot inherit from non-actor class 'NonActor'}}
actor NonActorSubclass : NonActor { } // expected-error{{actor types do not support inheritance}}

// expected-warning@+1{{'actor class' has been renamed to 'actor'}}{{14-20=}}
public actor class BobHope {}
Expand Down
5 changes: 3 additions & 2 deletions test/decl/protocol/special/Actor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,17 @@ actor A3<T>: Actor {
}

@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
actor A4: A1 {
actor A4: A1 { // expected-error{{actor types do not support inheritance}}
}

@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
actor A5: A2 {
actor A5: A2 { // expected-error{{actor types do not support inheritance}}
}

@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
actor A6: A1, Actor { // expected-error{{redundant conformance of 'A6' to protocol 'Actor'}}
// expected-note@-1{{'A6' inherits conformance to protocol 'Actor' from superclass here}}
// expected-error@-2{{actor types do not support inheritance}}
}

// Explicitly satisfying the requirement.
Expand Down