什么会导致宏扩展中的“ genLoad中的意外树”?

时间:2019-04-26 02:45:33

标签: scala scala-macros

我试图产生一个小的宏以隔离我遇到的另一个问题,并开始遇到此编译时错误。

Error:scalac: 
  Unexpected tree in genLoad: test.MacroTest$Baz.type/class scala.reflect.internal.Trees$TypeTree at: source-/Users/jpatterson/test/src/test/scala/test/MacroTest.scala,line-5,offset=114
     while compiling: /Users/jpatterson/test/src/test/scala/test/MacroTest.scala
        during phase: jvm
     library version: version 2.13.0-RC1
    compiler version: version 2.13.0-RC1
  reconstructed args: -deprecation -Vimplicits -language:higherKinds -language:implicitConversions -language:postfixOps -classpath ... (cut)
last tree to typer: Literal(Constant(test.MacroTest.MacroTest$Baz.type))
       tree position: line 4 of /Users/jpatterson/test/src/test/scala/test/MacroTest.scala
            tree tpe: Class(classOf[test.MacroTest$Baz$])
              symbol: null
           call site: constructor MacroTest$$anon$1 in package test
== Source file context for tree position ==
     1 package test
     2 
     3 object MacroTest {
     4   case class Baz(x: Int, y: Int)
     5   implicit def bazRead: Read[Baz] = Read.readFor[Baz]
     6 
     7   def main(args: Array[String]): Unit = {

我开始使用scala 2.12.8。我尝试切换到2.13.0-RC1只是为了查看它是否已解决。两种版本的scala都失败了。

宏代码:

package test

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

trait Read[A] {
  def read(in: String): A
}

object Read {
  implicit def intRead = new Read[Int] {
    override def read(in: String): Int = in.toInt
  }

  def CaseClassReadImpl[A: c.WeakTypeTag](c: Context): c.Expr[Read[A]] = {
    import c.universe._
    val aType = weakTypeOf[A]

    val params = aType.decls.collect {
      case m: MethodSymbol if m.isCaseAccessor => m
    }.toList

    val paramList = params.map(param => q"Read.read[${param.typeSignature}](in)")

    val src = q"""
      new Read[$aType] {
        def read(in: String) = ${aType.companion}.apply(..$paramList)
      }
    """

    println(src)
    c.Expr[Read[A]](src)
  }

  def readFor[A]: Read[A] = macro CaseClassReadImpl[A]

  def read[A](in: String)(implicit A: Read[A]): A = A.read(in)
}

执行它的代码:

package test

object MacroTest {
  case class Baz(x: Int, y: Int)
  implicit def bazRead: Read[Baz] = Read.readFor[Baz]

  def main(args: Array[String]): Unit = {
    println(Read.read[Baz]("4"))
  }
}

编译第二个块会导致上面的错误。

我期望它可以正确编译。我将那个println放入了宏定义中,这样我就可以抓取代码并尝试对其进行编译。当我将其添加到第二个块时,它可以正常编译。我什至可以用它替换bazRead的值,并且一切都会按预期进行:它会打印出Baz(4,4)

1 个答案:

答案 0 :(得分:1)

关于宏,请尝试将public class MapTest { int[][] map = new int[100][4]; // Syntax error on token ";", { expected after this token for(int i = 0; i < 101; i++) { map[i][1] = i; map[i][2] = i; map[i][3] = 1; map[i][4] = 0; } } //Syntax error, insert "}" to complete ClassBody 替换为${aType.companion}


要派生类型类,最好使用ShapelessMagnoliaScalaz-deriving而不是原始宏。

例如在Shapeless ${aType.typeSymbol.companion}中,可以如下得出

Read