2
votes

In a typed blackbox macro(implicit materializer), how do you check if a Type or Symbol is a tuple? There's the obvious solution of pattern matching or something like that, but is there an isTuple method that I can find anywhere?

So far I know I can do this:

def typed[A : c.WeakTypeTag]: Symbol = weakTypeOf[A].typeSymbol

object TupleSymbols {
  val tuple2 = typed[(_, _)]
  val tuple3 = typed[(_, _, _)]
  // ... and so on
}

Is there a more sane approach than the above monstrosity?

2
Check that name matches scala.Tuple\d*? - Alexey Romanov
@AlexeyRomanov Is that the best possible? Feels flimsy but doable. - flavian
I certainly would prefer it over defining tuple2 etc. but I don't know if there are better alternatives. - Alexey Romanov

2 Answers

1
votes

  import c.universe._
  import Flag._

  def tuple(i: Int) = {
    def list = (1 to i).toList
    c.typecheck(
      ExistentialTypeTree(
        tq"(..${list map (i => Ident(TypeName(s"_$i")))})", //just like (_,_, ...)
        list map (i =>
          TypeDef(Modifiers(DEFERRED | SYNTHETIC), TypeName(s"_$i"), List(), TypeBoundsTree(EmptyTree, EmptyTree))
          )
      )
    )
  }

//test

println(tuple(2).tpe <:< typeOf[(_, _)])//true 
println(tuple(3).tpe <:< typeOf[(_, _, _)])//true 

edit1 :

def asTuple(tpe: Type): Boolean = {
  def allTuple = 1 to 22 map { i =>
    val typeNames = 1 to i map (e => TypeName(s"_$e"))
    tq"(..$typeNames) forSome {..${typeNames.map(e => q"type $e")} }"
  } map (t => c.typecheck(t).tpe)

  allTuple.exists(_ <:< tpe)
}

//test

println(asTuple(typeOf[Int])) // false 
println(asTuple(typeOf[(_, _)])) // true 
println(asTuple(typeOf[(_, _,_)])) // true 
1
votes

As per the suggestion in the comments, this can be nicely handled with simple matching.

def isTuple(tpe: Type): Boolean = {
  tpe.typeSymbol.fullName.startsWith("scala.Tuple")
}