Macro return type depends on the arguments
scala, scala-macros
Solution
Yes, this is possible, thanks to the magic of whitebox macros: you can just tell the compiler that the return type is `c.Expr[Any]` and it'll infer the more precise type.
This behavior shocked me when I first ran into it—it's very, very powerful and very, very scary—but it definitely is intended, and will continue to be supported, although 2.11 will make a distinction between whitebox and blackbox macros, and the former are likely to remain in experimental status longer (if they ever leave it at all).
For example, the following is a quick sketch of what you're asking for (I'm using quasiquotes here via the macro paradise plugin for 2.10, but it would only be a little more verbose without quasiquotes):
import scala.language.experimental.macros
import scala.reflect.macros.Context
def funImpl[T: c.WeakTypeTag](c: Context)(
method: c.Expr[String]
): c.Expr[Any] = {
import c.universe._
val T = weakTypeOf[T]
val methodName: TermName = method.tree match {
case Literal(Constant(s: String)) => newTermName(s)
case _ => c.abort(c.enclosingPosition, "Must provide a string literal.")
}
c.Expr(q"(t: $T) => t.$methodName")
}
def fun[T](method: String) = macro funImpl[T]
And then:
scala> fun[String]("length")
res0: String => Int = <function1>
You can see that the inferred type is exactly what you want, not `Any`. You could (and probably should) set the return type of `funImpl` to `c.Expr[T => Any]` and return something like `c.Expr[T => Any](q"_.$methodName")`, but that's essentially just documentation—it doesn't have any effect on how the return type of the macro is inferred in this case.
Problem
I want to write a macro where the return type depends on arguments. Simplified example: ``` def fun[T](methodName: String) = macro funImpl[T] def funImpl[T: WeakTypeTag](c: Context)(methodName: c.Expr[String]): /* c.Expr[T => return type of T.methodName] */ = { // return x => x.methodName } ``` Obviously the commented-out return type of `funImpl` is illegal. I've tried simply returning a `Tree`, but this produces an error: ``` [error] macro implementation has wrong shape: [error] required: (c: scala.reflect.macros.Context): c.Expr[Any] [error] found : (context: scala.reflect.macros.Context): context.Tree [error] type mismatch for return type: c.universe.Tree does not conform to c.Expr[Any] [error] def fun[T] = macro PrivateMethodMacro.funImpl[T] [error] ^ ``` Is it possible to write a macro like this? Obviously it's possible if the return type is passed as another type argument, as in the answer to Is it possible to write a scala macro whose returntype depends on argument? but this isn't what I want.