covariant type occurs in invariant position in HList

356 Views Asked by At

I am trying to define a type safe heterogeneous list which has restrictions on the types of its elements, enforcing an hierarchy between the elements (e.g type A cannot appear after type B). The trouble happens when attempting to convert my structure to shapeless' HList.

Below is how I define the traits for my type:

sealed trait Hierarchy {
  type HListType <: HList
  def toHList : HListType

  def toCaseClass[C](implicit gen: Generic[C]{type Repr >: HListType}) = gen.from(toHList)
}

sealed trait <::[+H <: ElType[_], +T <: Hierarchy] extends Hierarchy {

  override type HListType = H :: tail.HListType

  val head: H
  val tail: T

  override def toHList: HListType = head :: tail.toHList

}

I get the following error:

Hierarchy.scala:26: covariant type H occurs in invariant position in type shapeless.::[H,<::.this.tail.HListType] of type HListType

This is quite puzzling, since the definition of shapeless.:: defines that both type parameters are covariant.

I am using scala 2.11.11 and shapeless 2.3.2. Is there a way to fix this error?

1

There are 1 best solutions below

0
On BEST ANSWER

From the Scala spec:

The right-hand side of a type alias is always in invariant position.

So the problem is not from the definition of HList, but from the fact that I'm using the type parameter in a type alias.

I changed the definition to

sealed trait <::[+H, +T <: Hierarchy] extends Hierarchy {

  type H_ <: ElType[H]

  override type HListType = H_ :: tail.HListType

  val head: H_
  val tail: T

  override def toHList: HListType = head :: tail.toHList

}

And the problem disappears.