Scala 宏注释错误的解决方法
Workaround for Scala macro annotation bug
我有一个宏注释,用于将隐式类型 class 注入伴随方法。
@MyMacro case class MyClass[T](a: String, b: Int, t: T)
大部分时间它都按预期工作,但是当我使用类型约束符号时它会中断:
@MyMacro case class MyClass[T: TypeClass](a: String, b: Int, t: T)
// private[this] not allowed for case class parameters
这个错误是 and reported as a bug。
问题是:宏 (v1) 不再维护,所以我不能指望它会得到修复。
所以我想知道的是:我可以在宏中自己解决这个问题吗?这种对 AST 的更改是否以我可以以某种方式撤消的方式完成?我想尝试在宏中修复它,而不是强迫所有用户将他们的代码重写为 ...(implicit tc: TypeClass[T])
.
class AnnotationType() extends scala.annotation.StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro AnnotationTypeImpl.impl
}
class AnnotationTypeImpl(val c: blackbox.Context) {
import c.universe._
def impl(annottees: Tree*): Tree = {
val tree = annottees.head.asInstanceOf[ClassDef]
val newTree = tree match {
case ClassDef(mods, name, tparams, impl@Template(parents, self, body)) =>
val newBody = body.map {
case ValDef(mods, name, tpt, rhs) =>
// look here
// the flag of `private[this]` is Flag.PRIVATE | Flag.LOCAL
// the flag of `private` is Flag.PRIVATE
// drop Flag.LOCAL in Modifiers.flags , it will change `private[this]` to `private`
val newMods =
if(mods.hasFlag(Flag.IMPLICIT))
mods.asInstanceOf[scala.reflect.internal.Trees#Modifiers].&~(Flag.LOCAL.asInstanceOf[Long]).&~(Flag.CASEACCESSOR.asInstanceOf[Long]).asInstanceOf[Modifiers]
else
mods
ValDef(newMods, name, tpt, rhs)
case e => e
}
ClassDef(mods, name, tparams, Template(parents, self, newBody))
}
println(show(tree))
println(show(newTree))
q"..${newTree +: annottees.tail}"
}
}
// 测试
@AnnotationType()
case class AnnotationTypeTest[T: Option](a: T){
def option = implicitly[Option[T]]
}
object AnnotationTypeTest {
def main(args: Array[String]): Unit = {
implicit val x = Option(1)
println(AnnotationTypeTest(100))
println(AnnotationTypeTest(100).option)
println(AnnotationTypeTest(100).copy(a =2222))
println(AnnotationTypeTest(100).copy(a =2222)(Some(999)).option)
}
}
我有一个宏注释,用于将隐式类型 class 注入伴随方法。
@MyMacro case class MyClass[T](a: String, b: Int, t: T)
大部分时间它都按预期工作,但是当我使用类型约束符号时它会中断:
@MyMacro case class MyClass[T: TypeClass](a: String, b: Int, t: T)
// private[this] not allowed for case class parameters
这个错误是
问题是:宏 (v1) 不再维护,所以我不能指望它会得到修复。
所以我想知道的是:我可以在宏中自己解决这个问题吗?这种对 AST 的更改是否以我可以以某种方式撤消的方式完成?我想尝试在宏中修复它,而不是强迫所有用户将他们的代码重写为 ...(implicit tc: TypeClass[T])
.
class AnnotationType() extends scala.annotation.StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro AnnotationTypeImpl.impl
}
class AnnotationTypeImpl(val c: blackbox.Context) {
import c.universe._
def impl(annottees: Tree*): Tree = {
val tree = annottees.head.asInstanceOf[ClassDef]
val newTree = tree match {
case ClassDef(mods, name, tparams, impl@Template(parents, self, body)) =>
val newBody = body.map {
case ValDef(mods, name, tpt, rhs) =>
// look here
// the flag of `private[this]` is Flag.PRIVATE | Flag.LOCAL
// the flag of `private` is Flag.PRIVATE
// drop Flag.LOCAL in Modifiers.flags , it will change `private[this]` to `private`
val newMods =
if(mods.hasFlag(Flag.IMPLICIT))
mods.asInstanceOf[scala.reflect.internal.Trees#Modifiers].&~(Flag.LOCAL.asInstanceOf[Long]).&~(Flag.CASEACCESSOR.asInstanceOf[Long]).asInstanceOf[Modifiers]
else
mods
ValDef(newMods, name, tpt, rhs)
case e => e
}
ClassDef(mods, name, tparams, Template(parents, self, newBody))
}
println(show(tree))
println(show(newTree))
q"..${newTree +: annottees.tail}"
}
}
// 测试
@AnnotationType()
case class AnnotationTypeTest[T: Option](a: T){
def option = implicitly[Option[T]]
}
object AnnotationTypeTest {
def main(args: Array[String]): Unit = {
implicit val x = Option(1)
println(AnnotationTypeTest(100))
println(AnnotationTypeTest(100).option)
println(AnnotationTypeTest(100).copy(a =2222))
println(AnnotationTypeTest(100).copy(a =2222)(Some(999)).option)
}
}