[英]Scala macro does not compile when code is crafted without reify
我一直在研究復雜的編譯時反射,並遇到了使用AST手動制作Scala代碼的需求。 在進行實驗時,我注意到了一個奇怪的編譯錯誤,這對我來說真的沒有意義,因此我嘗試在測試項目中重現它。
我使用Scala 2.10.4 。
這是代碼:
Macro.scala:
object Macro {
def reifyTestImpl(c: Context): c.Expr[OffsetDateTime] = {
import c.universe._
val expression = reify(OffsetDateTime.now())
c.echo(c.enclosingPosition, "With reify: " + show(expression.tree))
c.echo(c.enclosingPosition, "With reify (raw): " + showRaw(expression.tree))
expression
}
def manualAstTestImpl(c: Context): c.Expr[OffsetDateTime] = {
import c.universe._
val odtSymbol = typeOf[OffsetDateTime].typeSymbol
val now = newTermName("now")
val expression = c.Expr(
Apply(
Select(Ident(odtSymbol), now),
List()
)
)
c.echo(c.enclosingPosition, "Manual: " + show(expression.tree))
c.echo(c.enclosingPosition, "Manual (raw): " + showRaw(expression.tree))
expression
}
def reifyTest = macro reifyTestImpl
def manualAstTest = macro manualAstTestImpl
}
Tester.scala:
object Tester {
def main(args: Array[String]): Unit = {
println(Macro.reifyTest)
println(Macro.manualAstTest)
}
}
c.echo
的輸出是:
With reify: OffsetDateTime.now()
With reify (raw): Apply(Select(Ident(java.time.OffsetDateTime), newTermName("now")), List())
Manual: OffsetDateTime.now()
Manual (raw): Apply(Select(Ident(java.time.OffsetDateTime), newTermName("now")), List())
我得到的編譯錯誤是value now is not a member of java.time.OffsetDateTime
調用上的Macro.manualAstTest
。
正如回聲的輸出所暗示的那樣,這兩個表達式是相同的-一個有效(來自reify
的表達式),另一個無效(由apply-select精心制作的表達式)。
兩者之間有什么區別?
設法找到罪魁禍首。
顯然, typeOf[OffsetDateTime].typeSymbol
返回的符號與從Scala類返回的符號相同,即沒有其靜態成員。
添加.companionSymbol
似乎返回的符號與從Scala對象返回的符號相同,即僅具有靜態成員(顧名思義...)
因此,以下更改使其起作用:
val odtSymbol = typeOf[OffsetDateTime].typeSymbol.companionSymbol
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.