考虑以下代码:scastie
class A { }
class B extends A { def m = true }
trait X { def obj : A }
class Y extends X { def obj = new B }
val y = new Y
y.obj.m // Compiles in scala2, does not compile in scala3.
y.obj
的类型是什么?
似乎在scala2中
y.obj
是B
,而在scala3中y.obj
是A
!
结果查找 y.obj.m
在 scala2 中编译,但在 scala3 中不编译。
显然,在 scala3 中,
def obj: A
中的抽象成员 X
的类型优先于 Y
中的较窄类型推断。
正如预期的那样,
y.obj
是一个 B
当:
class Y /* extends X */ { def obj = new B } // member is not previously declared
class Y extends X { def obj : B = new B } // type is forced by ascription
这看起来是良性的,直到有人使用 透明内联方法 从宏中返回一些类型信息。
这是一个更具描述性的片段:scastie
class A
class B extends A:
def m = true
transparent inline def choose(b: Boolean): A =
if b then new A else new B
class X:
def obj1 : A
def obj2 : A
def obj3 : A
class Y extends X:
def obj1 = choose(true) // type A
def obj2 = choose(false) // type A ( from X.this.obj2 )
def obj3 : B = choose(false) // type B ( from ascription )
def obj4 = choose(false) // type B ( from inference )
val y = new Y
y.obj1.m // compile error EXPECTED
y.obj2.m // compile error UNEXPECTED
y.obj3.m // compiles EXPECTED
y.obj4.m // compiles EXPECTED