Ran into this strange behavior when changed upper bound in the implementation, but forgot to change it in the interface. I think last statement should not compile, but it does and returns unexpected result.
trait SuperBase
trait Base extends SuperBase
class SuperBaseImpl extends SuperBase
trait Service {
def doWork[T <: Base : Manifest](body: T => Unit): String
def print[T <: Base : Manifest]: String
}
object ServiceImpl extends Service {
override def doWork[T <: SuperBase : Manifest](body: T => Unit): String =
print[T]
def print[T <: SuperBase : Manifest]: String =
manifest[T].runtimeClass.toString
}
val s: Service = ServiceImpl
// does not compile as expected
// s.print[SuperBaseImpl]
// returns "interface Base"
s.doWork { x: SuperBaseImpl => () }
Edit
As @som-snytt mentioned with -Xprint:typer
option we can see what compiler actually infers:
s.doWork[Base with SuperBaseImpl]
This explains why we are getting "interface Base". But I still not quite understand how and why type inference work in this case.
-Xprint:typer
, it makes everything a bit clearer for me. But I still don't understand how and why it works in this way. Is it a bug? About bounds, upper bound was used to call some methods defined in Base/SuperBase before/after calling argument function. And then it was changed in Impl only by mistake. – Noellanoelle