2017-03-15 154 views
0

我一直在進行復雜的編譯時反射,並且遇到了需要使用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()) 

編譯在致電Macro.manualAstTest時,我收到的錯誤是value now is not a member of java.time.OffsetDateTime
由於回聲的輸出表明,這兩個表達式是相同的 - 但一個作品(表達從reify),另一個沒有(用apply-select製作的表達)。

這兩者有什麼區別?

回答

0

管理找到罪魁禍首。
顯然typeOf[OffsetDateTime].typeSymbol返回從Scala類返回的符號,也就是沒有它的靜態成員。

添加.companionSymbol似乎返回符號爲將已經從Scala的對象返回,也就是說,只有靜態成員(顧名思義...)

所以下面的變化使得它的工作:

val odtSymbol = typeOf[OffsetDateTime].typeSymbol.companionSymbol