Macros: how can we use quasiquotes to match on a function type?


#1

Hi,

I have a macro function that can successfully match on an expression
(functions only) using quasiquotes and get an identifier if possible (not
the case of anonymous functions). Now I would like to:

a) Find information regarding the function types
b) And in particular find were the function was declared (type and
position were it is defined)

As an initial step I defined this function:

  private def getFuncDef[T:c.WeakTypeTag](c: blackbox.Context)(expr: c.Expr[T]): String = {
    import c.universe._

    println(showRaw(expr.tree.tpe))
    expr.tree.tpe match {
      case tq"(..$param) => $body" =>
        println(showRaw(param))
        println(showRaw(body))
        ""
      case _ =>
        println("???????")
        ""
    }
  }

Now my problem is that when I pass a function, it never matches.
Say I have a class were in I define a method f.

class FuncBlob() {
  def f(b:Int):Int = -b
  val h: Int => Double = (b:Int) => (2*b).toDouble
}

When I pass on f, I have the following information:

func.tree = {
((b: Int) => blob.f(b))
}
func.tree.type = Int => Int
func.tree.class = class scala.reflect.internal.Trees$Block
func.actualType = Int => Int
func.staticType = Nothing
func.tree.isDef = false
func.tree.isTerm = true
func.tree.isType = false
Raw: Block(List(), Function(List(ValDef(Modifiers(PARAM | SYNTHETIC), TermName(“b”), TypeTree(), EmptyTree)), Apply(Select(Ident(TermName(“blob”)), TermName(“f”)), List(Ident(TermName(“b”))))))

In this case this match works:

    expr.tree match {
      case q"{ ($paramIn) => $call($param)}" =>
        println(s"$call($paramIn) => ???")
        call.toString

Notice how we have a Block that has a Function. The getFuncDef
prints out:

TypeRef(ThisType(scala), scala.Function1, List(TypeRef(ThisType(scala), scala.Int, List()), TypeRef(ThisType(scala), scala.Int, List())))

Again, we have a Functon1, but matching fails (2.12.6). So what is wrong
with the quasiquote?

In regards to point (b), is it possible for me to determine that blob.f is is the def f
in the FuncBlob class.

Appreciate any pointers.
TIA


#2

You receive a tree that is already typed, so the tree for the selection has a symbol.


#3

@som-snytt Apologies for being so obtuse but I cannot understand what your trying to explain.
Are you saying that to get the type information I simple match the function on the tree and then
extract the type information with the tq on the matched tree.symbol?


#4

To see what function is being applied,

  def mImpl(c: Context)(f: c.Expr[() => Any]): c.Expr[String] = {
    import c.universe._

    val q"() => $x($p)" = f.tree
    c.Expr[String](Literal(Constant(x.symbol.fullName.toString)))
    //c.Expr[String](Literal(Constant(showRaw(f.tree))))
  }

#5

Thank you.