lhunath
(Maarten Billemont)
1
Swift seems unable to recognize a protocol type that conforms to another protocol type in a where clause.
Let's assume protocol A and protocol B: A; in this case where B: A fails. The same is true for the is operator.
This does not match user expectations and breaks some generics use cases. Example:
protocol A {}
protocol B: A {}
class C: B {}
func f<P>(_ p: P.Type, _ i: @autoclosure () -> P) {
print("1")
}
func f<P>(_ p: P.Type, _ i: @autoclosure () -> P) where P: A {
print("2")
}
f(B.self, C())
f(C.self, C())
I expect to see:
2
2
but instead, I see:
1
2
Does anyone have insight? Should I file a bug?
1 Like
lhunath
(Maarten Billemont)
2
This problem is further complicated by the fact that Swift does not support generic type parameters that conform to other type parameters (unless the latter is explicitly defined as a class type – it is impossible to define type parameters as protocol types).
Thus, it is impossible to fix the above problem by testing the concrete type:
protocol A {}
protocol B: A {}
class C: B {}
func f<P, I: P>(_ p: P.Type, _ i: @autoclosure () -> I) { // Type 'I' constrained to non-protocol, non-class type 'P'
print("1")
}
func f<P, I: P>(_ p: P.Type, _ i: @autoclosure () -> I) where I: A { // Type 'I' constrained to non-protocol, non-class type 'P'
print("2")
}
f(B.self, C())
f(C.self, C())
IMO Swift should allow this as well, but yield a compiler error on the call site if the user attempts to pass an incompatible concrete type to the parameter.
1 Like
xwu
(Xiaodi Wu)
3
B.self is the protocol metatype value, also now spelt (any B).self.
The existential type any B does not conform to any protocol, not even B. You can see this clearly diagnosed if you create a similar function with a constraint where P: B that doesn’t have another overload of the same name.
This is not a bug: in the general case, an existential type cannot conform to its corresponding protocol. For example, any FixedWidthInteger does not, semantically, fulfill the semantics of a fixed-width integer type.
2 Likes
lhunath
(Maarten Billemont)
4
It would be nice if there was a way to declare P to be a protocol type; I was hoping the Swift compiler could infer it, but it appears that it cannot:
// cannot use 'Protocol' with non-protocol type 'P'
// Type 'I' constrained to non-protocol, non-class type 'P'
func f<P, I: P>(_ p: P.Protocol, _ i: @autoclosure () -> I) {