Reputation: 812
Could someone please share some insight as to why the following compiles just fine:
import shapeless.Typeable._
import shapeless._
import shapeless.labelled.FieldType
import shapeless.record._
import shapeless.tag.@@
trait Typeables[L <: HList] extends DepFn0 {
type Out <: HList
}
object Typeables {
type Aux[L <: HList, Out0 <: HList] = Typeables[L] {type Out = Out0}
def apply[L <: HList](implicit typeables: Typeables[L]): typeables.type = typeables
implicit def hnilTypeables[L <: HNil]: Aux[L, HNil] = new Typeables[L] {
type Out = HNil
def apply(): Out = HNil
}
implicit def hlistTypeables[K, V, Rest <: HList]
(implicit
head: Typeable[V]
, tail: Typeables[Rest]
): Aux[FieldType[K, V] :: Rest, Typeable[V] :: tail.Out] = new Typeables[FieldType[K, V] :: Rest] {
type Out = Typeable[V] :: tail.Out
def apply(): Out =
head :: tail()
}
}
object Testy {
/** Typeable instance for `T @@ U`. */
implicit def taggedTypeable[T, U]
(implicit
castT: Typeable[T]
, castU: Typeable[U]): Typeable[T @@ U] =
new Typeable[T @@ U] {
def cast(t: Any): Option[T @@ U] = {
if (t == null) None
else if (t.isInstanceOf[T]) {
val o = t.asInstanceOf[T]
Some(tag[U](o))
} else None
}
def describe = s"${castT.describe} @@ ${castU.describe}"
}
the[Typeable[Long @@ String]]
the[Typeables[Record.`'test -> Long`.T]]
// the[Typeables[Record.`'test -> Long @@ String`.T]]
}
whereas commenting in the second last line the[Typeables[Record.`'test -> Long @@ String`.T]]
gives a compilation error:
Error:(56, 8) could not find implicit value for parameter t: Typeables[Long with shapeless.tag.Tagged[String] with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("test")],Long with shapeless.tag.Tagged[String]] :: shapeless.HNil]
the[Typeables[Record.`'test -> Long @@ String`.T]]
Error:(56, 8) not enough arguments for macro method apply: (implicit t: Typeables[Long with shapeless.tag.Tagged[String] with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("test")],Long with shapeless.tag.Tagged[String]] :: shapeless.HNil])Typeables[Long with shapeless.tag.Tagged[String] with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("test")],Long with shapeless.tag.Tagged[String]] :: shapeless.HNil] in object the.
Unspecified value parameter t.
the[Typeables[Record.`'test -> Long @@ String`.T]]
Using scala 2.12.3, shapeless 2.3.2.
I would have expected it to work with a record with tagged field types since I have provided a correct implicit def for any tagged type, and proved that it works by itself. What am I missing?
Upvotes: 2
Views: 204
Reputation: 51723
T @@ U
is a synonym for T with Tagged[U]
.
And
Record.`'test -> Long`.T
is a shorthand for FieldType[Symbol @@ "test", Long] :: HNil
.
So
the[Typeables[Record.`'test -> Long @@ String`.T]]
can be rewritten as
the[Typeables[FieldType[Symbol @@ "test", Long @@ String] :: HNil]]
(whatever it means) and this one works.
So FieldType[Symbol @@ ..., ...] :: HNil
and Record. ... .T
are more or less equivalent syntaxes and obviously @@
not always correctly works inside Record. ... .T
.
(Here I used Typelevel Scala and scalac flag -Yliteral-types
for work with literal types.)
Upvotes: 1