Hi all,
Consider the following protocols:
protocol P {
associatedtype A : Q where A.B == Self
}
protocol Q {
associatedtype B
static func getB() -> B
}
Now suppose we have a pair of classes conforming to P and Q:
class C : P {
typealias A = D
}
class D : Q {
typealias B = C
static func getB() -> C { return C() }
}
Today, Swift allows this conformance, but let's look carefully to see what it actually means. Since P requires that 'Self == Self.A.B', then we should be able to define the following protocol extension method on P:
extension P {
static func getAB() -> Self {
return Self.A.getB()
}
}
Self.A.getB()
has type Self.A.B
, which we know is equal to Self
, so this code is correct.
However, now imagine we define a subclass of C:
class SubC : C {}
Calling SubC.getAB()
should return an instance of SubC
, since the type of getAB()
is (Self.Type) -> () -> Self
and we substitute Self := SubC
(protocol conformances in Swift are covariant!).
However, the implementation of getB()
on class D returns an instance of C, not an instance of SubC.
The problem is the same-type requirement in protocol P
-- it requires that the conforming Self
type is exactly C, not C or some subclass of C.
I don't think there's any way to make this construction sound, but also I'm sure it comes up in real code, so I'm introducing a compiler warning:
warning: non-final class 'C' cannot safely conform to protocol 'P', which requires that 'Self' is exactly equal to 'Self.A.B'; this is an error in Swift 6
As the diagnostic suggests, declaring the class as final closes the soundness hole. Also, I have made this an error in a (hypothetical) future -swift-version 6
, using the standard trick we've been using for newly-introduced type safety diagnostics that ban previously-allowed but invalid code patterns.
I'm of the opinion that this is a bug fix and not a real language change, so I don't think it warrants a pitch and a proposal; a forum post and changelog entry seems sufficient, but maybe I'm wrong.
If you have a legitimate reason to use a non-final class in this manner, we can discuss introducing some other way to muffle the warning while leaving the class non-final.
Let me know if you have questions or concerns.