eirirlar
eirirlar

Reputation: 812

Typeable implicits not applied

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

Answers (1)

Dmytro Mitin
Dmytro Mitin

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

Related Questions