Recently I stumbled across a strange (to me) compiler error message. Consider the following code:
trait Foo {
type Res <: Foo
type Bar[X <: Res]
}
class MyFoo extends Foo {
override type Res = MyFoo
override type Bar[X <: Res] = List[X]
}
type FOO[F <: Foo, R <: Foo, B[_ <: R]] = F { type Res = R;
type Bar[X <: R] = B[X] }
def process[F <: Foo, R <: Foo, B[_ <: R]](f: FOO[F, R, B]) {}
Now, if I want to call the process method I have to explicitly write the type parameters:
process[MyFoo, MyFoo, List](new MyFoo) // fine
If I write:
process(new MyFoo)
or
process((new MyFoo): FOO[MyFoo, MyFoo, List])
I get the following error message:
inferred kinds of the type arguments (MyFoo,MyFoo,List[X]) do not conform to the expected kinds of the type parameters (type F,type R,type B). List[X]’s type parameters do not match type B’s expected parameters: class List has one type parameter, but type B has one
Why isn´t the compiler able to infer the types (although I explicitly stated them at call parameter)? And what does that class List has one type parameter, but type B has one mean? Something has one, but the other has also one, and that´s why they don´t fit together???
If we look to the Scala compiler, the sources could help us understanding what the problem is. I have never contributed to the Scala compiler, but I found the sources very readable and I have already investigated on that.
The class responsible for type inference is
scala.tools.nsctypechecker.Inferwhich you can find simply by looking in the Scala compiler sources for a part of your error. You’ll find out the following fragment:So now the point is understanding why
checkKindBounds(tparams, targs, pre, owner)returns those errors. If you go down the method call chain, you will see that the checkKindBounds call another methodYou’ll see the problem is connected to checking bounds of higher-kinded type, at line 5784, inside checkKindBoundsHK :
The test is not passed, it appears that in my debugger:
So it appears like there is one higher kinded param, type R, but there is no provided value for that.
If you actually go back to the to checkKindBounds, you see that after the snippet:
the
arityMismatchescontains a tuple List, B. And now you can also see that the error message is wrong:In fact if you put a breakpoint at line 5859 on the following call
you can see that
Conclusion: