4

我正在尝试使用宏注释来注释类的构造函数值。假设实现了一个宏注解调用@identity,在类A的类定义中使用如下:

class A(@identity val foo: String, // causes error
        val bar: String) {
@identity val foobar: String = "" // doesn't cause error
}

当只是注释foobar一切编译就好了。但是,注释foo时出现以下编译时错误:

没有同伴的顶级类只能扩展为同名类或包含同名同伴的块

有人可以详细说明这个错误以及它发生的原因吗?

4

1 回答 1

3

我怀疑你调用宏

  import scala.annotation.{StaticAnnotation, compileTimeOnly}
  import scala.language.experimental.macros
  import scala.reflect.macros.whitebox

  @compileTimeOnly("enable macro paradise to expand macro annotations")
  class identity extends StaticAnnotation {
    def macroTransform(annottees: Any*): Any = macro identity.impl
  }

  object identity {
    def impl(c: whitebox.Context)(annottees: c.Tree*): c.Tree = {
      import c.universe._
      println(s"$annottees")
      q"..$annottees"
    }
  }

喜欢

  class A(@identity val foo: String,
          val bar: String) {
    @identity val foobar: String = ""
  }

  object A

然后你有错误

Warning:scalac: List(<paramaccessor> val foo: String = _, class A extends scala.AnyRef {
  <paramaccessor> val foo: String = _;
  <paramaccessor> val bar: String = _;
  def <init>(foo: String, bar: String) = {
    super.<init>();
    ()
  };
  @new identity() val foobar: String = ""
}, object A extends scala.AnyRef {
  def <init>() = {
    super.<init>();
    ()
  }
})
Warning:scalac: 
Warning:scalac: List(<paramaccessor> val foo: String = _, def <init>(foo: String, bar: String) = {
  super.<init>();
  ()
})
Warning:scalac: List(val foobar: String = "")
Error:(8, 12) top-level class with companion can only expand into a block consisting in eponymous companions
  class A(@identity val foo: String,
Error:(8, 12) foo is already defined as value foo
  class A(@identity val foo: String,
Error:(8, 12) foo  is already defined as value foo
  class A(@identity val foo: String,

问题是您接受一个类(可能还有伴随对象)并不仅返回它们,而且还val foo更改了顶级定义的数量/风格,这是被禁止的https://docs.scala-lang.org/overviews/macros /annotations.html

顶级扩展必须保留注释者的数量、他们的风格和他们的名字,唯一的例外是一个类可能会扩展成一个同名的类和一个同名的模块,在这种情况下,它们会按照之前的规则自动成为同伴.

例如,如果我们更改宏

   def impl(c: whitebox.Context)(annottees: c.Tree*): c.Tree = {
      import c.universe._
      println(s"$annottees")
      q"..${annottees.tail}" // addded tail
    }

然后一切都会编译。

于 2019-04-04T15:01:34.310 回答