Skip to content

Commit e039ab3

Browse files
committed
[SE-0306] Disallow actor inheritance from NSObject, but allow @objc actor.
Allow an actor to be exposed to Objective-C via `@objc` without inheriting from `NSObject`, and remove the loophole that allowed actors to inherit from `NSObject`. Fixes rdar://78333614 (cherry picked from commit 6406f08)
1 parent 4cd2bb6 commit e039ab3

File tree

8 files changed

+32
-36
lines changed

8 files changed

+32
-36
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4365,6 +4365,8 @@ ERROR(async_objc_dynamic_self,none,
43654365

43664366
ERROR(actor_inheritance,none,
43674367
"actor types do not support inheritance", ())
4368+
NOTE(actor_inheritance_nsobject,none,
4369+
"use '@objc' to expose actor %0 to Objective-C", (DeclName))
43684370

43694371
ERROR(actor_protocol_illegal_inheritance,none,
43704372
"non-actor type %0 cannot conform to the 'Actor' protocol",

lib/AST/Decl.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8205,15 +8205,14 @@ bool ClassDecl::isRootDefaultActor(ModuleDecl *M,
82058205
}
82068206

82078207
bool ClassDecl::isNativeNSObjectSubclass() const {
8208-
// Only if we inherit from NSObject.
8209-
auto superclass = getSuperclassDecl();
8210-
if (!superclass || !superclass->isNSObject())
8211-
return false;
8208+
// @objc actors implicitly inherit from NSObject.
8209+
if (isActor() && getAttrs().hasAttribute<ObjCAttr>())
8210+
return true;
82128211

8213-
// For now, only actors (regardless of whether they're default actors).
8214-
// Eventually we should roll this out to more classes, but we have to
8215-
// do it with ABI compatibility.
8216-
return isActor();
8212+
// For now, non-actor classes cannot use the native NSObject subclass.
8213+
// Eventually we should roll this out to more classes that directly
8214+
// inherit NSObject, but we have to do it with ABI compatibility.
8215+
return false;
82178216
}
82188217

82198218
bool ClassDecl::isNSObject() const {

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,10 +1204,11 @@ static Optional<ObjCReason> shouldMarkClassAsObjC(const ClassDecl *CD) {
12041204
.limitBehavior(behavior);
12051205
}
12061206

1207-
// Only allow ObjC-rooted classes to be @objc.
1207+
// Only allow actors and ObjC-rooted classes to be @objc.
12081208
// (Leave a hole for test cases.)
12091209
if (ancestry.contains(AncestryFlags::ObjC) &&
1210-
!ancestry.contains(AncestryFlags::ClangImported)) {
1210+
!ancestry.contains(AncestryFlags::ClangImported) &&
1211+
!CD->isActor()) {
12111212
if (ctx.LangOpts.EnableObjCAttrRequiresFoundation) {
12121213
ctx.Diags.diagnose(attrLoc,
12131214
diag::invalid_objc_swift_rooted_class)

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2293,10 +2293,16 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
22932293

22942294
if (auto superclass = CD->getSuperclassDecl()) {
22952295
// Actors cannot have superclasses, nor can they be superclasses.
2296-
if (CD->isActor() && !superclass->isNSObject())
2296+
if (CD->isActor()) {
22972297
CD->diagnose(diag::actor_inheritance);
2298-
else if (superclass->isActor())
2298+
if (superclass->isNSObject()) {
2299+
CD->diagnose(diag::actor_inheritance_nsobject, CD->getName())
2300+
.fixItInsert(CD->getAttributeInsertionLoc(/*forModifier=*/false),
2301+
"@objc ");
2302+
}
2303+
} else if (superclass->isActor()) {
22992304
CD->diagnose(diag::actor_inheritance);
2305+
}
23002306
}
23012307

23022308
// Force lowering of stored properties.

test/IRGen/actor_class_objc.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import Foundation
99

1010
// CHECK-LABEL: @"OBJC_METACLASS_$__TtC16actor_class_objc7MyClass" = global
1111
// Metaclass is an instance of the root class.
12-
// CHECK-SAME: %objc_class* {{.*}}@"OBJC_METACLASS_$_NSObject{{(.ptrauth)?}}"
13-
// Metaclass superclass is the metaclass of the superclass.
1412
// CHECK-SAME: %objc_class* {{.*}}@"OBJC_METACLASS_$_SwiftNativeNSObject{{(.ptrauth)?}}"
1513

1614
// CHECK: @"$s16actor_class_objc7MyClassCMf" = internal global
@@ -29,9 +27,9 @@ import Foundation
2927
// CHECK-64-SAME: i64 112,
3028
// CHECK-32-SAME: i32 56,
3129

32-
public actor MyClass: NSObject {
30+
@objc public actor MyClass {
3331
public var x: Int
34-
public override init() { self.x = 0 }
32+
public init() { self.x = 0 }
3533
}
3634

3735
// CHECK-LABEL: define {{.*}} @"$s16actor_class_objc7MyClassC1xSivg"

test/Interpreter/actor_class_forbid_objc_assoc_objects.swift

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
// UNSUPPORTED: back_deployment_runtime
1111

1212
import ObjectiveC
13+
import Foundation
1314
import _Concurrency
1415
import StdlibUnittest
1516

@@ -70,7 +71,7 @@ if #available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *) {
7071
}
7172

7273
@available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *)
73-
actor ActorNSObjectSubKlass : NSObject {}
74+
@objc actor ActorNSObjectSubKlass {}
7475

7576
if #available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *) {
7677
Tests.test("no crash when inherit from nsobject")
@@ -79,17 +80,3 @@ if #available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *) {
7980
objc_setAssociatedObject(x, "myKey", "myValue", .OBJC_ASSOCIATION_RETAIN)
8081
}
8182
}
82-
83-
@available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *)
84-
actor ActorNSObjectSubKlassGeneric<T> : NSObject {
85-
var state: T
86-
init(state: T) { self.state = state }
87-
}
88-
89-
if #available(macOS 10.4.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *) {
90-
Tests.test("no crash when generic inherit from nsobject")
91-
.code {
92-
let x = ActorNSObjectSubKlassGeneric(state: 5)
93-
objc_setAssociatedObject(x, "myKey", "myValue", .OBJC_ASSOCIATION_RETAIN)
94-
}
95-
}

test/ModuleInterface/actor_objc.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
import Foundation
1414

15-
// CHECK-LABEL: @objc @_inheritsConvenienceInitializers public actor SomeActor : ObjectiveC.NSObject {
16-
// CHECK: @objc override public init()
17-
public actor SomeActor: NSObject {
15+
// CHECK-LABEL: @objc public actor SomeActor {
16+
// CHECK-NOT: @objc override public init()
17+
@objc public actor SomeActor {
1818
}

test/attr/attr_objc_async.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ actor class MyActor2 { }
5151
// expected-error@-1 {{keyword 'class' cannot be used as an identifier here}}
5252

5353
// CHECK: @objc actor MyObjCActor
54-
@objc actor MyObjCActor: NSObject { }
54+
@objc actor MyObjCActor { }
5555

56-
@objc actor class MyObjCActor2: NSObject {}
56+
@objc actor class MyObjCActor2 {}
5757
// expected-error@-1 {{keyword 'class' cannot be used as an identifier here}}
58+
59+
actor MyObjCActor3: NSObject { } // expected-error{{actor types do not support inheritance}}
60+
// expected-note@-1{{use '@objc' to expose actor 'MyObjCActor3' to Objective-C}}

0 commit comments

Comments
 (0)