0

I have a sequence, val xs: Seq[T], and a function f(xs: T*).

I'd like to write a macro that expands f(xs: _*) to f(x1, x2, ... xn) at compile time, but I'm having a lot of trouble successfully evaling the Expr in the macro. I've tried a few different approaches. scala.tools.reflect.ToolBox complains about c.universe not matching the runtime universe. c.eval(...) complains that the tree has already been typechecked, and running c.untypecheck just gives me more type errors.

Leo
  • 3,036
  • 3
  • 13
  • 12
  • Are you aware that a macro receives trees, and that repeating args are already supplied as a Seq? You might have better luck on gitter clarifying those questions. – som-snytt Sep 30 '16 at 04:48
  • If repeating args are supplied as a Seq at compile time, why does `f(xs)` fail to typecheck and `f(xs: _*)` succeed? What exactly is the `_*` doing? – Leo Sep 30 '16 at 22:57
  • In any case, if that's true the problem becomes evaluating and expanding a `Seq` into an argument list. – Leo Sep 30 '16 at 22:58

1 Answers1

1

"Sequence arg" defined http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#function-applications

Your macro sees https://github.com/scala/scala/blob/v2.12.0-RC1/src/reflect/scala/reflect/internal/TreeInfo.scala#L578

scala> import reflect.macros.blackbox.Context
import reflect.macros.blackbox.Context

scala> def f[A: c.WeakTypeTag](c: Context)(arg: c.Expr[A]*) = { import c.universe._ ; println(arg.map(x => showRaw(x.tree))) ; q"${arg.size}" } 
f: [A](c: scala.reflect.macros.blackbox.Context)(arg: c.Expr[A]*)(implicit evidence$1: c.WeakTypeTag[A])c.universe.Tree

scala> def g[A](arg: A*): Int = macro f[A]
defined term macro g: [A](arg: A*)Int

scala> val xs = List(1,2,3)
xs: List[Int] = List(1, 2, 3)

scala> g(xs, 42)
List(Select(Select(Select(Select(Ident($line16), $line16.$read), $line16.$read.$iw), $line16.$read.$iw.$iw), TermName("xs")), Literal(Constant(42)))
res0: Int = 2

scala> g(42, xs: _*)
List(Literal(Constant(42)), Typed(Select(Select(Select(Select(Ident($line16), $line16.$read), $line16.$read.$iw), $line16.$read.$iw.$iw), TermName("xs")), Ident(typeNames.WILDCARD_STAR)))
res1: Int = 2

scala> g(1,2,3)
List(Literal(Constant(1)), Literal(Constant(2)), Literal(Constant(3)))
res2: Int = 3

Runtime code sees:

scala> def count[A](as: A*): Int = as.size
count: [A](as: A*)Int

scala> count(xs)
res4: Int = 1

scala> count(xs: _*)
res5: Int = 3
som-snytt
  • 39,429
  • 2
  • 47
  • 129