【问题标题】:Workaround for Scala macro annotation bugScala 宏注释错误的解决方法
【发布时间】:2018-09-07 11:59:25
【问题描述】:

我有一个宏注释,用于将隐式类型类注入伴随方法。

@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

这个错误是described on SOreported as a bug

问题是:不再维护宏 (v1),所以我不能指望这会得到修复。

所以我想知道的是:我可以自己在宏中解决这个问题吗?这种对 AST 的更改是否以某种我可以撤消的方式进行?我想尝试在宏中修复它,而不是强制所有用户将他们的代码重写为...(implicit tc: TypeClass[T])

【问题讨论】:

    标签: scala scala-macros scala-macro-paradise


    【解决方案1】:
    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)
      }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多