mixel
mixel

Reputation: 25836

Get generic value class parameter type via reflection

I want to get real Type of generic value class parameter. I tried:

import scala.reflect.runtime.universe._

case class Test[T](value: T) extends AnyVal

object Main extends App {
  val tag = implicitly[TypeTag[Test[String]]]
  val constructor = tag.tpe.members.collect {
    case m: MethodSymbol if m.isPrimaryConstructor => m
  }.headOption
  val constructorParams = constructor.map(_.paramLists.flatten).collect {
    case param :: Nil => param
  }
  constructorParams.map(_.typeSignature).foreach(println)
}

but it prints:

T

I know that I can get type arguments with:

tag.tpe.typeArgs.foreach(println)

which outputs:

String

but Test class can be defined like that:

case class Test[T](value: List[T]) extends AnyVal

so type of type argument and parameter type are different.

How can I do this?

Upvotes: 2

Views: 513

Answers (1)

Lukas Rytz
Lukas Rytz

Reputation: 1894

There's an operation in the compiler called "as seen from" which returns the type of a member with respect to a specific owner type.

Here's an example in a REPL session:

Welcome to Scala 2.12.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_102).
Type in expressions for evaluation. Or try :help.

scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._

scala> case class Test[T](value: List[T]) extends AnyVal
defined class Test

scala> val tp = typeOf[Test[String]]
tp: reflect.runtime.universe.Type = Test[String]

scala> val cls = tp.typeSymbol
cls: reflect.runtime.universe.Symbol = class Test

scala> val constructor = tp.members.collect({case m: MethodSymbol if m.isPrimaryConstructor => m}).head
constructor: reflect.runtime.universe.MethodSymbol = constructor Test

scala> constructor.info.asSeenFrom(tp, cls).paramLists.head.head.info
res0: reflect.runtime.universe.Type = scala.List[String]

scala> // alternatively

scala> constructor.infoIn(tp).paramLists.head.head.info
res1: reflect.runtime.universe.Type = scala.List[String]

Upvotes: 1

Related Questions