Getting type information inside scala repl via IMain

Intention

I am trying to add support for the command :kind in scala repl. Thanks to Eugene Burmako, I managed to get a working prototype. Although it only works with fully qualified names and does not allow imported names.

Now I'm trying to use IMain.exprTyper to do the job, since it knows the types imported into repl. But there's a problem. All I tried returns a ClassInfoType as shown below (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 a 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

It seems to me that I'm really close. Here is a playground that 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@3d34ec9 8 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 to convert ClassInfoType to a valid Type containing the necessary information? Alternatively, how do I get Type using IMain in the first place?

+6
source share
2 answers

How about this? I use a power mode that gives you access to the global from the current REPL, which is 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 to previously imported characters:

 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 for getting OP ClassInfoType instead of PolyType is due to phase. To get the same result as the global power mode, you need to set the phase to typer . To quote @retronym explanation from REPL: intp.global vs "global" is 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 a list of types (aka info -s) indexed by the compiler phase. (aka TypeHistory). In many phases of the compiler, install InfoTransformer to convert the type. See Src / compiler / scala / tools / nsc / transform / InfoTransform.scala for some documents.

To check the type as in a specific phase, you can use methods such as "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 convenient 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 
+3
source

You should use the mirror from IMain global:

 scala> val imain = new IMain() imain: scala.tools.nsc.interpreter.IMain = scala scala> val mirror = imain.global.rootMirror mirror: imain.global.Mirror = compiler mirror 
+1
source

All Articles