带有导入语句的 Scala 宏不起作用

标签 scala scala-macros scala-macro-paradise

我正在注释一个特征,例如:

@ScreenModel
trait TestTrait {
  .......
}

然后我得到了@ScreenModel 的实现,类似:

def impl(c: whitebox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._

val output : List[Tree] = annottees.map(_.tree) match {
  case(cd @ q"$mods trait $name[..$tparams] extends ..$parents { ..$body }") :: Nil =>

    val compObjVar = s"""{
        import models.presentation.blocks.BlockModel;
        class AAAA {
          class BBBB {

          }
        }
    }""";

    val rawTree=c.parse(compObjVar)

    val merged = q"{..$rawTree}";
    merged :: Nil
  case _ => c.abort(c.enclosingPosition, "Invalid test target")
}
c.Expr[Any](q"..$output")
}

因此,我得到:

“没有同伴的顶级类只能扩展为同名类或 block ”

但是,如果我将导入移动到 AAA 类中的 AAA 类之前,那么它会起作用:

    val compObjVar = s"""{
        class AAAA {
          import models.presentation.blocks.BlockModel;
          class BBBB {

          }
        }
    }""";

为什么?

最佳答案

它打破了 documentation 的这条规则:

Top-level expansions must retain the number of annottees, their flavors and their names, with the only exception that a class might expand into a same-named class plus a same-named module, in which case they automatically become companions as per previous rule.

这意味着,如果您要转换带有宏注释的类或特征,则它必须扩展为同名类,或具有同名伴随类的类。也就是说,我们保留正在扩展的树的根。

如果我们尝试将 class A 扩展为:

import package.name
class A

我们正在扩展的树的根不再是 class A 的根,而是包含类和新导入的树,但它是什么?不可能什么都没有。减少可能的扩展数量会降低插件的复杂性,从而减少可能出错的数量。

如果必须添加导入,可以在类中进行。如果导入需要同时出现在类和伴生对象中,则可以将它们分解到它们自己的 Tree 中以进行拼接。

关于带有导入语句的 Scala 宏不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37534343/

相关文章:

java - Akka BalancingDispatcher 配置

multithreading - 在函数式编程中如何避免副作用

scala - Scala宏可以打印代码?

scala - 新式 ("inline") 宏需要 scala.meta

scala - 如何评估 Scala 宏中的表达式?

scala - 如何区分宏中的三引号和单引号?

scala - Scala 中的选项 monad

scala - 同时使用 Shapeless 和 Scalaz 6 - 导入冲突

Scala 宏的快捷方式

Scala 宏 : Define Top Level Object