Reputation: 895
How can I see the definition of a symbol from within macros?
As a special case, I wonder how to evaluate constant values at compile time using macros. My approach works for "final val" but not for a local "val":
// scalaVersion := "2.11.0"
import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros
object Const {
def m_same(c: Context)(i: c.Tree) = {
import c.universe._
val Literal(Constant(_)) = i
i
}
def same(i: Any): Any = macro m_same
}
A local value is not recognized as a Literal(Constant(_))
:
import org.scalatest.FreeSpec
class ConstSpec extends FreeSpec {
"Int literal" in {
assert(Const.same(42) === 42)
}
final val iFinal = "mytest" // is a Literal(Constant(_))
"final Int value" in {
assert(Const.same(iFinal) === iFinal)
}
"local Int value" in {
val iLocal = 42 // is NOT a Literal(Constant(_))
assert(Const.same(iLocal) === iLocal) // does NOT compile
}
}
Upvotes: 1
Views: 96
Reputation: 39577
final val
has special significance for constants and means inline them.
Your ordinary val looks like:
scala> q"{ val i = 42 ; i }"
res0: reflect.runtime.universe.Tree =
{
val i = 42;
i
}
scala> showRaw(res0)
res1: String = Block(List(ValDef(Modifiers(), TermName("i"), TypeTree(), Literal(Constant(42)))), Ident(TermName("i")))
I think Travis Brown's Metaplasm blog, i.e., things you shouldn't try at home with macros, includes examining the surrounding context for a def.
In this case, consulting the enclosing context on a statement basis would discover the def of the i
you want, and you could examine its RHS.
Their macro philosophy is to think local and expand local. I just made that up. They also offer macro annotations for less-local things like companions.
But wait, they do offer an eval
facility on Context
. Is that sufficient for your use case?
Upvotes: 1