swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.3k stars 10.34k forks source link

[SR-8153] Can no longer inherit from a typealias'd protocol composition containing AnyObject #50685

Open hamishknight opened 6 years ago

hamishknight commented 6 years ago
Previous ID SR-8153
Radar None
Original Reporter @hamishknight
Type Bug
Status Reopened
Resolution
Environment Apple Swift version 3.1-dev (LLVM 9cb6a3ccee, Clang f38438fc01, Swift b5b79f88f6) Target: x86_64-apple-macosx10.9 Apple Swift version 4.1.2 (swiftlang-902.0.54 clang-902.0.39.2) Target: x86_64-apple-darwin17.6.0
Additional Detail from JIRA | | | |------------------|-----------------| |Votes | 0 | |Component/s | Compiler | |Labels | Bug, 4.0Regression, TypeChecker | |Assignee | None | |Priority | Medium | md5: 8a66f8482ae9d01a49d646d0c08030b5

Issue Description:

In Swift 3.1, it was possible to inherit from a protocol composition containing AnyObject through a type alias:

protocol P {}
typealias X = protocol<P, AnyObject>
class C : X {} // okay

However in Swift 4, both the above example in Swift 3 mode and the equivalent Swift 4 spelling no longer compile (presumably due to the fact that AnyObject is no longer an actual protocol):

protocol P {}
typealias X = protocol<P, AnyObject>
class C : X {} // error: Inheritance from non-protocol, non-class type 'X' (aka 'P & AnyObject')
protocol P {}
typealias X = P & AnyObject
class C : X {} // error: Inheritance from non-protocol, non-class type 'X' (aka 'P & AnyObject')

I would argue that this is a useful feature to have – being able to have a list of protocol constraints in a typealias along with the requirement of being a class, and then being able to directly conform a class to this typealias.

Especially given the fact that this is legal:

class A {}
typealias X = A & AnyObject
class C : X {} // okay
belkadan commented 6 years ago

Seems reasonable to me as well. @slavapestov, what do you think?

slavapestov commented 6 years ago

@DougGregor added a Swift 3 compatibility hack but it's still an error in Swift 4 mode. I'd rather it was an error too, otherwise you can write confusing and redundant things like "class Foo : AnyObject {}".

DougGregor commented 6 years ago

The error was intentional, and I think we should keep it. The superclass of a class is the single most important aspect of its definition, and should be called out explicitly, rather than buried behind a protocol composition. This same logic is why the superclass needs to be written first in the comma-separated list.

hamishknight commented 6 years ago

I agree regarding the superclass having to be stated explicitly in the inheritance clause, I filed SR-8151 for that. But I still think it's reasonable to state a conformance to a protocol composition that happens to contain AnyObject (furthermore I think that class C : AnyObject should be a warning rather than an error).

But if we are to continue rejecting these, should we also reject struct S : Any? I'm currently working on implementing a warning for it over at https://github.com/apple/swift/pull/17425, which I guess could be used to stage it in to an error if desired.

DougGregor commented 6 years ago

I agree that it makes sense to state conformance to a protocol composition that contains ``AnyObject``, or even a class bound--so long as the class satisfies the class bound. For example, we currently error on this:

protocol P { }
class C { }
typealias CP = C & P
class D: C { }
class E: D, CP { } // error: multiple inheritance from classes 'D' and 'C'

which seems wrong to me: the superclass is "D" (it's right there in the correct place!), and we should be checking that E inherits from C.

Now, I think it's reasonable to warn if a particular type in the list doesn't contribute anything, so "struct S: Any" and "class C: AnyObject" are reasonable to warn about, because "Any" and "AnyObject" contribute no information... but that's not an error, that's a "you did something meaningless, are you sure that's what you meant?" warning.

slavapestov commented 6 years ago

Re-opening based on Doug's response.