在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
以下行产生编译错误type arguments [Object] do not conform to class P's type parameter bounds [TT >: T]
(即使X >: Y
):
val x = new B[Y](new A[Y]).p[X]
有趣的是,此错误未出现在以下代码中:
new B[Y](new A[Y]).p[X]
val y = new B[Y](new A[Y])
val z = y.p[X]
我没有看到有什么区别?
我有一种预感,编译器无法为x
分配类型,但现在看来很奇怪,因为在以下代码中,q
被愉快地分配A[Y]#P[X]
:
val q = new A[Y].p[X]
据我所知,x
也应该分配A[Y]#P[X]
。
REPL给了我一些我认为是线索的信息,但我不确定如何:
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] }
类似B[Y]#a.P[Any]
(伪代码),在逻辑上等同于A[Y]#P[Any]
。
似乎编译器无法将其转换为A[Y]#P[Any]
可能是一个错误的事实?
我的下一个预感是编译器无法将new B[Y](new A[Y]).p[Any]
转换为A[Y]#P[Any]
,因为B
的构造函数的参数是多态的。我们可以定义一个类:
class C[T] extends A[T]
和new B[Y](new C[Y]).p[Any]
将是C[Y]#P[Any]
。但是A[Y]#P[Any] >: C[Y]#P[Any]
,因此编译器分配new B[Y](...).p[Any]
类型A[Y]#P[Any]
应该是安全的。现在我又回到了确信这是一个编译器错误。
另一个值得注意的有趣细节是,如果B.p
的返回类型更改为A[T]#P[TT]
,则错误消失。