From 753e848f3d6ac453871450161292139902669695 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Fri, 18 Nov 2016 18:09:28 +1000 Subject: SI-8779 Enable inlining of code within a REPL session The REPL has a long running instance of Global which outputs classfiles by default to a VirtualDirectory. The inliner did not find any of these class files when compiling calls to methods defined in previous runs (ie, previous lines of input.) This commit: - Adds a hook to augment the classpath that the optimizer searches, and uses this in the REPL to add the output directory - Fixes the implementation of `findClassFile` in VirtualDirectory, which doesn't seem to have been used in anger before. I've factored out some common code into a new method on `AbstractFile`. - Fixes a similar problem getSubDir reported by Li Haoyi - Adds missing unit test coverage. This also fixes a bug in REPL autocompletion for types defined in packages >= 2 level deep (with the `:paste -raw` command). I've added a test for this case. --- test/files/run/repl-inline.check | 6 ++++++ test/files/run/repl-inline.scala | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 test/files/run/repl-inline.check create mode 100644 test/files/run/repl-inline.scala (limited to 'test/files') diff --git a/test/files/run/repl-inline.check b/test/files/run/repl-inline.check new file mode 100644 index 0000000000..3b29f4d047 --- /dev/null +++ b/test/files/run/repl-inline.check @@ -0,0 +1,6 @@ +warning: there was one deprecation warning (since 2.11.0); re-run with -deprecation for details +callerOfCaller: String +g: String +h: String +g: String +h: String diff --git a/test/files/run/repl-inline.scala b/test/files/run/repl-inline.scala new file mode 100644 index 0000000000..5a5f205ad8 --- /dev/null +++ b/test/files/run/repl-inline.scala @@ -0,0 +1,21 @@ +import scala.tools.nsc._ + +object Test { + val testCode = """ +def callerOfCaller = Thread.currentThread.getStackTrace.drop(2).head.getMethodName +def g = callerOfCaller +def h = g +assert(h == "g", h) +@inline def g = callerOfCaller +def h = g +assert(h == "h", h) + """ + + def main(args: Array[String]) { + val settings = new Settings() + settings.processArgumentString("-opt:l:classpath") + settings.usejavacp.value = true + val repl = new interpreter.IMain(settings) + testCode.linesIterator.foreach(repl.interpret(_)) + } +} -- cgit v1.2.3 From 1b2cd1be9790bf9c14fd68c78f784d6cb4f7c907 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 23 Nov 2016 15:54:03 +1000 Subject: Support inlining under -Yrepl-class-based REPL By marking the wrapper classes as sealed, the inliner will be able to assume finality of defs introduces in the REPL without requiring the user to mark them as `final`, which is an odd thing to do in single line of REPL input. --- src/repl/scala/tools/nsc/interpreter/IMain.scala | 2 +- test/files/run/repl-inline.check | 5 +++++ test/files/run/repl-inline.scala | 18 ++++++++++++------ test/files/run/t7747-repl.check | 6 +++--- 4 files changed, 21 insertions(+), 10 deletions(-) (limited to 'test/files') diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index 65f2c95f73..99acc34811 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -889,7 +889,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends } class ClassBasedWrapper extends Wrapper { - def preambleHeader = "class %s extends _root_.java.io.Serializable { " + def preambleHeader = "sealed class %s extends _root_.java.io.Serializable { " /** Adds an object that instantiates the outer wrapping class. */ def postamble = s""" diff --git a/test/files/run/repl-inline.check b/test/files/run/repl-inline.check index 3b29f4d047..db729a67dd 100644 --- a/test/files/run/repl-inline.check +++ b/test/files/run/repl-inline.check @@ -4,3 +4,8 @@ g: String h: String g: String h: String +callerOfCaller: String +g: String +h: String +g: String +h: String diff --git a/test/files/run/repl-inline.scala b/test/files/run/repl-inline.scala index 5a5f205ad8..260ed28a4f 100644 --- a/test/files/run/repl-inline.scala +++ b/test/files/run/repl-inline.scala @@ -1,7 +1,8 @@ import scala.tools.nsc._ object Test { - val testCode = """ + val testCode = + """ def callerOfCaller = Thread.currentThread.getStackTrace.drop(2).head.getMethodName def g = callerOfCaller def h = g @@ -12,10 +13,15 @@ assert(h == "h", h) """ def main(args: Array[String]) { - val settings = new Settings() - settings.processArgumentString("-opt:l:classpath") - settings.usejavacp.value = true - val repl = new interpreter.IMain(settings) - testCode.linesIterator.foreach(repl.interpret(_)) + def test(f: Settings => Unit): Unit = { + val settings = new Settings() + settings.processArgumentString("-opt:l:classpath") + f(settings) + settings.usejavacp.value = true + val repl = new interpreter.IMain(settings) + testCode.linesIterator.foreach(repl.interpret(_)) + } + test(_ => ()) + test(_.Yreplclassbased.value = true) } } diff --git a/test/files/run/t7747-repl.check b/test/files/run/t7747-repl.check index 621a70205e..ab37da5722 100644 --- a/test/files/run/t7747-repl.check +++ b/test/files/run/t7747-repl.check @@ -246,12 +246,12 @@ scala> case class Bingo() defined class Bingo scala> List(BippyBups(), PuppyPups(), Bingo()) // show -class $read extends _root_.java.io.Serializable { +sealed class $read extends _root_.java.io.Serializable { def () = { super.; () }; - class $iw extends _root_.java.io.Serializable { + sealed class $iw extends _root_.java.io.Serializable { def () = { super.; () @@ -262,7 +262,7 @@ class $read extends _root_.java.io.Serializable { import $line45.$read.INSTANCE.$iw.$iw.PuppyPups; import $line46.$read.INSTANCE.$iw.$iw.Bingo; import $line46.$read.INSTANCE.$iw.$iw.Bingo; - class $iw extends _root_.java.io.Serializable { + sealed class $iw extends _root_.java.io.Serializable { def () = { super.; () -- cgit v1.2.3