如何向带有宏注释的Scala case类添加无参数构造函数?
我正试着回答 而不是写:如何向带有宏注释的Scala case类添加无参数构造函数?,scala,constructor,scala-macros,case-class,scala-quasiquotes,Scala,Constructor,Scala Macros,Case Class,Scala Quasiquotes,我正试着回答 而不是写: case class Person(name: String, age: Int) { def this() = this("",1) } 我想我应该使用宏注释来扩展它: @Annotation case class Person(name: String, age: Int) 因此,我尝试在宏注释的impl中使用quasiquetes将新构造函数添加为普通的旧DefDef,如: val newCtor = q"""def this() = this("", 1
case class Person(name: String, age: Int) {
def this() = this("",1)
}
我想我应该使用宏注释来扩展它:
@Annotation
case class Person(name: String, age: Int)
因此,我尝试在宏注释的impl中使用quasiquetes将新构造函数添加为普通的旧DefDef
,如:
val newCtor = q"""def this() = this("", 1)"""
val newBody = body :+ newCtor
q"$mods class $name[..$tparams](..$first)(...$rest) extends ..$parents { $self => ..$newBody }"
但这会返回一个错误:调用构造函数的定义必须在调用构造函数的定义之前
有办法解决这个问题吗?我错过了什么
谢谢您的关注,
-Julian事实证明,在宏注释中生成二级构造函数的自然意图暴露了两个不同的问题 1) 第一个问题()是关于准量子为二级构造函数发出错误的树形状。这在2.11.0-RC4(尚未发布,目前作为2.11.0-SNAPSHOT提供)和paradise 2.0.0-M6(昨天发布)中得到了修复 2) 第二个问题是关于在typechecker期间未分配的位置造成的严重破坏。奇怪的是,当对构造函数进行类型检查调用时,typer使用位置来决定这些调用是否合法。这不是那么容易修补的,我们必须解决:
val newCtor = q"""def this() = this(List(Some("")))"""
- val newBody = body :+ newCtor
+
+ // It looks like typer sometimes uses positions to decide whether stuff
+ // (secondary constructors in this case) typechecks or not (?!!):
+ // https://github.com/xeno-by/scala/blob/c74e1325ff1514b1042c959b0b268b3c6bf8d349/src/compiler/scala/tools/nsc/typechecker/Typers.scala#L2932
+ //
+ // In general, positions are important in getting error messages and debug
+ // information right, but maintaining positions is too hard, so macro writers typically don't care.
+ //
+ // This has never been a problem up until now, but here we're forced to work around
+ // by manually setting an artificial position for the secondary constructor to be greater
+ // than the position that the default constructor is going to get after macro expansion.
+ //
+ // We have a few ideas how to fix positions in a principled way in Palladium,
+ // but we'll have to see how it goes.
+ val defaultCtorPos = c.enclosingPosition
+ val newCtorPos = defaultCtorPos.withEnd(defaultCtorPos.endOrPoint + 1).withStart(defaultCtorPos.startOrPoint + 1).withPoint(defaultCtorPos. point + 1)
+ val newBody = body :+ atPos(newCtorPos)(newCtor)
唉,我在用天堂2.0.0-M6来制作2.10.3这是一个最小的可运行示例。这就是M4中的错误。哦,我明白了。我们这里有两个虫子。一个由M6修复,另一个仍然存在。看起来双注释类的解决方案也成功了,只要
@NewCtorAnnotation
紧跟在注释对象之前。但是,如果@AnotherAnnotation
介于两者之间,则会返回相同的错误(这对我来说不是问题,仅供参考)。