从编译到运行时具体化一个ValDef



我想将ValDef具体化到运行时,但它不能直接工作。如果我将ValDef封装到一个Block中,一切都可以完美地工作,就像下面的例子一样:

case class Container(expr: Expr[Any])
def lift(expr: Any): Container = macro reifyValDef
def reifyValDef(c: Context)(expr: c.Expr[Any]): c.Expr[Container] = {
  import c.universe._
  expr.tree match {
  case Block(List(v: ValDef), _) =>
    val asBlock = q"{$v}"
    val toRuntime = q"scala.reflect.runtime.universe.reify($asBlock)"
    c.Expr[Container](q"Container($toRuntime)")
  }
}
lift {
  val x: Int = 10
}

如果我直接使用v,而不是将其包装到一个块中,我会得到错误:

<>之前错误:(10,11)类型不匹配;发现:要求:任何注意,它扩展Any,而不是AnyRef。这些类型可以参与值类,但不能参与实例不能出现在单例类型或引用比较中。val x: Int = 10^之前

它只是不直接与ValDefs工作还是我的代码有问题?

这是反射API中已知的问题之一。定义在技术上不是表达式,所以你不能直接将它们作为参数传递给函数。将定义包装在块中是对块寻址的正确方法。

错误信息当然令人困惑,但它确实有一些扭曲的意义。为了表示定义本身没有类型,将相应的Treetpe字段设置为NoType。然后根据Any检查宏参数的类型,检查失败(因为NoType是一种特殊类型,它与任何东西都不兼容),因此打印一条标准错误消息。奇怪的打印输出是漂亮打印机在这种奇怪情况下的行为。

相关内容

  • 没有找到相关文章

最新更新