0

I am creating some macro libraries that reads some information from annotation on the enclosing method.

@info(foo(bar, baz))
def enclosing() = {
  myMacro()
}

These information are encoded as foo(bar, baz) in a StaticAnnotation @info.

foo(bar, baz) contains information myMacro need, however, foo(bar, baz) is not able to type-check at the position @info, and cause compiler error when type-checking foo(bar, baz).

I wonder if I can create a macro dontTypecheck that prevent foo(bar, baz) being type checked. So that I can create something like:

@info(dontTypecheck {
  foo(bar, baz)
})
def enclosing() = {
  myMacro()
}

The dontTypecheck macro should produce a Tree that contains untype-checked foo(bar, baz).

How to create the dontTypecheck macro?

Yang Bo
  • 3,586
  • 3
  • 22
  • 35

1 Answers1

1

one idea is use another annotation save info

class Info[T](t: T) extends scala.annotation.StaticAnnotation {
}

class AnnInfo extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro AnnInfImpl.impl
}

trait AnnotationUtils {
  val c: scala.reflect.macros.blackbox.Context

  import c.universe._

  final def getAnnotation(x: MemberDef) = x.mods.annotations


}

class AnnInfImpl(val c: blackbox.Context) extends AnnotationUtils {

  import c.universe._
  // edit 1 
  def impl(annottees: Tree*): Tree = {
    annottees.head match {
      case x: DefDef =>
        // collect value from `@Info(value)`
        val info: List[Tree] = getAnnotation(x).collect { case q"new $name ($value)" => value }
        val newBody  =
          q"""
              {
                val info = ${info.map(e => show(e))}
                println(info)// just print it
                ${x.rhs}
              }"""
        DefDef(
          mods = Modifiers(), //dropMods
          name = x.name,
          tparams = x.tparams,
          vparamss = x.vparamss,
          tpt = x.tpt,
          rhs = newBody
        )
    }
  }
}

// test

class AnnInfoTest {
  val a = 1
  val b = 2

  def f(a: Int, b: Int) = a + b


  @Info(f(a, b))
  @AnnInfo
  def e = ???
}

if you call e will print List(f(a, b))

余杰水
  • 1,404
  • 1
  • 11
  • 14
  • Does it work if you delete `def f(a: Int, b: Int) = a + b`? – Yang Bo Mar 05 '17 at 05:37
  • It compiles because the macro annotation `@AnnInfo` deleted `@Info(f(a, b))`. How can I recall the `@Info` in a macro inside `e` after `@Info` is deleted? – Yang Bo Mar 07 '17 at 03:26
  • see edit 1 ; how to use `value`( extract from `@Info(value)`) inside `e` ; but i am not sure it is you want ? – 余杰水 Mar 07 '17 at 03:56
  • I think the problem is how to pass an untyped tree to a typed def macro... – Yang Bo Mar 07 '17 at 07:15
  • sorry, i have not idea :( – 余杰水 Mar 07 '17 at 07:33
  • I think your solution is fine. I guess explicitly setting type on a `Tree` would prevent its children being type-checked. So I guess your solution works if replacing `show(e)` to something like `e.setSymbol(xxx); q"myMacro($e)"` or `e.tpe = xxx; q"myMacro($e)"` – Yang Bo Mar 07 '17 at 10:16