Scala bug:宏无法获取注解

最后更新日期:2014-08-25

  最近花了 n 小时调试一段 Scala 代码最后发现原来是 Scala 编译器的 bug:SI-7424。而且截至目前(2014-08-25),该 bug 仍然处于 Unresolved 状态。

  这个 bug 发生在用宏(macro)获取某个类的注解(annotation)的时候。重现方法如下(环境 Scala 2.10.4, 2.11.2):

  TestMacros.scala 定义了 rpc 这个注解,然后在一个宏中获取注解:

import scala.reflect.macros.Context

import scala.annotation.ClassfileAnnotation

class rpc extends ClassfileAnnotation

object TestMacros {
  def genModule_impl[T: c.WeakTypeTag](c: Context): c.Expr[Unit] = {
    import c.universe._
    val t = c.weakTypeOf[T]
    for (method <- t.declarations) {
      println(method.fullName + ": " + method.annotations)
    }
    c.Expr[Unit](Literal(Constant(())))
  }
}

  Mod1.scala 一个模块里有一个 rpc 方法:

object Mod1 {
  @rpc
  def add(a: Int, b: Int) = a + b
}

  Main.scala 主程序,调用宏:

import scala.language.experimental.macros

object Main extends App {

  def genModule[T] = macro TestMacros.genModule_impl[T]

  genModule[Mod1.type]
}

  编译的时候先运行 scalac TestMacros.scala ,然后如果运行 scalac Mod1.scala Main.scala 则结果正确,但如果运行 scalac Main.scala Mod1.scala 则找不到 rpc 这个注解。用 sbt 编译的时候,因为 sbt 传给 scalac 的参数顺序是我们无法控制的(貌似是文件名按照字母表顺序排序),表现为有些时候宏找不到注解。

  从 issue 的评论看是跟 scalac 内部的 lazy loading 机制有关,work around 是在宏里加入:

m.typeSignature // force loading method's signature
m.annotations.foreach(_.tpe) // force loading all the annotations