I have a type T
known reflectively runtime as a value of scala.reflect.runtime.Type
. I would like to create a type value representing scala.collection.Seq[T]
. How can I do this?
A background what I want this for:
I want to be able to extract reflectively generic types contained in companion objects of various types. The types have a form of type As[T] = T
or type As[T] = Seq[T]
. I want to be able to get a concrete type in a form of X
or Seq[X]
for any X
. The first case is already working for me, as in that case I simply return a Type
of X
I already have. The second case is harder - I have a Type
for Seq[T]
which is generic and a Type
for a concrete X
, but I do not know how could I either modify the Seq[T]
I already have or create a brand new Seq[X]
.
import scala.reflect.runtime.universe._
object Wrap {
type As[T] = T
}
case class Wrap[T](value: T)
object WrapSeq {
type As[T] = Seq[T]
}
case class WrapSeq[T](value: Seq[T])
object Main extends App {
def checkType(typeSignature: Type): Type = {
// find mapping in the companion object
val companion = typeSignature.typeSymbol.companion
val member = companion.typeSignature.member(TypeName("As"))
if (member != NoSymbol && member.isType) {
val memberType = member.asType
def extractSingleType(types: Seq[Type]): Option[Type] = types match {
case Seq(head) => Some(head)
case _ => None
}
(memberType.typeParams, typeSignature.typeArgs) match {
case (Seq(typePar), Seq(typeArg)) if memberType.isAliasType =>
if (member.typeSignature.resultType.typeSymbol.fullName == typePar.fullName) {
// As[T] == T
typeArg
} else if (member.typeSignature.resultType.typeSymbol.fullName == "scala.collection.Seq" && extractSingleType(member.typeSignature.resultType.typeArgs).exists(_.typeSymbol.name == typePar.name)) {
// As[T] == Seq[T]
// we want to return Seq[typeArg] here
// we need to construct the type reflectively somehow
???
} else {
throw new UnsupportedOperationException(s"Unsupported As value $typePar for $typeSignature")
}
case _ => // no type parameter, handle the plain type
member.typeSignature
}
} else {
typeSignature
}
}
println(checkType(typeOf[Wrap[String]])) // output: String
println(checkType(typeOf[WrapSeq[String]])) // desired output: Seq[String]
}
Aucun commentaire:
Enregistrer un commentaire