在没有reify的情况下编写代码时,Scala宏不会编译

时间:2017-03-15 21:23:50

标签: scala reflection macros scala-reflect

我一直致力于复杂的编译时反射,并且需要使用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制作的表达式)。

两者之间可能有什么区别?

1 个答案:

答案 0 :(得分:0)

管理找到罪魁祸首 显然typeOf[OffsetDateTime].typeSymbol会返回从Scala类返回的符号,即没有静态成员。

添加.companionSymbol似乎返回了从Scala对象返回的符号,即只有静态成员(顾名思义......)

因此,以下更改使其有效:

val odtSymbol = typeOf[OffsetDateTime].typeSymbol.companionSymbol