最后更新日期: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)
}
.Expr[Unit](Literal(Constant(())))
c}
}
Mod1.scala 一个模块里有一个 rpc 方法:
object Mod1 {
@rpcdef 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]
[Mod1.type]
genModule}
编译的时候先运行 scalac TestMacros.scala
,然后如果运行 scalac Mod1.scala Main.scala
则结果正确,但如果运行 scalac Main.scala Mod1.scala
则找不到 rpc
这个注解。用 sbt 编译的时候,因为 sbt 传给 scalac 的参数顺序是我们无法控制的(貌似是文件名按照字母表顺序排序),表现为有些时候宏找不到注解。
从 issue 的评论看是跟 scalac 内部的 lazy loading 机制有关,work around 是在宏里加入:
.typeSignature // force loading method's signature
m.annotations.foreach(_.tpe) // force loading all the annotations m