Reputation: 40461
I'm trying to evaluate an Expr
inside a macro using the Context#eval
method:
//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 )
}
However, the compiler complains with:
[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
If found in the scala-user ML, that the problem could be solved using resetAllAttrs
. However
So is there a way to solve my problem ?
The rest of the code:
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
}
Upvotes: 3
Views: 1665
Reputation: 13048
The docs for c.eval
indeed tell to use c.resetAllAttrs
, however this function has a number of known issues that sometimes make it to irreparably corrupt the tree it processes (that's why we're planning to remove it in Scala 2.11 - I just submitted a pull request that does that: https://github.com/scala/scala/pull/3485).
What you could try instead is c.resetLocalAttrs
, which has smaller potential for tree corruption. Unfortunately it's still a bit broken. We plan to fix it (https://groups.google.com/forum/#!topic/scala-internals/TtCTPlj_qcQ), however in Scala 2.10.x and 2.11.0 there's going to be no way to make c.eval
work reliably.
Upvotes: 3
Reputation: 4038
Well, I figured out what they meant by using resetAllAttrs
. My example is simplified for an Int
input, but I was able to replicate and fix the error you described by doing the following:
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
I'm going to make a guess that you're fine for using resetAllAttrs
, at least until some future versions of Scala come out. 2.11 doesn't even give a deprecation warning for its use.
Note: I'm using Scala 2.11. I believe this should be identical in 2.10, except you'll be using Context
instead of BlackboxContext
.
Upvotes: 1