When declaring multiple generic constraints on a type with where and then using the type with star-projection, I expect the upper bound to be a combination of all the types in the constraint.
However, it turns out, that only the first declared bound is recognized there.
If you switch where T : A, T : B to where T : B, T : A, the compile error also moves to the a-usage
See my example…
class GenericConstraintsTest {
interface A {
val a: String
}
open class B(val b: String)
class C(override val a: String, b: String) : B(b), A
open class D<T>(val d: T)
where T : A, T : B
fun foo(x: D<*>) {
x.d.a
x.d.b // compile error
// the below works!
val y = D(C("a", "b"))
y.d.a
y.d.b
}
}
I think the problem has something to do with this:
[…] Only one upper bound can be specified inside the angle brackets. If the same type parameter needs more than one upper bound, we need a separate where-clause
Seeing that explanation I can deduct that the JVM can only store one upper bound, so when you specify more than one using a where clause, only the first one is stored. This can be tested by changing the order of the upper bounds in the where clause:
First T:A then T:B
class GenericConstraintsTest {
interface A {
val a: String
}
open class B(val b: String)
class C(override val a: String, b: String) : B(b), A
//sampleStart
open class D<T>(val d: T)
where T : A, T : B // Only 'T:A' is taken into account
fun foo(x: D<*>) {
x.d.a
x.d.b // compile error
//sampleEnd
// the below works!
val y = D(C("a", "b"))
y.d.a
y.d.b
}
}
First T:B then T:A
class GenericConstraintsTest {
interface A {
val a: String
}
open class B(val b: String)
class C(override val a: String, b: String) : B(b), A
//sampleStart
open class D<T>(val d: T)
where T : B, T : A // Only 'T:B' is taken into account
fun foo(x: D<*>) {
x.d.a // compile error
x.d.b
//sampleEnd
// the below works!
val y = D(C("a", "b"))
y.d.a
y.d.b
}
}
Note: Click the play button to see the compilation error in the kotlin playground.
Disclaimer: I have no technical knowledge about the JVM or how it works, this is all based on some test I have done. Maybe I am completely wrong, or maybe not.