summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonio Cunei <antonio.cunei@epfl.ch>2009-12-17 11:42:29 +0000
committerAntonio Cunei <antonio.cunei@epfl.ch>2009-12-17 11:42:29 +0000
commit15523efdef8eadbdd8d79358ff002ed3958ec41b (patch)
treed37334bd213e291a2a8191aa3acf477fb532ed0f
parent32b6bb14ea0a6044f07ce1799649c6950d13d2fa (diff)
downloadscala-15523efdef8eadbdd8d79358ff002ed3958ec41b.tar.gz
scala-15523efdef8eadbdd8d79358ff002ed3958ec41b.tar.bz2
scala-15523efdef8eadbdd8d79358ff002ed3958ec41b.zip
Merged revisions 20172-20173,20175,20178 via sv...
Merged revisions 20172-20173,20175,20178 via svnmerge from https://lampsvn.epfl.ch/svn-repos/scala/scala/trunk ........ r20172 | extempore | 2009-12-16 18:37:27 +0100 (Wed, 16 Dec 2009) | 1 line Catch expanded names before they are visible in completion. no review. ........ r20173 | extempore | 2009-12-16 20:25:26 +0100 (Wed, 16 Dec 2009) | 2 lines REPL completion now understands type aliases defined in package objects. For instance try scala.List.<tab>. review by community. ........ r20175 | odersky | 2009-12-17 12:03:57 +0100 (Thu, 17 Dec 2009) | 1 line hardening the compiler to avoid exceptions I observed when used under Eclipse. ........ r20178 | cunei | 2009-12-17 12:16:58 +0100 (Thu, 17 Dec 2009) | 3 lines Adding target distpack-opt. Review by rytz. ........
-rw-r--r--build.xml8
-rw-r--r--src/compiler/scala/tools/nsc/Interpreter.scala16
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala8
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ByteCode.scala36
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Completion.scala44
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala15
-rw-r--r--src/compiler/scala/tools/nsc/transform/OverridingPairs.scala39
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala3
-rw-r--r--src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala2
-rw-r--r--src/library/scala/collection/Iterator.scala2
-rw-r--r--src/scalap/scala/tools/scalap/Decode.scala39
-rw-r--r--src/scalap/scala/tools/scalap/Main.scala3
12 files changed, 176 insertions, 39 deletions
diff --git a/build.xml b/build.xml
index fc315ee63f..32acdbfac8 100644
--- a/build.xml
+++ b/build.xml
@@ -1541,9 +1541,15 @@ FORWARDED TARGETS FOR PACKAGING
<target name="distpack" depends="dist.done">
<ant antfile="${src.dir}/build/pack.xml" target="pack-all.done" inheritall="yes" inheritrefs="yes"/>
</target>
+
+ <target name="distpack-opt"
+ description="Builds an optimised distribution.">
+ <antcall target="distpack">
+ <param name="scalac.args.optimise" value="-optimise"/>
+ </antcall>
+ </target>
<!-- Used by the scala-installer script -->
- <target name="alldistpack" depends="distpack"/>
<target name="allallclean" depends="all.clean"/>
<!-- ===========================================================================
diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala
index 7ca2a4ecf9..55e3b354e5 100644
--- a/src/compiler/scala/tools/nsc/Interpreter.scala
+++ b/src/compiler/scala/tools/nsc/Interpreter.scala
@@ -145,8 +145,8 @@ class Interpreter(val settings: Settings, out: PrintWriter)
shadow the old ones, and old code objects refer to the old
definitions.
*/
- private var classLoader: ScalaClassLoader = makeClassLoader()
- private def makeClassLoader(): ScalaClassLoader = {
+ private var classLoader: AbstractFileClassLoader = makeClassLoader()
+ private def makeClassLoader(): AbstractFileClassLoader = {
val parent =
if (parentClassLoader == null) ScalaClassLoader fromURLs compilerClasspath
else new URLClassLoader(compilerClasspath, parentClassLoader)
@@ -873,6 +873,9 @@ class Interpreter(val settings: Settings, out: PrintWriter)
| map(_.getName) .
| mkString(" ")""".stripMargin.format(filterFlags)
+ private def getOriginalName(name: String): String =
+ nme.originalName(newTermName(name)).toString
+
/** The main entry point for tab-completion. When the user types x.<tab>
* this method is called with "x" as an argument, and it discovers the
* fields and methods of x via reflection and returns their names to jline.
@@ -892,7 +895,7 @@ class Interpreter(val settings: Settings, out: PrintWriter)
str.substring(str.indexOf('=') + 1).trim .
split(" ").toList .
- map(decode) .
+ map(x => decode(getOriginalName(x))) .
filterNot(shouldHide) .
removeDuplicates
}
@@ -904,13 +907,14 @@ class Interpreter(val settings: Settings, out: PrintWriter)
/** Another entry point for tab-completion, ids in scope */
def unqualifiedIds(): List[String] =
- allBoundNames .
- map(_.toString) .
- filter(!isSynthVarName(_))
+ allBoundNames map (_.toString) filterNot isSynthVarName
/** For static/object method completion */
def getClassObject(path: String): Option[Class[_]] = classLoader tryToLoadClass path
+ /** Parse the ScalaSig to find type aliases */
+ def aliasForType(path: String) = ByteCode.aliasForType(path)
+
// debugging
private var debuggingOutput = false
def DBG(s: String) = if (debuggingOutput) out println s else ()
diff --git a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
index 1c5fa3a5b9..c821b9ed80 100644
--- a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
@@ -18,7 +18,7 @@ class AbstractFileClassLoader(root: AbstractFile, parent: ClassLoader)
extends ClassLoader(parent)
with ScalaClassLoader
{
- override def findClass(name: String): Class[_] = {
+ def getBytesForClass(name: String): Array[Byte] = {
def onull[T](x: T): T = if (x == null) throw new ClassNotFoundException(name) else x
var file: AbstractFile = root
val pathParts = name.split("[./]").toList
@@ -27,7 +27,11 @@ class AbstractFileClassLoader(root: AbstractFile, parent: ClassLoader)
file = onull(file.lookupName(dirPart, true))
file = onull(file.lookupName(pathParts.last+".class", false))
- val bytes = file.toByteArray
+ file.toByteArray
+ }
+
+ override def findClass(name: String): Class[_] = {
+ val bytes = getBytesForClass(name)
defineClass(name, bytes, 0, bytes.length)
}
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala b/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala
new file mode 100644
index 0000000000..d66cbb7818
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala
@@ -0,0 +1,36 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2010 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package interpreter
+
+import java.io.File
+import java.util.jar.{ JarEntry, JarFile }
+import java.util.concurrent.ConcurrentHashMap
+import util.ScalaClassLoader.getSystemLoader
+
+object ByteCode {
+ /** Until I figure out why I can't get scalap onto the classpath such
+ * that the compiler will bootstrap, we have to use reflection.
+ */
+ private lazy val DECODE: Option[String => Option[Map[String, String]]] =
+ for (clazz <- getSystemLoader.tryToLoadClass[AnyRef]("scala.tools.scalap.Decode$")) yield {
+ val module = clazz.getField("MODULE$").get()
+ val method = clazz.getMethod("typeAliases", classOf[String])
+ val map = method.invoke(module, _: String).asInstanceOf[Option[Map[String, String]]]
+ map
+ }
+
+ def aliasesForPackage(pkg: String) = DECODE flatMap (_(pkg))
+
+ /** Use scalap to look through type aliases */
+ def aliasForType(path: String): Option[String] = {
+ val (pkg, name) = (path lastIndexOf '.') match {
+ case -1 => return None
+ case idx => (path take idx, path drop (idx + 1))
+ }
+ aliasesForPackage(pkg) flatMap (_ get name)
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
index 3303ba3550..2ecafa974a 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
@@ -38,10 +38,7 @@ class Completion(val interpreter: Interpreter) extends Completor {
// it takes a little while to look through the jars so we use a future and a concurrent map
class CompletionAgent {
- val dottedPaths = new ConcurrentHashMap[String, List[String]]
- // TODO - type aliases defined in package objects, like scala.List.<tab>
- // val typeAliases = new ConcurrentHashMap[String, String]
- // val packageObjects = new ConcurrentHashMap[String, List[String]]
+ val dottedPaths = new ConcurrentHashMap[String, List[CompletionInfo]]
val topLevelPackages = new DelayedLazyVal(
() => enumToList(dottedPaths.keys) filterNot (_ contains '.'),
getDottedPaths(dottedPaths, interpreter)
@@ -121,14 +118,12 @@ class Completion(val interpreter: Interpreter) extends Completor {
}
}
- def getOrElse[K, V](map: ConcurrentHashMap[K, V], key: K, value: => V) =
- if (map containsKey key) map get key
- else value
-
def isValidId(s: String) = interpreter.unqualifiedIds contains s
def membersOfId(s: String) = interpreter membersOfIdentifier s
def membersOfPath(s: String) = {
- val xs = getOrElse(dottedPaths, s, Nil)
+ val xs =
+ if (dottedPaths containsKey s) dottedPaths get s map (_.visibleName)
+ else Nil
s match {
case "scala" => xs filterNot scalaToHide
@@ -191,7 +186,11 @@ class Completion(val interpreter: Interpreter) extends Completor {
// java style, static methods
val js = getClassObject(path) map (getMembers(_, true)) getOrElse Nil
// scala style, methods on companion object
- val ss = getClassObject(path + "$") map (getMembers(_, false)) getOrElse Nil
+ // if getClassObject fails, see if there is a type alias
+ val clazz = getClassObject(path + "$") orElse {
+ (ByteCode aliasForType path) flatMap (x => getClassObject(x + "$"))
+ }
+ val ss = clazz map (getMembers(_, false)) getOrElse Nil
js ::: ss
}
@@ -201,6 +200,7 @@ object Completion
{
import java.io.File
import java.util.jar.{ JarEntry, JarFile }
+ import scala.tools.nsc.io.Streamable
val EXPAND_SEPARATOR_STRING = "$$"
val ANON_CLASS_NAME = "$anon"
@@ -208,6 +208,24 @@ object Completion
val IMPL_CLASS_SUFFIX ="$class"
val INTERPRETER_VAR_PREFIX = "res"
+ case class CompletionInfo(visibleName: String, className: String, jar: String) {
+ lazy val jarfile = new JarFile(jar)
+ lazy val entry = jarfile getEntry className
+
+ override def hashCode = visibleName.hashCode
+ override def equals(other: Any) = other match {
+ case x: CompletionInfo => visibleName == x.visibleName
+ case _ => false
+ }
+
+ def getBytes(): Array[Byte] = {
+ if (entry == null) Array() else {
+ val x = new Streamable.Bytes { def inputStream() = jarfile getInputStream entry }
+ x.toByteArray()
+ }
+ }
+ }
+
def enumToList[T](e: java.util.Enumeration[T]): List[T] = enumToList(e, Nil)
def enumToList[T](e: java.util.Enumeration[T], xs: List[T]): List[T] =
if (e == null || !e.hasMoreElements) xs else enumToList(e, e.nextElement :: xs)
@@ -233,7 +251,7 @@ object Completion
// all the dotted path to classfiles we can find by poking through the jars
def getDottedPaths(
- map: ConcurrentHashMap[String, List[String]],
+ map: ConcurrentHashMap[String, List[CompletionInfo]],
interpreter: Interpreter): Unit =
{
val cp =
@@ -264,7 +282,9 @@ object Completion
def oneJar(jar: String): Unit = {
val classfiles = Completion getClassFiles jar
- for (cl <- classfiles.removeDuplicates ; (k, v) <- subpaths(cl)) {
+ for (cl <- classfiles.removeDuplicates ; (k, _v) <- subpaths(cl)) {
+ val v = CompletionInfo(_v, cl, jar)
+
if (map containsKey k) {
val vs = map.get(k)
if (vs contains v) ()
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 18597a037c..24abef8944 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -118,16 +118,23 @@ trait Types {
// `block` should not affect constraints on typevars
def undo[T](block: => T): T = {
val before = log
- val result = block
- undoTo(before)
+ val result = try {
+ block
+ } finally {
+ undoTo(before)
+ }
result
}
// if `block` evaluates to false, it should not affect constraints on typevars
def undoUnless(block: => Boolean): Boolean = {
val before = log
- val result = block
- if(!result) undoTo(before)
+ var result = false
+ try {
+ result = block
+ } finally {
+ if(!result) undoTo(before)
+ }
result
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala
index 9ccc4a8320..cdbea6fcfe 100644
--- a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala
+++ b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala
@@ -104,6 +104,10 @@ abstract class OverridingPairs {
*/
private val index = new HashMap[Symbol, Int]
+ // Note: overridingPairs can be called at odd instances by the Eclipse plugin
+ // Soemtimes symbols are not yet defined and we get missing keys.
+ // The implementation here is hardened so that it does not crash on a missing key.
+
{ var i = 0
for (bc <- base.info.baseClasses) {
index(bc) = i
@@ -126,22 +130,37 @@ abstract class OverridingPairs {
{ for (i <- List.range(0, size))
subParents(i) = new BitSet(size);
for (p <- parents) {
- val pIndex = index(p.typeSymbol)
- for (bc <- p.baseClasses)
- if (p.baseType(bc) =:= self.baseType(bc))
- include(subParents(index(bc)), pIndex)
- else if (settings.debug.value)
- log("SKIPPING "+p+" -> "+p.baseType(bc)+" / "+self.baseType(bc)+" from "+base)
+ index get p.typeSymbol match {
+ case Some(pIndex) =>
+ for (bc <- p.baseClasses)
+ if (p.baseType(bc) =:= self.baseType(bc))
+ index get bc match {
+ case Some(bcIndex) =>
+ include(subParents(bcIndex), pIndex)
+ case None =>
+ }
+ else if (settings.debug.value)
+ log("SKIPPING "+p+" -> "+p.baseType(bc)+" / "+self.baseType(bc)+" from "+base)
+ case None =>
+ }
}
- }
+ }
/** Do `sym1` and `sym2` have a common subclass in `parents`?
* In that case we do not follow their overriding pairs
*/
private def hasCommonParentAsSubclass(sym1: Symbol, sym2: Symbol) = {
- val index1 = index(sym1.owner)
- val index2 = index(sym2.owner)
- intersectionContainsElementLeq(subParents(index1), subParents(index2), index1 min index2)
+ index get sym1.owner match {
+ case Some(index1) =>
+ index get sym2.owner match {
+ case Some(index2) =>
+ intersectionContainsElementLeq(subParents(index1), subParents(index2), index1 min index2)
+ case None =>
+ false
+ }
+ case None =>
+ false
+ }
}
/** The scope entries that have already been visited as overridden
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 1c746d0ab9..e541c58c1a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -4026,6 +4026,9 @@ trait Typers { self: Analyzer =>
// and we try again (@see tryTypedApply). In that case we can assign
// whatever type to tree; we just have to survive until a real error message is issued.
tree setType AnyClass.tpe
+ case Import(expr, selectors) =>
+ assert(onlyPresentation) // should not happen in normal circumstances.
+ tree setType tree.symbol.tpe
case _ =>
throw new Error("unexpected tree: " + tree.getClass + "\n" + tree)//debug
}
diff --git a/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala
index 62f11c544c..95396dd95b 100644
--- a/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala
+++ b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala
@@ -67,7 +67,7 @@ object ScalaClassLoader {
def setContextLoader(cl: JavaClassLoader) = Thread.currentThread.setContextClassLoader(cl)
def getContextLoader() = Thread.currentThread.getContextClassLoader()
- def getSystemLoader() = JavaClassLoader.getSystemClassLoader()
+ def getSystemLoader(): ScalaClassLoader = new JavaClassLoader(JavaClassLoader.getSystemClassLoader()) with ScalaClassLoader
def defaultParentClassLoader() = findExtClassLoader()
def fromURLs(urls: Seq[URL]): URLClassLoader =
diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala
index 07a2d55668..54a38848dd 100644
--- a/src/library/scala/collection/Iterator.scala
+++ b/src/library/scala/collection/Iterator.scala
@@ -1098,7 +1098,7 @@ trait Iterator[+A] { self =>
* @param dest The buffer to which elements are copied
*/
def copyToBuffer[B >: A](dest: Buffer[B]) {
- while (hasNext) dest += next
+ while (hasNext) dest += next()
}
/** Traverses this iterator and returns all produced values in a list.
diff --git a/src/scalap/scala/tools/scalap/Decode.scala b/src/scalap/scala/tools/scalap/Decode.scala
new file mode 100644
index 0000000000..d859ac5766
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/Decode.scala
@@ -0,0 +1,39 @@
+/* ___ ____ ___ __ ___ ___
+** / _// __// _ | / / / _ | / _ \ Scala classfile decoder
+** __\ \/ /__/ __ |/ /__/ __ |/ ___/ (c) 2003-2010, LAMP/EPFL
+** /____/\___/_/ |_/____/_/ |_/_/ http://scala-lang.org/
+**
+*/
+
+// $Id$
+
+package scala.tools.scalap
+
+import scala.tools.scalap.scalax.rules.scalasig._
+import scala.tools.nsc.util.ScalaClassLoader.getSystemLoader
+
+/** Temporary decoder. This would be better off in the scala.tools.nsc
+ * but right now the compiler won't acknowledge scala.tools.scalap
+ * when it's bootstrapping, so the reference has to go from here to there.
+ */
+object Decode {
+ private def getAliasSymbol(t: Type): Symbol = t match {
+ case TypeRefType(_, s, _) => s
+ case PolyType(typeRef, _) => getAliasSymbol(typeRef)
+ case _ => NoSymbol
+ }
+
+ /** Returns a map of Alias -> Type for the given package.
+ */
+ def typeAliases(pkg: String) = {
+ for {
+ clazz <- getSystemLoader.tryToLoadClass[AnyRef](pkg + ".package")
+ ssig <- ScalaSigParser.parse(clazz)
+ }
+ yield {
+ val typeAliases = ssig.symbols partialMap { case x: AliasSymbol => x }
+ Map(typeAliases map (x => (x.name, getAliasSymbol(x.infoType).path)): _*)
+ }
+ }
+}
+
diff --git a/src/scalap/scala/tools/scalap/Main.scala b/src/scalap/scala/tools/scalap/Main.scala
index 2211945aab..59c77813dd 100644
--- a/src/scalap/scala/tools/scalap/Main.scala
+++ b/src/scalap/scala/tools/scalap/Main.scala
@@ -9,7 +9,6 @@
package scala.tools.scalap
-
import java.io.{File, PrintStream, OutputStreamWriter, ByteArrayOutputStream}
import scalax.rules.scalasig._
import tools.nsc.io.AbstractFile
@@ -46,7 +45,7 @@ object Main {
def isScalaFile(bytes: Array[Byte]): Boolean = {
val byteCode = ByteCode(bytes)
val classFile = ClassFileParser.parse(byteCode)
- classFile.attribute("ScalaSig") match {case Some(_) => true; case None => false}
+ classFile.attribute("ScalaSig").isDefined
}
/**Processes the given Java class file.