diff options
author | Antonio Cunei <antonio.cunei@epfl.ch> | 2009-12-17 11:42:29 +0000 |
---|---|---|
committer | Antonio Cunei <antonio.cunei@epfl.ch> | 2009-12-17 11:42:29 +0000 |
commit | 15523efdef8eadbdd8d79358ff002ed3958ec41b (patch) | |
tree | d37334bd213e291a2a8191aa3acf477fb532ed0f | |
parent | 32b6bb14ea0a6044f07ce1799649c6950d13d2fa (diff) | |
download | scala-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.xml | 8 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Interpreter.scala | 16 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala | 8 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/ByteCode.scala | 36 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/Completion.scala | 44 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Types.scala | 15 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/OverridingPairs.scala | 39 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 3 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala | 2 | ||||
-rw-r--r-- | src/library/scala/collection/Iterator.scala | 2 | ||||
-rw-r--r-- | src/scalap/scala/tools/scalap/Decode.scala | 39 | ||||
-rw-r--r-- | src/scalap/scala/tools/scalap/Main.scala | 3 |
12 files changed, 176 insertions, 39 deletions
@@ -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. |