3

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

  1. I don't understand how I am supposed to use it.
  2. This function seems to be deprecated.

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

}
paradigmatic
  • 40,153
  • 18
  • 88
  • 147
  • Would be helpful if you could publish the entire code in a github project. I'll then make sure that we don't miss your use case when fixing resetAttrs. – Eugene Burmako Feb 07 '14 at 19:12

2 Answers2

3

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.

Eugene Burmako
  • 13,028
  • 1
  • 46
  • 59
1

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.

KChaloux
  • 3,918
  • 6
  • 37
  • 52
  • I have weirder error: `object Ary is not a member of package ArrayOps` which is true because `Ary` is not an object but an implicit class as showed above. – paradigmatic Feb 05 '14 at 15:22
  • @paradigmatic What line are you getting it on? Are you sure it's a macro/context error? I know macros don't always play nice with implicits, though I'm not sure to what extent. – KChaloux Feb 05 '14 at 16:38
  • I added the main method and the error here: https://gist.github.com/paradigmatic/8827878 Thanks – paradigmatic Feb 05 '14 at 16:44
  • @paradigmatic I can get it working in the repl, but things fall apart during compilation. Unfortunately this is a bit beyond me, especially without access to the full codebase. You're going to have to tough this one out by yourself. It may be related to the restrictions scala puts on compiling macros (where the compilation of the macro needs to take place before the compilation of the rest of the program). – KChaloux Feb 05 '14 at 17:08
  • @Eugene Upvoted your answer. So now it'll actually appear above mine :P – KChaloux Feb 07 '14 at 19:13