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
[SR-8022] Unexpected call to parent protocol requirement in protocol extension of conditional conformance #50555
Comments
@swift-ci create |
It looks to me to be an instance of a problem described here: https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md#overloading-across-constrained-extensions The bidirection-ness of swift/stdlib/public/core/Filter.swift Lines 287 to 303 in a4230ab
So if anything, this requires a compiler change. Moving to the Compiler component and /cc @DougGregor and @huonw to maybe explain why this is not going to happen. |
I don't think that makes sense as a purposeful choice on our part. The Reduced: public protocol Collection2 {
// reduced form of: func index(_ i: Index, offsetBy n: Int, limitedBy limit: Index) -> Index?
func index()
}
extension Collection2 {
public func index() {
print("bad")
}
}
public protocol BidirectionalCollection2: Collection2 {
// func index()
}
extension BidirectionalCollection2 {
public func suffix() {
index()
}
public func index() {
print("good")
}
}
struct X: BidirectionalCollection2 {}
struct A<C: Collection2>: Collection2 {}
extension A: BidirectionalCollection2 where C: BidirectionalCollection2 {}
A<X>().suffix() // "bad" One way to work around this is to uncomment the |
I opened #18066 with the latter work-around... whether we want to merge it is up to the stdlib team. I'm personally probably not going to be able to look at the compiler in the near future. |
Here's an example demonstrating what's going on here without using constrained extensions. The behavior is expected. It probably makes sense to emit some kind of warning on the definition of f() in Q since what's happening here is pretty subtle. Having said that, it's not clear how you would silence this warning if you really intend to have a function with the same signature that doesn't have a corresponding requirement in the protocol it is extending (where that requirement exists in one of the protocols this protocol extends). protocol P {
func f()
}
extension P {
func f() { print("P") }
}
protocol Q : P {
// func f() // uncomment to generate a witness table entry for Q.f
}
extension Q {
func f() { print("Q") }
func test() {
f() // dynamic dispatch through witness
}
}
class X : P {}
class Y : X, Q {}
Y().test() // prints P rather than Q since test() calls f() through dynamic dispatch rather than statically resolving it to Q’s f() |
Relate to new bug for suggested warning: https://bugs.swift.org/browse/SR-8357 |
It surprises me that this is intended behaviour; is there a reason we're not going to try to make this code work as most people would expect (I would think)? |
That could also be incorrect, if X had its own implementation of |
@huonw I agree that behavior here is a bit surprising and I am not sure exactly what the reasoning behind this except perhaps that you can only provide default implementations in an extension for the stated requirements of the protocol (as opposed to inherited ones). Perhaps @DougGregor could comment on that? @belkadan I'm not sure I follow what you're saying, but if you add an implementation to X, we'll call that implementation through dynamic dispatch even if Q has |
Sorry, that was my point. It's important that Q's extension call X's implementation of We just had a very similar discussion in PR #17995. |
@xedin and I were talking with @DougGregor about this and he pointed out an aspect of this that I had overlooked. The reason the `f()` in `Q` isn't called here is actually because of the concrete types involved. Since `X` conforms to `P`, the default implementation in `P` is used in `Y`'s witness for `f`. If you remove that conformance from `X`, then when we produce `Y`'s witness table we find `Q`'s `f()` as a default to fulfill the requirement of `f` on `P`, and end up calling `Q`'s `f()` from `Y().test()`. |
Environment
Swift 4.1.5/4.2 (Xcode 10 beta)
Additional Detail from JIRA
md5: cab74402e124021f0f7a1439c4b68684
relates to:
Issue Description:
Enter the following code into a playground:
And you get this runtime error on the final line:
The text was updated successfully, but these errors were encountered: