Implicit conversion where there resulting type is a type projection on a generic type

186 Views Asked by At

I have some scala 2.13 code that basically boils down to this

import scala.language.implicitConversions

trait Base {
  type V
  def v: V
}

case class Derived(v: Int) extends Base {
  type V = Int
}


object TestImplicitConversion {
  implicit def getV[T <: Base](a: T): T#V = a.v

  val a: Int = Derived(5)
}

Here I would expect the compiler to use the implicit conversion getV to convert Derived to Int, but the code does not compile. Manually adding the call to getV, will make the code compile. Can someone help me understand why the conversion where in the standard it is explained.

The way I found of making such a conversion work is by adding a second generic parameter and a constraint

implicit def getV2[T <: Base, S](a: T)(implicit constraint: T#V =:= S): S = constraint(a.v)

with this version the compiler uses the conversion and the code does compile.

Edit:

The alternative solution provided by @user using refinement type does indeed seem like a better approach. But it does not really provide an answer to why it original implementation does not work. So I am still interested in understanding why the compiler does not use the implicit def when an explicit call will make the code compile.

1

There are 1 best solutions below

7
On

As gianluca aguzzi mentioned in the comments, type projection is unsound and should be avoided. Moreover, T is not a concrete type, so you can't use projections on it anyway. You can accept only Base#V as a type parameter instead, and use a refinement type for the type of a:

implicit def get[T](a: Base { type V = T }): T = a.v

Thus, you can avoid casting and type projections.

Scastie