我想将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 ,而不是将其包装到一个块中,我会收到错误:
Error:(10, 11) type mismatch; found : required: Any Note that extends Any, not AnyRef. Such types can participate in value classes, but instances cannot appear in singleton types or in reference comparisons. val x: Int = 10 ^
它是不是直接使用ValDefs还是我的代码有问题?
答案 0 :(得分:0)
这是反射API中的已知问题之一。定义在技术上不是表达式,因此您不能例如直接将它们作为参数传递给函数。在块中包装定义是解决块的正确方法。
错误信息当然令人困惑,但确实有些歪曲。为了表示定义本身没有类型,相应tpe
的{{1}}字段设置为Tree
。然后针对NoType
检查宏的参数类型,并且检查失败(因为Any
是一种特殊类型,它与任何东西都不兼容),因此标准错误消息是打印。令人尴尬的打印输出是漂亮打印机在这种奇怪情况下的表现。