8

意图

我正在尝试向 repl添加对:kind命令的支持。感谢 Eugene Burmako,我得到了一个工作原型。尽管它仅适用于完全限定名称并且无法解析导入的名称。

我现在正在尝试使用IMain.exprTyper它来完成这项工作,因为它知道类型,导入到 repl 中。但有一个问题。我尝试过的所有内容都返回ClassInfoType如下(用 显示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)

虽然工作实现返回特定的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))

问题

我觉得我真的很亲近。这是一个游乐场,您可以自己尝试一切:

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)

如何转换为包含所需信息ClassInfoType的有效值?Type或者,我如何首先获得Type使用IMain

4

2 回答 2

5

这个怎么样?我正在使用电源模式,它使您可以从当前运行的 REPL 访问全局,这比创建新的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)

也可以看看:

scala> intp.symbolOfType("Foo")
res26: $r.intp.global.Symbol = class Foo

但我不确定如何获取以前导入的符号:

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>

编辑:

OP得到ClassInfoType而不是的原因PolyType是由于阶段。要获得与电源模式相同的结果global,必须将相位设置为typer。引用REPL 中@retronym 的解释: 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

符号有一个类型列表(又名info-s),由编译器阶段索引。(又名 TypeHistory)。许多编译器阶段安装InfoTransformers 来变形类型。有关一些文档,请参阅 src/compiler/scala/tools/nsc/transform/InfoTransform.scala。

要在特定阶段检查类型,您可以使用“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

或者,在 :power 模式下更方便一些:

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
于 2013-03-28T23:34:39.133 回答
2

您应该使用IMain's 全局的镜像:

scala> val imain = new IMain()
imain: scala.tools.nsc.interpreter.IMain = scala

scala> val mirror = imain.global.rootMirror
mirror: imain.global.Mirror = compiler mirror
于 2013-03-28T13:02:35.767 回答