我正在尝试使用Expr
方法评估宏内的Context#eval
:
//Dummy implementation
def evalArrayTree(c: Context)(a: c.Expr[ArrayTree]): c.Expr[Array[Double]] = {
import c.universe._
println( c.eval(a) )
val tree = reify( Array(0.0,0.0,0.0) ).tree
c.Expr[Array[Double]]( tree )
}
然而,编译器抱怨:
[error] /home/falcone/prg/sbt-example-paradise/core/src/main/scala/Test.scala:20: exception during macro expansion:
[error] scala.tools.reflect.ToolBoxError: reflective toolbox has failed
如果在scala-user ML中找到,可以使用resetAllAttrs
解决问题。然而
那么有办法解决我的问题吗?
其余代码:
object ArrayEval {
import scala.language.experimental.macros
def eval( a: ArrayOps.ArrayTree ): Array[Double] = macro Macros.evalArrayTree
}
object ArrayOps {
sealed trait ArrayTree {
def +( that: ArrayTree ) = Plus( this, that )
}
implicit class Ary( val ary: Array[Double] ) extends ArrayTree
case class Plus( left: ArrayTree, right: ArrayTree ) extends ArrayTree
}
答案 0 :(得分:3)
c.eval
的文档确实告诉使用c.resetAllAttrs
,但是这个函数有许多已知的问题,有时会使它无法修复它所处理的树(这就是我们计划删除的原因)它在Scala 2.11中 - 我刚刚提交了一个拉取请求:https://github.com/scala/scala/pull/3485)。
您可以尝试的是c.resetLocalAttrs
,它具有较小的树腐败可能性。不幸的是,它仍然有点破碎。我们计划修复它(https://groups.google.com/forum/#!topic/scala-internals/TtCTPlj_qcQ),但是在Scala 2.10.x和2.11.0中,将无法使c.eval
可靠地工作。
答案 1 :(得分:1)
好吧,我通过resetAllAttrs
找出了他们的意思。我的示例已针对Int
输入进行了简化,但我能够通过执行以下操作来复制并修复您描述的错误:
import scala.language.experimental.macros
import scala.reflect.runtime.universe._
import scala.reflect.macros.BlackboxContext
def _evalMacro(c: BlackboxContext)(a: c.Expr[Int]) = {
import c.universe._
val treeReset = c.resetAllAttrs(a.tree) // Reset the symbols in the tree for 'a'
val newExpr = c.Expr(treeReset) // Construct a new expression for the updated tree
println(c.eval(newExpr)) // Perform evaluation on the newly constructed expression
... // Do what you do
}
def evalMacro(a: Int) = macro _evalMacro
我打算猜测你使用resetAllAttrs
是好的,至少在Scala的某些未来版本问世之前。 2.11甚至没有给出使用的弃用警告。
注意:我正在使用Scala 2.11。我相信这在2.10中应该相同,除非您使用Context
代替BlackboxContext
。