6

我在回答this question如何將一個無參數構造函數添加到具有宏註解的Scala案例類中?

而是寫的:

case class Person(name: String, age: Int) { 
    def this() = this("",1) 
} 

我想我會用宏註釋從展開:

@Annotation 
case class Person(name: String, age: Int) 

所以我嘗試添加新的構造函數作爲一個純老DefDef使用quasiquotes在宏註釋的impl中,如:

val newCtor = q"""def this() = this("", 1)""" 
val newBody = body :+ newCtor 
q"$mods class $name[..$tparams](..$first)(...$rest) extends ..$parents { $self => ..$newBody }" 

但是那個返回ns錯誤:called constructor's definition must precede calling constructor's definition

有沒有辦法解決這個問題?我錯過了什麼?

感謝您抽空看看, -Julian

回答

5

事實證明,一個很自然的意圖產生宏註釋二級構造暴露了兩個不同的問題。

1)第一個問題(https://issues.scala-lang.org/browse/SI-8451)是關於二次構造函數發出錯誤樹形的quasiquotes。在2.11.0-RC4(尚未發佈,目前以2.11.0-SNAPSHOT可用)和2.10.x(昨天發佈)的天堂2.0.0-M6中得到修復。

2)第二個問題是關於未指派的職位在typechecker期間造成嚴重破壞。奇怪的是,當typechecking調用構造函數時,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) 
+0

唉,我使用天堂2.0.0-M6爲2.10.3。 [Here](https://github.com/julianpeeters/macro-annotation-example/tree/no-args)是一個最小的可運行示例。並且[這裏](https://gist.github.com/julianpeeters/9888898)是M4中的錯誤。 –

+0

哦,我明白了。所以我們在這裏有兩個錯誤。一個由M6固定,另一個依然存在。 –

+2

https://github.com/julianpeeters/macro-annotation-example/pull/1 –

相關問題