1

Scala allows pattern matching on varargs for unapplySeq:

case class A(args: String*)

A("a", "b", "c") match {
  case A(args @ _*) => args  // Seq("a", "b", "c")
}

I want to generate such pattern with macros. How should I do it? A natural thing to try does not work:

scala> pq"x @ _*"
<console>:11: error: illegal start of simple pattern
              pq"x @ _*"
                       ^

It is possible to extract the actual type from a q pattern, however, and recreate the pattern with it:

scala> val q"??? match { case Hello($ident @ $thingy) => }" = q"??? match { case Hello(any @ _*) => }"
ident: reflect.runtime.universe.Name = any
thingy: reflect.runtime.universe.Tree = (_)*

scala> pq"$ident @ $thingy"
res1: reflect.runtime.universe.Bind = (any @ (_)*)

But this is too hacky and I don't want to do it.

Denys Shabalin
  • 1,696
  • 12
  • 12
Vladimir Matveev
  • 120,085
  • 34
  • 287
  • 296

2 Answers2

1

The reason why quasiquotes don't support pq"x @ _*" lies in the way pattern syntax is defined. The grammar of the language defines pattern syntax through Pattern production rule. As one can see _* is actually not a valid pattern by itself, it only works inside special Patterns production rule, that is used to model a sequence of patterns inside extractors.

Quasiquotes let you plug into different contexts in the grammar through variety of interpolators. Unfortunately we can not support all possible contexts as this would have caused us to have hundreds of interpolators in the API.

The simplest solution is indeed to use Star(Ident(termNames.WILDCARD)) here.

Denys Shabalin
  • 1,696
  • 12
  • 12
0

Oh well, I've forgotten about showRaw():

scala> showRaw(thingy)
res0: String = Star(Ident(termNames.WILDCARD))

Now I'll just make it a constant and use it instead of some literal pattern:

val wcard = Star(Ident(termNames.WILDCARD))

pq"$someIdent @ $wcard"

While awkward, it seems to be the best approach given that quasiquotes do not work.

Vladimir Matveev
  • 120,085
  • 34
  • 287
  • 296