-
Couldn't load subscription status.
- Fork 10.6k
[Experiment] [Objective-C interoperability] Eliminate import of NSObjectProtocol. #14654
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
Conversation
Stop importing the Objective-C protocol `NSObject` into Swift programs, because it causes more harm than good. Specifically, with this change: * The `NSObjectProtocol` protocol itself is not visible to Swift programs. * `NSObjectProtocol` is dropped from the inheritance list of any imported Objective-C protocol, e.g., `UITableViewDelegate` will not mention `NSObjectProtocol` in its inherited protocols. * `NSObjectProtocol` is removed from the list of protocols to which an imported Objective-C class conforms (e.g., the imported class `NSObject` will no longer state its conformance to `NSObjectProtocol`). * Qualified types in Objective-C will drop the `NSObject` protocol on import, e.g., an Objective-C type `id<NSCopying, NSObject>` will be imported as `NSCopying` rather than `NSCopying & NSObjectProtocol`. The type `id<NSObject>` will simply be imported as `AnyObject`. * Introduce a deprecated type alias into the ObjectiveC module overlay to ease transition: ```swift public typealias NSObjectProtocol = AnyObject ```
|
@swift-ci please test |
|
@swift-ci please test source compatibility |
We were emitting an error on the "inherit from NSObjectProtocol" example when the Swift version was > 3; allow the specific use of the NSObjectProtocol deprecated typealias here. Thanks to Charlie Monroe for noticing the issue here!
|
@swift-ci please test |
1 similar comment
|
@swift-ci please test |
|
Build failed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code mostly looks good. I'll go comment on the forums about the semantic changes.
|
|
||
| // For NSObject, add the otherwise-hidden NSObject protocol. This is only | ||
| // used to import mirrored members. | ||
| // FIXME: Check for any class that conforms to the NSObject protocol? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe NSProxy is the only other one in the Apple SDKs. We are absolutely terrible with it but if you wanted to avoid touching it maybe you could make the condition about root classes instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The principled thing would be to check whether it's a root class that adopts the protocol in Objective-C.
| importedType = ProtocolCompositionType::get(Impl.SwiftContext, | ||
| members, | ||
| /*HasExplicitAnyObject=*/false); | ||
| /*HasExplicitAnyObject=*/hasNSObjectProtocol); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem so important when members is known to contain at least one @objc protocol. Or does this handle the 0 case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's only really relevant for the 0 case; I can gate it on that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, this is the part that forces us to import such things as AnyObject rather than Any; @jckarter was arguing that we should import as Any.
| @objc var description : String { return "" } | ||
| @objc(conformsToProtocol:) func conforms(to _: Protocol) -> Bool { return false } | ||
| @objc(isKindOfClass:) func isKind(of aClass: AnyClass) -> Bool { return false } | ||
| class NSObjectable : NSObject { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it'd be more interesting if this didn't subclass anything, but it probably doesn't really matter at this point.
| // CHECK: NSObject: | ||
| // CHECK-NEXT: TU: NSObject | ||
| // CHECK-NEXT: NSObjectProtocol: | ||
| // CHECK: __NSObjectProtocol: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is the extra "Protocol" coming from? Does that kick in before the SwiftPrivate part?
| // CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER; | ||
| // CHECK-NEXT: @end | ||
| @objc class ClassWithNSObjectProtocol : NSObjectProtocol { | ||
| @objc class ClassWithNSObjectProtocol { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is no longer testing the same thing; please have it conform to something else. (Preferably something where the Objective-C name doesn't match the Swift name.)
| // CHECK-LABEL: @protocol MyProtocol | ||
| // CHECK-NEXT: @end | ||
| @objc protocol MyProtocol : NSObjectProtocol {} | ||
| @objc protocol MyProtocol {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly here, since we're testing printing.
| @IBOutlet var outletCollection: [Properties]! | ||
| @IBOutlet var outletCollectionOptional: [ClassWithCustomName]? = [] | ||
| @IBOutlet var outletCollectionAnyObject: [AnyObject]? | ||
| @IBOutlet var outletCollectionProto: [NSObjectProtocol]? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And here.
Stop importing the Objective-C protocol
NSObjectinto Swiftprograms, because it causes more harm than good. Specifically, with
this change:
NSObjectProtocolprotocol itself is not visible to Swiftprograms.
NSObjectProtocolis dropped from the inheritance list of anyimported Objective-C protocol, e.g.,
UITableViewDelegatewill notmention
NSObjectProtocolin its inherited protocols.NSObjectProtocolis removed from the list of protocols to which animported Objective-C class conforms (e.g., the imported class
NSObjectwill no longer state its conformance toNSObjectProtocol).NSObjectprotocol onimport, e.g., an Objective-C type
id<NSCopying, NSObject>will beimported as
NSCopyingrather thanNSCopying & NSObjectProtocol. The typeid<NSObject>will simply be importedas
AnyObject.to ease transition: