在Scala宏中检查varargs类型归属

在Scala宏中检查varargs类型归属,scala,macros,variadic-functions,scala-2.10,scala-macros,Scala,Macros,Variadic Functions,Scala 2.10,Scala Macros,假设我有这个宏: import language.experimental.macros import scala.reflect.macros.Context object FooExample { def foo[A](xs: A*): Int = macro foo_impl[A] def foo_impl[A](c: Context)(xs: c.Expr[A]*) = c.literal(xs.size) } 这与“真实”varargs的预期效果一样: 但我对varargs

假设我有这个宏:

import language.experimental.macros
import scala.reflect.macros.Context

object FooExample {
  def foo[A](xs: A*): Int = macro foo_impl[A]
  def foo_impl[A](c: Context)(xs: c.Expr[A]*) = c.literal(xs.size)
}
这与“真实”varargs的预期效果一样:

但我对varargs类型的序列行为感到困惑(在Scala 2.10.0-RC3中):

为了证明推断的类型没有可疑之处:

scala> FooExample.foo[Int](List(1, 2, 3): _*)
res2: Int = 1
我希望这里会出现编译时错误,这就是我想要的。在我编写的大多数宏中,我都使用了以下方法:

object BarExample {
  def bar(xs: Int*): Int = macro bar_impl
  def bar_impl(c: Context)(xs: c.Expr[Int]*) = {
    import c.universe._
    c.literal(
      xs.map(_.tree).headOption map {
        case Literal(Constant(x: Int)) => x
        case _ => c.abort(c.enclosingPosition, "bar wants literal arguments!")
      } getOrElse c.abort(c.enclosingPosition, "bar wants arguments!")
    )
  }
}
这在编译时解决了问题:

scala> BarExample.bar(3, 2, 1)
res3: Int = 3

scala> BarExample.bar(List(3, 2, 1): _*)
<console>:8: error: bar wants literal arguments!
              BarExample.bar(List(3, 2, 1): _*)

但这是一种处理非常简单(我认为是广泛必要的)论证验证的丑陋方式。这里有我错过的把戏吗?我可以用什么最简单的方法来确保我的第一个示例中的
foo(1::Nil:*)
出现编译时错误?

这是否按预期工作

object BarExample {
  def bar(xs: Int*): Int = macro bar_impl
  def bar_impl(c: Context)(xs: c.Expr[Int]*) = { 
    import c.universe._
    import scala.collection.immutable.Stack
    Stack[Tree](xs map (_.tree): _*) match { 
      case Stack(Literal(Constant(x: Int)), _*) => c.literal(x)
      case _ => c.abort(c.enclosingPosition, "bar wants integer constant arguments!")
    }
  }
}

谢谢,但这与我的
BarExample
基本相同,并且在一般情况下不起作用。当您编写“我在这里可能会遇到编译时错误”时,您能澄清一下吗?您会认为这是一个错误,因为这是您的域的要求?或者这对于所有类型的vararg宏都应该是一个错误?@EugeneBurmako:我担心的是,在归属案例中,
xs.head
实际上并不是一个
c.Expr[a]
它更像是一个
c.Expr[Seq[a]
。给你。
scala> BarExample.bar(3, 2, 1)
res3: Int = 3

scala> BarExample.bar(List(3, 2, 1): _*)
<console>:8: error: bar wants literal arguments!
              BarExample.bar(List(3, 2, 1): _*)
object BazExample {
  def baz[A](xs: A*): Int = macro baz_impl[A]
  def baz_impl[A](c: Context)(xs: c.Expr[A]*) = {
    import c.universe._

    xs.toList.map(_.tree) match {
      case Typed(_, Ident(tpnme.WILDCARD_STAR)) :: Nil =>
        c.abort(c.enclosingPosition, "baz wants real varargs!")
      case _ => c.literal(xs.size)
    }
  }
}
object BarExample {
  def bar(xs: Int*): Int = macro bar_impl
  def bar_impl(c: Context)(xs: c.Expr[Int]*) = { 
    import c.universe._
    import scala.collection.immutable.Stack
    Stack[Tree](xs map (_.tree): _*) match { 
      case Stack(Literal(Constant(x: Int)), _*) => c.literal(x)
      case _ => c.abort(c.enclosingPosition, "bar wants integer constant arguments!")
    }
  }
}