Search code examples
scalareflectionscala-reflect

How to reflect concrete return types for methods of classes defined at runtime using the Scala ToolBox?


When reflecting the foo() method of the class Cls we can easily get the concrete return type using the following.

class Cls {
  def foo() =
    List("A", "B")
}

val classType = ru.typeOf[Cls]
val classMirror = toolbox.mirror.reflectClass(classType.typeSymbol.asClass)
val ctorSymbol = classType.decl(ru.termNames.CONSTRUCTOR).asMethod
val methodSymb = classType.decl(ru.TermName("foo")).asMethod
val ctor = classMirror.reflectConstructor(ctorSymbol)
val instance = ctor()
val im = toolbox.mirror.reflect(instance)
val foo = im.reflectMethod(methodSymb)
println(foo())  // List(A, B)
println(methodSymb.returnType) // List[String]

However, if we define the class Cls at runtime via the toolbox and then use the same method reflection process, we will only get the abstract return type (List) of the foo() method.

import ru._

val tree =
  q"""class Cls {
        def foo() =
          List("A", "B")
    }""".asInstanceOf[ru.ClassDef]

val classSymbol = toolbox.define(tree).asClass
val classType = classSymbol.selfType

val classMirror = toolbox.mirror.reflectClass(classType.typeSymbol.asClass)
val ctorSymbol = classType.decl(ru.termNames.CONSTRUCTOR).asMethod
val methodSymb = classType.decl(ru.TermName("foo")).asMethod
val ctor = classMirror.reflectConstructor(ctorSymbol)
val instance = ctor()
val im = toolbox.mirror.reflect(instance)
val foo = im.reflectMethod(methodSymb)
println(foo())  // List("A", "B")
println(methodSymb.returnType)  // List

Why do these code snippets produce different results?

How can we reflect the concrete return type of the foo() method if Cls is defined at runtime using the toolbox?


Solution

  • I guess the thing is in type erasure.

    Try to replace

    val classType = classSymbol.selfType
    

    with

    val classType = toolbox.eval(q"scala.reflect.runtime.universe.typeOf[$classSymbol]").asInstanceOf[ru.Type]
    

    Then methodSymb.returnType is List[String].