Is there a convenient way to turn a MethodSymbol
into the left-hand side of a method definition tree (i.e., a DefDef
) in Scala 2.10?
For example, suppose I want to create a macro that will take an instance of a trait and wrap all of that trait's methods with some debugging functionality. I can write the following:
import scala.language.experimental.macros
import scala.reflect.macros.Context
object WrapperExample {
def wrap[A](a: A): A = macro wrap_impl[A]
def wrap_impl[A: c.WeakTypeTag](c: Context)(a: c.Expr[A]) = {
import c.universe._
val wrapped = weakTypeOf[A]
val f = Select(reify(Predef).tree, "println")
val methods = wrapped.declarations.collect {
case m: MethodSymbol if !m.isConstructor => DefDef(
Modifiers(Flag.OVERRIDE),
m.name,
Nil, Nil,
TypeTree(),
Block(
Apply(f, c.literal("Calling: " + m.name.decoded).tree :: Nil),
Select(a.tree, m.name)
)
)
}.toList
//...
}
I've elided the boring business of sticking these methods in a new anonymous class that implements the trait and then instantiating that class—you can find a complete working example here if you're interested.
Now I can write this, for example:
scala> trait X { def foo = 1; def bar = 'a }
defined trait X
scala> val x = new X {}
x: X = $anon$1@15dd533
scala> val w: X = WrapperExample.wrap[X](x)
w: X = $1$$1@27c3a4a3
scala> w.foo
Calling: foo
res0: Int = 1
scala> w.bar
Calling: bar
res1: Symbol = 'a
So it works, but only in very simple cases—it won't if the trait has methods with parameter lists, with access modifiers, annotations, etc.
What I really want is a function that will take a method symbol and a tree for the new body and return a DefDef
. I've started writing one by hand, but it involves a lot of fiddly stuff like this:
List(if (method.isImplicit) Some(Flag.IMPLICIT) else None, ...)
Which is annoying, verbose, and error-prone. Am I missing some nicer way to do this in the new Reflection API?
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…