jonderry
jonderry

Reputation: 23633

Compile errors when defining a macro to convert a case class instance into a map and back

I'm trying to understand the following blog post, which discusses how to use macros to create a generic macro-based approach to convert case class objects to and from a map: http://blog.echo.sh/post/65955606729/exploring-scala-macros-map-to-case-class-conversion

Even though I read the entire post and another article on scala macros, I still do not fully understand how they work. Unfortunately, I'm receiving a couple of compile errors from the example code given in the blog post and am not sure why the errors are occurring nor how to resolve them. I'm reproducing the code below, preceded by the compile errors, for completeness (I annotated the code snippet with comments regarding the compile errors). Does anyone know why these compiler issues are occurring and how to resolve them?

-type mismatch; found : field.NameType required: 
     c.universe.TermName
-Can't unquote List[Nothing] with .., bottom type values often indicate programmer mistake

Here's the code:

import scala.reflect.macros.Context
import scala.language.experimental.macros

trait Mappable[T] {
  def toMap(t: T): Map[String, Any]
  def fromMap(map: Map[String, Any]): T
}

object Mappable {
  implicit def materializeMappable[T]: Mappable[T] = macro materializeMappableImpl[T]

  def materializeMappableImpl[T: c.WeakTypeTag](c: Context): c.Expr[Mappable[T]] = {
    import c.universe._
    val tpe = weakTypeOf[T]
    val companion = tpe.typeSymbol.companionSymbol

    val fields = tpe.declarations.collectFirst {
      case m: MethodSymbol if m.isPrimaryConstructor ⇒ m
    }.get.paramss.head

    val (toMapParams, fromMapParams) = fields.map { field ⇒
      val name = field.name
      val decoded = name.decoded
      val returnType = tpe.declaration(name).typeSignature

      (q"$decoded → t.$name", q"map($decoded).asInstanceOf[$returnType]") // error 1
    }.unzip

    c.Expr[Mappable[T]] {
      q"""
      new Mappable[$tpe] {
        def toMap(t: $tpe): Map[String, Any] = Map(..$toMapParams)
        def fromMap(map: Map[String, Any]): $tpe = $companion(..$fromMapParams) // error 2
      }
    """
    }
  }
}

Upvotes: 2

Views: 314

Answers (1)

user1453345
user1453345

Reputation: 338

change t.$name to t.${name.toTermName}

Upvotes: 1

Related Questions