Getting type information inside scala repl via IMain
reflection, scala, scala-2.10
Solution
How about this? I'm using power mode which gives you access to the global from the currently running REPL, which is a shade more convenient than creating a new `IMain`.
scala> :power
Already in power mode.
scala> val g = global
g: $r.intp.global.type = <global>
scala> val context = g.analyzer.rootContext(NoCompilationUnit)
context: g.analyzer.Context = Context(<root>@EmptyTree unit=NoCompilationUnit scope=997093283 errors=false, reportErrors=true, throwErrors=false)
// aware imports of scala._, etc.
scala> val sym = context.lookupSymbol("Option": TypeName, _ => true).symbol
sym: g.analyzer.global.Symbol = class Option
scala> sym.tpeHK.typeParams
res21: List[g.analyzer.global.Symbol] = List(type A)
See also:
scala> intp.symbolOfType("Foo")
res26: $r.intp.global.Symbol = class Foo
But I'm not sure how to get at previously imported symbols:
scala> object Bar { class Bop }
defined object Bar
scala> import Bar.Bop
import Bar.Bop
scala> intp.symbolOfType("Bop")
res27: $r.intp.global.Symbol = <none>
Edit:
The reason OP's getting `ClassInfoType` instead of `PolyType` is due to phase. To get the same result as the power mode's `global`, one must set the phase to `typer`. To quote @retronym's explanation from REPL: intp.global vs "global" available in :power mode:
scala> :power
** Power User mode enabled - BEEP WHIR GYVE **
** :phase has been set to 'typer'. **
^
`---- this part is relevant
Symbols have an list of types (aka `info`-s), indexed by compiler phase. (aka TypeHistory). Many compiler phases install `InfoTransformer`s to morph the type. See src/compiler/scala/tools/nsc/transform/InfoTransform.scala for some documentation.
To inspect the type as-at particular phase, you can use methods like 'exitingTyper`.
scala> exitingPostErasure($intp.global.rootMirror.staticClass("scala.Option").typeSignature).getClass
res6: Class[_ <: $intp.global.Type] = class scala.reflect.internal.Types$ClassInfoType
scala> exitingTyper($intp.global.rootMirror.staticClass("scala.Option").typeSignature).getClass
res7: Class[_ <: $intp.global.Type] = class scala.reflect.internal.Types$PolyType
Or, a little more conveniently in :power mode:
scala> :phase typer
Active phase is now: Typer
scala> global.rootMirror.staticClass("scala.Option").typeSignature.getClass
res16: Class[_ <: $r.global.Type] = class scala.reflect.internal.Types$PolyType
scala> :phase cleanup
Active phase is now: Cleanup
scala> global.rootMirror.staticClass("scala.Option").typeSignature.getClass
res17: Class[_ <: $r.global.Type] = class scala.reflect.internal.Types$ClassInfoType
Problem
Intent I am trying to add support for `:kind` command to scala repl. Thanks to Eugene Burmako, I was able to get a working prototype. Though it only works with fully qualified names and fails to resolve imported names. I am now trying to use `IMain.exprTyper` to do the job, as it is aware of types, imported into the repl. But there is a problem. Everything I've tried returns a `ClassInfoType` like the following (displayed with `showRaw`): ``` ClassInfoType(List(TypeRef(TypeRef(TypeRef(TypeRef(NoPrefix(), package <root>, List()), package java, List()), package lang, List()), class Object, List()), TypeRef(TypeRef(TypeRef(NoPrefix(), package <root>, List()), package scala, List()), trait Serializable, List())), Scope{ def <init>(): Option.type; implicit def option2Iterable(xo: Option): Iterable; def apply(x: Object): Option; def empty(): Option; private def readResolve(): Object }, object Option) ``` While the working implementation returns specific `Type`: ``` PolyType(List(TypeName("A")), ClassInfoType(List(TypeRef(ThisType(scala), TypeName("AnyRef"), List()), TypeRef(ThisType(scala), scala.Product, List()), TypeRef(ThisType(scala), scala.Serializable, List())), Scope(nme.CONSTRUCTOR, TermName("isEmpty"), TermName("isDefined"), TermName("get"), TermName("getOrElse"), TermName("orNull"), TermName("map"), TermName("fold"), TermName("flatMap"), TermName("flatten"), TermName("filter"), TermName("filterNot"), TermName("nonEmpty"), TermName("withFilter"), TypeName("WithFilter"), TermName("contains"), TermName("exists"), TermName("forall"), TermName("foreach"), TermName("collect"), TermName("orElse"), TermName("iterator"), TermName("toList"), TermName("toRight"), TermName("toLeft")), scala.Option)) ``` Question I feel like I'm really close. Here's a playground, you can use to try everything yourself: ``` Welcome to Scala version 2.11.0-20130328-093148-47645c7e7e (OpenJDK 64-Bit Server VM, Java 1.7.0_17). Type in expressions to have them evaluated. Type :help for more information. scala> import scala.reflect.runtime.universe._ import scala.reflect.runtime.universe._ scala> import scala.tools.nsc.interpreter.IMain import scala.tools.nsc.interpreter.IMain scala> val mirror = runtimeMirror(getClass.getClassLoader) // Working approach mirror: reflect.runtime.universe.Mirror = JavaMirror with scala.tools.nsc.interpreter.IMain$TranslatingClassLoader@3d34ec98 of type class scala.tools.nsc.interpreter.IMain$TranslatingClassLoader with classpath [<unknown>] and parent being scala.tools.nsc.util.ScalaClassLoader$URLClassLoader@5d990e8c of type class scala.tools.nsc.util.ScalaClassLoader$URLClassLoader with classpath [file:/usr/lib/jvm/java-7-openjdk/jre/lib/resources.jar,file:/usr/lib/jvm/java-7-openjdk/jre/lib/rt.jar,file:/usr/lib/jvm/java-7-openjdk/jre/lib/jsse.jar,file:/usr/lib/jvm/java-7-openjdk/jre/lib/jce.jar,file:/usr/lib/jvm/java-7-openjdk/jre/lib/charsets.jar,file:/usr/lib/jvm/java-7-openjdk/jre/lib/rhino.jar,file:/home/folone/workspace/scala-myfork/build/pack/lib/jline.jar,file:/home/folone/workspace/scala-myfork... scala> val typer = new IMain().exprTyper // Not working approach typer: scala.tools.nsc.interpreter.IMain#exprTyper.type = scala.tools.nsc.interpreter.IMain$exprTyper$@68c181f0 scala> val expr = "scala.Option" expr: String = scala.Option scala> showRaw(mirror.staticClass(expr).toType.typeSymbol.typeSignature) // Correct signature res6: String = PolyType(List(TypeName("A")), ClassInfoType(List(TypeRef(ThisType(scala), TypeName("AnyRef"), List()), TypeRef(ThisType(scala), scala.Product, List()), TypeRef(ThisType(scala), scala.Serializable, List())), Scope(nme.CONSTRUCTOR, TermName("isEmpty"), TermName("isDefined"), TermName("get"), TermName("getOrElse"), TermName("orNull"), TermName("map"), TermName("fold"), TermName("flatMap"), TermName("flatten"), TermName("filter"), TermName("filterNot"), TermName("nonEmpty"), TermName("withFilter"), TypeName("WithFilter"), TermName("contains"), TermName("exists"), TermName("forall"), TermName("foreach"), TermName("collect"), TermName("orElse"), TermName("iterator"), TermName("toList"), TermName("toRight"), TermName("toLeft")), scala.Option)) scala> showRaw(typer.typeOfExpression(expr).typeSymbol.typeSignature) // Wrong signature res7: String = ClassInfoType(List(TypeRef(TypeRef(TypeRef(TypeRef(NoPrefix(), package <root>, List()), package java, List()), package lang, List()), class Object, List()), TypeRef(TypeRef(TypeRef(NoPrefix(), package <root>, List()), package scala, List()), trait Serializable, List())), Scope{ def <init>(): Option.type; implicit def option2Iterable(xo: Option): Iterable; def apply(x: Object): Option; def empty(): Option; private def readResolve(): Object }, object Option) ``` How do I transform `ClassInfoType` into a valid `Type` containing the needed info? Alternatively, how do I get the `Type` using `IMain` in the first place?