milessabin / shapeless

Generic programming for Scala

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Possible derivation regression since shapeless 2.3.8

pomadchin opened this issue · comments

The shapeless 2.3.8 dependency update caused frameless test compilation failure, you can find the PR and the CI failure here: typelevel/frameless#612

I decided to go investigate it a little and to prepare a scoped example of the code that causes compilation errors, it looks like it may be related to the type alias resolution and Generic derivation:

Code example, function fooPrintT compiles with Shapeless <= 2.3.7 but not with 2.3.8

import shapeless.{Generic, HList, HNil, ::}

trait TC[A] { def foo: A }
object TC {
  def apply[A](implicit ev: TC[A]): TC[A] = ev

  implicit val booleanTC = new TC[Boolean] { def foo: Boolean = true }
  implicit val intTC = new TC[Int] { def foo: Int = 42 }
  implicit val longTC = new TC[Long] { def foo: Long = 420L }

  implicit def genericTC[T, L <: HList](implicit gen: Generic.Aux[T, L], tc: TC[L]): TC[T] = new TC[T] { def foo: T = gen.from(tc.foo) }
  implicit def tcHNil: TC[HNil] = new TC[HNil] { def foo: HNil = HNil }
  implicit def tcHCons[H, T <: HList](implicit dh: TC[H], dt: TC[T]): TC[H :: T] = new TC[H :: T] { def foo: H :: T = dh.foo :: dt.foo }
}

case class TX2[A, B](a: A, b: B)
case class TX3[A, B, C](a: A, b: B, c: C)

def fooPrint[A: TC, B: TC](data: TX2[A, B]): Unit = println(TC[TX2[A, B]].foo)

fooPrint(TX2[Int, Boolean](1, true))

type TTX3[A, B] = TX3[Long, Int, TX2[A, B]]

// compiles with shapeless <= 2.3.7
def fooPrintT[A: TC, B: TC](data: TTX3[A, B]): Unit = println(TC[TTX3[A, B]].foo)

fooPrintT(TX3(1L, 1, TX2(1, true)))

build.sbt

libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.8"

scalaVersion := "2.13.8"

Compilation error

could not find implicit value for parameter ev: TC[TTX3[A,B]]
[error]     def fooPrintT[A: TC, B: TC](data: TTX3[A, B]): Unit = println(TC[TTX3[A, B]].foo)

Scastie (downgrade shapeless to see that compilation works)

https://scastie.scala-lang.org/pomadchin/Q8XBuPBVTTajvomVe3YZfQ/5

I tried to narrow the example more:

import shapeless.{Generic, HList}

case class TX2[A, B](a: A, b: B)
case class TX3[A, B, C](a: A, b: B, c: C)

def tx2[A, B](data: TX2[A, B])(implicit g: Generic[TX2[A, B]]): Unit = {}

tx2(TX2[Int, Boolean](1, true))

type TTX3[A, B] = TX3[Long, Int, TX2[A, B]]

def tx3[A, B](data: TTX3[A, B])(implicit g: Generic[TTX3[A, B]]): Unit = {}

// compiles with shapeless <= 2.3.7
// could be fixed for 2.3.8 by removing the type alias 
// def tx3[A, B](data: TTX3[A, B])(implicit g: Generic[TX3[Long, Int, TX2[A, B]]]): Unit = {}
tx3(TX3(1L, 1, TX2(1, true)))

Scastie: https://scastie.scala-lang.org/pomadchin/D46I0pY3TuegOXIqicrZkg/9

Thanks for the report. We might be missing a dealias call somewhere and it shouldn't be too hard by looking at the commits between 2.3.7 and 2.3.8

@joroKr21 that was indeed it! Thanks!