diff options
17 files changed, 137 insertions, 29 deletions
diff --git a/src/interactive/scala/tools/nsc/interactive/CompilerControl.scala b/src/interactive/scala/tools/nsc/interactive/CompilerControl.scala index 69cae24808..2e4f6b08e9 100644 --- a/src/interactive/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/interactive/scala/tools/nsc/interactive/CompilerControl.scala @@ -186,15 +186,20 @@ trait CompilerControl { self: Global => postWorkItem(new AskToDoFirstItem(source)) /** If source is not yet loaded, loads it, and starts a new run, otherwise - * continues with current pass. - * Waits until source is fully type checked and returns body in response. - * @param source The source file that needs to be fully typed. - * @param response The response, which is set to the fully attributed tree of `source`. + * continues with current pass. + * Waits until source is fully type checked and returns body in response. + * @param source The source file that needs to be fully typed. + * @param keepLoaded Whether to keep that file in the PC if it was not loaded before. If + the file is already loaded, this flag is ignored. + * @param response The response, which is set to the fully attributed tree of `source`. * If the unit corresponding to `source` has been removed in the meantime * the a NoSuchUnitError is raised in the response. */ - def askLoadedTyped(source: SourceFile, response: Response[Tree]) = - postWorkItem(new AskLoadedTypedItem(source, response)) + def askLoadedTyped(source:SourceFile, keepLoaded: Boolean, response: Response[Tree]): Unit = + postWorkItem(new AskLoadedTypedItem(source, keepLoaded, response)) + + final def askLoadedTyped(source: SourceFile, response: Response[Tree]): Unit = + askLoadedTyped(source, false, response) /** If source if not yet loaded, get an outline view with askParseEntered. * If source is loaded, wait for it to be typechecked. @@ -203,7 +208,7 @@ trait CompilerControl { self: Global => */ def askStructure(keepSrcLoaded: Boolean)(source: SourceFile, response: Response[Tree]) = { getUnit(source) match { - case Some(_) => askLoadedTyped(source, response) + case Some(_) => askLoadedTyped(source, keepSrcLoaded, response) case None => askParsedEntered(source, keepSrcLoaded, response) } } @@ -375,8 +380,8 @@ trait CompilerControl { self: Global => response raise new MissingResponse } - case class AskLoadedTypedItem(source: SourceFile, response: Response[Tree]) extends WorkItem { - def apply() = self.waitLoadedTyped(source, response, this.onCompilerThread) + case class AskLoadedTypedItem(source: SourceFile, keepLoaded: Boolean, response: Response[Tree]) extends WorkItem { + def apply() = self.waitLoadedTyped(source, response, keepLoaded, this.onCompilerThread) override def toString = "wait loaded & typed "+source def raiseMissing() = diff --git a/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala index 441398e443..467a210cab 100644 --- a/src/interactive/scala/tools/nsc/interactive/Global.scala +++ b/src/interactive/scala/tools/nsc/interactive/Global.scala @@ -327,7 +327,12 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") * @param result The transformed node */ override def signalDone(context: Context, old: Tree, result: Tree) { - if (interruptsEnabled && analyzer.lockedCount == 0) { + val canObserveTree = ( + interruptsEnabled + && analyzer.lockedCount == 0 + && !context.bufferErrors // SI-7558 look away during exploratory typing in "silent mode" + ) + if (canObserveTree) { if (context.unit.exists && result.pos.isOpaqueRange && (result.pos includes context.unit.targetPos)) { @@ -338,14 +343,16 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") } throw new TyperResult(located) } - try { - checkForMoreWork(old.pos) - } catch { - case ex: ValidateException => // Ignore, this will have been reported elsewhere - debugLog("validate exception caught: "+ex) - case ex: Throwable => - log.flush() - throw ex + else { + try { + checkForMoreWork(old.pos) + } catch { + case ex: ValidateException => // Ignore, this will have been reported elsewhere + debugLog("validate exception caught: "+ex) + case ex: Throwable => + log.flush() + throw ex + } } } } @@ -1127,7 +1134,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") } /** Implements CompilerControl.askLoadedTyped */ - private[interactive] def waitLoadedTyped(source: SourceFile, response: Response[Tree], onSameThread: Boolean = true) { + private[interactive] def waitLoadedTyped(source: SourceFile, response: Response[Tree], keepLoaded: Boolean = false, onSameThread: Boolean = true) { getUnit(source) match { case Some(unit) => if (unit.isUpToDate) { @@ -1145,7 +1152,10 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") case None => debugLog("load unit and type") try reloadSources(List(source)) - finally waitLoadedTyped(source, response, onSameThread) + finally { + waitLoadedTyped(source, response, onSameThread) + if (!keepLoaded) removeUnitOf(source) + } } } diff --git a/src/interactive/scala/tools/nsc/interactive/Picklers.scala b/src/interactive/scala/tools/nsc/interactive/Picklers.scala index 30d3048aa0..1f89e6d3aa 100644 --- a/src/interactive/scala/tools/nsc/interactive/Picklers.scala +++ b/src/interactive/scala/tools/nsc/interactive/Picklers.scala @@ -170,7 +170,7 @@ trait Picklers { self: Global => implicit def askLoadedTypedItem: CondPickler[AskLoadedTypedItem] = pkl[SourceFile] - .wrapped { source => new AskLoadedTypedItem(source, new Response) } { _.source } + .wrapped { source => new AskLoadedTypedItem(source, false, new Response) } { _.source } .asClass (classOf[AskLoadedTypedItem]) implicit def askParsedEnteredItem: CondPickler[AskParsedEnteredItem] = diff --git a/src/interactive/scala/tools/nsc/interactive/REPL.scala b/src/interactive/scala/tools/nsc/interactive/REPL.scala index 8e9b0ceee0..ffa61b0524 100644 --- a/src/interactive/scala/tools/nsc/interactive/REPL.scala +++ b/src/interactive/scala/tools/nsc/interactive/REPL.scala @@ -118,7 +118,7 @@ object REPL { comp.askReload(List(toSourceFile(file)), reloadResult) Thread.sleep(millis.toLong) println("ask type now") - comp.askLoadedTyped(toSourceFile(file), typedResult) + comp.askLoadedTyped(toSourceFile(file), keepLoaded = true, typedResult) typedResult.get case List("typeat", file, off1, off2) => doTypeAt(makePos(file, off1, off2)) diff --git a/src/interactive/scala/tools/nsc/interactive/tests/core/AskCommand.scala b/src/interactive/scala/tools/nsc/interactive/tests/core/AskCommand.scala index 4f9df6808f..d5da52bc13 100644 --- a/src/interactive/scala/tools/nsc/interactive/tests/core/AskCommand.scala +++ b/src/interactive/scala/tools/nsc/interactive/tests/core/AskCommand.scala @@ -113,9 +113,9 @@ trait AskTypeAt extends AskCommand { trait AskLoadedTyped extends AskCommand { import compiler.Tree - protected def askLoadedTyped(source: SourceFile)(implicit reporter: Reporter): Response[Tree] = { + protected def askLoadedTyped(source: SourceFile, keepLoaded: Boolean = false)(implicit reporter: Reporter): Response[Tree] = { ask { - compiler.askLoadedTyped(source, _) + compiler.askLoadedTyped(source, keepLoaded, _) } } diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index f905785bd6..d271c4cdeb 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -384,7 +384,10 @@ trait Future[+T] extends Awaitable[T] { val p = Promise[U]() onComplete { case s @ Success(_) => p complete s - case _ => p completeWith that + case f @ Failure(_) => that onComplete { + case s2 @ Success(_) => p complete s2 + case _ => p complete f // Use the first failure as the failure + } } p.future } diff --git a/test/files/jvm/future-spec/PromiseTests.scala b/test/files/jvm/future-spec/PromiseTests.scala index 49350586b8..12b9168c5d 100644 --- a/test/files/jvm/future-spec/PromiseTests.scala +++ b/test/files/jvm/future-spec/PromiseTests.scala @@ -38,10 +38,10 @@ class PromiseTests extends MinimalScalaTest { Await.result(failure fallbackTo timedOut, defaultTimeout) mustBe ("Timedout") Await.result(timedOut fallbackTo empty, defaultTimeout) mustBe ("Timedout") - Await.result(failure fallbackTo failure fallbackTo timedOut, defaultTimeout) mustBe ("Timedout") + Await.result(otherFailure fallbackTo failure fallbackTo timedOut, defaultTimeout) mustBe ("Timedout") intercept[RuntimeException] { Await.result(failure fallbackTo otherFailure, defaultTimeout) - }.getMessage mustBe ("last") + }.getMessage mustBe ("br0ken") } } diff --git a/test/files/jvm/scala-concurrent-tck.scala b/test/files/jvm/scala-concurrent-tck.scala index b431f6b8f8..ce86d4aef0 100644 --- a/test/files/jvm/scala-concurrent-tck.scala +++ b/test/files/jvm/scala-concurrent-tck.scala @@ -344,8 +344,8 @@ def testTransformFailure(): Unit = once { def testFallbackToFailure(): Unit = once { done => val cause = new Exception - val f = Future { sys.error("failed") } - val g = Future { throw cause } + val f = Future { throw cause } + val g = Future { sys.error("failed") } val h = f fallbackTo g h onSuccess { case _ => done(false) } diff --git a/test/files/presentation/ide-t1001388.check b/test/files/presentation/ide-t1001388.check new file mode 100644 index 0000000000..d58f86d6c6 --- /dev/null +++ b/test/files/presentation/ide-t1001388.check @@ -0,0 +1 @@ +Test OK
\ No newline at end of file diff --git a/test/files/presentation/ide-t1001388/Test.scala b/test/files/presentation/ide-t1001388/Test.scala new file mode 100644 index 0000000000..f6079cf0b2 --- /dev/null +++ b/test/files/presentation/ide-t1001388/Test.scala @@ -0,0 +1,28 @@ +import scala.tools.nsc.interactive.tests.InteractiveTest +import scala.reflect.internal.util.SourceFile +import scala.tools.nsc.interactive.Response + +object Test extends InteractiveTest { + override def execute(): Unit = { + val sourceA = loadSourceAndWaitUntilTypechecked("A.scala") + checkPresent(sourceA) + } + + private def loadSourceAndWaitUntilTypechecked(sourceName: String): SourceFile = { + val sourceFile = sourceFiles.find(_.file.name == sourceName).head + askLoadedTyped(sourceFile).get + /* The response to `askLoadedType` may return before `interactive.Global.waitLoadedType` + * fully executes. Because this test expects `waitLoadedType` is fully executed before + * calling `checkPresent`, with the below no-op presentation compiler request we make + * sure this requirement is fulfilled. + */ + compiler.askForResponse(() => ()).get + sourceFile + } + + private def checkPresent(source: SourceFile): Unit = compiler.getUnitOf(source) match { + case Some(unit) => reporter.println("Compilation Unit for " + source.file.name + " still loaded after askLoadedTyped") + + case None => reporter.println("Test OK") + } +} diff --git a/test/files/presentation/ide-t1001388/src/a/A.scala b/test/files/presentation/ide-t1001388/src/a/A.scala new file mode 100644 index 0000000000..be09097598 --- /dev/null +++ b/test/files/presentation/ide-t1001388/src/a/A.scala @@ -0,0 +1,6 @@ +package a + +object A { + val tagString = "foo" + Seq.empty[Byte].toArray.toSeq +} diff --git a/test/files/presentation/t7548.check b/test/files/presentation/t7548.check new file mode 100644 index 0000000000..5bfb0d27fe --- /dev/null +++ b/test/files/presentation/t7548.check @@ -0,0 +1 @@ +(x: Int)Unit diff --git a/test/files/presentation/t7548/Test.scala b/test/files/presentation/t7548/Test.scala new file mode 100644 index 0000000000..94a6048056 --- /dev/null +++ b/test/files/presentation/t7548/Test.scala @@ -0,0 +1,17 @@ +import scala.tools.nsc.interactive.tests.InteractiveTest + +object Test extends InteractiveTest { + override protected def loadSources() { /* don't parse or typecheck sources */ } + + import compiler._ + + override def runDefaultTests() { + val res = new Response[Tree] + val pos = compiler.rangePos(sourceFiles.head, 102,102,102) + compiler.askTypeAt(pos, res) + res.get match { + case Left(tree) => compiler.ask(() => reporter.println(tree.tpe)) + case Right(ex) => reporter.println(ex) + } + } +} diff --git a/test/files/presentation/t7548/src/Foo.scala b/test/files/presentation/t7548/src/Foo.scala new file mode 100644 index 0000000000..cc997f6e5f --- /dev/null +++ b/test/files/presentation/t7548/src/Foo.scala @@ -0,0 +1,7 @@ +object Foo { + def foo(x: Int) = {} + def foo(x: String) = {} + def foo(x: Int, y: String) = {} + + foo(2) +}
\ No newline at end of file diff --git a/test/files/presentation/t7548b.check b/test/files/presentation/t7548b.check new file mode 100644 index 0000000000..35445fedf6 --- /dev/null +++ b/test/files/presentation/t7548b.check @@ -0,0 +1 @@ +Foo.this.I2BI(Foo.this.I).+: (other: Foo.BI.type)Unit diff --git a/test/files/presentation/t7548b/Test.scala b/test/files/presentation/t7548b/Test.scala new file mode 100644 index 0000000000..0c022df839 --- /dev/null +++ b/test/files/presentation/t7548b/Test.scala @@ -0,0 +1,17 @@ +import scala.tools.nsc.interactive.tests.InteractiveTest + +object Test extends InteractiveTest { + override protected def loadSources() { /* don't parse or typecheck sources */ } + + import compiler._ + + override def runDefaultTests() { + val res = new Response[Tree] + val pos = compiler.rangePos(sourceFiles.head, 191, 191, 191) // + + compiler.askTypeAt(pos, res) + res.get match { + case Left(tree) => compiler.ask(() => reporter.println(s"$tree: ${tree.tpe}")) + case Right(ex) => reporter.println(ex) + } + } +} diff --git a/test/files/presentation/t7548b/src/Foo.scala b/test/files/presentation/t7548b/src/Foo.scala new file mode 100644 index 0000000000..5cf0a4ef4e --- /dev/null +++ b/test/files/presentation/t7548b/src/Foo.scala @@ -0,0 +1,12 @@ +import language._ + +object Foo { + object I { + def +(other: I.type) : Unit = () + } + object BI { + def +(other: BI.type): Unit = () + } + implicit def I2BI(i: I.type): BI.type = BI + I.+(BI) +} |