Macros: accessing Function from a val defined function

I am trying to collect and use a function’s name and argument/parameter names.
For functions defined with a def I can successfully match on these AST elements:

Function(params, _)

However when I define something like:

val h: Int => Double = (a:Int) => (2*a).toDouble

and try and analyze h, I can only match on:


So my question is: is their a way for me to access the definition of the function h above? More concretely how can I know that h has the parameter a of type Int.


let’s look at the tree shape:

% scala
Welcome to Scala 2.12.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_192).

scala 2.12.8> :power
Power mode enabled. :phase is at typer.
import,, definitions._
Try :help or completions for vals._ and power._

scala 2.12.8> global.reify { val h: Int => Double = (a:Int) => (2*a).toDouble }
res0: $[Unit] =
  val h: Function1[Int, Double] = ((a: Int) => 2.$times(a).toDouble);

scala 2.12.8> println(
    AppliedTypeTree( // abstract trait Function1[-T1, +R] extends AnyRef in package scala
      "Function1" // abstract trait Function1[-T1, +R] extends AnyRef in package scala
      // 2 type arguments
      "Int" // final abstract class Int extends AnyVal in package scala
      "Double" // final abstract class Double extends AnyVal in package scala
        "Int" // final abstract class Int extends AnyVal in package scala

It appears that the shape you’ll need to recognize is an outer ValDef (where you’ll find the val name) whose right-hand-side is a Function. Inside that Function is another ValDef that has the parameter names.

Well, and I should probably also go on and say, if your macro is running in a context where all you have is a reference to h, then I think you’re out of luck. When you val h = ..., the right-hand-side can be literally any expression with the right type, and needn’t be a lambda, and the compiler won’t record any information about the specifics of that right-hand-side within h itself.

If you absolutely need to do this kind of global analysis (I say global because h could be defined anywhere), perhaps you need to be writing a compiler plugin rather than a macro. Although even that won’t necessarily help you unless you can count on h being defined in the same compilation unit, which you can’t count on in general.

Appreciate the feedback. Indeed all I have is the val h. I am attempting to record information on functions that are passed via parameters. I guess I will have to simply fail when a val is used because they can be define in any compilation unit.