8

我有点受阻于以下(宏注释)情况。假设我有一个名为的注解@factory,旨在为apply相应伴随对象中的注解特征生成一个方法。例如,给定trait A

@factory
trait A {
  val a1: Int
}

预期生成的代码如下:

object A extends Factory[A] {
  def apply(_a1: Int) = new A {
    val a1 = _a1
  }
}

现在假设我们有一个B继承自的特征A

@factory
trait B extends A {
  val b1: String
}

应该生成:

object B extends Factory[B] {
  def apply(_a1: Int, _b1: String) = new B {
    val a1 = _a1
    val b1 = _b1
  }
}

在后一种情况下,我需要知道存在于哪些属性A但我不知道如何获取有关它们的任何信息。在处理宏注释时,我只能访问B特征 AST(作为 a ClassDef)。尽管它template包含对父级的引用(as TypeTrees),但两个字段tpesymbol都是空的。

能够访问AAST 对我来说很棒。但是,我认为这是不可行的。因此,任何符号或类型(指向父类型或当前类型)都足够好。

如果您想查看更多实现细节,我已将项目上传到https://github.com/jesuslopez-gonzalez/cool-factory。它可以生成apply局部值。

4

1 回答 1

12

Trees that go into macro annotation arguments are purposefully untyped. However running c.typeCheck(q"(??? : <tree that represents the parent>)").tpe will provide the missing information. Don't forget to duplicate that tree before typechecking, because c.typeCheck mutates the tree in place, which might be undesireable.

In case when both parent and child are declared in the same non-toplevel scope, there will be a problem of typeCheck not seeing the parent, as c.typeCheck's in macro annotations are performed in parent lexical scope, so that annotations don't get to see half-constructed scopes. Something similar has been reported here: https://github.com/aztek/scala-workflow/issues/2#issuecomment-23947943.

The decision to exclude current scope from typechecking is not a final one. This week I'll be thinking a bit more about how macro annotations should interact with enclosing scopes, and will probably change it to do what you would like it to do. I'd do the change right now, but I need to make sure there won't be any insane behaviour arising from that change.

于 2013-10-16T09:00:15.137 回答