什么会导致宏扩展中的 "Unexpected tree in genLoad"?
What can cause "Unexpected tree in genLoad" in a macro expansion?
我试图生成一个小宏来隔离我遇到的另一个问题,并开始 运行 进入这个编译时错误。
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 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)
.
关于您的宏,请尝试将 ${aType.companion}
替换为 ${aType.typeSymbol.companion}
。
对于派生类型 类 最好使用 Shapeless, Magnolia or Scalaz-deriving 而不是原始宏。
例如在Shapeless中Read
可以推导如下
import shapeless.{Generic, HList, HNil, ::}
trait Read[A] {
def read(in: String): A
}
object Read {
implicit def intRead: Read[Int] = _.toInt
implicit def hNilRead: Read[HNil] = _ => HNil
implicit def hConsRead[H, T <: HList](implicit r: Read[H], r1: Read[T]): Read[H :: T] =
in => r.read(in) :: r1.read(in)
implicit def caseClassRead[A, L <: HList](implicit gen: Generic.Aux[A, L], r: Read[L]): Read[A] =
in => gen.from(r.read(in))
def read[A](in: String)(implicit A: Read[A]): A = A.read(in)
}
case class Baz(x: Int, y: Int)
Read.read[Baz]("123") // Baz(123,123)
我试图生成一个小宏来隔离我遇到的另一个问题,并开始 运行 进入这个编译时错误。
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 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)
.
关于您的宏,请尝试将 ${aType.companion}
替换为 ${aType.typeSymbol.companion}
。
对于派生类型 类 最好使用 Shapeless, Magnolia or Scalaz-deriving 而不是原始宏。
例如在Shapeless中Read
可以推导如下
import shapeless.{Generic, HList, HNil, ::}
trait Read[A] {
def read(in: String): A
}
object Read {
implicit def intRead: Read[Int] = _.toInt
implicit def hNilRead: Read[HNil] = _ => HNil
implicit def hConsRead[H, T <: HList](implicit r: Read[H], r1: Read[T]): Read[H :: T] =
in => r.read(in) :: r1.read(in)
implicit def caseClassRead[A, L <: HList](implicit gen: Generic.Aux[A, L], r: Read[L]): Read[A] =
in => gen.from(r.read(in))
def read[A](in: String)(implicit A: Read[A]): A = A.read(in)
}
case class Baz(x: Int, y: Int)
Read.read[Baz]("123") // Baz(123,123)