diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/IMain.scala | 8 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/Line.scala | 24 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/io/Sources.scala | 33 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/util/Exceptional.scala | 2 | ||||
-rw-r--r-- | test/files/run/repl-exceptions.check | 25 | ||||
-rw-r--r-- | test/files/run/repl-exceptions.scala | 12 |
6 files changed, 77 insertions, 27 deletions
diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index b092574eaf..ff6100e9e8 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -237,12 +237,12 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends /** whether to bind the lastException variable */ private var bindExceptions = true /** takes AnyRef because it may be binding a Throwable or an Exceptional */ - private def withLastExceptionLock[T](body: => T): T = { + private def withLastExceptionLock[T](body: => T, alt: => T): T = { assert(bindExceptions, "withLastExceptionLock called incorrectly.") bindExceptions = false try beQuietDuring(body) - catch logAndDiscard("bindLastException", null.asInstanceOf[T]) + catch logAndDiscard("bindLastException", alt) finally bindExceptions = true } @@ -708,7 +708,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends throw t val unwrapped = unwrap(t) - withLastExceptionLock { + withLastExceptionLock[String]({ if (opt.richExes) { val ex = new LineExceptional(unwrapped) bind[Exceptional]("lastException", ex) @@ -718,7 +718,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends bind[Throwable]("lastException", unwrapped) util.stackTraceString(unwrapped) } - } + }, "" + unwrapped) } // TODO: split it out into a package object and a regular diff --git a/src/compiler/scala/tools/nsc/interpreter/Line.scala b/src/compiler/scala/tools/nsc/interpreter/Line.scala index deec9fcc4e..3062c95dae 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Line.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Line.scala @@ -19,11 +19,11 @@ import Line._ * completed or failed. */ class Line[+T](val code: String, classLoader: ClassLoader, body: => T) { - private var _state: State = Running - private var _result: Any = null - private var _caught: Throwable = null - private val lock = new ReentrantLock() - private val finished = lock.newCondition() + private var _state: State = Running + private var _result: Option[Any] = None + private var _caught: Option[Throwable] = None + private val lock = new ReentrantLock() + private val finished = lock.newCondition() private def withLock[T](body: => T) = { lock.lock() @@ -38,11 +38,8 @@ class Line[+T](val code: String, classLoader: ClassLoader, body: => T) { private def cancel() = if (running) setState(Cancelled) private def runAndSetState[T](body: => T) { - var ex: Throwable = null - - try { _result = body } - catch { case t => ex = t } - finally { setState( if (ex == null) Done else Threw ) } + try { _result = Some(body) ; setState(Done) } + catch { case t => _caught = Some(t) ; setState(Threw) } } // This is where the line thread is created and started. @@ -56,8 +53,11 @@ class Line[+T](val code: String, classLoader: ClassLoader, body: => T) { def success = _state == Done def running = _state == Running - def caught() = { await() ; _caught } - def get() = { await() ; _result } + def caught() = { await() ; _caught.orNull } + def get() = { + await() + _result getOrElse sys.error("Called get with no result. Code: " + code) + } def await() = withLock { while (running) finished.await() } } diff --git a/src/compiler/scala/tools/nsc/io/Sources.scala b/src/compiler/scala/tools/nsc/io/Sources.scala index 35c7a504a5..25d27acae8 100644 --- a/src/compiler/scala/tools/nsc/io/Sources.scala +++ b/src/compiler/scala/tools/nsc/io/Sources.scala @@ -13,6 +13,7 @@ class Sources(val path: String) { def allNames = cache.keys.asScala.toList.sorted def apply(name: String) = get(name) def size = cache.asScala.values map (_.length) sum + def isEmpty = path == "" private var debug = false private def dbg(msg: => Any) = if (debug) Console println msg @@ -20,14 +21,17 @@ class Sources(val path: String) { val dirs = partitioned._1 map (_.toDirectory) val jars = partitioned._2 filter Jar.isJarOrZip map (_.toFile) - val (isDone, force) = { - val f1 = spawn(calculateDirs()) - val f2 = spawn(calculateJars()) - val fn1 = () => { f1.isDone() && f2.isDone() } - val fn2 = () => { f1.get() ; f2.get() ; () } - - (fn1, fn2) - } + val (isDone, force) = ( + if (path == "") (() => true, () => ()) + else { + val f1 = spawn(calculateDirs()) + val f2 = spawn(calculateJars()) + val fn1 = () => { f1.isDone() && f2.isDone() } + val fn2 = () => { f1.get() ; f2.get() ; () } + + (fn1, fn2) + } + ) private def catchZip(body: => Unit): Unit = { try body @@ -62,12 +66,21 @@ trait LowPrioritySourcesImplicits { } object Sources extends LowPrioritySourcesImplicits { + val empty = new Sources("") + private def libraryInits = ClassPath.scalaLibrary.toList flatMap (_.toAbsolute.parents) private def librarySourceDir = libraryInits map (_ / "src") find (_.isDirectory) private def expandedSourceDir = librarySourceDir.toList flatMap (ClassPath expandDir _.path) - val sourcePathProp = sys.props.traceSourcePath.value - val defaultSources = apply(expandedSourceDir :+ sourcePathProp: _*) + private val initialPath = sys.props.traceSourcePath.value + private val initialSources = apply(expandedSourceDir :+ initialPath: _*) + + def defaultSources = { + val path = sys.props.traceSourcePath.value + if (path == "") empty + else if (path == initialPath) initialSources + else apply(expandedSourceDir :+ path: _*) + } def apply(paths: String*): Sources = new Sources(ClassPath.join(paths: _*)) } diff --git a/src/compiler/scala/tools/nsc/util/Exceptional.scala b/src/compiler/scala/tools/nsc/util/Exceptional.scala index 459881bb64..667b7d15a6 100644 --- a/src/compiler/scala/tools/nsc/util/Exceptional.scala +++ b/src/compiler/scala/tools/nsc/util/Exceptional.scala @@ -27,7 +27,7 @@ class Exceptional(val ex: Throwable)(implicit prefs: ScalaPrefs) { /** The result of this will be printed before a context trace. */ def contextPrelude: String = - if (isScanDone) "" + if (isScanDone || prefs.codeSources.isEmpty) "" else "/* Still scanning source path: there may be more momentarily. */\n" /** Frames with surrounding context. */ diff --git a/test/files/run/repl-exceptions.check b/test/files/run/repl-exceptions.check new file mode 100644 index 0000000000..f7ce018422 --- /dev/null +++ b/test/files/run/repl-exceptions.check @@ -0,0 +1,25 @@ +Type in expressions to have them evaluated. +Type :help for more information. + +scala> + +scala> sys.SystemProperties.traceSourcePath setValue "" +res0: String = null + +scala> def f = sys.error("hi mom") +f: Nothing + +scala> f +[package.error] (package.scala:27) +(access lastException for the full trace) + +scala> lastException.show +/* The repl internal portion of the stack trace is elided. */ +[package.error] (package.scala:27) +[.f] (<console>:7) +[.<init>] (<console>:9) +[.<clinit>] (<console>:-1) + +scala> + +scala> diff --git a/test/files/run/repl-exceptions.scala b/test/files/run/repl-exceptions.scala new file mode 100644 index 0000000000..aaf37c8ae7 --- /dev/null +++ b/test/files/run/repl-exceptions.scala @@ -0,0 +1,12 @@ +import scala.tools.partest.ReplTest +import scala.tools.util.Javap + +object Test extends ReplTest { + override def extraSettings = "-Yrich-exceptions" + def code = """ + |sys.SystemProperties.traceSourcePath setValue "" + |def f = sys.error("hi mom") + |f + |lastException.show + """.stripMargin +} |