summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/library/scala/concurrent/SyncVar.scala6
-rw-r--r--src/library/scala/util/MurmurHash.scala199
-rw-r--r--src/library/scala/util/hashing/MurmurHash3.scala8
-rw-r--r--src/reflect/scala/reflect/internal/Kinds.scala176
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala20
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ExprTyper.scala15
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ILoop.scala13
-rw-r--r--src/repl/scala/tools/nsc/interpreter/IMain.scala2
-rw-r--r--src/repl/scala/tools/nsc/interpreter/package.scala42
10 files changed, 473 insertions, 10 deletions
diff --git a/src/library/scala/concurrent/SyncVar.scala b/src/library/scala/concurrent/SyncVar.scala
index d22471ac0f..76d21c3dbf 100644
--- a/src/library/scala/concurrent/SyncVar.scala
+++ b/src/library/scala/concurrent/SyncVar.scala
@@ -79,7 +79,8 @@ class SyncVar[A] {
// whether or not the SyncVar is already defined. So, set has been
// deprecated in order to eventually be able to make "setting" private
@deprecated("Use `put` instead, as `set` is potentionally error-prone", "2.10.0")
- private[scala] def set(x: A): Unit = setVal(x)
+ // NOTE: Used by SBT 0.13.0-M2 and below
+ def set(x: A): Unit = setVal(x)
/** Places a value in the SyncVar. If the SyncVar already has a stored value,
* it waits until another thread takes it */
@@ -98,7 +99,8 @@ class SyncVar[A] {
// whether or not the SyncVar is already defined. So, unset has been
// deprecated in order to eventually be able to make "unsetting" private
@deprecated("Use `take` instead, as `unset` is potentionally error-prone", "2.10.0")
- private[scala] def unset(): Unit = synchronized {
+ // NOTE: Used by SBT 0.13.0-M2 and below
+ def unset(): Unit = synchronized {
isDefined = false
value = None
notifyAll()
diff --git a/src/library/scala/util/MurmurHash.scala b/src/library/scala/util/MurmurHash.scala
new file mode 100644
index 0000000000..6b306211dc
--- /dev/null
+++ b/src/library/scala/util/MurmurHash.scala
@@ -0,0 +1,199 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+package util
+
+/** An implementation of Austin Appleby's MurmurHash 3.0 algorithm
+ * (32 bit version); reference: http://code.google.com/p/smhasher
+ *
+ * This is the hash used by collections and case classes (including
+ * tuples).
+ *
+ * @author Rex Kerr
+ * @version 2.9
+ * @since 2.9
+ */
+
+import java.lang.Integer.{ rotateLeft => rotl }
+import scala.collection.Iterator
+
+/** A class designed to generate well-distributed non-cryptographic
+ * hashes. It is designed to be passed to a collection's foreach method,
+ * or can take individual hash values with append. Its own hash code is
+ * set equal to the hash code of whatever it is hashing.
+ */
+@deprecated("Use the object MurmurHash3 instead.", "2.10.0")
+class MurmurHash[@specialized(Int,Long,Float,Double) T](seed: Int) extends (T => Unit) {
+ import MurmurHash._
+
+ private var h = startHash(seed)
+ private var c = hiddenMagicA
+ private var k = hiddenMagicB
+ private var hashed = false
+ private var hashvalue = h
+
+ /** Begin a new hash using the same seed. */
+ def reset() {
+ h = startHash(seed)
+ c = hiddenMagicA
+ k = hiddenMagicB
+ hashed = false
+ }
+
+ /** Incorporate the hash value of one item. */
+ def apply(t: T) {
+ h = extendHash(h,t.##,c,k)
+ c = nextMagicA(c)
+ k = nextMagicB(k)
+ hashed = false
+ }
+
+ /** Incorporate a known hash value. */
+ def append(i: Int) {
+ h = extendHash(h,i,c,k)
+ c = nextMagicA(c)
+ k = nextMagicB(k)
+ hashed = false
+ }
+
+ /** Retrieve the hash value */
+ def hash = {
+ if (!hashed) {
+ hashvalue = finalizeHash(h)
+ hashed = true
+ }
+ hashvalue
+ }
+ override def hashCode = hash
+}
+
+/** An object designed to generate well-distributed non-cryptographic
+ * hashes. It is designed to hash a collection of integers; along with
+ * the integers to hash, it generates two magic streams of integers to
+ * increase the distribution of repetitive input sequences. Thus,
+ * three methods need to be called at each step (to start and to
+ * incorporate a new integer) to update the values. Only one method
+ * needs to be called to finalize the hash.
+ */
+@deprecated("Use the object MurmurHash3 instead.", "2.10.0")
+// NOTE: Used by SBT 0.13.0-M2 and below
+object MurmurHash {
+ // Magic values used for MurmurHash's 32 bit hash.
+ // Don't change these without consulting a hashing expert!
+ final private val visibleMagic = 0x971e137b
+ final private val hiddenMagicA = 0x95543787
+ final private val hiddenMagicB = 0x2ad7eb25
+ final private val visibleMixer = 0x52dce729
+ final private val hiddenMixerA = 0x7b7d159c
+ final private val hiddenMixerB = 0x6bce6396
+ final private val finalMixer1 = 0x85ebca6b
+ final private val finalMixer2 = 0xc2b2ae35
+
+ // Arbitrary values used for hashing certain classes
+ final private val seedString = 0xf7ca7fd2
+ final private val seedArray = 0x3c074a61
+
+ /** The first 23 magic integers from the first stream are stored here */
+ val storedMagicA =
+ Iterator.iterate(hiddenMagicA)(nextMagicA).take(23).toArray
+
+ /** The first 23 magic integers from the second stream are stored here */
+ val storedMagicB =
+ Iterator.iterate(hiddenMagicB)(nextMagicB).take(23).toArray
+
+ /** Begin a new hash with a seed value. */
+ def startHash(seed: Int) = seed ^ visibleMagic
+
+ /** The initial magic integers in the first stream. */
+ def startMagicA = hiddenMagicA
+
+ /** The initial magic integer in the second stream. */
+ def startMagicB = hiddenMagicB
+
+ /** Incorporates a new value into an existing hash.
+ *
+ * @param hash the prior hash value
+ * @param value the new value to incorporate
+ * @param magicA a magic integer from the stream
+ * @param magicB a magic integer from a different stream
+ * @return the updated hash value
+ */
+ def extendHash(hash: Int, value: Int, magicA: Int, magicB: Int) = {
+ (hash ^ rotl(value*magicA,11)*magicB)*3 + visibleMixer
+ }
+
+ /** Given a magic integer from the first stream, compute the next */
+ def nextMagicA(magicA: Int) = magicA*5 + hiddenMixerA
+
+ /** Given a magic integer from the second stream, compute the next */
+ def nextMagicB(magicB: Int) = magicB*5 + hiddenMixerB
+
+ /** Once all hashes have been incorporated, this performs a final mixing */
+ def finalizeHash(hash: Int) = {
+ var i = (hash ^ (hash>>>16))
+ i *= finalMixer1
+ i ^= (i >>> 13)
+ i *= finalMixer2
+ i ^= (i >>> 16)
+ i
+ }
+
+ /** Compute a high-quality hash of an array */
+ def arrayHash[@specialized T](a: Array[T]) = {
+ var h = startHash(a.length * seedArray)
+ var c = hiddenMagicA
+ var k = hiddenMagicB
+ var j = 0
+ while (j < a.length) {
+ h = extendHash(h, a(j).##, c, k)
+ c = nextMagicA(c)
+ k = nextMagicB(k)
+ j += 1
+ }
+ finalizeHash(h)
+ }
+
+ /** Compute a high-quality hash of a string */
+ def stringHash(s: String) = {
+ var h = startHash(s.length * seedString)
+ var c = hiddenMagicA
+ var k = hiddenMagicB
+ var j = 0
+ while (j+1 < s.length) {
+ val i = (s.charAt(j)<<16) + s.charAt(j+1)
+ h = extendHash(h,i,c,k)
+ c = nextMagicA(c)
+ k = nextMagicB(k)
+ j += 2
+ }
+ if (j < s.length) h = extendHash(h,s.charAt(j),c,k)
+ finalizeHash(h)
+ }
+
+ /** Compute a hash that is symmetric in its arguments--that is,
+ * where the order of appearance of elements does not matter.
+ * This is useful for hashing sets, for example.
+ */
+ def symmetricHash[T](xs: scala.collection.TraversableOnce[T], seed: Int) = {
+ var a,b,n = 0
+ var c = 1
+ xs.seq.foreach(i => {
+ val h = i.##
+ a += h
+ b ^= h
+ if (h != 0) c *= h
+ n += 1
+ })
+ var h = startHash(seed * n)
+ h = extendHash(h, a, storedMagicA(0), storedMagicB(0))
+ h = extendHash(h, b, storedMagicA(1), storedMagicB(1))
+ h = extendHash(h, c, storedMagicA(2), storedMagicB(2))
+ finalizeHash(h)
+ }
+}
diff --git a/src/library/scala/util/hashing/MurmurHash3.scala b/src/library/scala/util/hashing/MurmurHash3.scala
index c38d0f4da5..af0b12d8ba 100644
--- a/src/library/scala/util/hashing/MurmurHash3.scala
+++ b/src/library/scala/util/hashing/MurmurHash3.scala
@@ -275,4 +275,12 @@ object MurmurHash3 extends MurmurHash3 {
finalizeHash(h, n)
}
*/
+
+ @deprecated("Use unorderedHash", "2.10.0")
+ final def symmetricHash[T](xs: scala.collection.GenTraversableOnce[T], seed: Int = symmetricSeed): Int =
+ unorderedHash(xs.seq, seed)
+
+ @deprecated("Use orderedHash", "2.10.0")
+ final def traversableHash[T](xs: scala.collection.GenTraversableOnce[T], seed: Int = traversableSeed): Int =
+ orderedHash(xs.seq, seed)
}
diff --git a/src/reflect/scala/reflect/internal/Kinds.scala b/src/reflect/scala/reflect/internal/Kinds.scala
index 4612e65e7a..46a95c7d26 100644
--- a/src/reflect/scala/reflect/internal/Kinds.scala
+++ b/src/reflect/scala/reflect/internal/Kinds.scala
@@ -230,4 +230,180 @@ trait Kinds {
}
}
}
+
+ /**
+ * The data structure describing the kind of a given type.
+ *
+ * Proper types are represented using ProperTypeKind.
+ *
+ * Type constructors are reprented using TypeConKind.
+ */
+ abstract class Kind {
+ import Kind.StringState
+ def description: String
+ def order: Int
+ def bounds: TypeBounds
+
+ /** Scala syntax notation of this kind.
+ * Proper types are expresses as A.
+ * Type constructors are expressed as F[k1 >: lo <: hi, k2, ...] where k1, k2, ... are parameter kinds.
+ * If the bounds exists at any level, it preserves the type variable names. Otherwise,
+ * it uses prescribed letters for each level: A, F, X, Y, Z.
+ */
+ def scalaNotation: String
+
+ /** Kind notation used in http://adriaanm.github.com/files/higher.pdf.
+ * Proper types are expressed as *.
+ * Type constructors are expressed * -> *(lo, hi) -(+)-> *.
+ */
+ def starNotation: String
+
+ /** Contains bounds either as part of itself or its arguments.
+ */
+ def hasBounds: Boolean = !bounds.isEmptyBounds
+
+ private[internal] def buildState(sym: Symbol, v: Variance)(s: StringState): StringState
+ }
+ object Kind {
+ private[internal] sealed trait ScalaNotation
+ private[internal] sealed case class Head(order: Int, n: Option[Int], alias: Option[String]) extends ScalaNotation {
+ override def toString: String = {
+ alias getOrElse {
+ typeAlias(order) + n.map(_.toString).getOrElse("")
+ }
+ }
+ private def typeAlias(x: Int): String =
+ x match {
+ case 0 => "A"
+ case 1 => "F"
+ case 2 => "X"
+ case 3 => "Y"
+ case 4 => "Z"
+ case n if n < 12 => ('O'.toInt - 5 + n).toChar.toString
+ case _ => "V"
+ }
+ }
+ private[internal] sealed case class Text(value: String) extends ScalaNotation {
+ override def toString: String = value
+ }
+ private[internal] case class StringState(tokens: Seq[ScalaNotation]) {
+ override def toString: String = tokens.mkString
+ def append(value: String): StringState = StringState(tokens :+ Text(value))
+ def appendHead(order: Int, sym: Symbol): StringState = {
+ val n = countByOrder(order) + 1
+ val alias = if (sym eq NoSymbol) None
+ else Some(sym.nameString)
+ StringState(tokens :+ Head(order, Some(n), alias))
+ }
+ def countByOrder(o: Int): Int = tokens count {
+ case Head(`o`, _, _) => true
+ case t => false
+ }
+ // Replace Head(o, Some(1), a) with Head(o, None, a) if countByOrder(o) <= 1, so F1[A] becomes F[A]
+ def removeOnes: StringState = {
+ val maxOrder = (tokens map {
+ case Head(o, _, _) => o
+ case _ => 0
+ }).max
+ StringState((tokens /: (0 to maxOrder)) { (ts: Seq[ScalaNotation], o: Int) =>
+ if (countByOrder(o) <= 1)
+ ts map {
+ case Head(`o`, _, a) => Head(o, None, a)
+ case t => t
+ }
+ else ts
+ })
+ }
+ // Replace Head(o, n, Some(_)) with Head(o, n, None), so F[F] becomes F[A].
+ def removeAlias: StringState = {
+ StringState(tokens map {
+ case Head(o, n, Some(_)) => Head(o, n, None)
+ case t => t
+ })
+ }
+ }
+ private[internal] object StringState {
+ def empty: StringState = StringState(Seq())
+ }
+ }
+ class ProperTypeKind(val bounds: TypeBounds) extends Kind {
+ import Kind.StringState
+ val description: String = "This is a proper type."
+ val order = 0
+ private[internal] def buildState(sym: Symbol, v: Variance)(s: StringState): StringState = {
+ s.append(v.symbolicString).appendHead(order, sym).append(bounds.scalaNotation(_.toString))
+ }
+ def scalaNotation: String = Kind.Head(order, None, None) + bounds.scalaNotation(_.toString)
+ def starNotation: String = "*" + bounds.starNotation(_.toString)
+ }
+ object ProperTypeKind {
+ def apply: ProperTypeKind = this(TypeBounds.empty)
+ def apply(bounds: TypeBounds): ProperTypeKind = new ProperTypeKind(bounds)
+ def unapply(ptk: ProperTypeKind): Some[TypeBounds] = Some(ptk.bounds)
+ }
+
+ class TypeConKind(val bounds: TypeBounds, val args: Seq[TypeConKind.Argument]) extends Kind {
+ import Kind.StringState
+ val order = (args map {_.kind.order} max) + 1
+ def description: String =
+ if (order == 1) "This is a type constructor: a 1st-order-kinded type."
+ else "This is a type constructor that takes type constructor(s): a higher-kinded type."
+ override def hasBounds: Boolean = super.hasBounds || args.exists(_.kind.hasBounds)
+ def scalaNotation: String = {
+ val s = buildState(NoSymbol, Variance.Invariant)(StringState.empty).removeOnes
+ val s2 = if (hasBounds) s
+ else s.removeAlias
+ s2.toString
+ }
+ private[internal] def buildState(sym: Symbol, v: Variance)(s0: StringState): StringState = {
+ var s: StringState = s0
+ s = s.append(v.symbolicString).appendHead(order, sym).append("[")
+ args.zipWithIndex foreach { case (arg, i) =>
+ s = arg.kind.buildState(arg.sym, arg.variance)(s)
+ if (i != args.size - 1) {
+ s = s.append(",")
+ }
+ }
+ s = s.append("]").append(bounds.scalaNotation(_.toString))
+ s
+ }
+ def starNotation: String = {
+ import Variance._
+ (args map { arg =>
+ (if (arg.kind.order == 0) arg.kind.starNotation
+ else "(" + arg.kind.starNotation + ")") +
+ (if (arg.variance == Invariant) " -> "
+ else " -(" + arg.variance.symbolicString + ")-> ")
+ }).mkString + "*" + bounds.starNotation(_.toString)
+ }
+ }
+ object TypeConKind {
+ def apply(args: Seq[TypeConKind.Argument]): TypeConKind = this(TypeBounds.empty, args)
+ def apply(bounds: TypeBounds, args: Seq[TypeConKind.Argument]): TypeConKind = new TypeConKind(bounds, args)
+ def unapply(tck: TypeConKind): Some[(TypeBounds, Seq[TypeConKind.Argument])] = Some(tck.bounds, tck.args)
+ case class Argument(variance: Variance, kind: Kind)(val sym: Symbol) {}
+ }
+
+ /**
+ * Starting from a Symbol (sym) or a Type (tpe), infer the kind that classifies it (sym.tpeHK/tpe).
+ */
+ object inferKind {
+ import TypeConKind.Argument
+
+ abstract class InferKind {
+ protected def infer(tpe: Type, owner: Symbol, topLevel: Boolean): Kind
+ protected def infer(sym: Symbol, topLevel: Boolean): Kind = infer(sym.tpeHK, sym.owner, topLevel)
+ def apply(sym: Symbol): Kind = infer(sym, true)
+ def apply(tpe: Type, owner: Symbol): Kind = infer(tpe, owner, true)
+ }
+
+ def apply(pre: Type): InferKind = new InferKind {
+ protected def infer(tpe: Type, owner: Symbol, topLevel: Boolean): Kind = {
+ val bounds = if (topLevel) TypeBounds.empty
+ else tpe.asSeenFrom(pre, owner).bounds
+ if(!tpe.isHigherKinded) ProperTypeKind(bounds)
+ else TypeConKind(bounds, tpe.typeParams map { p => Argument(p.variance, infer(p, false))(p) })
+ }
+ }
+ }
}
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index cf4e210ccf..24bcfbb8d2 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -1506,7 +1506,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
def cookJavaRawInfo(): Unit = {
// only try once...
- if (this hasFlag TRIEDCOOKING)
+ if (phase.erasedTypes || (this hasFlag TRIEDCOOKING))
return
this setFlag TRIEDCOOKING
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 00fd20a46b..3956bbcdec 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -1435,13 +1435,27 @@ trait Types
case TypeBounds(_, _) => that <:< this
case _ => lo <:< that && that <:< hi
}
- private def lowerString = if (emptyLowerBound) "" else " >: " + lo
- private def upperString = if (emptyUpperBound) "" else " <: " + hi
private def emptyLowerBound = typeIsNothing(lo) || lo.isWildcard
private def emptyUpperBound = typeIsAny(hi) || hi.isWildcard
def isEmptyBounds = emptyLowerBound && emptyUpperBound
- override def safeToString = lowerString + upperString
+ override def safeToString = scalaNotation(_.toString)
+
+ /** Bounds notation used in Scala sytanx.
+ * For example +This <: scala.collection.generic.Sorted[K,This].
+ */
+ private[internal] def scalaNotation(typeString: Type => String): String = {
+ (if (emptyLowerBound) "" else " >: " + typeString(lo)) +
+ (if (emptyUpperBound) "" else " <: " + typeString(hi))
+ }
+ /** Bounds notation used in http://adriaanm.github.com/files/higher.pdf.
+ * For example *(scala.collection.generic.Sorted[K,This]).
+ */
+ private[internal] def starNotation(typeString: Type => String): String = {
+ if (emptyLowerBound && emptyUpperBound) ""
+ else if (emptyLowerBound) "(" + typeString(hi) + ")"
+ else "(%s, %s)" format (typeString(lo), typeString(hi))
+ }
override def kind = "TypeBoundsType"
}
diff --git a/src/repl/scala/tools/nsc/interpreter/ExprTyper.scala b/src/repl/scala/tools/nsc/interpreter/ExprTyper.scala
index 55182a4f95..9353215e1e 100644
--- a/src/repl/scala/tools/nsc/interpreter/ExprTyper.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ExprTyper.scala
@@ -95,4 +95,19 @@ trait ExprTyper {
}
finally typeOfExpressionDepth -= 1
}
+
+ // This only works for proper types.
+ def typeOfTypeString(typeString: String): Type = {
+ def asProperType(): Option[Type] = {
+ val name = freshInternalVarName()
+ val line = "def %s: %s = ???" format (name, typeString)
+ interpretSynthetic(line) match {
+ case IR.Success =>
+ val sym0 = symbolOfTerm(name)
+ Some(sym0.asMethod.returnType)
+ case _ => None
+ }
+ }
+ beSilentDuring(asProperType()) getOrElse NoType
+ }
}
diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
index 197e76d990..f4e06f6bfc 100644
--- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
@@ -222,6 +222,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
shCommand,
nullary("silent", "disable/enable automatic printing of results", verbosity),
cmd("type", "[-v] <expr>", "display the type of an expression without evaluating it", typeCommand),
+ cmd("kind", "[-v] <expr>", "display the kind of expression's type", kindCommand),
nullary("warnings", "show the suppressed warnings from the most recent line which had any", warningsCommand)
)
@@ -287,9 +288,15 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
// Still todo: modules.
private def typeCommand(line0: String): Result = {
line0.trim match {
- case "" => ":type [-v] <expression>"
- case s if s startsWith "-v " => intp.typeCommandInternal(s stripPrefix "-v " trim, verbose = true)
- case s => intp.typeCommandInternal(s, verbose = false)
+ case "" => ":type [-v] <expression>"
+ case s => intp.typeCommandInternal(s stripPrefix "-v " trim, verbose = s startsWith "-v ")
+ }
+ }
+
+ private def kindCommand(expr: String): Result = {
+ expr.trim match {
+ case "" => ":kind [-v] <expression>"
+ case s => intp.kindCommandInternal(s stripPrefix "-v " trim, verbose = s startsWith "-v ")
}
}
diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala
index 66129e0be8..379751b9a7 100644
--- a/src/repl/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala
@@ -899,7 +899,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
val preamble = """
|object %s {
| %s
- | val %s: String = %s {
+ | lazy val %s: String = %s {
| %s
| (""
""".stripMargin.format(
diff --git a/src/repl/scala/tools/nsc/interpreter/package.scala b/src/repl/scala/tools/nsc/interpreter/package.scala
index 52a085080b..f82c38f5e7 100644
--- a/src/repl/scala/tools/nsc/interpreter/package.scala
+++ b/src/repl/scala/tools/nsc/interpreter/package.scala
@@ -10,6 +10,7 @@ import scala.reflect.{ classTag, ClassTag }
import scala.reflect.runtime.{ universe => ru }
import scala.reflect.{ClassTag, classTag}
import scala.reflect.api.{Mirror, TypeCreator, Universe => ApiUniverse}
+import scala.util.control.Exception.catching
/** The main REPL related classes and values are as follows.
* In addition to standard compiler classes Global and Settings, there are:
@@ -127,6 +128,47 @@ package object interpreter extends ReplConfig with ReplStrings {
""
}
+ def kindCommandInternal(expr: String, verbose: Boolean): Unit = {
+ val catcher = catching(classOf[MissingRequirementError],
+ classOf[ScalaReflectionException])
+ def typeFromTypeString: Option[ClassSymbol] = catcher opt {
+ exprTyper.typeOfTypeString(expr).typeSymbol.asClass
+ }
+ def typeFromNameTreatedAsTerm: Option[ClassSymbol] = catcher opt {
+ val moduleClass = exprTyper.typeOfExpression(expr).typeSymbol
+ moduleClass.linkedClassOfClass.asClass
+ }
+ def typeFromFullName: Option[ClassSymbol] = catcher opt {
+ intp.global.rootMirror.staticClass(expr)
+ }
+ def typeOfTerm: Option[TypeSymbol] = replInfo(symbolOfLine(expr)).typeSymbol match {
+ case sym: TypeSymbol => Some(sym)
+ case _ => None
+ }
+ (typeFromTypeString orElse typeFromNameTreatedAsTerm orElse typeFromFullName orElse typeOfTerm) foreach { sym =>
+ val (kind, tpe) = exitingTyper {
+ val tpe = sym.tpeHK
+ (intp.global.inferKind(NoPrefix)(tpe, sym.owner), tpe)
+ }
+ echoKind(tpe, kind, verbose)
+ }
+ }
+
+ def echoKind(tpe: Type, kind: Kind, verbose: Boolean) {
+ def typeString(tpe: Type): String = {
+ tpe match {
+ case TypeRef(_, sym, _) => typeString(sym.typeSignature)
+ case RefinedType(_, _) => tpe.toString
+ case _ => tpe.typeSymbol.fullName
+ }
+ }
+ printAfterTyper(typeString(tpe) + "'s kind is " + kind.scalaNotation)
+ if (verbose) {
+ echo(kind.starNotation)
+ echo(kind.description)
+ }
+ }
+
/** TODO -
* -n normalize
* -l label with case class parameter names