While this problem was caught in code using shapeless and kind-projector, this behavior could be reproduced without them.
Suppose I have simple typeclass for reifying typeclass instances with incomplete implementation (mirror of LiftAll
).
sealed trait LiftAll1[F[_], In] {
type Out
def instances: Out
}
object LiftAll1 {
type Aux[F[_], In0, Out0] = LiftAll1[F, In0] {type Out = Out0}
implicit def unit[F[_]]: Aux[F, Unit, Unit] = new LiftAll1[F, Unit] {
type Out = Unit
def instances = Unit
}
}
And some very simple type class to test it
sealed class FirstIs[M, T]
object FirstIs {
implicit def firstIs[M, D]: FirstIs[M, (M, D)] = new FirstIs
}
Things are ok if I'll try to apply FirstIs
partially via alias, and get instance via LiftAll1
type FirstIsInt[D] = FirstIs[Int, D]
implicitly[LiftAll1[FirstIsInt, Unit]]
But inlined partial type application leads to compilation error
implicitly[LiftAll1[({type lambda[x] = FirstIs[Int, x]})#lambda, Unit]]
//Error: could not find implicit value for parameter e: LiftAll1[[x]FirstIs[Int,x],Unit]
How partially applied typeclasses could be found in such situations?
As @Reactormonk suggested, the compiler was brought to its senses with following line in the build.sbt
scalacOptions += "-Ypartial-unification"
After that original piece of code, which is close to
import shapeless._, ops.hlist._
LiftAll[FirstIs[Int, ?], HNil]
was succesfully compiled
AFAIK problem was in scala compiler incapability to understand FirstIs[Int,_]
as F[_]
in supplied implicit def
without direct type alias . Fortunately this was fixed in latest scala implementations.