summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-02-03 22:26:35 +0000
committerPaul Phillips <paulp@improving.org>2011-02-03 22:26:35 +0000
commit1038b708f23374439310f3a700a2e1170e2b61a0 (patch)
tree8179368c54ca2c1ad63ac1d05f9266d278ead0b4 /src/compiler/scala/tools
parentc332e580a3fec48dc193b518666f93c589163045 (diff)
downloadscala-1038b708f23374439310f3a700a2e1170e2b61a0.tar.gz
scala-1038b708f23374439310f3a700a2e1170e2b61a0.tar.bz2
scala-1038b708f23374439310f3a700a2e1170e2b61a0.zip
A couple long-threatened repl features.
1) :implicits command. scala> :implicits No implicits have been imported other than those in Predef. scala> import BigDecimal._ import BigDecimal._ scala> class Bippy[T] { implicit def makeMeABippy[U <: T] : Bippy[U] = new Bippy[U] } defined class Bippy scala> val bippy = new Bippy[String] bippy: Bippy[String] = Bippy@4f0bd71c scala> import bippy._ import bippy._ scala> :implicits /* 3 implicit members imported from scala.math.BigDecimal */ /* 3 defined in scala.math.BigDecimal */ implicit def double2bigDecimal(d: Double): scala.math.BigDecimal implicit def int2bigDecimal(i: Int): scala.math.BigDecimal implicit def long2bigDecimal(l: Long): scala.math.BigDecimal /* 1 implicit members imported from Bippy */ /* 1 defined in Bippy */ implicit def makeMeABippy[U <: T]: Bippy[U] 2) This one I will probably have to optionize, but: automatic rebinding to a more specific type, signalled via tab-completion failures. More easily demonstrated than explained. scala> val x: AnyRef = "abc" // does not apply to var/def x: AnyRef = abc scala> x.<tab> asInstanceOf isInstanceOf toString scala> x.<tab> Rebinding stable value x from AnyRef to java.lang.String + asInstanceOf charAt codePointAt codePointBefore codePointCount compareTo compareToIgnoreCase concat contains contentEquals endsWith equalsIgnoreCase getBytes getChars indexOf intern isEmpty isInstanceOf lastIndexOf length matches offsetByCodePoints regionMatches replace replaceAll replaceFirst split startsWith subSequence substring toCharArray toLowerCase toString toUpperCase trim scala> x res0: java.lang.String = abc Who's up for some reviewing? I'm taking volunteers! No review.
Diffstat (limited to 'src/compiler/scala/tools')
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala7
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Dossiers.scala53
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ILoop.scala74
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IMain.scala300
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala67
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala39
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/NamedParam.scala3
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ReflectionCompletion.scala109
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala30
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Names.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala21
11 files changed, 409 insertions, 296 deletions
diff --git a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
index 0dc35559a6..9c34565928 100644
--- a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
@@ -13,11 +13,10 @@ package interpreter
*/
trait CompletionOutput {
val global: Global
+
import global._
import definitions.{ NothingClass, AnyClass, isTupleTypeOrSubtype, isFunctionType, isRepeatedParamType }
- def DBG(msg: => Any): Unit
-
/** Reducing fully qualified noise for some common packages.
*/
val typeTransforms = List(
@@ -81,9 +80,7 @@ trait CompletionOutput {
case NullaryMethodType(resType) => ": " + typeToString(resType)
case PolyType(tparams, resType) => tparamsString(tparams) + typeToString(resType)
case mt @ MethodType(_, _) => methodTypeToString(mt)
- case x =>
- DBG("methodString(): %s / %s".format(x.getClass, x))
- x.toString
+ case x => x.toString
})
}
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/Dossiers.scala b/src/compiler/scala/tools/nsc/interpreter/Dossiers.scala
new file mode 100644
index 0000000000..bfa6576b25
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interpreter/Dossiers.scala
@@ -0,0 +1,53 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package interpreter
+
+// Coming soon
+trait Dossiers {
+ val intp: IMain
+
+ import intp._
+ import intp.global._
+
+ trait Dossier {
+ def symbol: Symbol
+ def staticType: Type
+
+ def id = name.toString
+ def name = symbol.name
+ def normalizedType = staticType.typeSymbolDirect.tpe.normalize
+ def simpleNameOfType = staticType.typeSymbol.simpleName
+ def staticTypeString = staticType.toString
+
+ override def toString = "Dossier on %s:\n static type %s (normalized %s)".format(
+ symbol, staticType, normalizedType
+ )
+ }
+
+ class TypeDossier(val symbol: TypeSymbol, val staticType: Type) extends Dossier {
+ override def toString = super.toString
+ }
+
+ class TermDossier(val symbol: TermSymbol, val staticType: Type, val value: AnyRef) extends Dossier {
+ def runtimeClass: Class[_] = value.getClass
+ def runtimeSymbol: Symbol = safeClass(runtimeClass.getName) getOrElse NoSymbol
+ def runtimeType: Type = runtimeSymbol.tpe
+ def runtimeTypeString = TypeStrings.fromClazz(runtimeClass)
+
+ def runtimeTypedParam = NamedParamClass(id, runtimeTypeString, value)
+ def staticTypedParam = NamedParamClass(id, staticTypeString, value)
+
+ def isRuntimeTypeTighter = runtimeSymbol.ancestors contains normalizedType.typeSymbol
+
+ override def toString = super.toString + (
+ "\n runtime type %s/%s\n value %s".format(
+ runtimeType, runtimeTypeString, value
+ )
+ )
+ }
+}
+
diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
index a075fe5bb0..c7739b8a8a 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
@@ -196,6 +196,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: PrintWriter)
NoArgs("help", "print this help message", printHelp),
VarArgs("history", "show the history (optional arg: lines to show)", printHistory),
LineArg("h?", "search the history", searchHistory),
+ LineArg("implicits", "show the implicits in scope (-v to include Predef)", implicitsCommand),
LineArg("javap", "disassemble a file or class name", javapCommand),
LineArg("keybindings", "show how ctrl-[A-Z] and other keys are bound", keybindingsCommand),
OneArg("load", "load and interpret a Scala file", load),
@@ -216,6 +217,79 @@ class ILoop(in0: Option[BufferedReader], protected val out: PrintWriter)
LineArg("wrap", "code to wrap around all executions", wrapCommand)
)
}
+
+ private val typeTransforms = List(
+ "scala.collection.immutable." -> "immutable.",
+ "scala.collection.mutable." -> "mutable.",
+ "scala.collection.generic." -> "generic.",
+ "java.lang." -> "jl.",
+ "scala.runtime." -> "runtime."
+ )
+
+ private def implicitsCommand(line: String): Result = {
+ val intp = ILoop.this.intp
+ import intp._
+ import global.Symbol
+
+ def p(x: Any) = intp.reporter.printMessage("" + x)
+ def toDefString(sym: Symbol) = {
+ TypeStrings.quieter(
+ intp.afterTyper(sym.defString),
+ sym.owner.name + ".this.",
+ sym.owner.fullName + "."
+ )
+ }
+
+ // If an argument is given, only show a source with that
+ // in its name somewhere.
+ val args = line split "\\s+"
+ val filtered = intp.implicitSymbolsBySource filter {
+ case (source, syms) =>
+ (args contains "-v") || {
+ if (line == "") (source.fullName.toString != "scala.Predef")
+ else (args exists (source.name.toString contains _))
+ }
+ }
+
+ if (filtered.isEmpty)
+ return "No implicits have been imported other than those in Predef."
+
+ filtered foreach {
+ case (source, syms) =>
+ p("/* " + syms.size + " implicit members imported from " + source.fullName + " */")
+
+ // This groups the members by where the symbol is defined
+ val byOwner = syms groupBy (_.owner)
+ val sortedOwners = byOwner.toList sortBy { case (owner, _) => intp.afterTyper(source.info.baseClasses indexOf owner) }
+
+ sortedOwners foreach {
+ case (owner, members) =>
+ // Within each owner, we cluster results based on the final result type
+ // if there are more than a couple, and sort each cluster based on name.
+ // This is really just trying to make the 100 or so implicits imported
+ // by default into something readable.
+ val memberGroups: List[List[Symbol]] = {
+ val groups = members groupBy (_.tpe.finalResultType) toList
+ val (big, small) = groups partition (_._2.size > 3)
+ val xss = (
+ (big sortBy (_._1.toString) map (_._2)) :+
+ (small flatMap (_._2))
+ )
+
+ xss map (xs => xs sortBy (_.name.toString))
+ }
+
+ val ownerMessage = if (owner == source) " defined in " else " inherited from "
+ p(" /* " + members.size + ownerMessage + owner.fullName + " */")
+
+ memberGroups foreach { group =>
+ group foreach (s => p(" " + toDefString(s)))
+ p("")
+ }
+ }
+ p("")
+ }
+ }
private def javapCommand(line: String): Result = {
if (line == "")
return ":javap <filename or classname>"
diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
index 3c54c18fe1..21c9dd735e 100644
--- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
@@ -58,7 +58,7 @@ import IMain._
* @author Lex Spoon
*/
class IMain(val settings: Settings, protected val out: PrintWriter) {
- intp =>
+ imain =>
/** construct an interpreter that reports to Console */
def this(settings: Settings) = this(settings, new NewLinePrintWriter(new ConsoleWriter, true))
@@ -150,10 +150,11 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
lazy val compiler = global
import global._
+ import definitions.{ ScalaPackage, JavaLangPackage, PredefModule, RootClass }
import nme.{ INTERPRETER_IMPORT_WRAPPER }
object naming extends {
- val global: intp.global.type = intp.global
+ val global: imain.global.type = imain.global
} with Naming {
// make sure we don't overwrite their unwisely named res3 etc.
override def freshUserVarName(): String = {
@@ -164,16 +165,26 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
}
import naming._
+ // object dossiers extends {
+ // val intp: imain.type = imain
+ // } with Dossiers { }
+ // import dossiers._
+
lazy val memberHandlers = new {
- val intp: IMain.this.type = IMain.this
+ val intp: imain.type = imain
} with MemberHandlers
import memberHandlers._
+ def atPickler[T](op: => T): T = atPhase(currentRun.picklerPhase)(op)
+ def afterTyper[T](op: => T): T = atPhase(currentRun.typerPhase.next)(op)
+
/** Temporarily be quiet */
def beQuietDuring[T](operation: => T): T = {
val wasPrinting = printResults
ultimately(printResults = wasPrinting) {
- printResults = false
+ if (isReplDebug) echo(">> beQuietDuring")
+ else printResults = false
+
operation
}
}
@@ -259,14 +270,6 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
// Set the current Java "context" class loader to this interpreter's class loader
def setContextClassLoader() = classLoader.setAsContext()
- /** the previous requests this interpreter has processed */
- private lazy val prevRequests = mutable.ArrayBuffer[Request]()
- private lazy val referencedNameMap = mutable.Map[Name, Request]()
- private lazy val definedNameMap = mutable.Map[Name, Request]()
- private def allHandlers = prevRequests.toList flatMap (_.handlers)
- private def allReqAndHandlers = prevRequests.toList flatMap (req => req.handlers map (req -> _))
- private def importHandlers = allHandlers collect { case x: ImportHandler => x }
-
/** Given a simple repl-defined name, returns the real name of
* the class representing it, e.g. for "Bippy" it may return
*
@@ -278,6 +281,7 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
case _ => id
}
}
+
def allDefinedNames = definedNameMap.keys.toList sortBy (_.toString)
def pathToType(id: String): String = pathToName(newTypeName(id))
def pathToTerm(id: String): String = pathToName(newTermName(id))
@@ -330,10 +334,6 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
}
}
- def allSeenTypes = prevRequests.toList flatMap (_.typeOf.values.toList) distinct
- def allDefinedTypes = prevRequests.toList flatMap (_.definedTypes.values.toList) distinct
- def allImplicits = allHandlers filter (_.definesImplicit) flatMap (_.definedNames)
-
/** Compute imports that allow definitions from previous
* requests to be visible in a new request. Returns
* three pieces of related code:
@@ -592,6 +592,15 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
case _ => DBG("Set failed in bind(%s, %s, %s)".format(name, boundType, value)) ; IR.Error
}
}
+ def rebind(p: NamedParam): IR.Result = {
+ val name = p.name
+ val oldType = typeOfTerm(name) getOrElse { return IR.Error }
+ val newType = p.tpe
+ val tempName = freshInternalVarName()
+
+ quietRun("val %s = %s".format(tempName, name))
+ quietRun("val %s = %s.asInstanceOf[%s]".format(name, tempName, newType))
+ }
def quietBind(p: NamedParam): IR.Result = beQuietDuring(bind(p))
def bind(p: NamedParam): IR.Result = bind(p.name, p.tpe, p.value)
@@ -651,16 +660,26 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
None
}
- lazy val readRoot = definitions.getModule(readPath) // the outermost wrapper
lazy val evalClass = loadByName(evalPath)
lazy val evalValue = callOpt(valueMethod)
def compile(source: String): Boolean = compileAndSaveRun("<console>", source)
- def afterTyper[T](op: => T): T = {
+ def lineAfterTyper[T](op: => T): T = {
assert(lastRun != null, "Internal error: trying to use atPhase, but Run is null." + this)
atPhase(lastRun.typerPhase.next)(op)
}
+ /** The innermost object inside the wrapper, found by
+ * following accessPath into the outer one.
+ */
+ def resolvePathToSymbol(accessPath: String): Symbol = {
+ val readRoot = definitions.getModule(readPath) // the outermost wrapper
+ (accessPath split '.').foldLeft(readRoot) { (sym, name) =>
+ if (name == "") sym else
+ lineAfterTyper(sym.info member newTermName(name))
+ }
+ }
+
// def compileAndTypeExpr(expr: String): Option[Typer] = {
// class TyperRun extends Run {
// override def stopPhase(name: String) = name == "superaccessors"
@@ -685,7 +704,7 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
// private
class Request(val line: String, val trees: List[Tree]) {
val lineRep = new ReadEvalPrint()
- import lineRep.{ afterTyper }
+ import lineRep.lineAfterTyper
private var _originalLine: String = null
def withOriginalLine(s: String): this.type = { _originalLine = s ; this }
@@ -778,7 +797,7 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
// ensure it has been compiled
compile
// try to load it and call the value method
- lineRep.evalValue
+ lineRep.evalValue filterNot (_ == null)
}
/** Compile the object file. Returns whether the compilation succeeded.
@@ -791,20 +810,15 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
lineRep.compile(ObjectSourceCode(handlers)) && {
// extract and remember types
typeOf
- definedTypes
+ typesOfDefinedTerms
// compile the result-extraction object
lineRep compile ResultObjectSourceCode(handlers)
}
}
- /** The innermost object inside the wrapper, found by
- * following accessPath into the outer one. */
- lazy val resObjSym =
- accessPath.split("\\.").foldLeft(lineRep.readRoot) { (sym, name) =>
- if (name == "") sym else
- afterTyper(sym.info member newTermName(name))
- }
+ lazy val resultSymbol = lineRep.resolvePathToSymbol(accessPath)
+ def applyToResultMember[T](name: Name, f: Symbol => T) = lineAfterTyper(f(resultSymbol.info.nonPrivateDecl(name)))
/* typeOf lookup with encoding */
def lookupTypeOf(name: Name) = typeOf.getOrElse(name, typeOf(global.encode(name.toString)))
@@ -813,12 +827,12 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
private def typeMap[T](f: Type => T): Map[Name, T] = {
def toType(name: Name): T = {
// the types are all =>T; remove the =>
- val tp1 = afterTyper(resObjSym.info.nonPrivateDecl(name).tpe match {
+ val tp1 = lineAfterTyper(resultSymbol.info.nonPrivateDecl(name).tpe match {
case NullaryMethodType(tp) => tp
case tp => tp
})
// normalize non-public types so we don't see protected aliases like Self
- afterTyper(tp1 match {
+ lineAfterTyper(tp1 match {
case TypeRef(_, sym, _) if !sym.isPublic => f(tp1.normalize)
case tp => f(tp)
})
@@ -830,9 +844,14 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
/** String representations of same. */
lazy val typeOf = typeMap[String](_.toString)
- lazy val definedTypes: Map[Name, Type] = {
- typeNames map (x => x -> afterTyper(resObjSym.info.nonPrivateDecl(x).tpe)) toMap
- }
+ // lazy val definedTypes: Map[Name, Type] = {
+ // typeNames map (x => x -> afterTyper(resultSymbol.info.nonPrivateDecl(x).tpe)) toMap
+ // }
+ lazy val definedSymbols: Map[Name, Symbol] =
+ termNames map (x => x -> applyToResultMember(x, x => x)) toMap
+
+ lazy val typesOfDefinedTerms: Map[Name, Type] =
+ termNames map (x => x -> applyToResultMember(x, _.tpe)) toMap
private def bindExceptionally(t: Throwable) = {
val ex: Exceptional =
@@ -866,9 +885,7 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
}
try {
- val execution = lineManager.set(originalLine) {
- lineRep call "$export"
- }
+ val execution = lineManager.set(originalLine)(lineRep call "$export")
execution.await()
execution.state match {
@@ -903,26 +920,62 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
private def requestForIdent(line: String): Option[Request] =
requestForName(newTermName(line)) orElse requestForName(newTypeName(line))
+ def safeClass(name: String): Option[Symbol] = {
+ try Some(definitions.getClass(newTypeName(name)))
+ catch { case _: MissingRequirementError => None }
+ }
+ def safeModule(name: String): Option[Symbol] = {
+ try Some(definitions.getModule(newTermName(name)))
+ catch { case _: MissingRequirementError => None }
+ }
+
def definitionForName(name: Name): Option[MemberHandler] =
requestForName(name) flatMap { req =>
req.handlers find (_.definedNames contains name)
}
+ //
+
+ def valueOfTerm(id: String): Option[AnyRef] =
+ requestForIdent(id) flatMap (_.getEval)
+
+ def classOfTerm(id: String): Option[Class[_]] =
+ valueOfTerm(id) map (_.getClass)
- def typeOfDefinedName(name: Name): Option[Type] =
- if (name == nme.ROOTPKG) Some(definitions.RootClass.tpe)
- else requestForName(name) flatMap (_.compilerTypeOf get name)
+ def typeOfTerm(id: String): Option[Type] = newTermName(id) match {
+ case nme.ROOTPKG => Some(RootClass.tpe)
+ case name => requestForName(name) flatMap (_.compilerTypeOf get name)
+ }
+ def symbolOfTerm(id: String): Symbol =
+ requestForIdent(id) flatMap (_.definedSymbols get newTermName(id)) getOrElse NoSymbol
+
+ def runtimeClassAndTypeOfTerm(id: String): Option[(Class[_], Type)] =
+ for (clazz <- classOfTerm(id) ; tpe <- runtimeTypeOfTerm(id)) yield ((clazz, tpe))
+
+ def runtimeTypeOfTerm(id: String): Option[Type] = {
+ for {
+ tpe <- typeOfTerm(id)
+ clazz <- classOfTerm(id)
+ val staticSym = tpe.typeSymbol
+ runtimeSym <- safeClass(clazz.getName)
+ if runtimeSym != staticSym
+ if runtimeSym isSubClass staticSym
+ } yield {
+ runtimeSym.info
+ }
+ }
// XXX literals.
// 1) Identifiers defined in the repl.
// 2) A path loadable via getModule.
// 3) Try interpreting it as an expression.
+ private var typeOfExpressionDepth = 0
def typeOfExpression(expr: String): Option[Type] = {
- val name = newTermName(expr)
-
- def asModule = {
- try Some(definitions.getModule(name).tpe)
- catch { case _: MissingRequirementError => None }
+ if (typeOfExpressionDepth > 2) {
+ DBG("Terminating typeOfExpression recursion for expression: " + expr)
+ return None
}
+
+ def asModule = safeModule(expr) map (_.tpe)
def asExpr = beSilentDuring {
val lhs = freshInternalVarName()
interpret("val " + lhs + " = { " + expr + " } ") match {
@@ -931,91 +984,40 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
}
}
- typeOfDefinedName(name) orElse asModule orElse asExpr
- }
-
- def clazzForIdent(id: String): Option[Class[_]] =
- for (res <- getEvalForIdent(id); v <- Option(res)) yield v.getClass
-
- def methodsOf(name: String) =
- evalExpr[List[String]](methodsCode(name)) map (x => NameTransformer.decode(getOriginalName(x)))
-
- def completionAware(name: String) = {
- // XXX working around "object is not a value" crash, i.e.
- // import java.util.ArrayList ; ArrayList.<tab>
- clazzForIdent(name) flatMap (_ => evalExpr[Option[CompletionAware]](asCompletionAwareCode(name)))
- }
-
- def getEvalForIdent(id: String): Option[AnyRef] =
- requestForIdent(id) flatMap (_.getEval)
-
- /** Executes code looking for a manifest of type T.
- */
- def manifestFor[T: Manifest] =
- evalExpr[Manifest[T]]("""manifest[%s]""".format(manifest[T]))
-
- /** Executes code looking for an implicit value of type T.
- */
- def implicitFor[T: Manifest] = {
- val s = manifest[T].toString
- evalExpr[Option[T]]("{ def f(implicit x: %s = null): %s = x ; Option(f) }".format(s, s))
- // We don't use implicitly so as to fail without failing.
- // evalExpr[T]("""implicitly[%s]""".format(manifest[T]))
+ typeOfExpressionDepth += 1
+ try typeOfTerm(expr) orElse asModule orElse asExpr
+ finally typeOfExpressionDepth -= 1
}
+ // def compileAndTypeExpr(expr: String): Option[Typer] = {
+ // class TyperRun extends Run {
+ // override def stopPhase(name: String) = name == "superaccessors"
+ // }
+ // }
- private def methodsCode(name: String) =
- "%s.%s(%s)".format(classOf[ReflectionCompletion].getName, "methodsOf", name)
-
- private def asCompletionAwareCode(name: String) =
- "%s.%s(%s)".format(classOf[CompletionAware].getName, "unapply", name)
-
- private def getOriginalName(name: String): String =
- nme.originalName(newTermName(name)).toString
+ private def onlyTerms(xs: List[Name]) = xs collect { case x: TermName => x }
+ private def onlyTypes(xs: List[Name]) = xs collect { case x: TypeName => x }
- case class InterpreterEvalException(msg: String) extends Exception(msg)
- def evalError(msg: String) = throw InterpreterEvalException(msg)
+ def importHandlers = allHandlers collect { case x: ImportHandler => x }
+ def definedTerms = onlyTerms(allDefinedNames) filterNot isInternalVarName
+ def definedTypes = onlyTypes(allDefinedNames)
+ def importedTerms = onlyTerms(importHandlers flatMap (_.importedNames))
+ def importedTypes = onlyTypes(importHandlers flatMap (_.importedNames))
- /** The user-facing eval in :power mode wraps an Option.
- */
- def eval[T: Manifest](line: String): Option[T] =
- try Some(evalExpr[T](line))
- catch { case InterpreterEvalException(msg) => out println indentCode(msg) ; None }
-
- def evalExpr[T: Manifest](line: String): T = {
- // Nothing means the type could not be inferred.
- if (manifest[T] eq Manifest.Nothing)
- evalError("Could not infer type: try 'eval[SomeType](%s)' instead".format(line))
-
- val lhs = freshInternalVarName()
- beQuietDuring { interpret("val " + lhs + " = { " + line + " } ") }
-
- // TODO - can we meaningfully compare the inferred type T with
- // the internal compiler Type assigned to lhs?
- // def assignedType = prevRequests.last.typeOf(newTermName(lhs))
-
- val req = requestFromLine(lhs, true) match {
- case Left(result) => evalError(result.toString)
- case Right(req) => req
- }
- if (req == null || !req.compile || req.handlers.size != 1)
- evalError("Eval error.")
-
- try req.getEvalTyped[T] getOrElse evalError("No result.")
- catch { case e: Exception => evalError(e.getMessage) }
- }
+ /** the previous requests this interpreter has processed */
+ private lazy val prevRequests = mutable.ArrayBuffer[Request]()
+ private lazy val referencedNameMap = mutable.Map[Name, Request]()
+ private lazy val definedNameMap = mutable.Map[Name, Request]()
+ private def allHandlers = prevRequests.toList flatMap (_.handlers)
+ private def allReqAndHandlers = prevRequests.toList flatMap (req => req.handlers map (req -> _))
+ def allSeenTypes = prevRequests.toList flatMap (_.typeOf.values.toList) distinct
+ def allImplicits = allHandlers filter (_.definesImplicit) flatMap (_.definedNames)
- def interpretExpr[T: Manifest](code: String): Option[T] = beQuietDuring {
- interpret(code) match {
- case IR.Success =>
- try prevRequests.last.getEvalTyped[T]
- catch { case e: Exception => out println e ; None }
- case _ => None
- }
- }
+ private def membersAtPickler(sym: Symbol): List[Symbol] =
+ atPickler(sym.info.nonPrivateMembers)
- /** Another entry point for tab-completion, ids in scope */
- private def simpleTermNames =
- allHandlers flatMap (_.definedOrImported) filter (x => x.isTermName && !isInternalVarName(x))
+ /** Symbols whose contents are language-defined to be imported. */
+ def languageWildcardSyms: List[Symbol] = List(JavaLangPackage, ScalaPackage, PredefModule)
+ def languageWildcards: List[Type] = languageWildcardSyms map (_.tpe)
/** Types which have been wildcard imported, such as:
* val x = "abc" ; import x._ // type java.lang.String
@@ -1028,36 +1030,68 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
* scope twiddling which should be swept away in favor of digging
* into the compiler scopes.
*/
- def wildcardImportedTypes(): List[Type] = {
+ def sessionWildcards: List[Type] = {
importHandlers flatMap {
case x if x.importsWildcard => x.targetType
case _ => None
} distinct
}
+ def wildcardTypes = languageWildcards ++ sessionWildcards
- /** Another entry point for tab-completion, ids in scope */
- def unqualifiedIds() = (simpleTermNames map (_.toString)).distinct.sorted
+ def languageSymbols = languageWildcardSyms flatMap membersAtPickler
+ def sessionSymbols = importHandlers flatMap (_.importedSymbols)
+ def importedSymbols = languageSymbols ++ sessionSymbols
+ def implicitSymbols = importedSymbols filter (_.isImplicit)
+
+ /** Tuples of (source, imported symbols) in the order they were imported.
+ */
+ def importedSymbolsBySource: List[(Symbol, List[Symbol])] = {
+ val lang = languageWildcardSyms map (sym => (sym, membersAtPickler(sym)))
+ val session = importHandlers filter (_.targetType.isDefined) map { mh =>
+ (mh.targetType.get.typeSymbol, mh.importedSymbols)
+ }
+
+ lang ++ session
+ }
+ def implicitSymbolsBySource: List[(Symbol, List[Symbol])] = {
+ importedSymbolsBySource map {
+ case (k, vs) => (k, vs filter (_.isImplicit))
+ } filterNot (_._2.isEmpty)
+ }
+
+ def visibleTermNames: List[Name] = definedTerms ++ importedTerms distinct
- /** For static/object method completion */
- def getClassObject(path: String): Option[Class[_]] = classLoader tryToLoadClass path
+ /** Another entry point for tab-completion, ids in scope */
+ def unqualifiedIds = visibleTermNames map (_.toString) filterNot (_ contains "$") sorted
/** Parse the ScalaSig to find type aliases */
def aliasForType(path: String) = ByteCode.aliasForType(path)
+ def withoutUnwrapping(op: => Unit): Unit = {
+ val saved = isettings.unwrapStrings
+ isettings.unwrapStrings = false
+ try op
+ finally isettings.unwrapStrings = saved
+ }
+
def showCodeIfDebugging(code: String) {
/** Secret bookcase entrance for repl debuggers: end the line
* with "// show" and see what's going on.
*/
if (code.lines exists (_.trim endsWith "// show")) {
echo(code)
- parse(code) foreach (ts => ts foreach (t => DBG(asCompactString(t))))
+ parse(code) foreach (ts => ts foreach (t => withoutUnwrapping(DBG(asCompactString(t)))))
}
}
// debugging
- def isCompletionDebug = settings.Ycompletion.value
- def DBG(s: => String) =
- try if (isReplDebug) repldbg(s)
+ def debugging[T](msg: String)(res: T) = {
+ DBG(msg + " " + res)
+ res
+ }
+ def DBG(s: => String) = if (isReplDebug) {
+ try repldbg(s)
catch { case x: AssertionError => repldbg("Assertion error printing debug string:\n " + x) }
+ }
}
/** Utility methods for the Interpreter. */
@@ -1121,7 +1155,7 @@ object IMain {
// $line3.$read.$iw.$iw.Bippy =
// $line3.$read$$iw$$iw$Bippy@4a6a00ca
private def removeLineWrapper(s: String) = s.replaceAll("""\$line\d+[./]\$(read|eval|print)[$.]""", "")
- private def removeIWPackages(s: String) = s.replaceAll("""\$iw[$.]""", "")
+ private def removeIWPackages(s: String) = s.replaceAll("""\$(iw|read|eval|print)[$.]""", "")
}
class ReplReporter(intp: IMain) extends ConsoleReporter(intp.settings, null, new ReplStrippingWriter(intp)) {
diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala b/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala
index 8093ae1d3c..2a19c6fb95 100644
--- a/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala
@@ -20,24 +20,12 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput
import global._
import definitions.{ PredefModule, RootClass, AnyClass, AnyRefClass, ScalaPackage, JavaLangPackage }
type ExecResult = Any
+ import intp.{ DBG, debugging, afterTyper }
// verbosity goes up with consecutive tabs
private var verbosity: Int = 0
def resetVerbosity() = verbosity = 0
- def isCompletionDebug = intp.isCompletionDebug
- def DBG(msg: => Any) = if (isCompletionDebug) println(msg.toString)
- def debugging[T](msg: String): T => T = (res: T) => returning[T](res)(x => DBG(msg + x))
-
- // XXX not yet used.
- lazy val dottedPaths = {
- def walk(tp: Type): scala.List[Symbol] = {
- val pkgs = tp.nonPrivateMembers filter (_.isPackage)
- pkgs ++ (pkgs map (_.tpe) flatMap walk)
- }
- walk(RootClass.tpe)
- }
-
def getType(name: String, isModule: Boolean) = {
val f = if (isModule) definitions.getModule(_: Name) else definitions.getClass(_: Name)
try Some(f(name).tpe)
@@ -66,7 +54,7 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput
// XXX we'd like to say "filterNot (_.isDeprecated)" but this causes the
// compiler to crash for reasons not yet known.
- def members = (effectiveTp.nonPrivateMembers ++ anyMembers) filter (_.isPublic)
+ def members = afterTyper((effectiveTp.nonPrivateMembers ++ anyMembers) filter (_.isPublic))
def methods = members filter (_.isMethod)
def packages = members filter (_.isPackage)
def aliases = members filter (_.isAliasType)
@@ -78,6 +66,31 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput
}
object TypeMemberCompletion {
+ def apply(tp: Type, runtimeType: Type, param: NamedParam): TypeMemberCompletion = {
+ new TypeMemberCompletion(tp) {
+ var upgraded = false
+ lazy val upgrade = {
+ intp rebind param
+ intp.reporter.printMessage("\nRebinding stable value %s from %s to %s".format(param.name, tp, param.tpe))
+ upgraded = true
+ new TypeMemberCompletion(runtimeType)
+ }
+ override def completions(verbosity: Int) = {
+ super.completions(verbosity) ++ (
+ if (verbosity == 0) Nil
+ else upgrade.completions(verbosity)
+ )
+ }
+ override def follow(s: String) = super.follow(s) orElse {
+ if (upgraded) upgrade.follow(s)
+ else None
+ }
+ override def alternativesFor(id: String) = super.alternativesFor(id) ++ (
+ if (upgraded) upgrade.alternativesFor(id)
+ else Nil
+ ) distinct
+ }
+ }
def apply(tp: Type): TypeMemberCompletion = {
if (tp.typeSymbol.isPackageClass) new PackageCompletion(tp)
else new TypeMemberCompletion(tp)
@@ -91,10 +104,7 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput
def excludeStartsWith: List[String] = List("<") // <byname>, <repeated>, etc.
def excludeNames: List[String] = (anyref.methodNames filterNot anyRefMethodsToShow) :+ "_root_"
- def methodSignatureString(sym: Symbol) = {
- def asString = new MethodSymbolOutput(sym).methodString()
- atPhase(currentRun.typerPhase)(asString)
- }
+ def methodSignatureString(sym: Symbol) = afterTyper(new MethodSymbolOutput(sym).methodString())
def exclude(name: String): Boolean = (
(name contains "$") ||
@@ -146,16 +156,29 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput
override def completions(verbosity: Int) = intp.unqualifiedIds ++ List("classOf") //, "_root_")
// now we use the compiler for everything.
override def follow(id: String) = {
- if (completions(0) contains id)
- intp typeOfExpression id map (tpe => TypeMemberCompletion(tpe))
+ if (completions(0) contains id) {
+ intp typeOfExpression id map { tpe =>
+ intp runtimeClassAndTypeOfTerm id match {
+ case Some((clazz, runtimeType)) =>
+ val sym = intp.symbolOfTerm(id)
+ if (sym.isStable) {
+ val param = new NamedParam.Untyped(id, intp valueOfTerm id getOrElse null)
+ TypeMemberCompletion(tpe, runtimeType, param)
+ }
+ else TypeMemberCompletion(tpe)
+ case _ =>
+ TypeMemberCompletion(tpe)
+ }
+ }
+ }
else
None
}
override def toString = "<repl ids> (%s)".format(completions(0).size)
}
- // wildcard imports in the repl like "import global._" or "import String._"
- private def imported = intp.wildcardImportedTypes map TypeMemberCompletion.imported
+ // user-issued wildcard imports like "import global._" or "import String._"
+ private def imported = intp.sessionWildcards map TypeMemberCompletion.imported
// literal Ints, Strings, etc.
object literals extends CompletionAware {
diff --git a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala
index 3992a0bdfa..29c31f50d6 100644
--- a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala
@@ -14,7 +14,7 @@ import util.Chars
trait MemberHandlers {
val intp: IMain
- import intp.{ Request, global, naming }
+ import intp.{ Request, global, naming, atPickler }
import global._
import naming._
@@ -81,10 +81,10 @@ trait MemberHandlers {
}
sealed abstract class MemberDefHandler(override val member: MemberDef) extends MemberHandler(member) {
- def name: Name = member.name
+ def name: Name = member.name
def mods: Modifiers = member.mods
- def keyword = member.keyword
- def prettyName = NameTransformer.decode(name)
+ def keyword = member.keyword
+ def prettyName = NameTransformer.decode(name)
override def definesImplicit = member.mods.isImplicit
override def definesTerm: Option[TermName] = Some(name.toTermName) filter (_ => name.isTermName)
@@ -95,7 +95,6 @@ trait MemberHandlers {
* in a single interpreter request.
*/
sealed abstract class MemberHandler(val member: Tree) {
- def tpe = member.tpe
def definesImplicit = false
def definesValue = false
def isLegalTopLevel = member match {
@@ -192,24 +191,30 @@ trait MemberHandlers {
val Import(expr, selectors) = imp
def targetType = intp.typeOfExpression("" + expr)
- private def selectorWild = selectors filter (_.name == nme.USCOREkw) // wildcard imports, e.g. import foo._
+ // wildcard imports, e.g. import foo._
+ private def selectorWild = selectors filter (_.name == nme.USCOREkw)
+ // renamed imports, e.g. import foo.{ bar => baz }
private def selectorRenames = selectors map (_.rename) filterNot (_ == null)
/** Whether this import includes a wildcard import */
val importsWildcard = selectorWild.nonEmpty
+ def implicitSymbols = importedSymbols filter (_.isImplicit)
+ def importedSymbols = individualSymbols ++ wildcardSymbols
+
+ lazy val individualSymbols: List[Symbol] =
+ atPickler(targetType.toList flatMap (tp => individualNames map (tp nonPrivateMember _)))
+
+ lazy val wildcardSymbols: List[Symbol] =
+ if (importsWildcard) atPickler(targetType.toList flatMap (_.nonPrivateMembers))
+ else Nil
+
/** Complete list of names imported by a wildcard */
- def wildcardImportedNames: List[Name] = (
- for (tpe <- targetType ; if importsWildcard) yield
- tpe.nonPrivateMembers filter (x => x.isMethod && x.isPublic) map (_.name) distinct
- ).toList.flatten
-
- /** The individual names imported by this statement */
- /** XXX come back to this and see what can be done with wildcards now that
- * we know how to enumerate the identifiers.
- */
- override lazy val importedNames: List[Name] =
- selectorRenames filterNot (_ == nme.USCOREkw) flatMap (_.bothNames)
+ lazy val wildcardNames: List[Name] = wildcardSymbols map (_.name)
+ lazy val individualNames: List[Name] = selectorRenames filterNot (_ == nme.USCOREkw) flatMap (_.bothNames)
+
+ /** The names imported by this statement */
+ override lazy val importedNames: List[Name] = wildcardNames ++ individualNames
override def resultExtractionCode(req: Request) = codegenln(imp.toString) + "\n"
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/NamedParam.scala b/src/compiler/scala/tools/nsc/interpreter/NamedParam.scala
index 878c5b20b1..e92888d89b 100644
--- a/src/compiler/scala/tools/nsc/interpreter/NamedParam.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/NamedParam.scala
@@ -11,6 +11,7 @@ import NamedParam._
trait NamedParamCreator {
protected def freshName: () => String
+ def apply(name: String, tpe: String, value: Any): NamedParam = NamedParamClass(name, tpe, value)
def apply[T: Manifest](name: String, x: T): NamedParam = new Typed[T](name, x)
def apply[T: Manifest](x: T): NamedParam = apply(freshName(), x)
@@ -35,6 +36,8 @@ object NamedParam extends NamedParamCreator {
}
}
+case class NamedParamClass(name: String, tpe: String, value: Any) extends NamedParam { }
+
trait NamedParam {
def name: String
def tpe: String
diff --git a/src/compiler/scala/tools/nsc/interpreter/ReflectionCompletion.scala b/src/compiler/scala/tools/nsc/interpreter/ReflectionCompletion.scala
deleted file mode 100644
index 0cbac2d0d6..0000000000
--- a/src/compiler/scala/tools/nsc/interpreter/ReflectionCompletion.scala
+++ /dev/null
@@ -1,109 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2011 LAMP/EPFL
- * @author Paul Phillips
- */
-
-package scala.tools.nsc
-package interpreter
-
-import java.lang.reflect
-import reflect.{ Modifier, AccessibleObject }
-import Modifier.{ isPrivate, isProtected, isStatic }
-import ReflectionCompletion._
-
-trait ReflectionCompletion extends CompletionAware {
- def clazz: JClass
- protected def visibleMembers: List[AccessibleObject]
- protected def memberCompletions = visibleMembers filter isPublic map reflectName
-
- def reflectName(m: AccessibleObject) = m match {
- case x: reflect.Method => x.getName
- case x: reflect.Field => x.getName
- case x => sys.error(x.toString)
- }
- def isPublic(m: AccessibleObject) = m match {
- case x: reflect.Method => Modifier isPublic x.getModifiers
- case x: reflect.Field => Modifier isPublic x.getModifiers
- case x => sys.error(x.toString)
- }
-
- lazy val (staticMethods, instanceMethods) = clazz.getMethods.toList partition (x => isStatic(x.getModifiers))
- lazy val (staticFields, instanceFields) = clazz.getFields.toList partition (x => isStatic(x.getModifiers))
-
- /** Oops, mirror classes don't descend from scalaobject.
- */
- def isScalaClazz(cl: JClass) = {
- (allInterfacesFor(cl) exists (_.getName == "scala.ScalaObject")) ||
- (classForName(cl.getName + "$").isDefined)
- }
- def allInterfacesFor(cl: JClass): List[JClass] = allInterfacesFor(cl, Nil)
-
- private def allInterfacesFor(cl: JClass, acc: List[JClass]): List[JClass] = {
- if (cl == null) acc.distinct
- else allInterfacesFor(cl.getSuperclass, acc ::: cl.getInterfaces.toList)
- }
-}
-
-/** A completion aware object representing a single instance of some class.
- * It completes to instance fields and methods, and delegates to another
- * InstanceCompletion object if it can determine the result type of the element.
- */
-class InstanceCompletion(val clazz: JClass) extends ReflectionCompletion {
- protected def visibleMembers = instanceMethods ::: instanceFields
- def extras = List("isInstanceOf", "asInstanceOf", "toString")
- lazy val completions = memberCompletions ::: extras
- def completions(verbosity: Int) = completions
-
- val (zeroArg, otherArg) = instanceMethods partition (_.getParameterTypes.size == 0)
- override def follow(id: String) = {
- val nextClazz = zeroArg find (m => m.getName == id) map (_.getReturnType)
- if (nextClazz.isDefined) nextClazz map (x => new InstanceCompletion(x))
- else instanceFields find (_.getName == id) map (x => new InstanceCompletion(x.getType))
- }
-}
-
-/** The complementary class to InstanceCompletion. It has logic to deal with
- * java static members and scala companion object members.
- */
-class StaticCompletion(val clazz: JClass) extends ReflectionCompletion {
- protected def visibleMembers = whichMethods ::: whichFields
- lazy val completions = memberCompletions
- def completions(verbosity: Int) = completions
-
- def className = clazz.getName
- def isJava = !isScalaClazz(clazz)
-
- private def whichMethods = if (isJava) staticMethods else instanceMethods
- private def whichFields = if (isJava) staticFields else instanceFields
- val (zeroArg, otherArg) = whichMethods partition (_.getParameterTypes.size == 0)
-
- override def follow(id: String) = {
- val nextClazz = zeroArg find (m => m.getName == id) map (_.getReturnType)
- if (nextClazz.isDefined) nextClazz map (x => new InstanceCompletion(x))
- else staticFields find (_.getName == id) map (x => new InstanceCompletion(x.getType))
- }
-
- override def toString = "StaticCompletion(%s) => %s".format(clazz.getName, completions)
-}
-
-object ReflectionCompletion {
- import java.io.File
- import java.util.jar.{ JarEntry, JarFile }
- import scala.tools.nsc.io.Streamable
-
- // XXX at the moment this is imperfect because scala's protected semantics
- // differ from java's, so protected methods appear public via reflection;
- // yet scala enforces the protection. The result is that protected members
- // appear in completion yet cannot actually be called. Fixing this
- // properly requires a scala.reflect.* API. Fixing it uglily is possible
- // too (cast to structural type!) but I deem poor use of energy.
- private def skipModifiers(m: reflect.Method) = {
- import java.lang.reflect.Modifier._
- val flags = STATIC | PRIVATE | PROTECTED
- (m.getModifiers & flags) == 0
- }
- private def getAnyClass(x: Any): JClass = x.asInstanceOf[AnyRef].getClass
-
- def methodsOf(target: Any): List[String] =
- getAnyClass(target).getMethods filter skipModifiers map (_.getName) toList
-}
diff --git a/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala b/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala
index f72409c8e7..4bc2246468 100644
--- a/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala
@@ -41,7 +41,18 @@ trait TypeStrings {
else if (primitives(s)) "scala." + s.capitalize
else primitiveMap.getOrElse(s, NameTransformer decode s)
}
- def scalaName(clazz: JClass): String = scalaName(clazz.getName)
+ def scalaName(clazz: JClass): String = {
+ val name = clazz.getName
+ scalaName(clazz.getEnclosingClass match {
+ case null => name
+ case encl =>
+ val enclName = encl.getName
+ if (name startsWith (enclName + "$"))
+ enclName + "." + (name stripPrefix (enclName + "$"))
+ else
+ name
+ })
+ }
def scalaName(m: ClassManifest[_]): String = scalaName(m.erasure)
def anyClass(x: Any): JClass = if (x == null) null else x.asInstanceOf[AnyRef].getClass
@@ -55,8 +66,9 @@ trait TypeStrings {
if (xs.isEmpty) "_"
else scalaName(xs.head)
}
- private def tparamString(clazz: JClass): String =
+ private def tparamString(clazz: JClass): String = {
brackets(clazz.getTypeParameters map tvarString: _*)
+ }
private def tparamString[T: Manifest] : String =
brackets(manifest[T].typeArguments map (m => tvarString(List(m.erasure))): _*)
@@ -76,6 +88,20 @@ trait TypeStrings {
/** Reducing fully qualified noise for some common packages.
*/
+ def quieter(tpe: String, alsoStrip: String*): String = {
+ val transforms = List(
+ "scala.collection.immutable." -> "immutable.",
+ "scala.collection.mutable." -> "mutable.",
+ "scala.collection.generic." -> "generic.",
+ "java.lang." -> "jl.",
+ "scala.runtime." -> "runtime."
+ ) ++ (alsoStrip map (_ -> ""))
+
+ transforms.foldLeft(tpe) {
+ case (res, (k, v)) => res.replaceAll(k, v)
+ }
+ }
+
val typeTransforms = List(
"java.lang." -> "",
"scala.collection.immutable." -> "immutable.",
diff --git a/src/compiler/scala/tools/nsc/symtab/Names.scala b/src/compiler/scala/tools/nsc/symtab/Names.scala
index 6772b8d5e2..4ca4880d35 100644
--- a/src/compiler/scala/tools/nsc/symtab/Names.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Names.scala
@@ -401,6 +401,8 @@ trait Names extends reflect.generic.Names {
(if (nameDebug && isTypeName) "!" else ""))//debug
def isOperatorName: Boolean = decode != toString
+ def nameKind: String = if (isTypeName) "type" else "term"
+ def longString: String = nameKind + " " + NameTransformer.decode(toString)
}
final class TermName(_index: Int, _len: Int, hash: Int) extends Name(_index, _len) {
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index f64af26b1c..6a15c929b9 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -597,6 +597,14 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
rawowner = owner
}
+ private[Symbols] def flattenName(): Name = {
+ // TODO: this assertion causes me a lot of trouble in the interpeter in situations
+ // where everything proceeds smoothly if there's no assert. I don't think calling "name"
+ // on a symbol is the right place to throw fatal exceptions if things don't look right.
+ // It really hampers exploration.
+ assert(rawowner.isClass, "fatal: %s has non-class owner %s after flatten.".format(rawname + idString, rawowner))
+ nme.flattenedName(rawowner.name, rawname)
+ }
def ownerChain: List[Symbol] = this :: owner.ownerChain
@@ -1757,10 +1765,9 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
override def name: TermName =
if (isFlatAdjusted) {
- if (flatname == null) {
- assert(rawowner.isClass, "fatal: %s has non-class owner %s after flatten.".format(rawname, rawowner))
- flatname = nme.flattenedName(rawowner.name, rawname)
- }
+ if (flatname == null)
+ flatname = flattenName().toTermName
+
flatname
} else rawname
@@ -1961,10 +1968,8 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
override def name: TypeName =
if (needsFlatClasses) {
- if (flatname == null) {
- assert(rawowner.isClass, "fatal: %s has owner %s, but a class owner is required".format(rawname+idString, rawowner))
- flatname = tpnme.flattenedName(rawowner.name, rawname)
- }
+ if (flatname == null)
+ flatname = flattenName().toTypeName
flatname
}
else rawname.asInstanceOf[TypeName]