0
votes

I want to reify a ValDef into runtime, but i does not work directly. If i encapsulate the ValDef into a Block, everything works perfectly, like in the following example:

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
}

If i would use v directly, instead of wrapping it into a block, I get the error:

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
          ^

Is it just not working directly with ValDefs or is something wrong with my code?

1

1 Answers

0
votes

That's one of the known issues in the reflection API. Definitions are technically not expressions, so you can't e.g. pass them directly as arguments to functions. Wrapping the definition in a block is a correct way of addressing the block.

The error message is of course confusing, but it does make some twisted sense. To signify the fact that a definition by itself doesn't have a type, the tpe field of the corresponding Tree is set to NoType. Then the type of the argument of a macro is checked against Any and the check fails (because NoType is a special type, which isn't compatible with anything), so a standard error message is printed. The awkward printout is an artifact of how the prettyprinter behaves in this weird situation.