diff options
author | Prashant Sharma <prashant.s@imaginea.com> | 2015-05-06 16:26:03 +0530 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2015-05-26 18:46:37 +1000 |
commit | a3bb887e0200cf47a1fa2382a18948b3c553cf26 (patch) | |
tree | 8a01ed0ffec7fea0b8bb499bb1a1964d260fc7f3 /src/repl/scala/tools/nsc/interpreter/Imports.scala | |
parent | e12ba55589192fc3a3cc7b441569fbcabc04dd33 (diff) | |
download | scala-a3bb887e0200cf47a1fa2382a18948b3c553cf26.tar.gz scala-a3bb887e0200cf47a1fa2382a18948b3c553cf26.tar.bz2 scala-a3bb887e0200cf47a1fa2382a18948b3c553cf26.zip |
SI-7747 Make REPL wrappers serialization friendly
Spark has been shipping a forked version of our REPL for
sometime. We have been trying to fold the patches back into
the mainline so they can defork. This is the last outstanding
issue.
Consider this REPL session:
```
scala> val x = StdIn.readInt
scala> class A(a: Int)
scala> serializedAndExecuteRemotely {
() => new A(x)
}
```
As shown by the enclosed test, the REPL, even with the
Spark friendly option `-Yrepl-class-based`, will re-initialize
`x` on the remote system.
This test simulates this by running a REPL session, and then
deserializing the resulting closure into a fresh classloader
based on the class files generated by that session. Before this
patch, it printed "evaluating x" twice.
This is based on the Spark change described:
https://github.com/mesos/spark/pull/535#discussion_r3541925
A followup commit will avoid the `val lineN$read = ` part if we
import classes or type aliases only.
[Original commit from Prashant Sharma, test case from Jason Zaugg]
Diffstat (limited to 'src/repl/scala/tools/nsc/interpreter/Imports.scala')
-rw-r--r-- | src/repl/scala/tools/nsc/interpreter/Imports.scala | 19 |
1 files changed, 18 insertions, 1 deletions
diff --git a/src/repl/scala/tools/nsc/interpreter/Imports.scala b/src/repl/scala/tools/nsc/interpreter/Imports.scala index 5244858a62..97798cd017 100644 --- a/src/repl/scala/tools/nsc/interpreter/Imports.scala +++ b/src/repl/scala/tools/nsc/interpreter/Imports.scala @@ -92,7 +92,7 @@ trait Imports { * last one imported is actually usable. */ case class ComputedImports(prepend: String, append: String, access: String) - protected def importsCode(wanted: Set[Name], wrapper: Request#Wrapper): ComputedImports = { + protected def importsCode(wanted: Set[Name], wrapper: Request#Wrapper, definesClass: Boolean): ComputedImports = { /** Narrow down the list of requests from which imports * should be taken. Removes requests which cannot contribute * useful imports for the specified set of wanted names. @@ -107,6 +107,8 @@ trait Imports { // Single symbol imports might be implicits! See bug #1752. Rather than // try to finesse this, we will mimic all imports for now. def keepHandler(handler: MemberHandler) = handler match { + /* While defining classes in class based mode - implicits are not needed. */ + case h: ImportHandler if isClassBased && definesClass => h.importedNames.exists(x => wanted.contains(x)) case _: ImportHandler => true case x => x.definesImplicit || (x.definedNames exists wanted) } @@ -146,7 +148,10 @@ trait Imports { // loop through previous requests, adding imports for each one wrapBeforeAndAfter { + // Reusing a single temporary value when import from a line with multiple definitions. + val tempValLines = mutable.Set[Int]() for (ReqAndHandler(req, handler) <- reqsToUse) { + val objName = req.lineRep.readPathInstance handler match { // If the user entered an import, then just use it; add an import wrapping // level if the import might conflict with some other import @@ -157,6 +162,18 @@ trait Imports { code append (x.member + "\n") currentImps ++= x.importedNames + case x if isClassBased => + for (imv <- x.definedNames) { + if (!currentImps.contains(imv)) { + val valName = req.lineRep.packageName + req.lineRep.readName + if (!tempValLines.contains(req.lineRep.lineId)) { + code.append(s"val $valName = $objName\n") + tempValLines += req.lineRep.lineId + } + code.append(s"import $valName ${req.accessPath}.`$imv`;\n") + currentImps += imv + } + } // For other requests, import each defined name. // import them explicitly instead of with _, so that // ambiguity errors will not be generated. Also, quote |