The type of macro return depends on the arguments.

I want to write a macro where the type of the return value depends on the arguments. A 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 return type of return funImplis illegal. I tried just returning Tree, but this causes 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 such a macro? Obviously, it is possible if the type of the return value is passed as an argument of another type, as in the answer to Can I write a scala macro whose return type depends on the argument? this is not what i want.

+3
source share
1 answer

, , : , c.Expr[Any], .

, - , , , - , 2.11 whitebox blackbox, , , ( ).

, , ( quasiquotes macro paradise plugin 2.10, ):

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]

:

scala> fun[String]("length")
res0: String => Int = <function1>

, - , , Any. (, , ) funImpl c.Expr[T => Any] - c.Expr[T => Any](q"_.$methodName"), , , - , .

+7

All Articles