2017-03-15 108 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