diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala | 20 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/IMain.scala | 41 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/ReplDir.scala | 48 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/settings/ScalaSettings.scala | 1 | ||||
-rw-r--r-- | src/library/scala/collection/immutable/Stream.scala | 45 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Mirrors.scala | 4 | ||||
-rw-r--r-- | src/reflect/scala/reflect/runtime/JavaUniverse.scala | 5 | ||||
-rw-r--r-- | test/files/run/repl-out-dir.check | 53 | ||||
-rw-r--r-- | test/files/run/repl-out-dir.scala | 13 | ||||
-rw-r--r-- | test/files/run/streams.check | 1 | ||||
-rw-r--r-- | test/files/run/streams.scala | 5 | ||||
-rw-r--r-- | test/files/run/t6223.check | 2 | ||||
-rw-r--r-- | test/files/run/t6223.scala | 2 | ||||
-rw-r--r-- | test/files/run/t6584.check | 8 | ||||
-rw-r--r-- | test/files/run/t6584.scala | 16 |
15 files changed, 214 insertions, 50 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index f4921e79e5..18222794a8 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -46,6 +46,16 @@ abstract class GenASM extends SubComponent with BytecodeWriters { private def getFile(sym: Symbol, clsName: String, suffix: String): AbstractFile = getFile(outputDirectory(sym), clsName, suffix) + /** From the reference documentation of the Android SDK: + * The `Parcelable` interface identifies classes whose instances can be written to and restored from a `Parcel`. + * Classes implementing the `Parcelable` interface must also have a static field called `CREATOR`, + * which is an object implementing the `Parcelable.Creator` interface. + */ + private val androidFieldName = newTermName("CREATOR") + + private lazy val AndroidParcelableInterface = rootMirror.getClassIfDefined("android.os.Parcelable") + private lazy val AndroidCreatorClass = rootMirror.getClassIfDefined("android.os.Parcelable$Creator") + /** JVM code generation phase */ class AsmPhase(prev: Phase) extends ICodePhase(prev) { @@ -1202,16 +1212,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { trait JAndroidBuilder { self: JPlainBuilder => - /** From the reference documentation of the Android SDK: - * The `Parcelable` interface identifies classes whose instances can be written to and restored from a `Parcel`. - * Classes implementing the `Parcelable` interface must also have a static field called `CREATOR`, - * which is an object implementing the `Parcelable.Creator` interface. - */ - private val androidFieldName = newTermName("CREATOR") - - private lazy val AndroidParcelableInterface = rootMirror.getClassIfDefined("android.os.Parcelable") - private lazy val AndroidCreatorClass = rootMirror.getClassIfDefined("android.os.Parcelable$Creator") - def isAndroidParcelableClass(sym: Symbol) = (AndroidParcelableInterface != NoSymbol) && (sym.parentSymbols contains AndroidParcelableInterface) diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index 92c2fc9768..4e702a09e6 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -30,18 +30,6 @@ import scala.reflect.runtime.{ universe => ru } import scala.reflect.{ ClassTag, classTag } import scala.tools.reflect.StdRuntimeTags._ -/** directory to save .class files to */ -private class ReplVirtualDirectory(out: JPrintWriter) extends VirtualDirectory("(memory)", None) { - private def pp(root: AbstractFile, indentLevel: Int) { - val spaces = " " * indentLevel - out.println(spaces + root.name) - if (root.isDirectory) - root.toList sortBy (_.name) foreach (x => pp(x, indentLevel + 1)) - } - // print the contents hierarchically - def show() = pp(this, 0) -} - /** An interpreter for Scala code. * * The main public entry points are compile(), interpret(), and bind(). @@ -77,16 +65,19 @@ private class ReplVirtualDirectory(out: JPrintWriter) extends VirtualDirectory(" class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends Imports { imain => - /** Leading with the eagerly evaluated. - */ - val virtualDirectory: VirtualDirectory = new ReplVirtualDirectory(out) // "directory" for classfiles - private var currentSettings: Settings = initialSettings - private[nsc] var printResults = true // whether to print result lines - private[nsc] var totalSilence = false // whether to print anything - private var _initializeComplete = false // compiler is initialized - private var _isInitialized: Future[Boolean] = null // set up initialization future - private var bindExceptions = true // whether to bind the lastException variable - private var _executionWrapper = "" // code to be wrapped around all lines + object replOutput extends ReplOutput(settings.Yreploutdir) { } + + @deprecated("Use replOutput.dir instead", "2.11.0") + def virtualDirectory = replOutput.dir + def showDirectory = replOutput.show(out) + + private var currentSettings: Settings = initialSettings + private[nsc] var printResults = true // whether to print result lines + private[nsc] var totalSilence = false // whether to print anything + private var _initializeComplete = false // compiler is initialized + private var _isInitialized: Future[Boolean] = null // set up initialization future + private var bindExceptions = true // whether to bind the lastException variable + private var _executionWrapper = "" // code to be wrapped around all lines /** We're going to go to some trouble to initialize the compiler asynchronously. * It's critical that nothing call into it until it's been initialized or we will @@ -258,7 +249,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends /** Instantiate a compiler. Overridable. */ protected def newCompiler(settings: Settings, reporter: Reporter): ReplGlobal = { - settings.outputDirs setSingleOutput virtualDirectory + settings.outputDirs setSingleOutput replOutput.dir settings.exposeEmptyPackage.value = true if (settings.Yrangepos.value) new Global(settings, reporter) with ReplGlobal with interactive.RangePositions @@ -296,7 +287,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends ensureClassLoader() _classLoader } - private class TranslatingClassLoader(parent: ClassLoader) extends AbstractFileClassLoader(virtualDirectory, parent) { + private class TranslatingClassLoader(parent: ClassLoader) extends AbstractFileClassLoader(replOutput.dir, parent) { /** Overridden here to try translating a simple name to the generated * class name if the original attempt fails. This method is used by * getResourceAsStream as well as findClass. @@ -670,7 +661,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends prevRequests.clear() referencedNameMap.clear() definedNameMap.clear() - virtualDirectory.clear() + replOutput.dir.clear() } /** This instance is no longer needed, so release any resources diff --git a/src/compiler/scala/tools/nsc/interpreter/ReplDir.scala b/src/compiler/scala/tools/nsc/interpreter/ReplDir.scala new file mode 100644 index 0000000000..9fbf64acb5 --- /dev/null +++ b/src/compiler/scala/tools/nsc/interpreter/ReplDir.scala @@ -0,0 +1,48 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2012 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools.nsc +package interpreter + +import io.VirtualDirectory +import settings.MutableSettings +import scala.reflect.io.{ AbstractFile, PlainDirectory, Directory } +import scala.collection.generic.Clearable + +/** Directory to save .class files to. */ +trait ReplDir extends AbstractFile with Clearable { } + +private class ReplVirtualDir() extends VirtualDirectory("(memory)", None) with ReplDir { } +private class ReplRealDir(dir: Directory) extends PlainDirectory(dir) with ReplDir { + def clear() = { + dir.deleteRecursively() + dir.createDirectory() + } +} + +class ReplOutput(val dirSetting: MutableSettings#StringSetting) { + // outdir for generated classfiles - may be in-memory (the default), + // a generated temporary directory, or a specified outdir. + val dir: ReplDir = ( + if (dirSetting.isDefault) + new ReplVirtualDir() + else if (dirSetting.value == "") + new ReplRealDir(Directory.makeTemp("repl")) + else + new ReplRealDir(Directory(dirSetting.value)) + ) + + // print the contents hierarchically + def show(out: JPrintWriter) = { + def pp(root: AbstractFile, indentLevel: Int) { + val label = root.name + val spaces = " " * indentLevel + out.println(spaces + label) + if (root.isDirectory) + root.toList sortBy (_.name) foreach (x => pp(x, indentLevel + 1)) + } + pp(dir, 0) + } +} diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 404f5e6b6e..80336d9fa3 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -170,6 +170,7 @@ trait ScalaSettings extends AbsScalaSettings val Ybuilderdebug = ChoiceSetting ("-Ybuilder-debug", "manager", "Compile using the specified build manager.", List("none", "refined", "simple"), "none") val Yreifycopypaste = BooleanSetting ("-Yreify-copypaste", "Dump the reified trees in copypasteable representation.") val Yreplsync = BooleanSetting ("-Yrepl-sync", "Do not use asynchronous code for repl startup") + val Yreploutdir = StringSetting ("-Yrepl-outdir", "path", "Write repl-generated classfiles to given output directory (use \"\" to generate a temporary dir)" , "") val Ynotnull = BooleanSetting ("-Ynotnull", "Enable (experimental and incomplete) scala.NotNull.") val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overriden methods.") val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.") diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index 461a375317..5566806c55 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -181,6 +181,7 @@ import scala.language.implicitConversions * @define coll stream * @define orderDependent * @define orderDependentFold + * @define willTerminateInf Note: lazily evaluated; will terminate for infinite-sized collections. */ abstract class Stream[+A] extends AbstractSeq[A] with LinearSeq[A] @@ -286,9 +287,8 @@ self => len } - /** It's an imperfect world, but at least we can bottle up the - * imperfection in a capsule. - */ + // It's an imperfect world, but at least we can bottle up the + // imperfection in a capsule. @inline private def asThat[That](x: AnyRef): That = x.asInstanceOf[That] @inline private def asStream[B](x: AnyRef): Stream[B] = x.asInstanceOf[Stream[B]] @inline private def isStreamBuilder[B, That](bf: CanBuildFrom[Stream[A], B, That]) = @@ -725,10 +725,15 @@ self => * // produces: "5, 6, 7, 8, 9" * }}} */ - override def take(n: Int): Stream[A] = + override def take(n: Int): Stream[A] = ( + // Note that the n == 1 condition appears redundant but is not. + // It prevents "tail" from being referenced (and its head being evaluated) + // when obtaining the last element of the result. Such are the challenges + // of working with a lazy-but-not-really sequence. if (n <= 0 || isEmpty) Stream.empty else if (n == 1) cons(head, Stream.empty) else cons(head, tail take n-1) + ) @tailrec final override def drop(n: Int): Stream[A] = if (n <= 0 || isEmpty) this @@ -784,8 +789,23 @@ self => these } - // there's nothing we can do about dropRight, so we just keep the definition - // in LinearSeq + /** + * @inheritdoc + * $willTerminateInf + */ + override def dropRight(n: Int): Stream[A] = { + // We make dropRight work for possibly infinite streams by carrying + // a buffer of the dropped size. As long as the buffer is full and the + // rest is non-empty, we can feed elements off the buffer head. When + // the rest becomes empty, the full buffer is the dropped elements. + def advance(stub0: List[A], stub1: List[A], rest: Stream[A]): Stream[A] = { + if (rest.isEmpty) Stream.empty + else if (stub0.isEmpty) advance(stub1.reverse, Nil, rest) + else cons(stub0.head, advance(stub0.tail, rest.head :: stub1, rest.tail)) + } + if (n <= 0) this + else advance((this take n).toList, Nil, this drop n) + } /** Returns the longest prefix of this `Stream` whose elements satisfy the * predicate `p`. @@ -841,9 +861,16 @@ self => * // produces: "1, 2, 3, 4, 5, 6" * }}} */ - override def distinct: Stream[A] = - if (isEmpty) this - else cons(head, tail.filter(head != _).distinct) + override def distinct: Stream[A] = { + // This should use max memory proportional to N, whereas + // recursively calling distinct on the tail is N^2. + def loop(seen: Set[A], rest: Stream[A]): Stream[A] = { + if (rest.isEmpty) rest + else if (seen(rest.head)) loop(seen, rest.tail) + else cons(rest.head, loop(seen + rest.head, rest.tail)) + } + loop(Set(), this) + } /** Returns a new sequence of given length containing the elements of this * sequence followed by zero or more occurrences of given elements. diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala index d16374476a..ff58a31d20 100644 --- a/src/reflect/scala/reflect/internal/Mirrors.scala +++ b/src/reflect/scala/reflect/internal/Mirrors.scala @@ -79,7 +79,9 @@ trait Mirrors extends api.Mirrors { protected def universeMissingHook(owner: Symbol, name: Name): Symbol = thisUniverse.missingHook(owner, name) - private[scala] def missingHook(owner: Symbol, name: Name): Symbol = mirrorMissingHook(owner, name) orElse universeMissingHook(owner, name) + private[scala] def missingHook(owner: Symbol, name: Name): Symbol = logResult(s"missingHook($owner, $name)")( + mirrorMissingHook(owner, name) orElse universeMissingHook(owner, name) + ) // todo: get rid of most the methods here and keep just staticClass/Module/Package diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index e18435d5b0..0f70a676fa 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -13,11 +13,12 @@ class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.S def picklerPhase = SomePhase - lazy val settings = new Settings def forInteractive = false def forScaladoc = false + lazy val settings = new Settings + private val isLogging = sys.props contains "scala.debug.reflect" - def log(msg: => AnyRef): Unit = println(" [] "+msg) + def log(msg: => AnyRef): Unit = if (isLogging) Console.err.println("[reflect] " + msg) type TreeCopier = InternalTreeCopierOps def newStrictTreeCopier: TreeCopier = new StrictTreeCopier diff --git a/test/files/run/repl-out-dir.check b/test/files/run/repl-out-dir.check new file mode 100644 index 0000000000..a96f9ba9d9 --- /dev/null +++ b/test/files/run/repl-out-dir.check @@ -0,0 +1,53 @@ +Type in expressions to have them evaluated. +Type :help for more information. + +scala> + +scala> case class Bippy(x: Int) +defined class Bippy + +scala> val x = Bippy(1) +x: Bippy = Bippy(1) + +scala> $intp.showDirectory +repl-out-dir-run.obj + $line1 + $eval$.class + $eval.class + $line2 + $eval$.class + $eval.class + $read$$iw$$iw$.class + $read$$iw$.class + $read$.class + $read.class + $line3 + $eval$.class + $eval.class + $read$$iw$$iw$.class + $read$$iw$$iw$Bippy$.class + $read$$iw$$iw$Bippy.class + $read$$iw$.class + $read$.class + $read.class + $line4 + $eval$.class + $eval.class + $read$$iw$$iw$.class + $read$$iw$.class + $read$.class + $read.class + $line5 + $eval$.class + $eval.class + $read$$iw$$iw$.class + $read$$iw$.class + $read$.class + $read.class + $repl_$init.class + Test$.class + Test.class + +scala> + +scala> diff --git a/test/files/run/repl-out-dir.scala b/test/files/run/repl-out-dir.scala new file mode 100644 index 0000000000..33c823aa2d --- /dev/null +++ b/test/files/run/repl-out-dir.scala @@ -0,0 +1,13 @@ +import scala.tools.partest.ReplTest +import scala.tools.nsc.Settings + +object Test extends ReplTest { + override def extraSettings = s"-Yrepl-outdir ${testOutput.path}" + + def code = s""" +case class Bippy(x: Int) +val x = Bippy(1) +$$intp.showDirectory + """ + +} diff --git a/test/files/run/streams.check b/test/files/run/streams.check index 7f894052d9..032057d4a1 100644 --- a/test/files/run/streams.check +++ b/test/files/run/streams.check @@ -23,3 +23,4 @@ Stream(100001, ?) true true 705082704 +6 diff --git a/test/files/run/streams.scala b/test/files/run/streams.scala index 51b4e5d76c..dc5d0204ac 100644 --- a/test/files/run/streams.scala +++ b/test/files/run/streams.scala @@ -29,7 +29,7 @@ object Test extends App { def powers(x: Int) = if ((x&(x-1)) == 0) Some(x) else None println(s3.flatMap(powers).reverse.head) - // large enough to generate StackOverflows (on most systems) + // large enough to generate StackOverflows (on most systems) // unless the following methods are tail call optimized. val size = 100000 @@ -43,4 +43,7 @@ object Test extends App { println(Stream.from(1).take(size).foldLeft(0)(_ + _)) val arr = new Array[Int](size) Stream.from(1).take(size).copyToArray(arr, 0) + + // dropRight terminates + println(Stream from 1 dropRight 1000 take 3 sum) } diff --git a/test/files/run/t6223.check b/test/files/run/t6223.check index 90ec019407..4a09d1930f 100644 --- a/test/files/run/t6223.check +++ b/test/files/run/t6223.check @@ -1,4 +1,4 @@ bar -bar$mcI$sp bar$mIc$sp bar$mIcI$sp +bar$mcI$sp diff --git a/test/files/run/t6223.scala b/test/files/run/t6223.scala index 4ab7c832e6..fb176e32e6 100644 --- a/test/files/run/t6223.scala +++ b/test/files/run/t6223.scala @@ -5,7 +5,7 @@ class Foo[@specialized(Int) A](a:A) { object Test { def main(args:Array[String]) { val f = new Foo(333) - val ms = f.getClass().getDeclaredMethods() + val ms = f.getClass().getDeclaredMethods().sortBy(_.getName) ms.foreach(m => println(m.getName)) } } diff --git a/test/files/run/t6584.check b/test/files/run/t6584.check new file mode 100644 index 0000000000..35c8688751 --- /dev/null +++ b/test/files/run/t6584.check @@ -0,0 +1,8 @@ +Array: 102400 +Vector: 102400 +List: 102400 +Stream: 102400 +Array: 102400 +Vector: 102400 +List: 102400 +Stream: 102400 diff --git a/test/files/run/t6584.scala b/test/files/run/t6584.scala new file mode 100644 index 0000000000..24c236ef35 --- /dev/null +++ b/test/files/run/t6584.scala @@ -0,0 +1,16 @@ +object Test { + def main(args: Array[String]): Unit = { + val size = 100 * 1024 + val doubled = (1 to size) ++ (1 to size) + + println("Array: " + Array.tabulate(size)(x => x).distinct.size) + println("Vector: " + Vector.tabulate(size)(x => x).distinct.size) + println("List: " + List.tabulate(size)(x => x).distinct.size) + println("Stream: " + Stream.tabulate(size)(x => x).distinct.size) + + println("Array: " + doubled.toArray.distinct.size) + println("Vector: " + doubled.toVector.distinct.size) + println("List: " + doubled.toList.distinct.size) + println("Stream: " + doubled.toStream.distinct.size) + } +} |