Given these classes in Scala 2.11.8:
class A[T] {
class P[TT >: T]
def p[TT >: T]: P[TT] = new P[TT]
}
class B[T](val a: A[T]) {
def p[TT >: T]: a.P[TT] = a.p[TT]
}
class X
class Y extends X
The following line produces the compile error type arguments [Object] do not conform to class P's type parameter bounds [TT >: T]
(even though X >: Y
):
val x = new B[Y](new A[Y]).p[X]
Interestingly, this error does not appear in the following code:
new B[Y](new A[Y]).p[X]
val y = new B[Y](new A[Y])
val z = y.p[X]
What is the difference that I am not seeing?
I had a hunch that the compiler could not assign a type to x
, but that now seems strange given that in the following code, q
is happily assigned A[Y]#P[X]
:
val q = new A[Y].p[X]
As far as I can tell, x
should also be assigned A[Y]#P[X]
.
The REPL gave me what I think is a clue, but I'm not sure how:
scala> :t new B[Y](new A[Y]).p[Any]
_6.a.P[Any] forSome { val _6: B[Y] }
_6.a.P[Any] forSome { val _6: B[Y] }
is something along the lines of B[Y]#a.P[Any]
(pseudocode), which seems logically equivalent to A[Y]#P[Any]
.
Seems like the fact that the compiler can't turn that into A[Y]#P[Any]
may be a bug?
My next hunch was that the compiler couldn't turn new B[Y](new A[Y]).p[Any]
into A[Y]#P[Any]
because the argument to B
's constructor is polymorphic. We could define a class:
class C[T] extends A[T]
and new B[Y](new C[Y]).p[Any]
would be C[Y]#P[Any]
. But A[Y]#P[Any] >: C[Y]#P[Any]
, thus it should be safe for the compiler to assign new B[Y](...).p[Any]
the type A[Y]#P[Any]
. Now I'm back to being convinced that this is a compiler bug.
Another interesting detail to note is that the error disappears if the return type of B.p
is changed to A[T]#P[TT]
.