3

I have the following macro

object Example {
  def doIt(s: String): String = macro doItImpl

  def doItImpl(c: Context)(s: c.Expr[String]): c.Expr[String] = {
    import c.{ universe => u }
    import u._
    ???
  }
}

Instead of the ??? I would like to inspect the line where the method doIt was called to check if the result of the method was used (in an assignment, method call or whatever). If the result is not used I respond with an error-message.

Call-example:

val s: String = doIt("Hallo") // alright
doIt("Hallo") // ERROR!

Is there a simple way to get the Tree of the whole line?

Erik
  • 2,888
  • 2
  • 18
  • 35
  • See [this somewhat similar question](http://stackoverflow.com/q/18450203/334519), the comments there, and [my answer](http://stackoverflow.com/a/18451114/334519) for some ideas. – Travis Brown Dec 08 '13 at 15:47
  • @TravisBrown I'm going to stay up late this Christmas Eve to try and catch Travis bringing macro answers to all the good girls and boys. – som-snytt Dec 08 '13 at 16:34

1 Answers1

4

For completeness, here's a lightly adapted version of the solution I mention above:

import scala.language.experimental.macros
import scala.reflect.macros.Context

object Example {
  def doIt(s: String): String = macro doItImpl

  def doItImpl(c: Context)(s: c.Expr[String]): c.Expr[String] = {
    import c.universe._

    c.enclosingClass.collect {
      case ValDef(_, name, _, rhs) if rhs.pos == c.macroApplication.pos =>
        c.literal(s"Okay, defining a variable named ${name.decoded}.")
    }.headOption.getOrElse(
      c.abort(c.enclosingPosition, "Not a valid application.")
    )
  }
}

Now in a REPL:

scala> import Example._
import Example._

scala> object Test1 { val x = doIt("foo") }
defined module Test1

scala> Test1.x
res0: String = Okay, defining a variable named x.

And in the case that we don't have an definition:

scala> object Test2 { doIt("foo") }
<console>:13: error: Not a valid application.
       object Test2 { doIt("foo") }
                          ^

As expected. See the comments on the question linked above for some caveats, but unless your real use case is much more complicated, this approach should work fine.

Community
  • 1
  • 1
Travis Brown
  • 138,631
  • 12
  • 375
  • 680
  • That addresses a part of the problem. I was aiming for something like the warning you get when typing `1 + 2` (a pure expression does nothing in statement position; you may be omitting necessary parentheses). This is very difficult to achieve with extractors like `ValDef`. I guess there isn't another way? – Erik Dec 12 '13 at 12:41