Compile errors when defining a macro to convert a

2020-04-12 16:37发布

问题:

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
      }
    """
    }
  }
}

回答1:

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



标签: scala macros