5
votes

I have a trait Outer with a member F that is a type constructor. I want to supply type-class instances for F, but somehow at one point the implicit resolution of scalac stops working.

I tried to build a smaller minimal example, but I had to add everything below to make the error appear. Note how the second-to-last line still compiles, properly picking up the implicit from the nested companion object in sub.

But the last line doesn't compile anymore. Also note that when specifying the implicit method in the second-to-last line, it compiles.

Can anyone provide a clue for why this happens?

trait TC[F[_]]

trait Outer[N[_]] {
  trait F[_]
  object F {
    implicit val tcInst: TC[F] = new TC[F]{}
  }
}

case class Sub[N[_]]() extends Outer[N]

object Test{
  implicit val optionInst: TC[Option] = new TC[Option]{}

  val sub = Sub[Option]()
  val sub2 = Sub[sub.F]()

  implicitly[TC[sub.F]]                  //compiles
  implicitly[TC[sub2.F]](sub2.F.tcInst)  //compiles
  implicitly[TC[sub2.F]]                 //doesn't compile
}

The last line yields the following error:

Error:(22, 13) could not find implicit value for parameter e: test.novariance.TC[test.novariance.Test.sub2.F]
  implicitly[TC[sub2.F]]                 //doesn't compile
            ^
Error:(22, 13) not enough arguments for method implicitly: (implicit e: test.novariance.TC[test.novariance.Test.sub2.F])test.novariance.TC[test.novariance.Test.sub2.F].
Unspecified value parameter e.
  implicitly[TC[sub2.F]]                 //doesn't compile
            ^
1

1 Answers

0
votes

I can see why your implicit doesn't resolve, so I'll try to explain why it doesn't satisfy the scoping rules.

But I'm not clear what your intent is, so I can't suggest a workaround.

Step by step:

  1. To satisfy this expression implicitly[TC[sub2.F]], the compiler will search lexical (surrounding) scope, and then the companions (if any) of types TC and sub2.F.type (ie the type of the object F nested within Outer).
  2. In lexical scope there is only TC[Option], which isn't the same type as sub2.F.type.
  3. In companion scope, TC has no companion object. sub2.F isn't a class, its an object, so it cannot have a companion object.

If you meant to refer to the trait F within Outer, you need the type projection operator #, eg sub2#F