0

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?

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
akunft
  • 3
  • 1

1 Answers1

0

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.

Eugene Burmako
  • 13,028
  • 1
  • 46
  • 59