diff options
author | Paul Phillips <paulp@improving.org> | 2009-05-26 18:12:53 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2009-05-26 18:12:53 +0000 |
commit | 103c97f7deef02d81d6d87c21f751899c63683b1 (patch) | |
tree | 50680eb96e39e016f28df03582164cce1b73d5e2 /src/compiler | |
parent | 5e12bab4777dc63711834cd39bf8514fb7e8da40 (diff) | |
download | scala-103c97f7deef02d81d6d87c21f751899c63683b1.tar.gz scala-103c97f7deef02d81d6d87c21f751899c63683b1.tar.bz2 scala-103c97f7deef02d81d6d87c21f751899c63683b1.zip |
A big yet interim patch emerging from my attemp...
A big yet interim patch emerging from my attempts to centralize common
classloader-related code. As it turns out, not that much of the
patch is directly associated with that. Most of it is cleanup in the
neighborhoods I was visiting, but there are a few new library files
about which I'm open to feedback:
scala/util/control/Exception - lots of exception handling code.
scala/net/Utility - what would be the first file in scala.net.*,
more code to follow if that sounds like a good package idea.
scala/util/ScalaClassLoader - mostly convenience methods right
now, more sophistication to come
Also, this adds a :jar command to the repl which adds a jar to your
classpath and replays the session.
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/ant/ScalaBazaar.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/ant/ScalaTool.scala | 28 | ||||
-rw-r--r-- | src/compiler/scala/tools/ant/Scalac.scala | 310 | ||||
-rw-r--r-- | src/compiler/scala/tools/ant/sabbus/Compiler.scala | 26 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Interpreter.scala | 102 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/InterpreterLoop.scala | 20 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/MainGenericRunner.scala | 53 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ObjectRunner.scala | 72 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Settings.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala | 20 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/Completion.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/SymbolTable.scala | 4 |
12 files changed, 240 insertions, 402 deletions
diff --git a/src/compiler/scala/tools/ant/ScalaBazaar.scala b/src/compiler/scala/tools/ant/ScalaBazaar.scala index 74f311a376..a787d08365 100644 --- a/src/compiler/scala/tools/ant/ScalaBazaar.scala +++ b/src/compiler/scala/tools/ant/ScalaBazaar.scala @@ -15,7 +15,7 @@ package scala.tools.ant { import scala.collection.mutable.HashMap import java.io.{File, FileInputStream, FileOutputStream, FileWriter, StringReader} - import java.net.{URL, URLClassLoader} + import java.net.URL import java.util.{ArrayList, Vector} import java.util.zip.{ZipOutputStream, ZipEntry} diff --git a/src/compiler/scala/tools/ant/ScalaTool.scala b/src/compiler/scala/tools/ant/ScalaTool.scala index 6917da1287..9fc02859c8 100644 --- a/src/compiler/scala/tools/ant/ScalaTool.scala +++ b/src/compiler/scala/tools/ant/ScalaTool.scala @@ -169,20 +169,17 @@ class ScalaTool extends MatchingTask { private def error(message: String): Nothing = throw new BuildException(message, getLocation()) + // XXX encoding and generalize + private def getResourceAsCharStream(clazz: Class[_], resource: String): Stream[Char] = { + val stream = clazz.getClassLoader() getResourceAsStream resource + if (stream == null) Stream.empty + else Stream continually stream.read() takeWhile (_ != -1) map (_.asInstanceOf[Char]) + } + private def readAndPatchResource(resource: String, tokens: Map[String, String]): String = { - val chars = new Iterator[Char] { - private val stream = - this.getClass().getClassLoader().getResourceAsStream(resource) - private def readStream(): Char = stream.read().asInstanceOf[Char] - private var buf: Char = readStream() - def hasNext: Boolean = (buf != (-1.).asInstanceOf[Char]) - def next: Char = { - val bufbuf = buf - buf = readStream() - bufbuf - } - } + val chars = getResourceAsCharStream(this.getClass, resource).elements val builder = new StringBuilder() + while (chars.hasNext) { val char = chars.next if (char == '@') { @@ -212,13 +209,6 @@ class ScalaTool extends MatchingTask { writer.close() } - private def expandUnixVar(vars: Map[String,String]): Map[String,String] = - vars transform { (x, vari) => vari.replaceAll("#([^#]*)#", "\\$$1") } - - private def expandWinVar(vars: Map[String,String]): Map[String,String] = - vars transform { (x, vari) => vari.replaceAll("#([^#]*)#", "%_$1%") } - - /*============================================================================*\ ** The big execute method ** \*============================================================================*/ diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala index e9007c4238..3ede08f40c 100644 --- a/src/compiler/scala/tools/ant/Scalac.scala +++ b/src/compiler/scala/tools/ant/Scalac.scala @@ -12,7 +12,7 @@ package scala.tools.ant import java.io.{File,PrintWriter,BufferedWriter,FileWriter} -import org.apache.tools.ant.{BuildException, Project} +import org.apache.tools.ant.{ BuildException, Project, AntClassLoader } import org.apache.tools.ant.taskdefs.{MatchingTask,Java} import org.apache.tools.ant.types.{Path, Reference, FileSet} import org.apache.tools.ant.util.{FileUtils, GlobPatternMapper, @@ -106,6 +106,10 @@ class Scalac extends MatchingTask { * <code>unchecked</code> properties. */ object Flag extends PermissibleValue { val values = List("yes", "no", "on", "off") + def toBoolean(flag: String) = + if (flag == "yes" || flag == "on") Some(true) + else if (flag == "no" || flag == "off") Some(false) + else None } /** The directories that contain source files to compile. */ @@ -164,23 +168,39 @@ class Scalac extends MatchingTask { * (not only the number of files). */ protected var scalacDebugging: Boolean = false + /** Helpers */ + private def setOrAppend(old: Option[Path], arg: Path): Option[Path] = old match { + case Some(x) => x append arg ; Some(x) + case None => Some(arg) + } + private def pathAsList(p: Option[Path], name: String): List[File] = p match { + case None => error("Member '" + name + "' is empty.") + case Some(x) => x.list.toList map nameToFile + } + private def createNewPath(getter: () => Option[Path], setter: (Option[Path]) => Unit) = { + if (getter().isEmpty) + setter(Some(new Path(getProject()))) + + getter().get.createPath() + } + + private def plural(xs: List[Any]) = if (xs.size > 1) "s" else "" + private def plural(x: Int) = if (x > 1) "s" else "" + /*============================================================================*\ ** Properties setters ** \*============================================================================*/ + /** Sets the srcdir attribute. Used by Ant. * @param input The value of <code>origin</code>. */ def setSrcdir(input: Path) { - if (origin.isEmpty) origin = Some(input) - else origin.get.append(input) + origin = setOrAppend(origin, input) } /** Sets the <code>origin</code> as a nested src Ant parameter. * @return An origin path to be configured. */ - def createSrc(): Path = { - if (origin.isEmpty) origin = Some(new Path(getProject())) - origin.get.createPath() - } + def createSrc(): Path = createNewPath(origin _, origin = _) /** Sets the <code>origin</code> as an external reference Ant parameter. * @param input A reference to an origin path. */ @@ -194,20 +214,16 @@ class Scalac extends MatchingTask { /** Sets the <code>classpath</code> attribute. Used by Ant. * @param input The value of <code>classpath</code>. */ def setClasspath(input: Path) { - if (classpath.isEmpty) classpath = Some(input) - else classpath.get.append(input) + classpath = setOrAppend(classpath, input) } /** Sets the <code>compilerPath</code> attribute. Used by Ant. * @param input The value of <code>compilerPath</code>. */ def setCompilerPath(input : Path) { - if(compilerPath.isEmpty) compilerPath = Some(input) - else compilerPath.get.append(input) + compilerPath = setOrAppend(compilerPath, input) } - def createCompilerPath: Path = { - if (compilerPath.isEmpty) compilerPath = Some(new Path(getProject())) - compilerPath.get.createPath() - } + def createCompilerPath: Path = createNewPath(compilerPath _, compilerPath = _) + /** Sets the <code>compilerpathref</code> attribute. Used by Ant. * @param input The value of <code>compilerpathref</code>. */ def setCompilerPathRef(input: Reference) { @@ -216,10 +232,7 @@ class Scalac extends MatchingTask { /** Sets the <code>classpath</code> as a nested classpath Ant parameter. * @return A class path to be configured. */ - def createClasspath(): Path = { - if (classpath.isEmpty) classpath = Some(new Path(getProject())) - classpath.get.createPath() - } + def createClasspath(): Path = createNewPath(classpath _, classpath = _) /** Sets the <code>classpath</code> as an external reference Ant parameter. * @param input A reference to a class path. */ @@ -230,16 +243,12 @@ class Scalac extends MatchingTask { /** Sets the <code>sourcepath</code> attribute. Used by Ant. * @param input The value of <code>sourcepath</code>. */ def setSourcepath(input: Path) { - if (sourcepath.isEmpty) sourcepath = Some(input) - else sourcepath.get.append(input) + sourcepath = setOrAppend(sourcepath, input) } /** Sets the <code>sourcepath</code> as a nested sourcepath Ant parameter. * @return A source path to be configured. */ - def createSourcepath(): Path = { - if (sourcepath.isEmpty) sourcepath = Some(new Path(getProject())) - sourcepath.get.createPath() - } + def createSourcepath(): Path = createNewPath(sourcepath _, sourcepath = _) /** Sets the <code>sourcepath</code> as an external reference Ant parameter. * @param input A reference to a source path. */ @@ -251,17 +260,13 @@ class Scalac extends MatchingTask { * * @param input The value of <code>bootclasspath</code>. */ def setBootclasspath(input: Path) { - if (bootclasspath.isEmpty) bootclasspath = Some(input) - else bootclasspath.get.append(input) + bootclasspath = setOrAppend(bootclasspath, input) } /** Sets the <code>bootclasspath</code> as a nested sourcepath Ant * parameter. * @return A source path to be configured. */ - def createBootclasspath(): Path = { - if (bootclasspath.isEmpty) bootclasspath = Some(new Path(getProject())) - bootclasspath.get.createPath() - } + def createBootclasspath(): Path = createNewPath(bootclasspath _, bootclasspath = _) /** Sets the <code>bootclasspath</code> as an external reference Ant * parameter. @@ -272,15 +277,11 @@ class Scalac extends MatchingTask { /** Sets the external extensions path attribute. Used by Ant. * @param input The value of <code>extdirs</code>. */ def setExtdirs(input: Path) = - if (extdirs.isEmpty) extdirs = Some(input) - else extdirs.get.append(input) + extdirs = setOrAppend(extdirs, input) /** Sets the <code>extdirs</code> as a nested sourcepath Ant parameter. * @return An extensions path to be configured. */ - def createExtdirs(): Path = { - if (extdirs.isEmpty) extdirs = Some(new Path(getProject())) - extdirs.get.createPath() - } + def createExtdirs(): Path = createNewPath(extdirs _, extdirs = _) /** Sets the <code>extdirs</code> as an external reference Ant parameter. * @param input A reference to an extensions path. */ @@ -345,28 +346,19 @@ class Scalac extends MatchingTask { /** Set the <code>deprecation</code> info attribute. * @param input One of the flags <code>yes/no</code> or <code>on/off</code>. */ def setDeprecation(input: String) { - if (Flag.isPermissible(input)) - deprecation = Some("yes" == input || "on" == input) - else - error("Unknown deprecation flag '" + input + "'") + deprecation = Flag toBoolean input orElse error("Unknown deprecation flag '" + input + "'") } /** Set the <code>optimise</code> info attribute. * @param input One of the flags <code>yes/no</code> or <code>on/off</code>. */ def setOptimise(input: String) { - if (Flag.isPermissible(input)) - optimise = Some("yes" == input || "on" == input) - else - error("Unknown optimisation flag '" + input + "'") + optimise = Flag toBoolean input orElse error("Unknown optimisation flag '" + input + "'") } /** Set the <code>unchecked</code> info attribute. * @param input One of the flags <code>yes/no</code> or <code>on/off</code>. */ def setUnchecked(input: String) { - if (Flag.isPermissible(input)) - unchecked = Some("yes" == input || "on" == input) - else - error("Unknown unchecked flag '" + input + "'") + unchecked = Flag toBoolean input orElse error("Unknown unchecked flag '" + input + "'") } /** Sets the <code>force</code> attribute. Used by Ant. @@ -380,7 +372,6 @@ class Scalac extends MatchingTask { def setScalacdebugging(input: Boolean) { scalacDebugging = input } def setAssemname(input: String) { assemname = Some(input) } - def setAssemrefs(input: String) { assemrefs = Some(input) } /*============================================================================*\ @@ -390,16 +381,12 @@ class Scalac extends MatchingTask { /** Gets the value of the <code>classpath</code> attribute in a * Scala-friendly form. * @return The class path as a list of files. */ - protected def getClasspath: List[File] = - if (classpath.isEmpty) error("Member 'classpath' is empty.") - else List.fromArray(classpath.get.list()).map(nameToFile) + protected def getClasspath: List[File] = pathAsList(classpath, "classpath") /** Gets the value of the <code>origin</code> attribute in a * Scala-friendly form. * @return The origin path as a list of files. */ - protected def getOrigin: List[File] = - if (origin.isEmpty) error("Member 'origin' is empty.") - else List.fromArray(origin.get.list()).map(nameToFile) + protected def getOrigin: List[File] = pathAsList(origin, "origin") /** Gets the value of the <code>destination</code> attribute in a * Scala-friendly form. @@ -411,33 +398,22 @@ class Scalac extends MatchingTask { /** Gets the value of the <code>sourcepath</code> attribute in a * Scala-friendly form. * @return The source path as a list of files. */ - protected def getSourcepath: List[File] = - if (sourcepath.isEmpty) error("Member 'sourcepath' is empty.") - else List.fromArray(sourcepath.get.list()).map(nameToFile) + protected def getSourcepath: List[File] = pathAsList(sourcepath, "sourcepath") /** Gets the value of the <code>bootclasspath</code> attribute in a * Scala-friendly form. * @return The boot class path as a list of files. */ - protected def getBootclasspath: List[File] = - if (bootclasspath.isEmpty) error("Member 'bootclasspath' is empty.") - else List.fromArray(bootclasspath.get.list()).map(nameToFile) + protected def getBootclasspath: List[File] = pathAsList(bootclasspath, "bootclasspath") /** Gets the value of the <code>extdirs</code> attribute in a * Scala-friendly form. * @return The extensions path as a list of files. */ - protected def getExtdirs: List[File] = - if (extdirs.isEmpty) error("Member 'extdirs' is empty.") - else List.fromArray(extdirs.get.list()).map(nameToFile) + protected def getExtdirs: List[File] = pathAsList(extdirs, "extdirs") /*============================================================================*\ ** Compilation and support methods ** \*============================================================================*/ - /** This is forwarding method to circumvent bug #281 in Scala 2. Remove when - * bug has been corrected. */ - override protected def getDirectoryScanner(baseDir: File) = - super.getDirectoryScanner(baseDir) - /** Transforms a string name into a file relative to the provided base * directory. * @param base A file pointing to the location relative to which the name @@ -503,59 +479,52 @@ class Scalac extends MatchingTask { protected def initialize: (Settings, List[File], Boolean) = { // Tests if all mandatory attributes are set and valid. if (origin.isEmpty) error("Attribute 'srcdir' is not set.") - if (getOrigin.isEmpty) error("Attribute 'srcdir' is not set.") if (!destination.isEmpty && !destination.get.isDirectory()) error("Attribute 'destdir' does not refer to an existing directory.") if (destination.isEmpty) destination = Some(getOrigin.head) val mapper = new GlobPatternMapper() - mapper.setTo("*.class") - mapper.setFrom("*.scala") + mapper setTo "*.class" + mapper setFrom "*.scala" var javaOnly = true + def getOriginFiles(originDir: File) = { + val includedFiles = getDirectoryScanner(originDir).getIncludedFiles() + val javaFiles = includedFiles filter (_ endsWith ".java") + val scalaFiles = { + val xs = includedFiles filter (_ endsWith ".scala") + if (force) xs + else new SourceFileScanner(this).restrict(xs, originDir, destination.get, mapper) + } + + javaOnly = javaOnly && (scalaFiles.length == 0) + val list = (scalaFiles ++ javaFiles).toList + + if (scalacDebugging && !list.isEmpty) + log("Compiling source file%s: %s to %s".format( + plural(list), + list.mkString(", "), + getDestination.toString + )) + else if (!list.isEmpty) { + val str = + if (javaFiles.isEmpty) "%d source file%s".format(list.length, plural(list)) + else "%d scala and %d java source files".format(scalaFiles.length, javaFiles.length) + log("Compiling %s to %s".format(str, getDestination.toString)) + } + else log("No files selected for compilation", Project.MSG_VERBOSE) + + list + } + // Scans source directories to build up a compile lists. // If force is false, only files were the .class file in destination is // older than the .scala file will be used. val sourceFiles: List[File] = - for { - val originDir <- getOrigin - val originFiles <- { - val includedFiles = getDirectoryScanner(originDir).getIncludedFiles() - var scalaFiles = includedFiles.filter(_.endsWith(".scala")) - val javaFiles = includedFiles.filter(_.endsWith(".java")) - if (!force) { - scalaFiles = new SourceFileScanner(this). - restrict(scalaFiles, originDir, destination.get, mapper) - } - javaOnly = javaOnly && (scalaFiles.length == 0) - val list = scalaFiles.toList ::: javaFiles.toList - if (scalacDebugging && list.length > 0) - log( - list.mkString( - "Compiling source file" + - (if (list.length > 1) "s: " else ": "), - ", ", - " " - ) + "to " + getDestination.toString - ) - else if (list.length > 0) - log( - "Compiling " + ( - if (javaFiles.length > 0) - (scalaFiles.length +" scala and "+ javaFiles.length +" java source files") - else - (list.length +" source file"+ (if (list.length > 1) "s" else "")) - ) +" to "+ getDestination.toString - ) - else - log("No files selected for compilation", Project.MSG_VERBOSE) - list - } - } - yield { - log(originFiles, Project.MSG_DEBUG) - nameToFile(originDir)(originFiles) + for (originDir <- getOrigin ; originFile <- getOriginFiles(originDir)) yield { + log(originFile, Project.MSG_DEBUG) + nameToFile(originDir)(originFile) } // Builds-up the compilation settings for Scalac with the existing Ant @@ -597,115 +566,82 @@ class Scalac extends MatchingTask { override def execute() { val (settings, sourceFiles, javaOnly) = initialize - if (sourceFiles.isEmpty || javaOnly) { + if (sourceFiles.isEmpty || javaOnly) return - } - if(fork) { - //TODO - Error - executeFork(settings, sourceFiles) - } else { - executeInternal(settings, sourceFiles) - } + + if (fork) executeFork(settings, sourceFiles) // TODO - Error + else executeInternal(settings, sourceFiles) } - protected def executeFork(settings: Settings, sourceFiles : List[File]) { - val java = new Java(this) // set this as owner - java.setFork(true) - // using 'setLine' creates multiple arguments out of a space-separated string - for(args <- jvmArgs) { - java.createJvmarg().setLine(args) - } + protected def executeFork(settings: Settings, sourceFiles: List[File]) { + val java = new Java(this) + java setFork true + // using 'setLine' creates multiple arguments out of a space-separated string + jvmArgs foreach { java.createJvmarg() setLine _ } - //Determine the path for scalac! - val scalacPath = { + // use user-provided path or retrieve from classloader + // TODO - Allow user to override the compiler classpath + val scalacPath: Path = { val path = new Path(getProject) - compilerPath match { - case Some(p) => - //Use the user provided path - path.add(p) - case None => - //Pull classpath off our classloader - //TODO - Allow user to override the compiler classpath - import _root_.org.apache.tools.ant.AntClassLoader - val classLoader = getClass.getClassLoader - if(classLoader.isInstanceOf[AntClassLoader]) { - path.add(new Path(getProject, classLoader.asInstanceOf[AntClassLoader].getClasspath)) - } else { - throw new BuildException("Cannot determine default classpath for sclac, please specify one!") - } + if (compilerPath.isDefined) path add compilerPath.get + else getClass.getClassLoader match { + case cl: AntClassLoader => path add new Path(getProject, cl.getClasspath) + case _ => error("Cannot determine default classpath for sclac, please specify one!") } path } - java.setClasspath(scalacPath) - - java.setClassname("scala.tools.nsc.Main") - //if (!timeout.isEmpty) java.setTimeout(timeout.get) + java setClasspath scalacPath + java setClassname "scala.tools.nsc.Main" - //Write all settings to a temporary file + // Write all settings to a temporary file def writeSettings() : File = { def escapeArgument(arg : String) = if(arg.matches(".*\\s.*")) ('"' + arg + '"') else arg val file = File.createTempFile("scalac-ant-",".args") file.deleteOnExit() val out = new PrintWriter(new BufferedWriter(new FileWriter(file))) + try { - for ( setting <- settings.allSettings; - arg <- setting.unparse){ - out.println(escapeArgument(arg)) - } - for (file <- sourceFiles) { - out.println(file.getAbsolutePath) - } - } finally { - out.close(); + for (setting <- settings.allSettings ; arg <- setting.unparse) + out println escapeArgument(arg) + for (file <- sourceFiles) + out println file.getAbsolutePath } + finally out.close() + file } - java.createArg().setValue("@" + writeSettings.getCanonicalPath) - log(java.getCommandLine.getCommandline.mkString("", " ", ""), Project.MSG_VERBOSE) + java.createArg() setValue ("@" + writeSettings.getCanonicalPath) + log(java.getCommandLine.getCommandline.mkString(" "), Project.MSG_VERBOSE) + val res = java.executeJava() if (failonerror && res != 0) error("Compilation failed because of an internal compiler error;"+ " see the error output for details.") - } + /** Performs the compilation. */ protected def executeInternal(settings: Settings, sourceFiles : List[File]) { - - val reporter = new ConsoleReporter(settings) - - // Compiles the actual code - val compiler = newGlobal(settings, reporter) - try { - (new compiler.Run).compile(sourceFiles.map (_.toString)) - } - catch { - case exception: Throwable if (exception.getMessage ne null) => - exception.printStackTrace() - error("Compile failed because of an internal compiler error (" + - exception.getMessage + "); see the error output for details.") - case exception => - exception.printStackTrace() - error("Compile failed because of an internal compiler error " + - "(no error message provided); see the error output for details.") + val compiler = newGlobal(settings, reporter) // compiles the actual code + + try new compiler.Run compile (sourceFiles map (_.toString)) + catch { + case ex: Throwable => + ex.printStackTrace() + val msg = if (ex.getMessage == null) "no error message provided" else ex.getMessage + error("Compile failed because of an internal compiler error (" + msg + "); see the error output for details.") } + reporter.printSummary() if (reporter.hasErrors) { - val msg = - "Compile failed with " + - reporter.ERROR.count + " error" + - (if (reporter.ERROR.count > 1) "s" else "") + - "; see the compiler error output for details." + val msg = "Compile failed with %d error%s; see the compiler error output for details.".format( + reporter.ERROR.count, plural(reporter.ERROR.count)) if (failonerror) error(msg) else log(msg) } else if (reporter.WARNING.count > 0) - log( - "Compile suceeded with " + - reporter.WARNING.count + " warning" + - (if (reporter.WARNING.count > 1) "s" else "") + - "; see the compiler output for details.") + log("Compile succeeded with %d warning%s; see the compiler output for details.".format( + reporter.WARNING.count, plural(reporter.WARNING.count))) } - } diff --git a/src/compiler/scala/tools/ant/sabbus/Compiler.scala b/src/compiler/scala/tools/ant/sabbus/Compiler.scala index cd5b4a88aa..787c6af870 100644 --- a/src/compiler/scala/tools/ant/sabbus/Compiler.scala +++ b/src/compiler/scala/tools/ant/sabbus/Compiler.scala @@ -13,25 +13,19 @@ package scala.tools.ant.sabbus import java.io.File import java.net.URL import java.lang.reflect.InvocationTargetException +import scala.util.ScalaClassLoader -class Compiler(classpath: Array[URL], val settings: Settings) { - - private lazy val classLoader: ClassLoader = - new java.net.URLClassLoader(classpath, null) - - private lazy val foreignCompilerName: String = - "scala.tools.ant.sabbus.ForeignCompiler" - private lazy val foreignCompiler: AnyRef = - classLoader.loadClass(foreignCompilerName).newInstance.asInstanceOf[AnyRef] +class Compiler(classpath: Array[URL], val settings: Settings) +{ + val foreignCompilerName: String = "scala.tools.ant.sabbus.ForeignCompiler" + private lazy val classLoader = ScalaClassLoader fromURLs classpath + private lazy val foreignCompiler: AnyRef = classLoader create foreignCompilerName private def settingsArray: Array[String] = settings.toArgs.toArray - foreignInvoke("args_$eq", Array(classOf[Array[String]]), Array(settingsArray)) - private def foreignInvoke(method: String, types: Array[Class[T] forSome { type T }] , args: Array[AnyRef]) = - try { - foreignCompiler.getClass.getMethod(method, types : _*).invoke(foreignCompiler, args : _*) - } + private def foreignInvoke(method: String, types: Array[Class[_]], args: Array[AnyRef]) = + try foreignCompiler.getClass.getMethod(method, types: _*).invoke(foreignCompiler, args: _*) catch { case e: InvocationTargetException => throw e.getCause } @@ -44,8 +38,6 @@ class Compiler(classpath: Array[URL], val settings: Settings) { (result >> 16, result & 0x00FF) } catch { - case ex: Exception => - throw CompilationFailure(ex.getMessage, ex) + case ex: Exception => throw CompilationFailure(ex.getMessage, ex) } - } diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala index 0fbd115f4d..453f96120e 100644 --- a/src/compiler/scala/tools/nsc/Interpreter.scala +++ b/src/compiler/scala/tools/nsc/Interpreter.scala @@ -8,13 +8,15 @@ package scala.tools.nsc import java.io.{ File, PrintWriter, StringWriter, Writer } import java.lang.{ Class, ClassLoader } -import java.net.{ MalformedURLException, URL, URLClassLoader } +import java.net.{ MalformedURLException, URL } import java.lang.reflect import reflect.InvocationTargetException import scala.collection.immutable.ListSet import scala.collection.mutable import scala.collection.mutable.{ ListBuffer, HashSet, ArrayBuffer } +import scala.util.{ ScalaClassLoader, URLClassLoader } +import scala.util.control.Exception.reflectionUnwrapper import io.{ PlainFile, VirtualDirectory } import reporters.{ ConsoleReporter, Reporter } @@ -70,7 +72,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) val virtualDirectory = new VirtualDirectory("(memory)", None) /** the compiler to compile expressions with */ - val compiler: nsc.Global = newCompiler(settings, reporter) + val compiler: Global = newCompiler(settings, reporter) import compiler.{ Traverser, CompilationUnit, Symbol, Name, Type } import compiler.{ @@ -112,18 +114,15 @@ class Interpreter(val settings: Settings, out: PrintWriter) /** Instantiate a compiler. Subclasses can override this to * change the compiler class used by this interpreter. */ protected def newCompiler(settings: Settings, reporter: Reporter) = { - settings.outputDirs.setSingleOutput(virtualDirectory) - val comp = new nsc.Global(settings, reporter) - comp + settings.outputDirs setSingleOutput virtualDirectory + new Global(settings, reporter) } /** the compiler's classpath, as URL's */ val compilerClasspath: List[URL] = { + import net.Utility.parseURL val classpathPart = ClassPath.expandPath(compiler.settings.classpath.value).map(s => new File(s).toURL) - def parseURL(s: String): Option[URL] = - try { Some(new URL(s)) } - catch { case _: MalformedURLException => None } val codebasePart = (compiler.settings.Xcodebase.value.split(" ")).toList flatMap parseURL classpathPart ::: codebasePart @@ -142,58 +141,49 @@ class Interpreter(val settings: Settings, out: PrintWriter) shadow the old ones, and old code objects refer to the old definitions. */ - private var classLoader = makeClassLoader() - private def makeClassLoader(): ClassLoader = { - val cp = compilerClasspath.toArray + private var classLoader: ScalaClassLoader = makeClassLoader() + private def makeClassLoader(): ScalaClassLoader = { val parent = - if (parentClassLoader == null) new URLClassLoader(cp) - else new URLClassLoader(cp, parentClassLoader) + if (parentClassLoader == null) ScalaClassLoader fromURLs compilerClasspath + else new URLClassLoader(compilerClasspath, parentClassLoader) new AbstractFileClassLoader(virtualDirectory, parent) } + private def loadByName(s: String): Class[_] = (classLoader tryToInitializeClass s).get + private def methodByName(c: Class[_], name: String): reflect.Method = + c.getMethod(name, classOf[Object]) - private def loadByName(s: String): Class[_] = Class.forName(s, true, classLoader) - // XXX how does this differ from getMethod("set") ? - private def methodByName(c: Class[_], name: String): Option[reflect.Method] = - c.getDeclaredMethods.toList.find(_.getName == name) + protected def parentClassLoader: ClassLoader = this.getClass.getClassLoader() // Set the current Java "context" class loader to this interpreter's class loader - def setContextClassLoader() = Thread.currentThread.setContextClassLoader(classLoader) - - protected def parentClassLoader: ClassLoader = this.getClass.getClassLoader() + def setContextClassLoader() = classLoader.setAsContext() /** the previous requests this interpreter has processed */ private val prevRequests = new ArrayBuffer[Request]() private def allUsedNames = prevRequests.toList.flatMap(_.usedNames).removeDuplicates private def allBoundNames = prevRequests.toList.flatMap(_.boundNames).removeDuplicates - /** counter creator */ - def mkNameCreator(s: String) = new Function0[String] with Function1[String,String] { + /** Generates names pre0, pre1, etc. via calls to apply method */ + class NameCreator(pre: String) { private var x = -1 - def apply(): String = { x += 1 ; s + x.toString } - // second apply method temp for newInternalVarName's bug compatibility - def apply(pre: String) = { x += 1 ; pre + x.toString } + def apply(): String = { x += 1 ; pre + x.toString } def reset(): Unit = x = -1 + def didGenerate(name: String) = + (name startsWith pre) && ((name drop pre.length) forall (_.isDigit)) } /** allocate a fresh line name */ - private val newLineName = mkNameCreator(INTERPRETER_LINE_PREFIX) + private val lineNameCreator = new NameCreator(INTERPRETER_LINE_PREFIX) /** allocate a fresh var name */ - private val newVarName = mkNameCreator(INTERPRETER_VAR_PREFIX) + private val varNameCreator = new NameCreator(INTERPRETER_VAR_PREFIX) /** allocate a fresh internal variable name */ - /** XXX temporarily shares newVarName's creator to be bug-compatible with - * test case interpreter.scala */ - private def newInternalVarName = () => newVarName(INTERPRETER_SYNTHVAR_PREFIX) - // private val newInternalVarName = mkNameCreator(INTERPRETER_SYNTHVAR_PREFIX) + private def synthVarNameCreator = new NameCreator(INTERPRETER_SYNTHVAR_PREFIX) - private def isGenerated(pre: String, name: String) = - (name startsWith pre) && (name drop pre.length).forall(_.isDigit) - - /** Check if a name looks like it was generated by newVarName */ - private def isGeneratedVarName(name: String): Boolean = isGenerated(INTERPRETER_VAR_PREFIX, name) - private def isSynthVarName(name: String): Boolean = isGenerated(INTERPRETER_SYNTHVAR_PREFIX, name) + /** Check if a name looks like it was generated by varNameCreator */ + private def isGeneratedVarName(name: String): Boolean = varNameCreator didGenerate name + private def isSynthVarName(name: String): Boolean = synthVarNameCreator didGenerate name /** generate a string using a routine that wants to write on a stream */ private def stringFrom(writer: PrintWriter => Unit): String = { @@ -424,12 +414,12 @@ class Interpreter(val settings: Settings, out: PrintWriter) if (trees.size == 1) trees.head match { case _:Assign => // we don't want to include assignments case _:TermTree | _:Ident | _:Select => - return interpret("val %s =\n%s".format(newVarName(), line)) + return interpret("val %s =\n%s".format(varNameCreator(), line)) case _ => } // figure out what kind of request - val req = buildRequest(trees, line, newLineName()) + val req = buildRequest(trees, line, lineNameCreator()) // null is a disallowed statement type; otherwise compile and fail if false (implying e.g. a type error) if (req == null || !req.compile) return IR.Error @@ -446,7 +436,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) } /** A name creator used for objects created by <code>bind()</code>. */ - private val newBinder = mkNameCreator("binder") + private val newBinder = new NameCreator("binder") /** Bind a specified name to a specified value. The name may * later be used by expressions passed to interpret. @@ -467,7 +457,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) """.stripMargin.format(binderName, boundType, boundType)) val binderObject = loadByName(binderName) - val setterMethod = methodByName(binderObject, "set").get + val setterMethod = methodByName(binderObject, "set") // this roundabout approach is to ensure the value is boxed var argsHolder: Array[Any] = null @@ -480,8 +470,8 @@ class Interpreter(val settings: Settings, out: PrintWriter) def reset() { virtualDirectory.clear classLoader = makeClassLoader - newLineName.reset() - newVarName.reset() + lineNameCreator.reset() + varNameCreator.reset() prevRequests.clear } @@ -572,7 +562,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) private class AssignHandler(member: Assign) extends MemberHandler(member) { val lhs = member.lhs.asInstanceOf[Ident] // an unfortunate limitation - val helperName = newTermName(newInternalVarName()) + val helperName = newTermName(synthVarNameCreator()) override val valAndVarNames = List(helperName) override def extraCodeToEvaluate(req: Request, code: PrintWriter) = @@ -773,16 +763,11 @@ class Interpreter(val settings: Settings, out: PrintWriter) def loadAndRun: (String, Boolean) = { val resultObject: Class[_] = loadByName(resultObjectName) val resultValMethod: reflect.Method = resultObject getMethod "result" + lazy val pair = (resultValMethod.invoke(resultObject).toString, true) - try { (resultValMethod.invoke(resultObject).toString, true) } - catch { case e => - // unwrap unhelpful nested exceptions so the most interesting one is reported - def unwrap(e: Throwable): Throwable = e match { - case (_: InvocationTargetException | _: ExceptionInInitializerError) if e.getCause ne null => - unwrap(e.getCause) - case _ => e - } - (stringFrom(unwrap(e).printStackTrace(_)), false) + (reflectionUnwrapper either pair) match { + case Left(e) => (stringFrom(e.printStackTrace(_)), false) + case Right((res, success)) => (res, success) } } } @@ -870,11 +855,11 @@ class Interpreter(val settings: Settings, out: PrintWriter) val res = beQuietDuring { for (name <- nameOfIdent(line) ; req <- requestForName(name)) yield { - if (interpret("val " + newInternalVarName() + " = " + name + methodsCode) != IR.Success) Nil + if (interpret("val " + synthVarNameCreator() + " = " + name + methodsCode) != IR.Success) Nil else { val result = prevRequests.last.resultObjectName - val resultObj = Class.forName(result, true, classLoader) - val valMethod = resultObj.getMethod("result") + val resultObj = (classLoader tryToInitializeClass result).get + val valMethod = resultObj getMethod "result" val str = valMethod.invoke(resultObj).toString str.substring(str.indexOf('=') + 1).trim . @@ -896,10 +881,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) filter(!isSynthVarName(_)) /** For static/object method completion */ - def tryToLoadClass(path: String): Option[Class[_]] = { - try { Some(Class.forName(path, false, classLoader)) } - catch { case _: ClassNotFoundException | _: NoClassDefFoundError => None } - } + def getClassObject(path: String): Option[Class[_]] = classLoader tryToLoadClass path // debugging private var debuggingOutput = false diff --git a/src/compiler/scala/tools/nsc/InterpreterLoop.scala b/src/compiler/scala/tools/nsc/InterpreterLoop.scala index 15a57729fc..2beeec28e4 100644 --- a/src/compiler/scala/tools/nsc/InterpreterLoop.scala +++ b/src/compiler/scala/tools/nsc/InterpreterLoop.scala @@ -8,7 +8,6 @@ package scala.tools.nsc import java.io.{BufferedReader, File, FileReader, PrintWriter} import java.io.IOException -import java.lang.{ClassLoader, System} import scala.tools.nsc.{InterpreterResults => IR} import scala.tools.nsc.interpreter._ @@ -84,6 +83,9 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { var interpreter: Interpreter = _ // set by createInterpreter() def isettings = interpreter.isettings + // XXX + var addedClasspath: List[String] = Nil + /** A reverse list of commands to replay if the user requests a :replay */ var replayCommandsRev: List[String] = Nil @@ -104,6 +106,9 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { /** Create a new interpreter. */ def createInterpreter() { + if (!addedClasspath.isEmpty) + settings.classpath.value += addedClasspath.map(File.pathSeparator + _).mkString + interpreter = new Interpreter(settings, out) { override protected def parentClassLoader = classOf[InterpreterLoop].getClassLoader } @@ -155,6 +160,7 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { import CommandImplicits._ List( NoArgs("help", "prints this help message", printHelp), + OneArg("jar", "add a jar to the classpath", addJar), OneArg("load", "followed by a filename loads a Scala file", load), NoArgs("power", "enable power user mode", power), NoArgs("quit", "exits the interpreter", () => Result(false, None)), @@ -262,6 +268,18 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { Result(true, shouldReplay) } + + def addJar(arg: String): Unit = { + val f = new java.io.File(arg) + if (!f.exists) { + out.println("The file '" + f + "' doesn't seem to exist.") + return + } + addedClasspath = addedClasspath ::: List(f.getCanonicalPath) + println("Added " + f.getCanonicalPath + " to your classpath.") + replay() + } + def power() = { powerUserOn = true interpreter.powerUser() diff --git a/src/compiler/scala/tools/nsc/MainGenericRunner.scala b/src/compiler/scala/tools/nsc/MainGenericRunner.scala index 3d7b5ac7ee..55967222c1 100644 --- a/src/compiler/scala/tools/nsc/MainGenericRunner.scala +++ b/src/compiler/scala/tools/nsc/MainGenericRunner.scala @@ -10,7 +10,8 @@ package scala.tools.nsc import java.io.{File, IOException} import java.lang.{ClassNotFoundException, NoSuchMethodException} import java.lang.reflect.InvocationTargetException -import java.net.URL +import java.net.{ URL, MalformedURLException } +import scala.util.ScalaClassLoader import util.ClassPath import File.pathSeparator @@ -25,40 +26,23 @@ object MainGenericRunner { * input classpath is empty; otherwise do not. * * @param classpath - * @return ... + * @return the new classpath */ private def addClasspathExtras(classpath: String): String = { val scalaHome = Properties.scalaHome - val extraClassPath = - if (scalaHome eq null) - "" - else { - def listDir(name:String):Array[File] = { - val libdir = new File(new File(scalaHome), name) - if (!libdir.exists || libdir.isFile) - Array() - else - libdir.listFiles - } - { - val filesInLib = listDir("lib") - val jarsInLib = - filesInLib.filter(f => - f.isFile && f.getName.endsWith(".jar")) - jarsInLib.toList - } ::: { - val filesInClasses = listDir("classes") - val dirsInClasses = - filesInClasses.filter(f => f.isDirectory) - dirsInClasses.toList - } - }.mkString("", pathSeparator, "") - - if (classpath == "") - extraClassPath + pathSeparator + "." - else - classpath + pathSeparator + extraClassPath + def listDir(name: String): List[File] = { + val libdir = new File(new File(scalaHome), name) + if (!libdir.exists || libdir.isFile) Nil else libdir.listFiles.toList + } + lazy val jarsInLib = listDir("lib") filter (_.getName endsWith ".jar") + lazy val dirsInClasses = listDir("classes") filter (_.isDirectory) + val cpScala = + if (scalaHome == null) Nil + else (jarsInLib ::: dirsInClasses) map (_.toString) + + // either prepend existing classpath or append "." + (if (classpath == "") cpScala ::: List(".") else classpath :: cpScala) mkString pathSeparator } def main(args: Array[String]) { @@ -114,8 +98,8 @@ object MainGenericRunner { ) yield url.get def specToURL(spec: String): Option[URL] = - try { Some(new URL(spec)) } - catch { case e => Console.println(e); None } + try { Some(new URL(spec)) } + catch { case e: MalformedURLException => Console.println(e); None } def urls(specs: String): List[URL] = if (specs == null || specs.length == 0) Nil @@ -146,8 +130,7 @@ object MainGenericRunner { settings.howtorun.value match { case "object" => true case "script" => false - case "guess" => - ObjectRunner.classExists(classpath, thingToRun) + case "guess" => ScalaClassLoader.classExists(classpath, thingToRun) } if (isObjectName) { diff --git a/src/compiler/scala/tools/nsc/ObjectRunner.scala b/src/compiler/scala/tools/nsc/ObjectRunner.scala index 58da7b16eb..e4e0826d32 100644 --- a/src/compiler/scala/tools/nsc/ObjectRunner.scala +++ b/src/compiler/scala/tools/nsc/ObjectRunner.scala @@ -7,9 +7,8 @@ package scala.tools.nsc -import java.lang.{Class, ClassNotFoundException, NoSuchMethodException} -import java.lang.reflect.{Method, Modifier} -import java.net.{URL, URLClassLoader} +import java.net.URL +import scala.util.ScalaClassLoader /** An object that runs another object specified by name. * @@ -18,57 +17,10 @@ import java.net.{URL, URLClassLoader} */ object ObjectRunner { - // we cannot use the app classloader here or we get what looks to - // be classloader deadlock, but if we pass null we bypass the extension - // classloader and our extensions, so we search the hierarchy to find - // the classloader whose parent is null. Resolves bug #857. - private def findExtClassLoader(): ClassLoader = { - def search(cl: ClassLoader): ClassLoader = { - if (cl == null) null - else if (cl.getParent == null) cl - else search(cl.getParent) - } - - search(Thread.currentThread.getContextClassLoader) - } - - /** Create a class loader for the specified class path */ - private def makeClassLoader(classpath: List[URL]): URLClassLoader = - makeClassLoader(classpath, findExtClassLoader()) - private def makeClassLoader(classpath: List[URL], parent: ClassLoader): URLClassLoader = - new URLClassLoader(classpath.toArray, parent) - - /** Look up a class with a given class path. */ - private def findClass(loader: ClassLoader, objectName: String) - : Option[Class[T] forSome { type T }] = - { - try { - Some(Class.forName(objectName, true, loader)) - } catch { - case e: SecurityException => - Console.println(e.getMessage) - None - case _: ClassNotFoundException => - None - } - } - /** Check whether a class with the specified name * exists on the specified class path. */ - def classExists(classpath: List[URL], objectName: String): Boolean = - !findClass(makeClassLoader(classpath), objectName).isEmpty - - /** Set the Java context class loader while executing an action */ - def withContextClassLoader[T](loader: ClassLoader)(action: =>T): T = { - val oldLoader = Thread.currentThread.getContextClassLoader - try { - Thread.currentThread.setContextClassLoader(loader) - action - } finally { - Thread.currentThread.setContextClassLoader(oldLoader) - } - } - + def classExists(urls: List[URL], objectName: String): Boolean = + ScalaClassLoader.classExists(urls, objectName) /** Run a given object, specified by name, using a * specified classpath and argument list. @@ -77,19 +29,7 @@ object ObjectRunner * @throws NoSuchMethodError * @throws InvocationTargetException */ - def run(classpath: List[URL], objectName: String, arguments: Seq[String]) { - val loader = makeClassLoader(classpath) - val clsToRun = findClass(loader, objectName) match { - case Some(cls) => cls - case None => throw new ClassNotFoundException(objectName) - } - - val method = clsToRun.getMethod("main", classOf[Array[String]]) - if ((method.getModifiers & Modifier.STATIC) == 0) - throw new NoSuchMethodException(objectName + ".main is not static") - - withContextClassLoader(loader) { - method.invoke(null, List(arguments.toArray).toArray: _*) - } + def run(urls: List[URL], objectName: String, arguments: Seq[String]) { + (ScalaClassLoader fromURLs urls).run(objectName, arguments) } } diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala index cefbecee81..5d96a54f64 100644 --- a/src/compiler/scala/tools/nsc/Settings.scala +++ b/src/compiler/scala/tools/nsc/Settings.scala @@ -753,7 +753,6 @@ trait ScalacSettings val noCompletion = BooleanSetting ("-Yno-completion", "Disable tab-completion in the REPL") val Xdce = BooleanSetting ("-Ydead-code", "Perform dead code elimination") val debug = BooleanSetting ("-Ydebug", "Output debugging messages") - val debugger = BooleanSetting ("-Ydebugger", "Enable interactive debugger") val Xdetach = BooleanSetting ("-Ydetach", "Perform detaching of remote closures") // val doc = BooleanSetting ("-Ydoc", "Generate documentation") val inline = BooleanSetting ("-Yinline", "Perform inlining when possible") diff --git a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala index bb1d049677..964fd3f377 100644 --- a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala +++ b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala @@ -6,6 +6,7 @@ package scala.tools.nsc.interpreter import scala.tools.nsc.io.AbstractFile +import scala.util.ScalaClassLoader /** * A class loader that loads files from a {@link scala.tools.nsc.io.AbstractFile}. @@ -13,21 +14,18 @@ import scala.tools.nsc.io.AbstractFile * @author Lex Spoon */ class AbstractFileClassLoader(root: AbstractFile, parent: ClassLoader) -extends ClassLoader(parent) + extends ClassLoader(parent) + with ScalaClassLoader { override def findClass(name: String): Class[_] = { + def onull[T](x: T): T = if (x == null) throw new ClassNotFoundException(name) else x var file: AbstractFile = root val pathParts = name.split("[./]").toList - for (dirPart <- pathParts.init) { - file = file.lookupName(dirPart, true) - if (file == null) { - throw new ClassNotFoundException(name) - } - } - file = file.lookupName(pathParts.last+".class", false) - if (file == null) { - throw new ClassNotFoundException(name) - } + + for (dirPart <- pathParts.init) + file = onull(file.lookupName(dirPart, true)) + + file = onull(file.lookupName(pathParts.last+".class", false)) val bytes = file.toByteArray defineClass(name, bytes, 0, bytes.length) } diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala index 2a6362568a..27259e0d2e 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Completion.scala @@ -136,9 +136,9 @@ class Completion(val interpreter: Interpreter) extends Completor { filter (isValidCompletion) // java style, static methods - val js = interpreter.tryToLoadClass(path).map(getMembers(_, true)) getOrElse Nil + val js = (interpreter getClassObject path).map(getMembers(_, true)) getOrElse Nil // scala style, methods on companion object - val ss = interpreter.tryToLoadClass(path + "$").map(getMembers(_, false)) getOrElse Nil + val ss = (interpreter getClassObject (path + "$")).map(getMembers(_, false)) getOrElse Nil js ::: ss } diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala index 3559b1f5b1..9fd93ab6ff 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala @@ -108,9 +108,9 @@ abstract class SymbolTable extends Names } } - /** Break into repl debugger if assertion is true and debugging enabled */ + /** Break into repl debugger if assertion is true */ def breakIf(assertion: => Boolean, args: Any*): Unit = - if (settings.debugger.value && assertion) + if (assertion) Interpreter.break(args.toList) /** The set of all installed infotransformers */ |