简体   繁体   English

在未经验证的情况下编写代码时,Scala宏不会编译

[英]Scala macro does not compile when code is crafted without reify

I've been working on complex compile-time reflection and have come across the need to craft Scala code manually, using the AST. 我一直在研究复杂的编译时反射,并遇到了使用AST手动制作Scala代码的需求。 While experimenting I noticed a weird compilation error which doesn't really make sense to me, so I tried reproducing it on a test project. 在进行实验时,我注意到了一个奇怪的编译错误,这对我来说真的没有意义,因此我尝试在测试项目中重现它。

I use Scala 2.10.4 . 我使用Scala 2.10.4

Here's the code: 这是代码:

Macro.scala: 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: Tester.scala:

object Tester {
  def main(args: Array[String]): Unit = {
    println(Macro.reifyTest)
    println(Macro.manualAstTest)
  }
}

The output from c.echo is: 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())

The compilation error I get is value now is not a member of java.time.OffsetDateTime on the call to Macro.manualAstTest . 我得到的编译错误是value now is not a member of java.time.OffsetDateTime调用上的Macro.manualAstTest
As the output from the echoes suggests, the two expressions are identical - yet one works (the expression from reify ) and the other does not (the expression crafted with apply-select). 正如回声的输出所暗示的那样,这两个表达式是相同的-一个有效(来自reify的表达式),另一个无效(由apply-select精心制作的表达式)。

What could be the difference between the two? 两者之间有什么区别?

Managed to find the culprit. 设法找到罪魁祸首。
Apparently typeOf[OffsetDateTime].typeSymbol returns the symbol as would've returned from a Scala class, that is, without its static members. 显然, typeOf[OffsetDateTime].typeSymbol返回的符号与从Scala类返回的符号相同,即没有其静态成员。

Adding .companionSymbol seems to return the symbol as would've returned from a Scala object, that is, with only the static members (as the name implies...) 添加.companionSymbol似乎返回的符号与从Scala对象返回的符号相同,即仅具有静态成员(顾名思义...)

So the following change makes it work: 因此,以下更改使其起作用:

val odtSymbol = typeOf[OffsetDateTime].typeSymbol.companionSymbol

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM