summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-12-27 15:54:32 -0800
committerPaul Phillips <paulp@improving.org>2011-12-28 08:43:13 -0800
commitd05881e42e661986286ac15c2a8c32f651b0101e (patch)
treee09f124ca83106f542682d51bc10e430c35bdd72 /src/compiler
parent33ab1a574af0d5f736ab73c5a18cc6a4cb36cbb0 (diff)
downloadscala-d05881e42e661986286ac15c2a8c32f651b0101e.tar.gz
scala-d05881e42e661986286ac15c2a8c32f651b0101e.tar.bz2
scala-d05881e42e661986286ac15c2a8c32f651b0101e.zip
repl power mode improvements.
Implemented great suggestion from moors. More imports in power mode, including the contents of treedsl. Also, another swing at overcoming the mismatched global singletons problem, this time taking advantage of dependent method types. Amazingly, it seems to work. Continuing in the quest to create a useful compiler hacking environment, there is now an implicit from Symbol which allows you to pretend a Symbol takes type parameters, and the result is the applied type based on the manifests of the type arguments and the type constructor of the symbol. Examples: // magic with manifests scala> val tp = ArrayClass[scala.util.Random] tp: $r.global.Type = Array[scala.util.Random] // evidence scala> tp.memberType(Array_apply) res0: $r.global.Type = (i: Int)scala.util.Random // treedsl scala> val m = LIT(10) MATCH (CASE(LIT(5)) ==> FALSE, DEFAULT ==> TRUE) m: $r.treedsl.global.Match = 10 match { case 5 => false case _ => true } // typed is in scope scala> typed(m).tpe res1: $r.treedsl.global.Type = Boolean
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala24
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala4
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ILoop.scala4
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Power.scala111
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ReplVals.scala75
-rw-r--r--src/compiler/scala/tools/reflect/Mock.scala3
6 files changed, 126 insertions, 95 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala
index 15f89e1382..fe20613c22 100644
--- a/src/compiler/scala/reflect/internal/Definitions.scala
+++ b/src/compiler/scala/reflect/internal/Definitions.scala
@@ -386,6 +386,30 @@ trait Definitions extends reflect.api.StandardDefinitions {
lazy val NoneModule: Symbol = getModule("scala.None")
lazy val SomeModule: Symbol = getModule("scala.Some")
+ /** Note: don't use this manifest/type function for anything important,
+ * as it is incomplete. Would love to have things like existential types
+ * working, but very unfortunately the manifests just stuff the relevant
+ * information into the toString method.
+ */
+ def manifestToType(m: OptManifest[_]): Type = m match {
+ case x: AnyValManifest[_] =>
+ getClassIfDefined("scala." + x).tpe
+ case m: ClassManifest[_] =>
+ val name = m.erasure.getName
+ if (name endsWith nme.MODULE_SUFFIX_STRING)
+ getModuleIfDefined(name stripSuffix nme.MODULE_SUFFIX_STRING).tpe
+ else {
+ val sym = getClassIfDefined(name)
+ val args = m.typeArguments
+
+ if (sym eq NoSymbol) NoType
+ else if (args.isEmpty) sym.tpe
+ else appliedType(sym.typeConstructor, args map manifestToType)
+ }
+ case _ =>
+ NoType
+ }
+
// The given symbol represents either String.+ or StringAdd.+
def isStringAddition(sym: Symbol) = sym == String_+ || sym == StringAdd_+
def isArrowAssoc(sym: Symbol) = ArrowAssocClass.tpe.decls.toList contains sym
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index 47184eee51..38f51b1459 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -5487,6 +5487,10 @@ A type's typeSymbol should never be inspected directly.
case _ =>
t
}
+ def elimRefinement(t: Type) = t match {
+ case RefinedType(parents, decls) if !decls.isEmpty => intersectionType(parents)
+ case _ => t
+ }
/** A collector that tests for existential types appearing at given variance in a type */
class ContainsVariantExistentialCollector(v: Int) extends TypeCollector(false) {
diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
index 391d5ab8ee..3ddbffa75e 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
@@ -51,7 +51,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
intp.reporter.printMessage(msg)
def isAsync = !settings.Yreplsync.value
- lazy val power = Power(this)
+ lazy val power = new Power(intp, new StdReplVals(this))
// TODO
// object opt extends AestheticSettings
@@ -253,6 +253,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
/** Power user commands */
lazy val powerCommands: List[LoopCommand] = List(
nullary("dump", "displays a view of the interpreter's internal state", dumpCommand),
+ nullary("vals", "gives information about the power mode repl vals", valsCommand),
cmd("phase", "<phase>", "set the implicit phase for power commands", phaseCommand),
cmd("wrap", "<method>", "name of method to wrap around each repl line", wrapCommand) withLongHelp ("""
|:wrap
@@ -283,6 +284,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
history.asStrings takeRight 30 foreach echo
in.redrawLine()
}
+ private def valsCommand(): Result = power.valsDescription
private val typeTransforms = List(
"scala.collection.immutable." -> "immutable.",
diff --git a/src/compiler/scala/tools/nsc/interpreter/Power.scala b/src/compiler/scala/tools/nsc/interpreter/Power.scala
index ac7c2b1ecc..82a466a7e5 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Power.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Power.scala
@@ -15,54 +15,12 @@ import scala.io.Codec
import java.net.{ URL, MalformedURLException }
import io.{ Path }
-trait SharesGlobal {
- type GlobalType <: Global
- val global: GlobalType
-
- // This business gets really old:
- //
- // found : power.intp.global.Symbol
- // required: global.Symbol
- //
- // Have tried many ways to cast it aside, this is the current winner.
- // Todo: figure out a way to abstract over all the type members.
- type AnySymbol = Global#Symbol
- type AnyType = Global#Type
- type AnyName = Global#Name
- type AnyTree = Global#Tree
-
- type Symbol = global.Symbol
- type Type = global.Type
- type Name = global.Name
- type Tree = global.Tree
-
- implicit def upDependentSymbol(x: AnySymbol): Symbol = x.asInstanceOf[Symbol]
- implicit def upDependentType(x: AnyType): Type = x.asInstanceOf[Type]
- implicit def upDependentName(x: AnyName): Name = x.asInstanceOf[Name]
- implicit def upDependentTree(x: AnyTree): Tree = x.asInstanceOf[Tree]
-}
-
-object Power {
- def apply(intp: IMain): Power = apply(null, intp)
- def apply(repl: ILoop): Power = apply(repl, repl.intp)
- def apply(repl: ILoop, intp: IMain): Power =
- new Power(repl, intp) {
- type GlobalType = intp.global.type
- final val global: intp.global.type = intp.global
- }
-}
-
/** A class for methods to be injected into the intp in power mode.
*/
-abstract class Power(
- val repl: ILoop,
- val intp: IMain
-) extends SharesGlobal {
- import intp.{
- beQuietDuring, typeOfExpression, interpret, parse
- }
- import global._
- import definitions.{ getClassIfDefined, getModuleIfDefined }
+class Power[ReplValsImpl <: ReplVals : Manifest](val intp: IMain, replVals: ReplValsImpl) {
+ import intp.{ beQuietDuring, typeOfExpression, interpret, parse }
+ import intp.global._
+ import definitions.{ manifestToType, getClassIfDefined, getModuleIfDefined }
abstract class SymSlurper {
def isKeep(sym: Symbol): Boolean
@@ -130,11 +88,11 @@ abstract class Power(
private def customInit = replProps.powerInitCode.option flatMap (f => io.File(f).safeSlurp())
def banner = customBanner getOrElse """
- |** Power User mode enabled - BEEP BOOP SPIZ **
+ |** Power User mode enabled - BEEP WHIR GYVE **
|** :phase has been set to 'typer'. **
|** scala.tools.nsc._ has been imported **
- |** global._ and definitions._ also imported **
- |** Try :help, vals.<tab>, power.<tab> **
+ |** global._, definitions._ also imported **
+ |** Try :help, :vals, power.<tab> **
""".stripMargin.trim
private def initImports = List(
@@ -142,8 +100,9 @@ abstract class Power(
"scala.collection.JavaConverters._",
"intp.global.{ error => _, _ }",
"definitions.{ getClass => _, _ }",
- "power.Implicits._",
- "power.rutil._"
+ "power.rutil._",
+ "replImplicits._",
+ "treedsl.CODE._"
)
def init = customInit match {
@@ -155,12 +114,23 @@ abstract class Power(
*/
def unleash(): Unit = beQuietDuring {
// First we create the ReplVals instance and bind it to $r
- intp.bind("$r", new ReplVals(repl))
+ intp.bind("$r", replVals)
// Then we import everything from $r.
intp interpret ("import " + intp.pathToTerm("$r") + "._")
// And whatever else there is to do.
init.lines foreach (intp interpret _)
}
+ def valsDescription: String = {
+ def to_str(m: Symbol) = "%12s %s".format(
+ m.decodedName, "" + elimRefinement(m.accessedOrSelf.tpe) stripPrefix "scala.tools.nsc.")
+
+ ( rutil.info[ReplValsImpl].declares
+ filter (m => m.isPublic && !m.hasModuleFlag && !m.isConstructor)
+ sortBy (_.decodedName)
+ map to_str
+ mkString ("Name and type of values imported into the repl in power mode.\n\n", "\n", "")
+ )
+ }
trait LowPriorityInternalInfo {
implicit def apply[T: Manifest] : InternalInfo[T] = new InternalInfo[T](None)
@@ -180,25 +150,6 @@ abstract class Power(
private def symbol = symbol_
private def name = name_
- // Would love to have stuff like existential types working,
- // but very unfortunately those manifests just stuff the relevant
- // information into the toString method. Boo.
- private def manifestToType(m: Manifest[_]): Type = m match {
- case x: AnyValManifest[_] =>
- getClassIfDefined("scala." + x).tpe
- case _ =>
- val name = m.erasure.getName
- if (name endsWith nme.MODULE_SUFFIX_STRING)
- getModuleIfDefined(name stripSuffix nme.MODULE_SUFFIX_STRING).tpe
- else {
- val sym = getClassIfDefined(name)
- val args = m.typeArguments
-
- if (args.isEmpty) sym.tpe
- else typeRef(NoPrefix, sym, args map manifestToType)
- }
- }
-
def symbol_ : Symbol = getClassIfDefined(erasure.getName)
def tpe_ : Type = manifestToType(man)
def name_ : Name = symbol.name
@@ -208,9 +159,10 @@ abstract class Power(
def owner = symbol.owner
def owners = symbol.ownerChain drop 1
def defn = symbol.defString
+ def decls = symbol.info.decls
- def declares = members filter (_.owner == symbol)
- def inherits = members filterNot (_.owner == symbol)
+ def declares = decls.toList
+ def inherits = members filterNot (declares contains _)
def types = members filter (_.name.isTypeName)
def methods = members filter (_.isMethod)
def overrides = declares filter (_.isOverride)
@@ -233,8 +185,8 @@ abstract class Power(
def whoHas(name: String) = bts filter (_.decls exists (_.name.toString == name))
def <:<[U: Manifest](other: U) = tpe <:< InternalInfo[U].tpe
- def lub[U: Manifest](other: U) = global.lub(List(tpe, InternalInfo[U].tpe))
- def glb[U: Manifest](other: U) = global.glb(List(tpe, InternalInfo[U].tpe))
+ def lub[U: Manifest](other: U) = intp.global.lub(List(tpe, InternalInfo[U].tpe))
+ def glb[U: Manifest](other: U) = intp.global.glb(List(tpe, InternalInfo[U].tpe))
def shortClass = erasure.getName split "[$.]" last
override def toString = value match {
@@ -337,7 +289,7 @@ abstract class Power(
def pp() { intp prettyPrint slurp() }
}
- protected trait Implicits1 {
+ trait Implicits1 {
// fallback
implicit def replPrinting[T](x: T)(implicit pretty: Prettifier[T] = Prettifier.default[T]) =
new SinglePrettifierClass[T](x)
@@ -367,7 +319,6 @@ abstract class Power(
implicit def replInputStream(in: InputStream)(implicit codec: Codec) = new RichInputStream(in)
implicit def replEnhancedURLs(url: URL)(implicit codec: Codec): RichReplURL = new RichReplURL(url)(codec)
}
- object Implicits extends Implicits2 { }
trait ReplUtilities {
def module[T: Manifest] = getModuleIfDefined(manifest[T].erasure.getName stripSuffix nme.MODULE_SUFFIX_STRING)
@@ -396,11 +347,7 @@ abstract class Power(
}
lazy val rutil: ReplUtilities = new ReplUtilities { }
-
- lazy val phased: Phased = new Phased with SharesGlobal {
- type GlobalType = Power.this.global.type
- final val global: Power.this.global.type = Power.this.global
- }
+ lazy val phased: Phased = new { val global: intp.global.type = intp.global } with Phased { }
def context(code: String) = analyzer.rootContext(unit(code))
def source(code: String) = new BatchSourceFile("<console>", code)
diff --git a/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala b/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala
index 2f2489b242..6e5dec4205 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala
@@ -6,15 +6,68 @@
package scala.tools.nsc
package interpreter
-final class ReplVals(r: ILoop) {
- lazy val repl = r
- lazy val intp = r.intp
- lazy val power = r.power
- lazy val reader = r.in
- lazy val vals = this
- lazy val global = intp.global
- lazy val isettings = intp.isettings
- lazy val completion = reader.completion
- lazy val history = reader.history
- lazy val phased = power.phased
+/** A class which the repl utilizes to expose predefined objects.
+ * The base implementation is empty; the standard repl implementation
+ * is StdReplVals.
+ */
+abstract class ReplVals { }
+
+class StdReplVals(final val r: ILoop) extends ReplVals {
+ final lazy val repl = r
+ final lazy val intp = r.intp
+ final lazy val power = r.power
+ final lazy val reader = r.in
+ final lazy val vals = this
+ final lazy val global: intp.global.type = intp.global
+ final lazy val isettings = intp.isettings
+ final lazy val completion = reader.completion
+ final lazy val history = reader.history
+ final lazy val phased = power.phased
+ final lazy val analyzer = global.analyzer
+
+ final lazy val treedsl = new { val global: intp.global.type = intp.global } with ast.TreeDSL { }
+ final lazy val typer = analyzer.newTyper(
+ analyzer.rootContext(
+ power.unit("").asInstanceOf[analyzer.global.CompilationUnit]
+ )
+ )
+
+ final lazy val replImplicits = new power.Implicits2 {
+ import intp.global._
+
+ private val manifestFn = ReplVals.mkManifestToType[intp.global.type](global)
+ implicit def mkManifestToType(sym: Symbol) = manifestFn(sym)
+ }
+
+ def typed[T <: analyzer.global.Tree](tree: T): T = typer.typed(tree).asInstanceOf[T]
+}
+
+object ReplVals {
+ /** Latest attempt to work around the challenge of foo.global.Type
+ * not being seen as the same type as bar.global.Type even though
+ * the globals are the same. Dependent method types to the rescue.
+ */
+ def mkManifestToType[T <: Global](global: T) = {
+ import global._
+ import definitions._
+
+ /** We can't use definitions.manifestToType directly because we're passing
+ * it to map and the compiler refuses to perform eta expansion on a method
+ * with a dependent return type. (Can this be relaxed?) To get around this
+ * I have this forwarder which widens the type and then cast the result back
+ * to the dependent type.
+ */
+ def manifestToType(m: OptManifest[_]): Global#Type =
+ definitions.manifestToType(m)
+
+ class AppliedTypeFromManifests(sym: Symbol) {
+ def apply[M](implicit m1: Manifest[M]): Type =
+ appliedType(sym.typeConstructor, List(m1) map (x => manifestToType(x).asInstanceOf[Type]))
+
+ def apply[M1, M2](implicit m1: Manifest[M1], m2: Manifest[M2]): Type =
+ appliedType(sym.typeConstructor, List(m1, m2) map (x => manifestToType(x).asInstanceOf[Type]))
+ }
+
+ (sym: Symbol) => new AppliedTypeFromManifests(sym)
+ }
}
diff --git a/src/compiler/scala/tools/reflect/Mock.scala b/src/compiler/scala/tools/reflect/Mock.scala
index 5301816b4b..52c052b8a2 100644
--- a/src/compiler/scala/tools/reflect/Mock.scala
+++ b/src/compiler/scala/tools/reflect/Mock.scala
@@ -25,7 +25,8 @@ trait Mock extends (Invoked => AnyRef) {
def newInvocationHandler() = new InvocationHandler {
def invoke(proxy: AnyRef, method: Method, args: Array[AnyRef]) =
- mock(Invoked(proxy, method, args))
+ try { mock(Invoked(proxy, method, args)) }
+ catch { case _: NoClassDefFoundError => sys.exit(1) }
}
}