I'm trying to understand why can't the Scala compiler infer the following restriction on a path-dependent type:
trait MyTrait
class MyTraitImpl extends MyTrait
trait MyTrait2[A <: MyTrait] {
type MyTraitType = A
}
class MyTrait2Impl[A <: MyTrait] extends MyTrait2[A]
val obj: MyTrait2[_] = new MyTrait2Impl[MyTraitImpl]
def myMethod[A <: MyTrait](t2: MyTrait2[A]) = println("Hi!")
myMethod[obj.MyTraitType](obj)
// <console>:14: error: type arguments [obj.MyTraitType] do not conform to method myMethod's type parameter bounds [A <: MyTrait]
// myMethod[obj.MyTraitType](obj)
For me, intuitively, MyTraitType
can't be anything other than a subclass of a MyTrait
, as the bound is right on A
in MyTrait2
. If there is, can you give me an example or point me to where this code snippet is wrong?
If this is a Scala compiler limitation, can anyone show me a way to achieve this using the type system? Note that:
MyTrait
object, nor does myMethod
receive one;myMethod
to know the concrete type of A
; all it needs to know is that A
it is a subtype of MyTrait
and that t2
is parametrized on A
;obj
is intentional; where I call myMethod
, I don't know the concrete type of A
(or else it would not be a problem);myMethod
.You should just use constraints on type member instead of bounds on type parameter in MyTrait2
declaration:
trait MyTrait
class MyTraitImpl extends MyTrait
trait MyTrait2 { // Remove [A <: MyTrait]
type MyTraitType <: MyTrait // add <: MyTrait
}
class MyTrait2Impl[A <: MyTrait] extends MyTrait2 { type MyTraitType = A }
val obj: MyTrait2 = new MyTrait2Impl[MyTraitImpl]
def myMethod[A <: MyTrait](t2: MyTrait2{ type MyTraitType = A }) = println("Hi!")
myMethod[obj.MyTraitType](obj)
You'll get a compilation error on wrong types, just as expected:
scala> val otherObj: MyTrait2 = new MyTrait2Impl[MyTraitImpl]
otherObj: MyTrait2 = MyTrait2Impl@8afcd0c
scala> myMethod[obj.MyTraitType](otherObj)
<console>:15: error: type mismatch;
found : otherObj.type (with underlying type MyTrait2)
required: MyTrait2{type MyTraitType = obj.MyTraitType}
myMethod[obj.MyTraitType](otherObj)
^
Proof it works with List[MyTrait2]
:
scala> for {
| obj <- List[MyTrait2](
| new MyTrait2Impl[MyTraitImpl],
| new MyTrait2Impl[MyTraitImpl]
| )
| } myMethod[obj.MyTraitType](obj)
Hi!
Hi!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With