Hello Adrian. I looked through your issue. It really is an analogous constraint, but for an associated type. I didn't generalize my proposal for associated types because they are quite different to regular generics (they are strictly concrete and therefore, as a person here SR-6109 mentioned, non-existential) and should be considered separately or in the boundaries of a larger generics enhancement topic.
I revised 0126-refactor-metatypes and found it a bit confusing in some places, but that is a slightly different subject.
Classes and structs, though, allow existentials as generic parameters, but only if there are no constraints.
Swift has a very intuitive, neat and standard generics syntax and I am confident that resolving namely this issue doesn't require metatype refactoring.
Personally, I would be more happy to write
class Some<T: P> {...}
// or
class Some<protocol T: P> {...}
rather than the pseudocode example you provided:
class Some<T> where AnyType<T> : AnyType<P> {...}
Doesn't it look simpler and more neat? :)
Although I will not deny that your proposal might be a key for some larger generics enhancement.
Furthermore, as far as I understand, 0126-refactor-metatypes doesn't account for unwanted concrete type interaction when allowing existentials as constrained generic parameters (constrained with existentials, obviously).
We don't want something like this to happen, regardless of the syntax:
class A<T: Equatable, P: Comparable> {
func foo1(_ arg: P) { foo2(arg) }
func foo2(_ arg: T) {}
}
let a = A<String, Int>()
Notice what happens if foo1 is called on a. As such, the compiler rightly spits an error. Something very similar to:
Cannot invoke foo2 with an argument list of ( P )
I propose to eliminate such possibilities by adding a protocol specifier directly to a generic parameter to indicate the existentiality of this parameter:
class A<protocol T: Equatable, protocol P: Comparable> {...}
Thus, we are restrained to using only protocols for T and P and the behavior in class A can be allowed.