diff options
62 files changed, 634 insertions, 514 deletions
diff --git a/src/compiler/scala/tools/ant/FastScalac.scala b/src/compiler/scala/tools/ant/FastScalac.scala index 3c39bcf24d..403d9cc117 100644 --- a/src/compiler/scala/tools/ant/FastScalac.scala +++ b/src/compiler/scala/tools/ant/FastScalac.scala @@ -80,7 +80,6 @@ class FastScalac extends Scalac { * Most likely this manifests in confusing and very difficult to debug behavior in fsc. * We should warn or fix. */ - val stringSettings = List(s.outdir, s.classpath, s.bootclasspath, s.extdirs, s.encoding) flatMap (x => List(x.name, x.value)) @@ -104,7 +103,7 @@ class FastScalac extends Scalac { val args = (cmdOptions ::: (sourceFiles map (_.toString))).toArray try { - if (scala.tools.nsc.CompileClient.main0(args) > 0 && failonerror) + if (scala.tools.nsc.CompileClient.process(args) != 0 && failonerror) buildError("Compile failed; see the compiler error output for details.") } catch { diff --git a/src/compiler/scala/tools/nsc/CompileClient.scala b/src/compiler/scala/tools/nsc/CompileClient.scala index d1b1f751ef..9987eb0204 100644 --- a/src/compiler/scala/tools/nsc/CompileClient.scala +++ b/src/compiler/scala/tools/nsc/CompileClient.scala @@ -6,40 +6,37 @@ package scala.tools.nsc import java.io.{ BufferedReader, File, InputStreamReader, PrintWriter } -import Properties.fileEndings -import io.Path import settings.FscSettings +import scala.tools.util.CompileOutputCommon +import sys.SystemProperties.preferIPv4Stack /** The client part of the fsc offline compiler. Instead of compiling * things itself, it send requests to a CompileServer. */ -class StandardCompileClient extends HasCompileSocket { +class StandardCompileClient extends HasCompileSocket with CompileOutputCommon { lazy val compileSocket: CompileSocket = CompileSocket val versionMsg = "Fast " + Properties.versionMsg var verbose = false - def logVerbose(msg: String) = - if (verbose) - Console println msg - - def main0(argsIn: Array[String]): Int = { - // TODO: put -J -and -D options back. Right now they are lost - // because bash parses them out and they don't arrive. - val (vmArgs, fscArgs) = (Nil, argsIn.toList) + def process(args: Array[String]): Int = { + val fscArgs = args.toList val settings = new FscSettings val command = new CompilerCommand(fscArgs, settings) verbose = settings.verbose.value val shutdown = settings.shutdown.value + val vmArgs = settings.jvmargs.unparse ++ settings.defines.unparse ++ ( + if (settings.preferIPv4.value) List("-D%s=true".format(preferIPv4Stack.key)) else Nil + ) if (settings.version.value) { Console println versionMsg return 0 } - logVerbose(versionMsg) - logVerbose(fscArgs.mkString("[Given arguments: ", " ", "]")) - logVerbose(vmArgs.mkString("[VM arguments: ", " ", "]")) + info(versionMsg) + info(fscArgs.mkString("[Given arguments: ", " ", "]")) + info(vmArgs.mkString("[VM arguments: ", " ", "]")) val socket = if (settings.server.value == "") compileSocket.getOrCreateSocket(vmArgs mkString " ", !shutdown) @@ -48,7 +45,7 @@ class StandardCompileClient extends HasCompileSocket { val success = socket match { case Some(sock) => compileOnServer(sock, fscArgs) case _ => - Console.println( + echo( if (shutdown) "[No compilation server running.]" else "Compilation failed." ) @@ -60,7 +57,7 @@ class StandardCompileClient extends HasCompileSocket { object CompileClient extends StandardCompileClient { def main(args: Array[String]): Unit = sys exit { - try main0(args) + try process(args) catch { case _: Exception => 1 } } } diff --git a/src/compiler/scala/tools/nsc/CompileServer.scala b/src/compiler/scala/tools/nsc/CompileServer.scala index fc98e30085..a34be6226b 100644 --- a/src/compiler/scala/tools/nsc/CompileServer.scala +++ b/src/compiler/scala/tools/nsc/CompileServer.scala @@ -21,6 +21,11 @@ import settings.FscSettings */ class StandardCompileServer extends SocketServer { lazy val compileSocket: CompileSocket = CompileSocket + private var compiler: Global = null + + var reporter: ConsoleReporter = _ + var shutdown = false + var verbose = false val versionMsg = "Fast Scala compiler " + Properties.versionString + " -- " + @@ -28,16 +33,6 @@ class StandardCompileServer extends SocketServer { val MaxCharge = 0.8 - private var compiler: Global = null - var reporter: ConsoleReporter = _ - var shutdown = false - - private def exit(code: Int): Nothing = { - System.err.close() - System.out.close() - sys.exit(code) - } - private val runtime = Runtime.getRuntime() import runtime.{ totalMemory, freeMemory, maxMemory } @@ -53,9 +48,9 @@ class StandardCompileServer extends SocketServer { } def printMemoryStats() { - System.out.println("New session, total memory = %s, max memory = %s, free memory = %s".format( - totalMemory, maxMemory, freeMemory)) - System.out.flush() + def mb(bytes: Long) = "%dMB".format(bytes / 1000000) + info("New session: total memory = %s, max memory = %s, free memory = %s".format( + mb(totalMemory), mb(maxMemory), mb(freeMemory))) } def isMemoryFullEnough() = { @@ -97,13 +92,18 @@ class StandardCompileServer extends SocketServer { if (input == null || password != guessedPassword) return - val args = input.split("\0", -1).toList + val args = input.split("\0", -1).toList val settings = new FscSettings(fscError) - def logVerbose(msg: String) = - if (settings.verbose.value) - out println msg + val command = newOfflineCompilerCommand(args, settings) - val command = newOfflineCompilerCommand(args, settings) + // Update the idle timeout if given + if (!settings.idleMins.isDefault) { + val mins = settings.idleMins.value + if (mins == 0) echo("Disabling idle timeout on compile server.") + else echo("Setting idle timeout to " + mins + " minutes.") + + this.idleMinutes = mins + } if (settings.shutdown.value) { shutdown = true return out.println("[Compile server exited]") @@ -112,6 +112,7 @@ class StandardCompileServer extends SocketServer { compiler = null return out.println("[Compile server was reset]") } + this.verbose = settings.verbose.value reporter = new ConsoleReporter(command.settings, in, out) { // disable prompts, so that compile server cannot block @@ -119,14 +120,14 @@ class StandardCompileServer extends SocketServer { } def isCompilerReusable: Boolean = { if (compiler == null) { - logVerbose("[Creating new instance for compile server.]") - logVerbose("[Compiler version: " + Properties.versionString + ".]") + info("[Creating new instance for compile server.]") + info("[Compiler version: " + Properties.versionString + ".]") return false } val unequal = unequalSettings(command.settings, compiler.settings) if (unequal.nonEmpty) { - logVerbose("[Replacing compiler with new instance because settings are unequal.]") - logVerbose("[Asymmetric settings: " + unequal.mkString(", ") + "]") + info("[Replacing compiler with new instance because settings are unequal.]") + info("[Asymmetric settings: " + unequal.mkString(", ") + "]") } unequal.isEmpty } @@ -144,8 +145,7 @@ class StandardCompileServer extends SocketServer { compiler = newGlobal(command.settings, reporter) } val c = compiler - val run = new c.Run() - try run compile command.files + try new c.Run() compile command.files catch { case ex @ FatalError(msg) => reporter.error(null, "fatal error: " + msg) @@ -157,7 +157,7 @@ class StandardCompileServer extends SocketServer { } reporter.printSummary() if (isMemoryFullEnough) { - logVerbose("Nulling out compiler due to memory utilization.") + info("Nulling out compiler due to memory utilization.") compiler = null } } @@ -166,12 +166,19 @@ class StandardCompileServer extends SocketServer { object CompileServer extends StandardCompileServer { /** A directory holding redirected output */ - private val redirectDir = (compileSocket.tmpDir / "output-redirects").createDirectory() + private lazy val redirectDir = (compileSocket.tmpDir / "output-redirects").createDirectory() private def redirect(setter: PrintStream => Unit, filename: String): Unit = setter(new PrintStream((redirectDir / filename).createFile().bufferedOutput())) def main(args: Array[String]) { + val debug = args contains "-v" + + if (debug) { + echo("Starting CompileServer on port " + port) + echo("Redirect dir is " + redirectDir) + } + redirect(System.setOut, "scala-compile-server-out.log") redirect(System.setErr, "scala-compile-server-err.log") System.err.println("...starting server on socket "+port+"...") diff --git a/src/compiler/scala/tools/nsc/CompileSocket.scala b/src/compiler/scala/tools/nsc/CompileSocket.scala index c75c6d0f22..1fd37eb70c 100644 --- a/src/compiler/scala/tools/nsc/CompileSocket.scala +++ b/src/compiler/scala/tools/nsc/CompileSocket.scala @@ -10,14 +10,19 @@ import java.io.{ BufferedReader, FileReader } import java.util.regex.Pattern import java.net._ import java.security.SecureRandom - -import io.{ File, Path, Socket } +import io.{ File, Path, Directory, Socket } import scala.util.control.Exception.catching +import scala.tools.util.CompileOutputCommon import scala.tools.util.StringOps.splitWhere import scala.sys.process._ trait HasCompileSocket { def compileSocket: CompileSocket + + // This is kind of a suboptimal way to identify error situations. + val errorMarkers = Set("error:", "error found", "errors found", "bad option") + def isErrorMessage(msg: String) = errorMarkers exists (msg contains _) + def compileOnServer(sock: Socket, args: Seq[String]): Boolean = { var noErrors = true @@ -28,10 +33,10 @@ trait HasCompileSocket { def loop(): Boolean = in.readLine() match { case null => noErrors case line => - if (compileSocket.errorPattern matcher line matches) + if (isErrorMessage(line)) noErrors = false - Console.err println line + compileSocket.echo(line) loop() } try loop() @@ -41,8 +46,9 @@ trait HasCompileSocket { } /** This class manages sockets for the fsc offline compiler. */ -class CompileSocket { +class CompileSocket extends CompileOutputCommon { protected lazy val compileClient: StandardCompileClient = CompileClient + def verbose = compileClient.verbose /** The prefix of the port identification file, which is followed * by the port number. @@ -60,23 +66,8 @@ class CompileSocket { } /** The class name of the scala compile server */ - protected val serverClass = "scala.tools.nsc.CompileServer" - - /** A regular expression for checking compiler output for errors */ - val errorRegex = ".*(errors? found|don't know|bad option).*" - - /** A Pattern object for checking compiler output for errors */ - val errorPattern = Pattern compile errorRegex - - protected def fscError(msg: String) = System.err.println(msg) - - protected def fatal(msg: String) = { - fscError(msg) - sys.error("fsc failure") - } - - protected def info(msg: String) = - if (compileClient.verbose) System.out.println(msg) + protected val serverClass = "scala.tools.nsc.CompileServer" + protected def serverClassArgs = if (verbose) List("-v") else Nil // debug /** A temporary directory to use */ val tmpDir = { @@ -93,23 +84,17 @@ class CompileSocket { /* A directory holding port identification files */ val portsDir = (tmpDir / dirName).createDirectory() - /** Maximum number of polls for an available port */ - private val MaxAttempts = 100 - - /** Time (in ms) to sleep between two polls */ - private val sleepTime = 20 - /** The command which starts the compile server, given vm arguments. * * @param vmArgs the argument string to be passed to the java or scala command */ private def serverCommand(vmArgs: Seq[String]): Seq[String] = - Seq(vmCommand) ++ vmArgs ++ Seq(serverClass) filterNot (_ == "") + Seq(vmCommand) ++ vmArgs ++ Seq(serverClass) ++ serverClassArgs filterNot (_ == "") /** Start a new server. */ private def startNewServer(vmArgs: String) = { val cmd = serverCommand(vmArgs split " " toSeq) - info("[Executing command: %s]" format cmd) + info("[Executing command: %s]" format cmd.mkString(" ")) cmd.daemonized().run() } @@ -117,18 +102,18 @@ class CompileSocket { def portFile(port: Int) = portsDir / File(port.toString) /** Poll for a server port number; return -1 if none exists yet */ - private def pollPort(): Int = portsDir.list match { - case it if !it.hasNext => -1 - case it => - val ret = it.next.name.toInt - it foreach (_.delete()) - ret + private def pollPort(): Int = portsDir.list.toList match { + case Nil => -1 + case x :: xs => try x.name.toInt finally xs foreach (_.delete()) } /** Get the port number to which a scala compile server is connected; * If no server is running yet, then create one. */ def getPort(vmArgs: String): Int = { + val maxPolls = 300 + val sleepTime = 25 + var attempts = 0 var port = pollPort() @@ -136,15 +121,14 @@ class CompileSocket { info("No compile server running: starting one with args '" + vmArgs + "'") startNewServer(vmArgs) } - - while (port < 0 && attempts < MaxAttempts) { + while (port < 0 && attempts < maxPolls) { attempts += 1 Thread.sleep(sleepTime) port = pollPort() } info("[Port number: " + port + "]") if (port < 0) - fatal("Could not connect to compilation daemon.") + fatal("Could not connect to compilation daemon after " + attempts + " attempts.") port } @@ -167,17 +151,17 @@ class CompileSocket { * cannot be established. */ def getOrCreateSocket(vmArgs: String, create: Boolean = true): Option[Socket] = { - // try for 10 seconds - val retryDelay = 100 - val maxAttempts = (10 * 1000) / retryDelay + val maxMillis = 10 * 1000 // try for 10 seconds + val retryDelay = 50 + val maxAttempts = maxMillis / retryDelay def getsock(attempts: Int): Option[Socket] = attempts match { - case 0 => fscError("Unable to establish connection to compilation daemon") ; None + case 0 => warn("Unable to establish connection to compilation daemon") ; None case num => val port = if (create) getPort(vmArgs) else pollPort() if (port < 0) return None - Socket(InetAddress.getLocalHost(), port).either match { + Socket.localhost(port).either match { case Right(socket) => info("[Connected to compilation daemon at port %d]" format port) Some(socket) diff --git a/src/compiler/scala/tools/nsc/CompilerCommand.scala b/src/compiler/scala/tools/nsc/CompilerCommand.scala index 2e3bc32007..1c0fd8b9de 100644 --- a/src/compiler/scala/tools/nsc/CompilerCommand.scala +++ b/src/compiler/scala/tools/nsc/CompilerCommand.scala @@ -17,9 +17,11 @@ class CompilerCommand(arguments: List[String], val settings: Settings) { /** file extensions of files that the compiler can process */ lazy val fileEndings = Properties.fileEndings - val (ok, files) = + private val processArgumentsResult = if (shouldProcessArguments) processArguments else (true, Nil) + def ok = processArgumentsResult._1 + def files = processArgumentsResult._2 /** The name of the command */ def cmdName = "scalac" diff --git a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala index c8e86a752d..68689a4109 100644 --- a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala +++ b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala @@ -27,8 +27,8 @@ extends CompilerCommand(args, settings) { /** thingToRun: What to run. If it is None, then the interpreter should be started * arguments: Arguments to pass to the object or script to run */ - val (thingToRun, arguments) = { - val (_, remaining) = settings.processArguments(args, false) + val (_ok, thingToRun, arguments) = { + val (ok, remaining) = settings.processArguments(args, false) val mainClass = if (settings.jarfile.isDefault) None else new io.Jar(settings.jarfile.value).mainClass @@ -37,17 +37,23 @@ extends CompilerCommand(args, settings) { // Otherwise, the first remaining argument is the program to run, and the rest // of the arguments go to it. If remaining is empty, we'll start the repl. mainClass match { - case Some(name) => (Some(name), remaining) - case _ => (remaining.headOption, remaining drop 1) + case Some(name) => (ok, Some(name), remaining) + case _ => (ok, remaining.headOption, remaining drop 1) } } + override def ok = _ok - override def usageMsg =""" + private def interpolate(s: String) = s.trim.replaceAll("@cmd@", cmdName).replaceAll("@compileCmd@", compCmdName) + "\n" + + def shortUsageMsg = interpolate(""" Usage: @cmd@ <options> [<script|class|object> <arguments>] or @cmd@ <options> [-jar <jarfile> <arguments>] + or @cmd@ -help -All options to @compileCmd@ are allowed. See @compileCmd@ -help. +All options to @compileCmd@ are also allowed. See @compileCmd@ -help. + """) + override def usageMsg = shortUsageMsg + "\n" + interpolate(""" The first given argument other than options to @cmd@ designates what to run. Runnable targets are: @@ -74,6 +80,5 @@ A file argument will be run as a scala script unless it contains only top level classes and objects, and exactly one runnable main method. In that case the file will be compiled and the main method invoked. This provides a bridge between scripts and standard scala source. - - """.replaceAll("@cmd@", cmdName).replaceAll("@compileCmd@", compCmdName) + """) + "\n" } diff --git a/src/compiler/scala/tools/nsc/MainGenericRunner.scala b/src/compiler/scala/tools/nsc/MainGenericRunner.scala index ad7cde1e30..e40fdea3b9 100644 --- a/src/compiler/scala/tools/nsc/MainGenericRunner.scala +++ b/src/compiler/scala/tools/nsc/MainGenericRunner.scala @@ -38,7 +38,7 @@ object MainGenericRunner { import command.settings def sampleCompiler = new Global(settings) // def so its not created unless needed - if (!command.ok) return errorFn("%s\n%s".format(command.usageMsg, sampleCompiler.pluginOptionsHelp)) + if (!command.ok) return errorFn("\n" + command.shortUsageMsg) else if (settings.version.value) return errorFn("Scala code runner %s -- %s".format(versionString, copyrightString)) else if (command.shouldStopWithInfo) return errorFn(command getInfoMessage sampleCompiler) diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala index 5eb6027d0a..07aa62d164 100644 --- a/src/compiler/scala/tools/nsc/ScriptRunner.scala +++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala @@ -49,12 +49,6 @@ import util.Exceptional.unwrap class ScriptRunner extends HasCompileSocket { lazy val compileSocket = CompileSocket - /* While I'm chasing down the fsc and script bugs. */ - def DBG(msg: Any) { - System.err.println(msg.toString) - System.err.flush() - } - /** Default name to use for the wrapped script */ val defaultScriptMain = "Main" diff --git a/src/compiler/scala/tools/nsc/interpreter/Power.scala b/src/compiler/scala/tools/nsc/interpreter/Power.scala index 8ad799a265..6dc8cee219 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Power.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Power.scala @@ -7,6 +7,7 @@ package scala.tools.nsc package interpreter import scala.collection.{ mutable, immutable } +import scala.util.matching.Regex import scala.tools.nsc.util.{ BatchSourceFile } import session.{ History } @@ -17,29 +18,68 @@ class Power(repl: ILoop, intp: IMain) { def this(intp: IMain) = this(null, intp) val global: intp.global.type = intp.global - import global._ - import definitions.{ getMember, getModule, getClass => getCompilerClass } import intp.{ beQuietDuring, interpret, parse } - object phased extends Phased { - val global: Power.this.global.type = Power.this.global - } - - class ReplSnippet[T](val path: String, initial: T) { - var code: String = "" - var value: T = initial + abstract class SymSlurper { + def isKeep(sym: Symbol): Boolean + def isIgnore(sym: Symbol): Boolean + def isRecur(sym: Symbol): Boolean + def isFinished(): Boolean + + val keep = mutable.HashSet[Symbol]() + val seen = mutable.HashSet[Symbol]() + def processed = keep.size + seen.size + def discarded = seen.size - keep.size + + def members(x: Symbol): List[Symbol] = + if (x.rawInfo.isComplete) x.info.members + else Nil + + var lastCount = -1 + var pass = 0 + val unseenHistory = new mutable.ListBuffer[Int] + + def loop(todo: Set[Symbol]): Set[Symbol] = { + pass += 1 + val (repeats, unseen) = todo partition seen + unseenHistory += unseen.size + if (opt.verbose) { + println("%3d %s accumulated, %s discarded. This pass: %s unseen, %s repeats".format( + pass, keep.size, discarded, unseen.size, repeats.size)) + } + if (lastCount == processed || unseen.isEmpty || isFinished()) + return keep.toSet + + lastCount = processed + keep ++= (unseen filter isKeep filterNot isIgnore) + seen ++= unseen + loop(unseen filter isRecur flatMap members) + } - def set(code: String) = interpret(path + ".value = " + code) - def get: T = value - override def toString = "intp." + path + ".value = \"" + code + "\"" + def apply(sym: Symbol): Set[Symbol] = { + keep.clear() + seen.clear() + loop(Set(sym)) + } } - object vars { - private def create[T](name: String, initial: T): ReplSnippet[T] = - new ReplSnippet[T]("power.vars." + name, initial) + class PackageSlurper(pkgName: String) extends SymSlurper { + val pkgSymbol = getCompilerModule(pkgName) + val modClass = pkgSymbol.moduleClass + + /** Looking for dwindling returns */ + def droppedEnough() = unseenHistory.size >= 4 && ( + unseenHistory.takeRight(4).sliding(2) map (_.toList) forall { + case List(a, b) => a > b + } + ) - val symfilter = create("symfilter", (s: Symbol) => true) + def isRecur(sym: Symbol) = true + def isIgnore(sym: Symbol) = sym.isAnonOrRefinementClass || (sym.name.toString contains "$mc") + def isKeep(sym: Symbol) = sym.hasTransOwner(modClass) + def isFinished() = droppedEnough() + def slurp() = apply(modClass) } def banner = """ @@ -56,7 +96,8 @@ class Power(repl: ILoop, intp: IMain) { |val global: intp.global.type = intp.global |import global._ |import definitions._ - |import power.{ phased, show, clazz, module } + |import power.phased + |import power.Implicits._ """.stripMargin /** Starts up power mode and runs whatever is in init. @@ -74,62 +115,94 @@ class Power(repl: ILoop, intp: IMain) { init split '\n' foreach interpret } - object show { - private def defStrings(sym: Symbol, p: Symbol => Boolean) = - phased(sym.info.members filter p map (_.defString)) - - private def display(sym: Symbol, p: Symbol => Boolean) = - defStrings(sym, p) foreach println - - def methods[T: Manifest] = display(clazz[T], _.isMethod) - def apply[T: Manifest] = display(clazz[T], vars.symfilter.get) - } - - abstract class NameBased[T <: Name] { - def mkName(s: String): T - def mkSymbol(s: String): Symbol - - def apply[T: Manifest] = mkSymbol(manifest[T].erasure.getName) - def tpe[T: Manifest] = apply[T].tpe - def members[T: Manifest] = tpe[T].members - def member[T: Manifest](name: Name) = getMember(apply[T], name) - def vmember[T: Manifest](name: String) = member[T](newTermName(name)) - def tmember[T: Manifest](name: String) = member[T](newTypeName(name)) - } private def missingWrap(op: => Symbol): Symbol = try op catch { case _: MissingRequirementError => NoSymbol } - object clazz extends NameBased[TypeName] { - def mkName(s: String) = newTypeName(s) - def mkSymbol(s: String): Symbol = missingWrap(getCompilerClass(s)) + private def getCompilerClass(name: String) = missingWrap(definitions.getClass(name)) + private def getCompilerModule(name: String) = missingWrap(definitions.getModule(name)) + + object InternalInfo { + implicit def apply[T: Manifest] : InternalInfo[T] = new InternalInfo[T](None) } - object module extends NameBased[TermName] { - def mkName(s: String) = newTermName(s) - def mkSymbol(s: String): Symbol = missingWrap(getModule(s)) + /** Todo: translate manifest type arguments into applied types. */ + class InternalInfo[T: Manifest](value: Option[T] = None) { + def companion = symbol.companionSymbol + def info = symbol.info + def module = symbol.moduleClass + def owner = symbol.owner + def symDef = symbol.defString + def symName = symbol.name + def tpe = symbol.tpe + + def declares = members filter (_.owner == symbol) + def inherits = members filterNot (_.owner == symbol) + def types = members filter (_.name.isTypeName) + def methods = members filter (_.isMethod) + def overrides = declares filter (_.isOverride) + + def erasure = manifest[T].erasure + def symbol = getCompilerClass(erasure.getName) + def members = tpe.members + def bts = info.baseTypeSeq.toList + def btsmap = bts map (x => (x, x.decls.toList)) toMap + def pkgName = erasure.getPackage.getName + def pkg = getCompilerModule(pkgName) + def pkgmates = pkg.tpe.members + def pkgslurp = new PackageSlurper(pkgName) slurp() + + def ? = this + + def whoHas(name: String) = bts filter (_.decls.toList exists (_.name.toString == name)) + def <:<[U: Manifest](other: U) = tpe <:< InternalInfo[U].tpe + def lub[U: Manifest](other: U) = global.lub(List(tpe, InternalInfo[U].tpe)) + def glb[U: Manifest](other: U) = global.glb(List(tpe, InternalInfo[U].tpe)) + + def shortClass = erasure.getName split "[$.]" last + override def toString = value match { + case Some(x) => "%s (%s)".format(x, shortClass) + case _ => erasure.getName + } } - def mkContext(code: String = "") = analyzer.rootContext(mkUnit(code)) - def mkAlias(name: String, what: String) = interpret("type %s = %s".format(name, what)) - def mkSourceFile(code: String) = new BatchSourceFile("<console>", code) - def mkUnit(code: String) = new CompilationUnit(mkSourceFile(code)) - - def mkTree(code: String): Tree = mkTrees(code).headOption getOrElse EmptyTree - def mkTrees(code: String): List[Tree] = parse(code) getOrElse Nil - def mkTypedTrees(code: String*): List[Tree] = { - class TyperRun extends Run { - override def stopPhase(name: String) = name == "superaccessors" + trait PCFormatter extends (Any => List[String]) { + def apply(x: Any): List[String] + def show(x: Any): Unit = grep(x, _ => true) + def grep(x: Any, p: String => Boolean): Unit = apply(x) filter p foreach println + } + class PrintingConvenience[T](value: T)(implicit fmt: PCFormatter) { + def > : Unit = >(_ => true) + def >(s: String): Unit = >(_ contains s) + def >(r: Regex): Unit = >(_ matches r.pattern.toString) + def >(p: String => Boolean): Unit = fmt.grep(value, p) + } + object Implicits { + implicit lazy val powerNameOrdering: Ordering[Name] = Ordering[String] on (_.toString) + implicit object powerSymbolOrdering extends Ordering[Symbol] { + def compare(s1: Symbol, s2: Symbol) = + if (s1 eq s2) 0 + else if (s1 isLess s2) -1 + else 1 + } + implicit def replPrinting[T](x: T)(implicit fmt: PCFormatter) = new PrintingConvenience[T](x) + implicit def replInternalInfo[T: Manifest](x: T): InternalInfo[T] = new InternalInfo[T](Some(x)) + implicit object ReplDefaultFormatter extends PCFormatter { + def apply(x: Any): List[String] = x match { + case Tuple2(k, v) => apply(k) + " -> " + apply(v) + case xs: Traversable[_] => (xs.toList flatMap apply).sorted.distinct + case x => List("" + x) + } } + } - reporter.reset() - val run = new TyperRun - run compileSources (code.toList.zipWithIndex map { - case (s, i) => new BatchSourceFile("<console %d>".format(i), s) - }) - run.units.toList map (_.body) + object phased extends Phased { + val global: Power.this.global.type = Power.this.global } - def mkTypedTree(code: String) = mkTypedTrees(code).head - def mkType(id: String): Type = intp.typeOfExpression(id) getOrElse NoType + def context(code: String) = analyzer.rootContext(unit(code)) + def source(code: String) = new BatchSourceFile("<console>", code) + def unit(code: String) = new CompilationUnit(source(code)) + def trees(code: String): List[Tree] = parse(code) getOrElse Nil + def typeOf(id: String): Type = intp.typeOfExpression(id) getOrElse NoType override def toString = """ |** Power mode status ** diff --git a/src/compiler/scala/tools/nsc/io/Socket.scala b/src/compiler/scala/tools/nsc/io/Socket.scala index 0be7de3873..b7920921fa 100644 --- a/src/compiler/scala/tools/nsc/io/Socket.scala +++ b/src/compiler/scala/tools/nsc/io/Socket.scala @@ -6,36 +6,56 @@ package scala.tools.nsc package io -import java.io.{ IOException, InputStreamReader, BufferedReader, PrintWriter } -import java.net.{ InetAddress, Socket => JSocket } -import scala.util.control.Exception._ +import java.io.{ IOException, InputStreamReader, BufferedReader, PrintWriter, Closeable } +import java.io.{ BufferedOutputStream, BufferedReader } +import java.net.{ ServerSocket, SocketException, SocketTimeoutException, InetAddress, Socket => JSocket } +import scala.sys.SystemProperties._ +import scala.io.Codec /** A skeletal only-as-much-as-I-need Socket wrapper. */ -object Socket -{ - private val socketExceptions = List(classOf[IOException], classOf[SecurityException]) +object Socket { + def preferringIPv4[T](body: => T): T = exclusively { + val saved = preferIPv4Stack.value + try { preferIPv4Stack.enable() ; body } + finally preferIPv4Stack setValue saved + } + + class Box[+T](f: () => T) { + private def handlerFn[U](f: Throwable => U): PartialFunction[Throwable, U] = { + case x @ (_: IOException | _: SecurityException) => f(x) + } + private val optHandler = handlerFn[Option[T]](_ => None) + private val eitherHandler = handlerFn[Either[Throwable, T]](x => Left(x)) - class SocketBox(f: () => Socket) { - def either: Either[Throwable, Socket] = catching(socketExceptions: _*) either f() - def opt: Option[Socket] = catching(socketExceptions: _*) opt f() + def getOrElse[T1 >: T](alt: T1): T1 = opt getOrElse alt + def either: Either[Throwable, T] = try Right(f()) catch eitherHandler + def opt: Option[T] = try Some(f()) catch optHandler } - def apply(host: InetAddress, port: Int) = new SocketBox(() => new Socket(new JSocket(host, port))) - def apply(host: String, port: Int) = new SocketBox(() => new Socket(new JSocket(host, port))) + def newIPv4Server(port: Int = 0) = new Box(() => preferringIPv4(new ServerSocket(0))) + def newServer(port: Int = 0) = new Box(() => new ServerSocket(0)) + def localhost(port: Int) = apply(InetAddress.getLocalHost(), port) + def apply(host: InetAddress, port: Int) = new Box(() => new Socket(new JSocket(host, port))) + def apply(host: String, port: Int) = new Box(() => new Socket(new JSocket(host, port))) } -class Socket(jsocket: JSocket) { - def getOutputStream() = jsocket.getOutputStream() - def getInputStream() = jsocket.getInputStream() - def getPort() = jsocket.getPort() - def close() = jsocket.close() +class Socket(jsocket: JSocket) extends Streamable.Bytes with Closeable { + def inputStream() = jsocket.getInputStream() + def outputStream() = jsocket.getOutputStream() + def getPort() = jsocket.getPort() + def close() = jsocket.close() + + def printWriter() = new PrintWriter(outputStream(), true) + def bufferedReader(implicit codec: Codec) = new BufferedReader(new InputStreamReader(inputStream())) + def bufferedOutput(size: Int) = new BufferedOutputStream(outputStream(), size) /** Creates an InputStream and applies the closure, automatically closing it on completion. */ def applyReaderAndWriter[T](f: (BufferedReader, PrintWriter) => T): T = { - val out = new PrintWriter(getOutputStream(), true) - val in = new BufferedReader(new InputStreamReader(getInputStream())) + val out = printWriter() + val in = bufferedReader + try f(in, out) finally { in.close() diff --git a/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala index 80183791ed..6f130b9e74 100644 --- a/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala @@ -16,7 +16,7 @@ trait AbsScalaSettings { type PathSetting <: AbsSetting { type T = String } type PhasesSetting <: AbsSetting { type T = List[String] } type StringSetting <: AbsSetting { type T = String } - type MapSetting <: AbsSetting { type T = Map[String, String] } + type PrefixSetting <: AbsSetting { type T = List[String] } type OutputDirs type OutputSetting <: AbsSetting @@ -29,7 +29,7 @@ trait AbsScalaSettings { def PathSetting(name: String, descr: String, default: String): PathSetting def PhasesSetting(name: String, descr: String): PhasesSetting def StringSetting(name: String, helpArg: String, descr: String, default: String): StringSetting - def MapSetting(name: String, prefix: String, descr: String): MapSetting + def PrefixSetting(name: String, prefix: String, descr: String): PrefixSetting /** **/ abstract class SettingGroup(val prefix: String) extends AbsSetting { diff --git a/src/compiler/scala/tools/nsc/settings/FscSettings.scala b/src/compiler/scala/tools/nsc/settings/FscSettings.scala index b7f0c553f6..a219148b16 100644 --- a/src/compiler/scala/tools/nsc/settings/FscSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/FscSettings.scala @@ -14,16 +14,22 @@ class FscSettings(error: String => Unit) extends Settings(error) { def this() = this(Console.println) - val reset = BooleanSetting("-reset", "Reset compile server caches") - val shutdown = BooleanSetting("-shutdown", "Shutdown compile server") - val server = StringSetting ("-server", "hostname:portnumber", "Specify compile server socket", "") + val reset = BooleanSetting("-reset", "Reset compile server caches") + val shutdown = BooleanSetting("-shutdown", "Shutdown compile server") + val server = StringSetting ("-server", "hostname:portnumber", "Specify compile server socket", "") + val preferIPv4 = BooleanSetting("-ipv4", "Use IPv4 rather than IPv6 for the server socket") + val absClasspath = BooleanSetting("-absolute-cp", "Make classpath elements absolute paths before sending to server") . + withPostSetHook (_ => absolutizeClasspath()) + val idleMins = IntSetting ("-max-idle", "Set idle timeout in minutes for fsc (use 0 for no timeout)", + 30, Some(0, Int.MaxValue), (_: String) => None) disable(prompt) disable(resident) - // Make all paths absolute since we may be going from client to server - userSetSettings foreach { - case x: PathSetting => x.value = ClassPath.makeAbsolute(x.value) - case _ => () + // Make the classpath absolute: for going from client to server. + private def absolutizeClasspath() { + userSetSettings collect { + case x: PathSetting => x.value = ClassPath.makeAbsolute(x.value) + } } } diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala index f67a9a84dc..6a357cc08a 100644 --- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala @@ -80,6 +80,11 @@ class MutableSettings(val errorFn: String => Unit) extends AbsSettings with Scal */ lazy val outputDirs = new OutputDirs + /** A list of settings which act based on prefix rather than an exact + * match. This is basically -D and -J. + */ + lazy val prefixSettings = allSettings collect { case x: PrefixSetting => x } + /** Split the given line into parameters. */ def splitParams(line: String) = cmd.Parser.tokenize(line, errorFn) @@ -124,12 +129,18 @@ class MutableSettings(val errorFn: String => Unit) extends AbsSettings with Scal } else { // we dispatch differently based on the appearance of p: - // 1) If it has a : it is presumed to be -Xfoo:bar,baz - // 2) Otherwise, the whole string should be a command name + // 1) If it matches a prefix setting it is sent there directly. + // 2) If it has a : it is presumed to be -Xfoo:bar,baz + // 3) Otherwise, the whole string should be a command name // // Internally we use Option[List[String]] to discover error, // but the outside expects our arguments back unchanged on failure - if (arg contains ":") parseColonArg(arg) match { + val prefix = prefixSettings find (_ respondsTo arg) + if (prefix.isDefined) { + prefix.get tryToSet args + rest + } + else if (arg contains ":") parseColonArg(arg) match { case Some(_) => rest case None => args } @@ -188,7 +199,7 @@ class MutableSettings(val errorFn: String => Unit) extends AbsSettings with Scal add(new PathSetting(name, descr, default, prepend, append)) } - def MapSetting(name: String, prefix: String, descr: String): MapSetting = add(new MapSetting(name, prefix, descr)) + def PrefixSetting(name: String, prefix: String, descr: String): PrefixSetting = add(new PrefixSetting(name, prefix, descr)) // basically this is a value which remembers if it's been modified trait SettingValue extends AbsSettingValue { @@ -410,31 +421,23 @@ class MutableSettings(val errorFn: String => Unit) extends AbsSettings with Scal } /** A special setting for accumulating arguments like -Dfoo=bar. */ - class MapSetting private[nsc]( + class PrefixSetting private[nsc]( name: String, prefix: String, descr: String) extends Setting(name, descr) { - type T = Map[String, String] - protected var v: Map[String, String] = Map() - - def tryToSet(args: List[String]) = { - val (xs, rest) = args partition (_ startsWith prefix) - val pairs = xs map (_ stripPrefix prefix) map { x => - (x indexOf '=') match { - case -1 => (x, "") - case idx => (x take idx, x drop (idx + 1)) - } - } - v = v ++ pairs - Some(rest) - } + type T = List[String] + protected var v: List[String] = Nil - override def respondsTo(label: String) = label startsWith prefix - def unparse: List[String] = v.toList map { - case (k, "") => prefix + k - case (k, v) => prefix + k + "=" + v + def tryToSet(args: List[String]) = args match { + case x :: xs if x startsWith prefix => + v = v :+ x + Some(xs) + case _ => + None } + override def respondsTo(token: String) = token startsWith prefix + def unparse: List[String] = value } /** A setting represented by a string, (`default' unless set) */ diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 16289f11d9..1670dfb94a 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -23,8 +23,8 @@ trait ScalaSettings extends AbsScalaSettings with StandardScalaSettings { /** Disable a setting */ def disable(s: Setting) = allSettings -= s - val jvmargs = MapSetting("-J<flag>", "-J", "Pass <flag> directly to the runtime system.") - val defines = MapSetting("-Dproperty=value", "-D", "Pass -Dproperty=value directly to the runtime system.") + val jvmargs = PrefixSetting("-J<flag>", "-J", "Pass <flag> directly to the runtime system.") + val defines = PrefixSetting("-Dproperty=value", "-D", "Pass -Dproperty=value directly to the runtime system.") val toolcp = PathSetting("-toolcp", "Add to the runner classpath.", "") val nobootcp = BooleanSetting("-nobootcp", "Do not use the boot classpath for the scala jars.") diff --git a/src/compiler/scala/tools/util/SocketServer.scala b/src/compiler/scala/tools/util/SocketServer.scala index 0094333402..fba3d4ce48 100644 --- a/src/compiler/scala/tools/util/SocketServer.scala +++ b/src/compiler/scala/tools/util/SocketServer.scala @@ -6,100 +6,95 @@ ** |/ ** \* */ - package scala.tools.util -import java.io.{ PrintWriter, BufferedOutputStream, BufferedReader, InputStreamReader, IOException } -import java.net.{ Socket, ServerSocket, SocketException, SocketTimeoutException } +import java.net.{ ServerSocket, SocketException, SocketTimeoutException } +import java.io.{ PrintWriter, BufferedReader } +import scala.tools.nsc.io.Socket -object SocketServer { - val BufferSize = 10240 +trait CompileOutputCommon { + def verbose: Boolean - def bufferedReader(s: Socket) = new BufferedReader(new InputStreamReader(s.getInputStream())) - def bufferedOutput(s: Socket) = new BufferedOutputStream(s.getOutputStream, BufferSize) + def info(msg: String) = if (verbose) echo(msg) + def echo(msg: String) = Console println msg + def warn(msg: String) = System.err println msg + def fatal(msg: String) = { warn(msg) ; sys.exit(1) } } -import SocketServer._ -/** The abstract class <code>SocketServer</code> implements the server +/** The abstract class SocketServer implements the server * communication for the fast Scala compiler. * * @author Martin Odersky * @version 1.0 */ -abstract class SocketServer { - // After some number of idle minutes, politely exit. - // Should the port file disappear, and the clients - // therefore unable to contact this server instance, - // the process will just eventually terminate by itself. - def fscIdleMinutes = { - sys.props("scala.config.fsc.idle-minutes") match { - case null => 30 - case str => try str.toInt catch { case _: Exception => 30 } - } - } - def fscIdleMillis = fscIdleMinutes * 60 * 1000 - +abstract class SocketServer extends CompileOutputCommon { def shutdown: Boolean def session(): Unit + def timeout(): Unit = () // called after a timeout is detected for subclasses to cleanup + // a hook for subclasses + protected def createServerSocket(): ServerSocket = new ServerSocket(0) - var out: PrintWriter = _ var in: BufferedReader = _ - - def fatal(msg: String): Nothing = { - System.err.println(msg) - sys.exit(1) - } - - private def warn(msg: String) { - System.err.println(msg) + var out: PrintWriter = _ + val BufferSize = 10240 + lazy val serverSocket = createServerSocket() + lazy val port = serverSocket.getLocalPort() + + // Default to 30 minute idle timeout, settable with -max-idle + protected var idleMinutes = 30 + private var savedTimeout = 0 + private val acceptBox = new Socket.Box(() => { + // update the timeout if it has changed + if (savedTimeout != idleMinutes) { + savedTimeout = idleMinutes + setTimeoutOnSocket(savedTimeout) + } + new Socket(serverSocket.accept()) + }) + private def setTimeoutOnSocket(mins: Int) = { + try { + serverSocket setSoTimeout (mins * 60 * 1000) + info("Set socket timeout to " + mins + " minutes.") + true + } + catch { + case ex: SocketException => + warn("Failed to set socket timeout: " + ex) + false + } } - // called after a timeout is detected, - // for SocketServer subclasses to perform - // some cleanup, if any - def timeout() {} - - val serverSocket = - try new ServerSocket(0) - catch { case e: IOException => fatal("Could not listen on any port; exiting.") } - - val port: Int = serverSocket.getLocalPort() - - // @todo: this is going to be a prime candidate for ARM def doSession(clientSocket: Socket) = { - out = new PrintWriter(clientSocket.getOutputStream(), true) - in = bufferedReader(clientSocket) - val bufout = bufferedOutput(clientSocket) + clientSocket.applyReaderAndWriter { (in, out) => + this.in = in + this.out = out + val bufout = clientSocket.bufferedOutput(BufferSize) - try scala.Console.withOut(bufout)(session()) - finally { - bufout.close() - out.close() - in.close() + try scala.Console.withOut(bufout)(session()) + finally bufout.close() } } def run() { - def fail(s: String) = fatal(s format port) - Console.println("Setting timeout to " + fscIdleMillis) - try serverSocket setSoTimeout fscIdleMillis catch { - case e: SocketException => fatal("Could not set timeout on server socket; exiting.") - } - - try { - while (!shutdown) { - val clientSocket = try serverSocket.accept() catch { - case e: IOException => fail("Accept on port %d failed; exiting.") - } - try doSession(clientSocket) - finally clientSocket.close() + info("Starting SocketServer run() loop.") + + def loop() { + acceptBox.either match { + case Right(clientSocket) => + try doSession(clientSocket) + finally clientSocket.close() + case Left(_: SocketTimeoutException) => + warn("Idle timeout exceeded on port %d; exiting" format port) + timeout() + return + case _ => + warn("Accept on port %d failed") } + if (!shutdown) + loop() } - catch { - case e: SocketTimeoutException => - warn("Timeout elapsed with no requests from clients on port %d; exiting" format port) - timeout() - } + try loop() + catch { case ex: SocketException => fatal("Compile server caught fatal exception: " + ex) } finally serverSocket.close() } } diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala index 4e349cb423..d8a3514954 100644 --- a/src/library/scala/collection/Iterator.scala +++ b/src/library/scala/collection/Iterator.scala @@ -12,6 +12,7 @@ package scala.collection import mutable.ArrayBuffer import annotation.{ tailrec, migration } +import parallel.ParIterable /** The `Iterator` object provides various functions for * creating specialized iterators. @@ -250,7 +251,7 @@ import Iterator.empty * @define mayNotTerminateInf * Note: may not terminate for infinite iterators. */ -trait Iterator[+A] extends TraversableOnce[A] { +trait Iterator[+A] extends TraversableOnce[A] with Parallelizable[A, ParIterable[A]] { self => /** Tests whether this iterator can provide another element. @@ -275,6 +276,8 @@ trait Iterator[+A] extends TraversableOnce[A] { */ def isTraversableAgain = false + protected[this] def parCombiner = ParIterable.newCombiner[A] + /** Tests whether this Iterator has a known size. * * @return `true` for empty Iterators, `false` otherwise. diff --git a/src/library/scala/collection/MapLike.scala b/src/library/scala/collection/MapLike.scala index 6fb971d128..fd58540086 100644 --- a/src/library/scala/collection/MapLike.scala +++ b/src/library/scala/collection/MapLike.scala @@ -12,6 +12,7 @@ package scala.collection import generic._ import mutable.{ Builder, MapBuilder } import annotation.migration +import parallel.ParMap /** A template trait for maps, which associate keys with values. * @@ -56,7 +57,8 @@ import annotation.migration trait MapLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]] extends PartialFunction[A, B] with IterableLike[(A, B), This] - with Subtractable[A, This] { + with Subtractable[A, This] + with Parallelizable[(A, B), ParMap[A, B]] { self => /** The empty map of the same type as this map @@ -311,6 +313,8 @@ self => result } + protected[this] override def parCombiner = ParMap.newCombiner[A, B] + /** Appends all bindings of this map to a string builder using start, end, and separator strings. * The written text begins with the string `start` and ends with the string * `end`. Inside, the string representations of all bindings of this map diff --git a/src/library/scala/collection/Parallelizable.scala b/src/library/scala/collection/Parallelizable.scala index 999849fbab..207bb25cb6 100644 --- a/src/library/scala/collection/Parallelizable.scala +++ b/src/library/scala/collection/Parallelizable.scala @@ -1,8 +1,18 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + + package scala.collection import parallel.ParIterableLike +import parallel.Combiner @@ -10,19 +20,50 @@ import parallel.ParIterableLike * by invoking the method `par`. Parallelizable collections may be parametrized with * a target type different than their own. * + * @tparam A the type of the elements in the collection * @tparam ParRepr the actual type of the collection, which has to be parallel */ -trait Parallelizable[+ParRepr <: Parallel] { - - /** Returns a parallel implementation of a collection. +trait Parallelizable[+A, +ParRepr <: Parallel] { +self: TraversableOnce[A] => + + /** Returns a parallel implementation of this collection. + * + * For most collection types, this method creates a new parallel collection by copying + * all the elements. For these collection, `par` takes linear time. Mutable collections + * in this category do not produce a mutable parallel collection that has the same + * underlying dataset, so changes in one collection will not be reflected in the other one. + * + * Specific collections (e.g. `ParArray` or `mutable.ParHashMap`) override this default + * behaviour by creating a parallel collection which shares the same underlying dataset. + * For these collections, `par` takes constant or sublinear time. + * + * All parallel collections return a reference to themselves. + * + * @return a parallel implementation of this collection */ - def par: ParRepr + def par: ParRepr = { + val cb = parCombiner + for (x <- this) cb += x + cb.result + } + + /** The default `par` implementation uses the combiner provided by this method + * to create a new parallel collection. + * + * @return a combiner for the parallel collection of type `ParRepr` + */ + protected[this] def parCombiner: Combiner[A, ParRepr] } +trait CustomParallelizable[+A, +ParRepr <: Parallel] extends Parallelizable[A, ParRepr] { +self: TraversableOnce[A] => + override def par: ParRepr + protected override def parCombiner = throw new UnsupportedOperationException("") +} diff --git a/src/library/scala/collection/SeqLike.scala b/src/library/scala/collection/SeqLike.scala index 12e4c45c75..4936e652b2 100644 --- a/src/library/scala/collection/SeqLike.scala +++ b/src/library/scala/collection/SeqLike.scala @@ -13,6 +13,7 @@ package scala.collection import mutable.{ListBuffer, HashMap, ArraySeq} import immutable.{List, Range} import generic._ +import parallel.ParSeq /** The companion object for trait `SeqLike`. */ @@ -168,7 +169,7 @@ object SeqLike { * * Note: will not terminate for infinite-sized collections. */ -trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => +trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] with Parallelizable[A, ParSeq[A]] { self => override protected[this] def thisCollection: Seq[A] = this.asInstanceOf[Seq[A]] override protected[this] def toCollection(repr: Repr): Seq[A] = repr.asInstanceOf[Seq[A]] @@ -191,6 +192,8 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => */ def apply(idx: Int): A + protected[this] override def parCombiner = ParSeq.newCombiner[A] + /** Compares the length of this $coll to a test value. * * @param len the test value that gets compared with the length. diff --git a/src/library/scala/collection/SetLike.scala b/src/library/scala/collection/SetLike.scala index 73f0b9c839..7cbb8ee2ef 100644 --- a/src/library/scala/collection/SetLike.scala +++ b/src/library/scala/collection/SetLike.scala @@ -12,6 +12,7 @@ package scala.collection import generic._ import mutable.{ Builder, SetBuilder } import scala.annotation.migration +import parallel.ParSet /** A template trait for sets. * @@ -57,7 +58,8 @@ import scala.annotation.migration */ trait SetLike[A, +This <: SetLike[A, This] with Set[A]] extends IterableLike[A, This] - with Subtractable[A, This] { + with Subtractable[A, This] + with Parallelizable[A, ParSet[A]] { self => /** The empty set of the same type as this set @@ -72,6 +74,8 @@ self => */ override protected[this] def newBuilder: Builder[A, This] = new SetBuilder[A, This](empty) + protected[this] override def parCombiner = ParSet.newCombiner[A] + /** Overridden for efficiency. */ override def toSeq: Seq[A] = toBuffer[A] override def toBuffer[A1 >: A]: mutable.Buffer[A1] = { diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala index 9cf73142e6..70d5c37837 100644 --- a/src/library/scala/collection/TraversableLike.scala +++ b/src/library/scala/collection/TraversableLike.scala @@ -15,6 +15,7 @@ import mutable.{ Builder, ListBuffer } import annotation.tailrec import annotation.migration import annotation.unchecked.{ uncheckedVariance => uV } +import parallel.ParIterable /** A template trait for traversable collections of type `Traversable[A]`. @@ -90,7 +91,8 @@ import annotation.unchecked.{ uncheckedVariance => uV } */ trait TraversableLike[+A, +Repr] extends HasNewBuilder[A, Repr] with FilterMonadic[A, Repr] - with TraversableOnce[A] { + with TraversableOnce[A] + with Parallelizable[A, ParIterable[A]] { self => import Traversable.breaks._ @@ -119,6 +121,8 @@ trait TraversableLike[+A, +Repr] extends HasNewBuilder[A, Repr] */ protected[this] def newBuilder: Builder[A, Repr] + protected[this] def parCombiner = ParIterable.newCombiner[A] + /** Applies a function `f` to all elements of this $coll. * * Note: this method underlies the implementation of most other bulk operations. diff --git a/src/library/scala/collection/TraversableOnce.scala b/src/library/scala/collection/TraversableOnce.scala index 5b8abb3e5e..de3b4770f3 100644 --- a/src/library/scala/collection/TraversableOnce.scala +++ b/src/library/scala/collection/TraversableOnce.scala @@ -501,66 +501,6 @@ trait TraversableOnce[+A] { b.result } - /* The following 4 methods are implemented in a generic way here, - * but are specialized further down the hierarchy where possible. - * In particular: - * - * - all concrete sequential collection classes that can be - * parallelized have their corresponding `toPar*` methods - * overridden (e.g. ArrayBuffer overrides `toParIterable` - * and `toParSeq`) - * - ParIterableLike overrides all 4 methods - * - ParSeqLike again overrides `toParSeq` - * - ParSetLike again overrides `toParSet` - * - ParMapLike again overrides `toParMap` - * - immutable.ParIterable overrides all 4 methods to have immutable return types - * - immutable.ParSet overrides `toParSet` to `this` - * - immutable.ParSeq overrides nothing yet TODO vector - * - immutable.ParMap overrides `toParMap` to `this` - */ - - /** Converts this $coll to a parallel iterable. - * $willNotTerminateInf - * @return a parallel iterable containing all elements of this $coll. - */ - def toParIterable: parallel.ParIterable[A] = toParSeq - - /** Converts this $coll to a parallel sequence. - * $willNotTerminateInf - * @return a parallel sequence containing all elements of this $coll. - */ - def toParSeq: parallel.ParSeq[A] = { - val cb = parallel.mutable.ParArray.newCombiner[A] - for (elem <- this) cb += elem - cb.result - } - - /** Converts this $coll to a parallel set. - * $willNotTerminateInf - * @return a parallel set containing all elements of this $coll. - */ - def toParSet[B >: A]: parallel.ParSet[B] = { - val cb = parallel.mutable.ParHashSet.newCombiner[B] - for (elem <- this) cb += elem - cb.result - } - - /** Converts this $coll to a parallel map. - * $willNotTerminateInf - * - * This operation is only available on collections containing pairs of elements. - * - * @return a parallel map containing all elements of this $coll. - * @usecase def toParMap[T, U]: ParMap[T, U] - * @return a parallel map of type `parallel.ParMap[T, U]` - * containing all key/value pairs of type `(T, U)` of this $coll. - */ - def toParMap[T, U](implicit ev: A <:< (T, U)): parallel.ParMap[T, U] = { - val cb = parallel.mutable.ParHashMap.newCombiner[T, U] - for (elem <- this) cb += elem - cb.result - } - /** Displays all elements of this $coll in a string using start, end, and * separator strings. * diff --git a/src/library/scala/collection/immutable/HashMap.scala b/src/library/scala/collection/immutable/HashMap.scala index d44791c2eb..cf7b0d423a 100644 --- a/src/library/scala/collection/immutable/HashMap.scala +++ b/src/library/scala/collection/immutable/HashMap.scala @@ -33,7 +33,7 @@ import parallel.immutable.ParHashMap * @define willNotTerminateInf */ @SerialVersionUID(2L) -class HashMap[A, +B] extends Map[A,B] with MapLike[A, B, HashMap[A, B]] with Parallelizable[ParHashMap[A, B]] with Serializable { +class HashMap[A, +B] extends Map[A,B] with MapLike[A, B, HashMap[A, B]] with CustomParallelizable[(A, B), ParHashMap[A, B]] with Serializable { override def size: Int = 0 @@ -87,12 +87,8 @@ class HashMap[A, +B] extends Map[A,B] with MapLike[A, B, HashMap[A, B]] with Par protected def merge0[B1 >: B](that: HashMap[A, B1], level: Int, merger: Merger[B1]): HashMap[A, B1] = that - def par = ParHashMap.fromTrie(this) + override def par = ParHashMap.fromTrie(this) - override def toParIterable = par - - private type C = (A, B) - override def toParMap[D, E](implicit ev: C <:< (D, E)) = par.asInstanceOf[ParHashMap[D, E]] } /** $factoryInfo diff --git a/src/library/scala/collection/immutable/HashSet.scala b/src/library/scala/collection/immutable/HashSet.scala index 7d31f20e14..951f6d235e 100644 --- a/src/library/scala/collection/immutable/HashSet.scala +++ b/src/library/scala/collection/immutable/HashSet.scala @@ -32,13 +32,15 @@ import collection.parallel.immutable.ParHashSet class HashSet[A] extends Set[A] with GenericSetTemplate[A, HashSet] with SetLike[A, HashSet[A]] - with Parallelizable[ParHashSet[A]] + with CustomParallelizable[A, ParHashSet[A]] with Serializable { override def companion: GenericCompanion[HashSet] = HashSet //class HashSet[A] extends Set[A] with SetLike[A, HashSet[A]] { + override def par = ParHashSet.fromTrie(this) + override def size: Int = 0 override def empty = HashSet.empty[A] @@ -58,8 +60,6 @@ class HashSet[A] extends Set[A] def - (e: A): HashSet[A] = removed0(e, computeHash(e), 0) - def par = ParHashSet.fromTrie(this) - protected def elemHashCode(key: A) = key.## protected final def improve(hcode: Int) = { @@ -79,8 +79,7 @@ class HashSet[A] extends Set[A] protected def removed0(key: A, hash: Int, level: Int): HashSet[A] = this protected def writeReplace(): AnyRef = new HashSet.SerializationProxy(this) - override def toParIterable = par - override def toParSet[B >: A] = par.asInstanceOf[ParHashSet[B]] + } /** $factoryInfo diff --git a/src/library/scala/collection/immutable/Iterable.scala b/src/library/scala/collection/immutable/Iterable.scala index 51227556ad..7f5cb055f4 100644 --- a/src/library/scala/collection/immutable/Iterable.scala +++ b/src/library/scala/collection/immutable/Iterable.scala @@ -13,6 +13,7 @@ package immutable import generic._ import mutable.Builder +import parallel.immutable.ParIterable /** A base trait for iterable collections that are guaranteed immutable. * $iterableInfo @@ -23,8 +24,10 @@ import mutable.Builder trait Iterable[+A] extends Traversable[A] with scala.collection.Iterable[A] with GenericTraversableTemplate[A, Iterable] - with IterableLike[A, Iterable[A]] { + with IterableLike[A, Iterable[A]] + with Parallelizable[A, ParIterable[A]] { override def companion: GenericCompanion[Iterable] = Iterable + protected[this] override def parCombiner = ParIterable.newCombiner[A] // if `immutable.IterableLike` gets introduced, please move this there! } /** $factoryInfo diff --git a/src/library/scala/collection/immutable/MapLike.scala b/src/library/scala/collection/immutable/MapLike.scala index a0f1632d1e..13054b9f83 100644 --- a/src/library/scala/collection/immutable/MapLike.scala +++ b/src/library/scala/collection/immutable/MapLike.scala @@ -10,6 +10,7 @@ package scala.collection package immutable import generic._ +import parallel.immutable.ParMap /** * A generic template for immutable maps from keys of type `A` @@ -46,8 +47,11 @@ import generic._ */ trait MapLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]] extends scala.collection.MapLike[A, B, This] + with Parallelizable[(A, B), ParMap[A, B]] { self => + protected[this] override def parCombiner = ParMap.newCombiner[A, B] + /** A new immutable map containing updating this map with a given key/value mapping. * @param key the key * @param value the value diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala index f8b3dfa54f..90a1383353 100644 --- a/src/library/scala/collection/immutable/Range.scala +++ b/src/library/scala/collection/immutable/Range.scala @@ -41,10 +41,10 @@ import scala.collection.parallel.immutable.ParRange @SerialVersionUID(7618862778670199309L) class Range(val start: Int, val end: Int, val step: Int) extends IndexedSeq[Int] - with collection.Parallelizable[ParRange] + with collection.CustomParallelizable[Int, ParRange] with Serializable { - def par = new ParRange(this) + override def par = new ParRange(this) // Note that this value is calculated eagerly intentionally: it also // serves to enforce conditions (step != 0) && (length <= Int.MaxValue) @@ -205,11 +205,9 @@ extends IndexedSeq[Int] final def contains(x: Int) = isWithinBoundaries(x) && ((x - start) % step == 0) - override def toParIterable = par + override def toIterable = this - override def toParSeq = par - - override def toParSet[U >: Int] = par.toParSet[U] + override def toSeq = this override def equals(other: Any) = other match { case x: Range => diff --git a/src/library/scala/collection/immutable/Seq.scala b/src/library/scala/collection/immutable/Seq.scala index c3c34d3f89..4f061983de 100644 --- a/src/library/scala/collection/immutable/Seq.scala +++ b/src/library/scala/collection/immutable/Seq.scala @@ -13,6 +13,7 @@ package immutable import generic._ import mutable.Builder +import parallel.immutable.ParSeq /** A subtrait of `collection.Seq` which represents sequences * that are guaranteed immutable. @@ -24,9 +25,11 @@ import mutable.Builder trait Seq[+A] extends Iterable[A] with scala.collection.Seq[A] with GenericTraversableTemplate[A, Seq] - with SeqLike[A, Seq[A]] { + with SeqLike[A, Seq[A]] + with Parallelizable[A, ParSeq[A]] { override def companion: GenericCompanion[Seq] = Seq override def toSeq: Seq[A] = this + protected[this] override def parCombiner = ParSeq.newCombiner[A] // if `immutable.SeqLike` gets introduced, please move this there! } /** $factoryInfo diff --git a/src/library/scala/collection/immutable/Set.scala b/src/library/scala/collection/immutable/Set.scala index e2bad2f052..1b61c6f565 100644 --- a/src/library/scala/collection/immutable/Set.scala +++ b/src/library/scala/collection/immutable/Set.scala @@ -12,6 +12,7 @@ package scala.collection package immutable import generic._ +import parallel.immutable.ParSet /** A generic trait for immutable sets. * @@ -27,9 +28,11 @@ import generic._ trait Set[A] extends Iterable[A] with scala.collection.Set[A] with GenericSetTemplate[A, Set] - with SetLike[A, Set[A]] { + with SetLike[A, Set[A]] + with Parallelizable[A, ParSet[A]] { override def companion: GenericCompanion[Set] = Set override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]] + protected override def parCombiner = ParSet.newCombiner[A] // if `immutable.SetLike` gets introduced, please move this there! } /** $factoryInfo diff --git a/src/library/scala/collection/immutable/Vector.scala b/src/library/scala/collection/immutable/Vector.scala index 92a6160213..3078a26411 100644 --- a/src/library/scala/collection/immutable/Vector.scala +++ b/src/library/scala/collection/immutable/Vector.scala @@ -39,7 +39,7 @@ extends IndexedSeq[A] with IndexedSeqLike[A, Vector[A]] with VectorPointer[A @uncheckedVariance] with Serializable - with Parallelizable[ParVector[A]] + with CustomParallelizable[A, ParVector[A]] { self => override def companion: GenericCompanion[Vector] = Vector @@ -53,7 +53,7 @@ override def companion: GenericCompanion[Vector] = Vector def length = endIndex - startIndex - def par = new ParVector(this) + override def par = new ParVector(this) override def lengthCompare(len: Int): Int = length - len diff --git a/src/library/scala/collection/interfaces/TraversableOnceMethods.scala b/src/library/scala/collection/interfaces/TraversableOnceMethods.scala index 8967e15a34..5e1325fef6 100644 --- a/src/library/scala/collection/interfaces/TraversableOnceMethods.scala +++ b/src/library/scala/collection/interfaces/TraversableOnceMethods.scala @@ -53,10 +53,6 @@ trait TraversableOnceMethods[+A] { def toIterator: Iterator[A] def toList: List[A] def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] - def toParIterable: parallel.ParIterable[A] - def toParMap[T, U](implicit ev: A <:< (T, U)): parallel.ParMap[T, U] - def toParSeq: parallel.ParSeq[A] - def toParSet[B >: A]: parallel.ParSet[B] def toSeq: Seq[A] def toSet[B >: A]: immutable.Set[B] def toStream: Stream[A] diff --git a/src/library/scala/collection/mutable/ArrayBuffer.scala b/src/library/scala/collection/mutable/ArrayBuffer.scala index 9d07294f51..daa3c48578 100644 --- a/src/library/scala/collection/mutable/ArrayBuffer.scala +++ b/src/library/scala/collection/mutable/ArrayBuffer.scala @@ -48,7 +48,7 @@ class ArrayBuffer[A](override protected val initialSize: Int) with IndexedSeqOptimized[A, ArrayBuffer[A]] with Builder[A, ArrayBuffer[A]] with ResizableArray[A] - with Parallelizable[ParArray[A]] + with CustomParallelizable[A, ParArray[A]] with Serializable { override def companion: GenericCompanion[ArrayBuffer] = ArrayBuffer @@ -67,7 +67,7 @@ class ArrayBuffer[A](override protected val initialSize: Int) } } - def par = ParArray.handoff[A](array.asInstanceOf[Array[A]], size) + override def par = ParArray.handoff[A](array.asInstanceOf[Array[A]], size) /** Appends a single element to this buffer and returns * the identity of the buffer. It takes constant amortized time. @@ -177,10 +177,6 @@ class ArrayBuffer[A](override protected val initialSize: Int) */ override def stringPrefix: String = "ArrayBuffer" - override def toParIterable = par - - override def toParSeq = par - } /** Factory object for the `ArrayBuffer` class. diff --git a/src/library/scala/collection/mutable/ArrayOps.scala b/src/library/scala/collection/mutable/ArrayOps.scala index 3cf1795e80..b72206e6f3 100644 --- a/src/library/scala/collection/mutable/ArrayOps.scala +++ b/src/library/scala/collection/mutable/ArrayOps.scala @@ -35,7 +35,7 @@ import parallel.mutable.ParArray * @define mayNotTerminateInf * @define willNotTerminateInf */ -abstract class ArrayOps[T] extends ArrayLike[T, Array[T]] with Parallelizable[ParArray[T]] { +abstract class ArrayOps[T] extends ArrayLike[T, Array[T]] with CustomParallelizable[T, ParArray[T]] { private def rowBuilder[U]: Builder[U, Array[U]] = Array.newBuilder( @@ -55,7 +55,7 @@ abstract class ArrayOps[T] extends ArrayLike[T, Array[T]] with Parallelizable[Pa else super.toArray[U] - def par = ParArray.handoff(repr) + override def par = ParArray.handoff(repr) /** Flattens a two-dimensional array by concatenating all its rows * into a single array. diff --git a/src/library/scala/collection/mutable/ArraySeq.scala b/src/library/scala/collection/mutable/ArraySeq.scala index cd53a24680..0b3f0ebc5b 100644 --- a/src/library/scala/collection/mutable/ArraySeq.scala +++ b/src/library/scala/collection/mutable/ArraySeq.scala @@ -44,7 +44,7 @@ class ArraySeq[A](override val length: Int) extends IndexedSeq[A] with GenericTraversableTemplate[A, ArraySeq] with IndexedSeqOptimized[A, ArraySeq[A]] - with Parallelizable[ParArray[A]] + with CustomParallelizable[A, ParArray[A]] with Serializable { @@ -52,7 +52,7 @@ extends IndexedSeq[A] val array: Array[AnyRef] = new Array[AnyRef](length) - def par = ParArray.handoff(array.asInstanceOf[Array[A]]) + override def par = ParArray.handoff(array.asInstanceOf[Array[A]]) def apply(idx: Int): A = { if (idx >= length) throw new IndexOutOfBoundsException(idx.toString) @@ -86,10 +86,6 @@ extends IndexedSeq[A] Array.copy(array, 0, xs, start, len1) } - override def toParIterable = par - - override def toParSeq = par - } /** $factoryInfo diff --git a/src/library/scala/collection/mutable/HashMap.scala b/src/library/scala/collection/mutable/HashMap.scala index 890a6cbf24..e78e9a1296 100644 --- a/src/library/scala/collection/mutable/HashMap.scala +++ b/src/library/scala/collection/mutable/HashMap.scala @@ -44,7 +44,7 @@ class HashMap[A, B] private[collection] (contents: HashTable.Contents[A, Default extends Map[A, B] with MapLike[A, B, HashMap[A, B]] with HashTable[A, DefaultEntry[A, B]] - with Parallelizable[ParHashMap[A, B]] + with CustomParallelizable[(A, B), ParHashMap[A, B]] with Serializable { initWithContents(contents) @@ -57,7 +57,7 @@ extends Map[A, B] def this() = this(null) - def par = new ParHashMap[A, B](hashTableContents) + override def par = new ParHashMap[A, B](hashTableContents) def get(key: A): Option[B] = { val e = findEntry(key) @@ -130,11 +130,6 @@ extends Map[A, B] init[B](in, new Entry(_, _)) } - override def toParIterable = par - - private type C = (A, B) - override def toParMap[D, E](implicit ev: C <:< (D, E)) = par.asInstanceOf[ParHashMap[D, E]] - } /** $factoryInfo diff --git a/src/library/scala/collection/mutable/HashSet.scala b/src/library/scala/collection/mutable/HashSet.scala index a1b85fa16e..2ba5065964 100644 --- a/src/library/scala/collection/mutable/HashSet.scala +++ b/src/library/scala/collection/mutable/HashSet.scala @@ -44,7 +44,7 @@ extends Set[A] with GenericSetTemplate[A, HashSet] with SetLike[A, HashSet[A]] with FlatHashTable[A] - with Parallelizable[ParHashSet[A]] + with CustomParallelizable[A, ParHashSet[A]] with Serializable { initWithContents(contents) @@ -60,7 +60,7 @@ extends Set[A] def += (elem: A): this.type = { addEntry(elem); this } def -= (elem: A): this.type = { removeEntry(elem); this } - def par = new ParHashSet(hashTableContents) + override def par = new ParHashSet(hashTableContents) override def add(elem: A): Boolean = addEntry(elem) override def remove(elem: A): Boolean = removeEntry(elem).isDefined @@ -93,10 +93,6 @@ extends Set[A] if (!isSizeMapDefined) sizeMapInitAndRebuild } else sizeMapDisable - override def toParIterable = par - - override def toParSet[B >: A] = par.asInstanceOf[ParHashSet[B]] - } /** $factoryInfo diff --git a/src/library/scala/collection/mutable/Iterable.scala b/src/library/scala/collection/mutable/Iterable.scala index ddf917ba82..8e244d980d 100644 --- a/src/library/scala/collection/mutable/Iterable.scala +++ b/src/library/scala/collection/mutable/Iterable.scala @@ -9,6 +9,7 @@ package scala.collection package mutable import generic._ +import parallel.mutable.ParIterable /** A base trait for iterable collections that can be mutated. * $iterableInfo @@ -16,8 +17,10 @@ import generic._ trait Iterable[A] extends Traversable[A] with scala.collection.Iterable[A] with GenericTraversableTemplate[A, Iterable] - with IterableLike[A, Iterable[A]] { + with IterableLike[A, Iterable[A]] + with Parallelizable[A, ParIterable[A]] { override def companion: GenericCompanion[Iterable] = Iterable + protected[this] override def parCombiner = ParIterable.newCombiner[A] // if `mutable.IterableLike` gets introduced, please move this there! } /** $factoryInfo diff --git a/src/library/scala/collection/mutable/MapLike.scala b/src/library/scala/collection/mutable/MapLike.scala index 1708d25234..04ba8608b9 100644 --- a/src/library/scala/collection/mutable/MapLike.scala +++ b/src/library/scala/collection/mutable/MapLike.scala @@ -13,6 +13,7 @@ package mutable import generic._ import annotation.migration +import parallel.mutable.ParMap /** A template trait for mutable maps. * $mapNote @@ -25,6 +26,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] with Growable[(A, B)] with Shrinkable[A] with Cloneable[This] + with Parallelizable[(A, B), ParMap[A, B]] { self => import scala.collection.Traversable @@ -36,6 +38,8 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] */ override protected[this] def newBuilder: Builder[(A, B), This] = empty + protected[this] override def parCombiner = ParMap.newCombiner[A, B] + /** Adds a new key/value pair to this map and optionally returns previously bound value. * If the map already contains a * mapping for the key, it will be overridden by the new value. diff --git a/src/library/scala/collection/mutable/SeqLike.scala b/src/library/scala/collection/mutable/SeqLike.scala index 910dd1aab9..4d315b8256 100644 --- a/src/library/scala/collection/mutable/SeqLike.scala +++ b/src/library/scala/collection/mutable/SeqLike.scala @@ -10,6 +10,7 @@ package scala.collection package mutable import generic._ +import parallel.mutable.ParSeq /** A template trait for mutable sequences of type `mutable.Seq[A]`. * @tparam A the type of the elements of the set @@ -18,9 +19,12 @@ import generic._ */ trait SeqLike[A, +This <: SeqLike[A, This] with Seq[A]] extends scala.collection.SeqLike[A, This] - with Cloneable[This] { + with Cloneable[This] + with Parallelizable[A, ParSeq[A]] { self => + protected[this] override def parCombiner = ParSeq.newCombiner[A] + /** Replaces element at given index with a new value. * * @param n the index of the element to replace. diff --git a/src/library/scala/collection/mutable/SetLike.scala b/src/library/scala/collection/mutable/SetLike.scala index c85349fc1a..985e7a3b47 100644 --- a/src/library/scala/collection/mutable/SetLike.scala +++ b/src/library/scala/collection/mutable/SetLike.scala @@ -14,6 +14,7 @@ package mutable import generic._ import script._ import scala.annotation.migration +import parallel.mutable.ParSet /** A template trait for mutable sets of type `mutable.Set[A]`. * @tparam A the type of the elements of the set @@ -60,6 +61,7 @@ trait SetLike[A, +This <: SetLike[A, This] with Set[A]] with Growable[A] with Shrinkable[A] with Cloneable[mutable.Set[A]] + with Parallelizable[A, ParSet[A]] { self => /** A common implementation of `newBuilder` for all mutable sets @@ -68,6 +70,8 @@ trait SetLike[A, +This <: SetLike[A, This] with Set[A]] */ override protected[this] def newBuilder: Builder[A, This] = empty + protected[this] override def parCombiner = ParSet.newCombiner[A] + /** Adds an element to this $coll. * * @param elem the element to be added diff --git a/src/library/scala/collection/mutable/WrappedArray.scala b/src/library/scala/collection/mutable/WrappedArray.scala index 319053d488..21e62306e7 100644 --- a/src/library/scala/collection/mutable/WrappedArray.scala +++ b/src/library/scala/collection/mutable/WrappedArray.scala @@ -33,7 +33,7 @@ import scala.collection.parallel.mutable.ParArray abstract class WrappedArray[T] extends IndexedSeq[T] with ArrayLike[T, WrappedArray[T]] - with Parallelizable[ParArray[T]] + with CustomParallelizable[T, ParArray[T]] { override protected[this] def thisCollection: WrappedArray[T] = this @@ -54,7 +54,7 @@ extends IndexedSeq[T] /** The underlying array */ def array: Array[T] - def par = ParArray.handoff(array) + override def par = ParArray.handoff(array) override def toArray[U >: T : ClassManifest]: Array[U] = if (implicitly[ClassManifest[U]].erasure eq array.getClass.getComponentType) @@ -72,10 +72,6 @@ extends IndexedSeq[T] override protected[this] def newBuilder: Builder[T, WrappedArray[T]] = new WrappedArrayBuilder[T](elemManifest) - override def toParIterable = par - - override def toParSeq = par - } /** A companion object used to create instances of `WrappedArray`. diff --git a/src/library/scala/collection/parallel/ParIterableLike.scala b/src/library/scala/collection/parallel/ParIterableLike.scala index a92c4f15fb..6b7f244867 100644 --- a/src/library/scala/collection/parallel/ParIterableLike.scala +++ b/src/library/scala/collection/parallel/ParIterableLike.scala @@ -16,7 +16,7 @@ import scala.collection.mutable.Builder import scala.collection.mutable.ArrayBuffer import scala.collection.IterableLike import scala.collection.Parallel -import scala.collection.Parallelizable +import scala.collection.CustomParallelizable import scala.collection.Sequentializable import scala.collection.generic._ import immutable.HashMapCombiner @@ -82,10 +82,15 @@ import annotation.unchecked.uncheckedVariance * def par: Repr * }}} * - * produce a view of the collection that has sequential or parallel operations, respectively. - * These methods are efficient - they will not copy the elements, but have fixed target - * types. The combination of methods `toParMap`, `toParSeq` or `toParSet` is more flexible, - * but may copy the elements in some cases. + * produce the sequential or parallel implementation of the collection, respectively. + * Method `par` just returns a reference to this parallel collection. + * Method `seq` is efficient - it will not copy the elements. Instead, + * it will create a sequential version of the collection using the same underlying data structure. + * Note that this is not the case for sequential collections in general - they may copy the elements + * and produce a different underlying data structure. + * + * The combination of methods `toMap`, `toSeq` or `toSet` along with `par` and `seq` is a flexible + * way to change between different collection types. * * The method: * @@ -152,9 +157,9 @@ import annotation.unchecked.uncheckedVariance * that splitters may set and read the `indexFlag` state. * */ -trait ParIterableLike[+T, +Repr <: Parallel, +Sequential <: Iterable[T] with IterableLike[T, Sequential]] +trait ParIterableLike[+T, +Repr <: ParIterable[T], +Sequential <: Iterable[T] with IterableLike[T, Sequential]] extends IterableLike[T, Repr] - with Parallelizable[Repr] + with CustomParallelizable[T, Repr] with Sequentializable[T, Sequential] with Parallel with HasNewCombiner[T, Repr] @@ -215,7 +220,7 @@ self => */ def iterator: Splitter[T] = parallelIterator - def par = repr + override def par = repr /** Denotes whether this parallel collection has strict splitters. * @@ -730,8 +735,6 @@ self => def parallelIterator = self.parallelIterator } - override def toIterable: Iterable[T] = seq.drop(0).asInstanceOf[Iterable[T]] - override def toArray[U >: T: ClassManifest]: Array[U] = { val arr = new Array[U](size) copyToArray(arr) @@ -744,25 +747,21 @@ self => override def toStream: Stream[T] = seq.toStream - override def toSet[U >: T]: collection.immutable.Set[U] = seq.toSet - - override def toSeq: Seq[T] = seq.toSeq - - override def toIterator: Iterator[T] = seq.toIterator + override def toIterator: Iterator[T] = parallelIterator - override def toTraversable: Traversable[T] = seq.toTraversable + // the methods below are overridden - override def toBuffer[U >: T]: collection.mutable.Buffer[U] = seq.toBuffer + override def toBuffer[U >: T]: collection.mutable.Buffer[U] = seq.toBuffer // have additional, parallel buffers? - override def toMap[K, V](implicit ev: T <:< (K, V)): collection.immutable.Map[K, V] = seq.toMap + override def toTraversable: Traversable[T] = this.asInstanceOf[Traversable[T]] // TODO add ParTraversable[T] - override def toParIterable: ParIterable[T] = this.asInstanceOf[ParIterable[T]] + override def toIterable: ParIterable[T] = this.asInstanceOf[ParIterable[T]] - override def toParSeq: ParSeq[T] = toParCollection[T, ParSeq[T]](() => mutable.ParArrayCombiner[T]()) + override def toSeq: ParSeq[T] = toParCollection[T, ParSeq[T]](() => ParSeq.newCombiner[T]) - override def toParSet[U >: T]: ParSet[U] = toParCollection[U, ParSet[U]](() => mutable.ParHashSetCombiner[U]) + override def toSet[U >: T]: immutable.ParSet[U] = toParCollection[U, immutable.ParSet[U]](() => immutable.ParSet.newCombiner[U]) - override def toParMap[K, V](implicit ev: T <:< (K, V)): ParMap[K, V] = toParMap[K, V, mutable.ParHashMap[K, V]](() => mutable.ParHashMapCombiner[K, V]) + override def toMap[K, V](implicit ev: T <:< (K, V)): immutable.ParMap[K, V] = toParMap[K, V, immutable.ParMap[K, V]](() => immutable.ParMap.newCombiner[K, V]) /* tasks */ diff --git a/src/library/scala/collection/parallel/ParMapLike.scala b/src/library/scala/collection/parallel/ParMapLike.scala index e8f076dc4f..1cd5ad02d7 100644 --- a/src/library/scala/collection/parallel/ParMapLike.scala +++ b/src/library/scala/collection/parallel/ParMapLike.scala @@ -48,9 +48,7 @@ extends MapLike[K, V, Repr] override def empty: Repr - private type T = (K, V) - override def toParMap[K, V](implicit ev: T <:< (K, V)) = this.asInstanceOf[ParMap[K, V]] - + // note - should not override toMap (could be mutable) } diff --git a/src/library/scala/collection/parallel/ParSeqLike.scala b/src/library/scala/collection/parallel/ParSeqLike.scala index d40ced0cd8..1e49f69753 100644 --- a/src/library/scala/collection/parallel/ParSeqLike.scala +++ b/src/library/scala/collection/parallel/ParSeqLike.scala @@ -45,7 +45,7 @@ import scala.collection.generic.VolatileAbort * @author Aleksandar Prokopec * @since 2.9 */ -trait ParSeqLike[+T, +Repr <: Parallel, +Sequential <: Seq[T] with SeqLike[T, Sequential]] +trait ParSeqLike[+T, +Repr <: ParSeq[T], +Sequential <: Seq[T] with SeqLike[T, Sequential]] extends scala.collection.SeqLike[T, Repr] with ParIterableLike[T, Repr, Sequential] { self => @@ -314,7 +314,7 @@ self => override def toString = seq.mkString(stringPrefix + "(", ", ", ")") - override def toParSeq = this.asInstanceOf[ParSeq[T]] // TODO add a type bound for `Repr` + override def toSeq = this.asInstanceOf[ParSeq[T]] override def view = new ParSeqView[T, Repr, Sequential] { protected lazy val underlying = self.repr diff --git a/src/library/scala/collection/parallel/ParSetLike.scala b/src/library/scala/collection/parallel/ParSetLike.scala index d888d5865f..9e769f425b 100644 --- a/src/library/scala/collection/parallel/ParSetLike.scala +++ b/src/library/scala/collection/parallel/ParSetLike.scala @@ -45,8 +45,7 @@ extends SetLike[T, Repr] override def empty: Repr - override def toParSet[U >: T] = this.asInstanceOf[ParSet[U]] - + // note: should not override toSet (could be mutable) } diff --git a/src/library/scala/collection/parallel/immutable/ParIterable.scala b/src/library/scala/collection/parallel/immutable/ParIterable.scala index 0118452cb8..c4da1ced8e 100644 --- a/src/library/scala/collection/parallel/immutable/ParIterable.scala +++ b/src/library/scala/collection/parallel/immutable/ParIterable.scala @@ -36,16 +36,14 @@ extends collection.immutable.Iterable[T] { override def companion: GenericCompanion[ParIterable] with GenericParCompanion[ParIterable] = ParIterable - override def toParIterable: ParIterable[T] = this + // if `immutable.ParIterableLike` is introduced, please move these 4 methods there + override def toIterable: ParIterable[T] = this - // override def toParSeq: ParSeq TODO vector - - override def toParSet[U >: T]: ParSet[U] = toParCollection[U, ParHashSet[U]](() => HashSetCombiner[U]) - - override def toParMap[K, V](implicit ev: T <:< (K, V)): ParMap[K, V] = toParMap(() => HashMapCombiner[K, V]) + override def toSeq: ParSeq[T] = toParCollection[T, ParSeq[T]](() => ParSeq.newCombiner[T]) } + /** $factoryinfo */ object ParIterable extends ParFactory[ParIterable] { diff --git a/src/library/scala/collection/parallel/immutable/ParMap.scala b/src/library/scala/collection/parallel/immutable/ParMap.scala index d99091c57c..5db07a6a3b 100644 --- a/src/library/scala/collection/parallel/immutable/ParMap.scala +++ b/src/library/scala/collection/parallel/immutable/ParMap.scala @@ -50,7 +50,7 @@ self => override def stringPrefix = "ParMap" - override def toParMap[P, Q](implicit ev: (K, V) <:< (P, Q)): ParMap[P, Q] = this.asInstanceOf[ParMap[P, Q]] + override def toMap[P, Q](implicit ev: (K, V) <:< (P, Q)): ParMap[P, Q] = this.asInstanceOf[ParMap[P, Q]] } diff --git a/src/library/scala/collection/parallel/immutable/ParNumericRange.scala.disabled b/src/library/scala/collection/parallel/immutable/ParNumericRange.scala.disabled index a32d7bb086..fb411ec0ac 100644 --- a/src/library/scala/collection/parallel/immutable/ParNumericRange.scala.disabled +++ b/src/library/scala/collection/parallel/immutable/ParNumericRange.scala.disabled @@ -49,10 +49,6 @@ self => type SCPI = SignalContextPassingIterator[ParNumericRangeIterator] - override def toParSeq = this - - override def toParSet[U >: T] = toParCollection[U, ParSet[U]](() => HashSetCombiner[U]) - class ParNumericRangeIterator(range: NumericRange[T] = self.range, num: Integral[T] = self.num) extends ParIterator { me: SignalContextPassingIterator[ParNumericRangeIterator] => diff --git a/src/library/scala/collection/parallel/immutable/ParRange.scala b/src/library/scala/collection/parallel/immutable/ParRange.scala index 19d2a6d3b8..f68c7c9062 100644 --- a/src/library/scala/collection/parallel/immutable/ParRange.scala +++ b/src/library/scala/collection/parallel/immutable/ParRange.scala @@ -49,10 +49,6 @@ self => type SCPI = SignalContextPassingIterator[ParRangeIterator] - override def toParSeq = this - - override def toParSet[U >: Int] = toParCollection[U, ParSet[U]](() => HashSetCombiner[U]) - class ParRangeIterator(range: Range = self.range) extends ParIterator { me: SignalContextPassingIterator[ParRangeIterator] => diff --git a/src/library/scala/collection/parallel/immutable/ParSet.scala b/src/library/scala/collection/parallel/immutable/ParSet.scala index 2002d6432d..73d27df994 100644 --- a/src/library/scala/collection/parallel/immutable/ParSet.scala +++ b/src/library/scala/collection/parallel/immutable/ParSet.scala @@ -42,8 +42,8 @@ self => override def stringPrefix = "ParSet" - override def toParSet[U >: T] = this.asInstanceOf[ParSet[U]] - + // ok, because this could only violate `apply` and we can live with that + override def toSet[U >: T]: ParSet[U] = this.asInstanceOf[ParSet[U]] } diff --git a/src/library/scala/collection/parallel/mutable/ParIterable.scala b/src/library/scala/collection/parallel/mutable/ParIterable.scala index eba4ff2e72..fcba75452f 100644 --- a/src/library/scala/collection/parallel/mutable/ParIterable.scala +++ b/src/library/scala/collection/parallel/mutable/ParIterable.scala @@ -32,6 +32,11 @@ trait ParIterable[T] extends collection.mutable.Iterable[T] with GenericParTemplate[T, ParIterable] with ParIterableLike[T, ParIterable[T], Iterable[T]] { override def companion: GenericCompanion[ParIterable] with GenericParCompanion[ParIterable] = ParIterable + + // if `mutable.ParIterableLike` is introduced, please move these 4 methods there + override def toIterable: ParIterable[T] = this + + override def toSeq: ParSeq[T] = toParCollection[T, ParSeq[T]](() => ParSeq.newCombiner[T]) } /** $factoryinfo diff --git a/src/library/scala/collection/parallel/mutable/ParMapLike.scala b/src/library/scala/collection/parallel/mutable/ParMapLike.scala index cd2bea1419..46352829aa 100644 --- a/src/library/scala/collection/parallel/mutable/ParMapLike.scala +++ b/src/library/scala/collection/parallel/mutable/ParMapLike.scala @@ -33,5 +33,9 @@ trait ParMapLike[K, +Repr <: ParMapLike[K, V, Repr, Sequential] with ParMap[K, V], +Sequential <: collection.mutable.Map[K, V] with collection.mutable.MapLike[K, V, Sequential]] extends collection.mutable.MapLike[K, V, Repr] - with collection.parallel.ParMapLike[K, V, Repr, Sequential] + with collection.parallel.ParMapLike[K, V, Repr, Sequential] { + + // note: should not override toMap + +} diff --git a/src/library/scala/collection/parallel/mutable/ParSeq.scala b/src/library/scala/collection/parallel/mutable/ParSeq.scala index 10d3033701..1b2b9f9854 100644 --- a/src/library/scala/collection/parallel/mutable/ParSeq.scala +++ b/src/library/scala/collection/parallel/mutable/ParSeq.scala @@ -39,6 +39,8 @@ trait ParSeq[T] extends collection.mutable.Seq[T] def update(i: Int, elem: T): Unit + override def toSeq: ParSeq[T] = this + } diff --git a/src/library/scala/collection/parallel/mutable/ParSetLike.scala b/src/library/scala/collection/parallel/mutable/ParSetLike.scala index df87eff42c..68f142cda7 100644 --- a/src/library/scala/collection/parallel/mutable/ParSetLike.scala +++ b/src/library/scala/collection/parallel/mutable/ParSetLike.scala @@ -46,6 +46,7 @@ extends mutable.SetLike[T, Repr] override def empty: Repr + // note: should not override toSet } diff --git a/src/library/scala/sys/BooleanProp.scala b/src/library/scala/sys/BooleanProp.scala index e598d81307..85719103de 100644 --- a/src/library/scala/sys/BooleanProp.scala +++ b/src/library/scala/sys/BooleanProp.scala @@ -31,7 +31,11 @@ trait BooleanProp extends Prop[Boolean] { object BooleanProp { private[sys] class BooleanPropImpl(key: String, valueFn: String => Boolean) extends PropImpl(key, valueFn) with BooleanProp { - def enable() = this set "true" + override def setValue[T1 >: Boolean](newValue: T1): Boolean = newValue match { + case x: Boolean if !x => val old = value ; clear() ; old + case x => super.setValue(newValue) + } + def enable() = this setValue true def disable() = this.clear() def toggle() = if (value) disable() else enable() } @@ -39,6 +43,7 @@ object BooleanProp { class ConstantImpl(val key: String, val value: Boolean) extends BooleanProp { val isSet = value def set(newValue: String) = "" + value + def setValue[T1 >: Boolean](newValue: T1): Boolean = value def get: String = "" + value val clear, enable, disable, toggle = () protected def zero = false diff --git a/src/library/scala/sys/Prop.scala b/src/library/scala/sys/Prop.scala index e3cbd4e515..de38a56c73 100644 --- a/src/library/scala/sys/Prop.scala +++ b/src/library/scala/sys/Prop.scala @@ -43,6 +43,10 @@ trait Prop[+T] { */ def set(newValue: String): String + /** Sets the property with a value of the represented type. + */ + def setValue[T1 >: T](value: T1): T + /** Gets the current string value if any. Will not return null: use * `isSet` to test for existence. * @return the current string value if any, else the empty string diff --git a/src/library/scala/sys/PropImpl.scala b/src/library/scala/sys/PropImpl.scala index 55073c35d3..888e9d7327 100644 --- a/src/library/scala/sys/PropImpl.scala +++ b/src/library/scala/sys/PropImpl.scala @@ -20,6 +20,12 @@ private[sys] class PropImpl[+T](val key: String, valueFn: String => T) extends P underlying(key) = newValue old } + def setValue[T1 >: T](newValue: T1): T = { + val old = value + if (newValue == null) set(null) + else set("" + newValue) + old + } def get: String = if (isSet) underlying.getOrElse(key, "") else "" diff --git a/src/library/scala/sys/SystemProperties.scala b/src/library/scala/sys/SystemProperties.scala index 7c6286516b..228ca6315e 100644 --- a/src/library/scala/sys/SystemProperties.scala +++ b/src/library/scala/sys/SystemProperties.scala @@ -48,9 +48,14 @@ class SystemProperties extends mutable.Map[String, String] { * }}} */ object SystemProperties { + /** An unenforceable, advisory only place to do some synchronization when + * mutating system properties. + */ + def exclusively[T](body: => T) = this synchronized body + implicit def systemPropertiesToCompanion(p: SystemProperties): SystemProperties.type = this private lazy val propertyHelp = mutable.Map[String, String]() - private def bool(key: String, helpText: String) = { + private def bool(key: String, helpText: String): BooleanProp = { val prop = ( if (key startsWith "java.") BooleanProp.valueIsTrue(key) else BooleanProp.keyExists(key) @@ -63,8 +68,9 @@ object SystemProperties { // Todo: bring some sanity to the intersection of system properties aka "mutable // state shared by everyone and everything" and the reality that there is no other // mechanism for accomplishing some things on the jvm. - lazy val headless = bool("java.awt.headless", "system should not utilize a display device") - lazy val preferIPv4 = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets") - lazy val noTraceSupression = bool("scala.control.no-trace-suppression", "scala should not suppress any stack trace creation") + lazy val headless = bool("java.awt.headless", "system should not utilize a display device") + lazy val preferIPv4Stack = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets") + lazy val preferIPv6Addresses = bool("java.net.preferIPv6Addresses", "system should prefer IPv6 addresses") + lazy val noTraceSupression = bool("scala.control.noTraceSuppression", "scala should not suppress any stack trace creation") } diff --git a/test/files/run/coder/Coder.scala b/test/files/run/coder/Coder.scala index 5c81efc9c0..06dd4b6355 100644 --- a/test/files/run/coder/Coder.scala +++ b/test/files/run/coder/Coder.scala @@ -85,7 +85,7 @@ class ParCoder(words: List[String]) { def encode(number: String): ParSet[List[String]] = if (number.isEmpty) ParSet(List()) else { - val splits = (1 to number.length).toParSet + val splits = (1 to number.length).toSet.par // for { // split <- splits // word <- wordsForNum(number take split) diff --git a/test/files/run/coder2/Coder2.scala b/test/files/run/coder2/Coder2.scala index 7ecc5e67d1..abe284a398 100644 --- a/test/files/run/coder2/Coder2.scala +++ b/test/files/run/coder2/Coder2.scala @@ -77,7 +77,7 @@ class ParCoder(words: List[String]) { * them e.g. `5282` -> List(`Java`, `Kata`, `Lava`, ...) */ val wordsForNum: Map[String, ParSeq[String]] = - (words groupBy wordCode).map(t => (t._1, t._2.toParSeq)) withDefaultValue ParSeq() + (words groupBy wordCode).map(t => (t._1, t._2.toSeq.par)) withDefaultValue ParSeq() val comparison = new SeqCoder(words) @@ -85,7 +85,7 @@ class ParCoder(words: List[String]) { def encode(number: String): ParSet[ParSeq[String]] = if (number.isEmpty) ParSet(ParSeq()) else { - val splits = (1 to number.length).toParSet + val splits = (1 to number.length).toSet.par // for { // split <- splits // word <- wordsForNum(number take split) @@ -118,7 +118,7 @@ class ParCoder(words: List[String]) { def assertWfn(num: String, split: String, dropped: String, r: ParSeq[ParSeq[String]]) { val m = comparison.wfnmemo((num, split)) - val rs = r.toParSet + val rs = r.toSet.par val words: ParSeq[String] = wordsForNum(split) if (rs != m) { println("flatmap for number with split: " + num + ", " + split) @@ -168,32 +168,32 @@ object Test { /* */ def main(args : Array[String]) { - // for (i <- 0 until 10) { - // val seqcoder = new SeqCoder(Dictionary.wordlist) - // val st = seqcoder.translate(code) - // //println("Translation check: " + st.size) - - // val parcoder = new ParCoder(Dictionary.wordlist) - // val pt = parcoder.translate(code) - // //println("Translation check: " + pt.size) - - // // val st = sts.toList.sorted - // // val pt = pts.toList.sorted - // if (st.size != pt.size) { - // // val zipped = st.zip(pt) - // // val ind = zipped.indexWhere { case (a, b) => a != b } - // // val sliced = zipped.slice(ind - 10, ind + 10) - // // println(sliced.map(t => t._1 + "\n" + t._2 + "\n--------").mkString("\n")) - // println(i + ") seq vs par: " + st.size + " vs " + pt.size) - // } - // if (st != pt) { - // val zipped = (st.toList.sorted zip pt.toList.sorted); - // val diffp = zipped indexWhere { case (x, y) => x != y } - // println(zipped/*.slice(diffp - 10, diffp + 10)*/ mkString ("\n")) - // println((st.toList.sorted zip pt.toList.sorted) map { case (x, y) => (x == y) } reduceLeft(_ && _)) - // } - // assert(st == pt) - // } + for (i <- 0 until 10) { + val seqcoder = new SeqCoder(Dictionary.wordlist) + val sts = seqcoder.translate(code) + //println("Translation check: " + st.size) + + val parcoder = new ParCoder(Dictionary.wordlist) + val pts = parcoder.translate(code) + //println("Translation check: " + pt.size) + + val st = sts.toList.sorted + val pt = pts.toList.sorted + if (st.size != pt.size) { + val zipped = st.zip(pt) + val ind = zipped.indexWhere { case (a, b) => a != b } + val sliced = zipped.slice(ind - 10, ind + 10) + //println(sliced.map(t => t._1 + "\n" + t._2 + "\n--------").mkString("\n")) + //println(i + ") seq vs par: " + st.size + " vs " + pt.size) + } + if (st != pt) { + val zipped = (st.toList.sorted zip pt.toList.sorted); + val diffp = zipped indexWhere { case (x, y) => x != y } + //println(zipped/*.slice(diffp - 10, diffp + 10)*/ mkString ("\n")) + //println((st.toList.sorted zip pt.toList.sorted) map { case (x, y) => (x == y) } reduceLeft(_ && _)) + } + assert(st == pt) + } } } diff --git a/test/files/run/pc-conversions.scala b/test/files/run/pc-conversions.scala index 7e894f70f3..23fcb9fa59 100644 --- a/test/files/run/pc-conversions.scala +++ b/test/files/run/pc-conversions.scala @@ -30,7 +30,7 @@ object Test { assertPar(immutable.HashMap(1 -> 1, 2 -> 2)) assertPar(immutable.HashSet(1, 2, 3)) - // toPar* + // par.to* and to*.par tests assertToPar(List(1 -> 1, 2 -> 2, 3 -> 3)) assertToPar(Stream(1 -> 1, 2 -> 2)) assertToPar(Array(1 -> 1, 2 -> 2)) @@ -55,28 +55,49 @@ object Test { def assertSeq[T](pc: parallel.ParIterable[T]) = assert(pc.seq == pc) - def assertPar[T, P <: Parallel](xs: Iterable[T] with Parallelizable[P]) = assert(xs == xs.par) + def assertPar[T, P <: Parallel](xs: Iterable[T]) = assert(xs == xs.par) def assertToPar[K, V](xs: Traversable[(K, V)]) { xs match { - case _: Seq[_] => assert(xs.toParIterable == xs) + case _: Seq[_] => + assert(xs.toIterable.par == xs) + assert(xs.par.toIterable == xs) case _ => } - assert(xs.toParSeq == xs.toSeq) - assert(xs.toParSet == xs.toSet) - assert(xs.toParMap == xs.toMap) + + assert(xs.toSeq.par == xs.toSeq) + assert(xs.par.toSeq == xs.toSeq) + + assert(xs.toSet.par == xs.toSet) + assert(xs.par.toSet == xs.toSet) + + assert(xs.toMap.par == xs.toMap) + assert(xs.par.toMap == xs.toMap) } - def assertToParWoMap[T](xs: Traversable[T]) { - assert(xs.toParIterable == xs) - assert(xs.toParSeq == xs.toSeq) - assert(xs.toParSet == xs.toSet) + def assertToParWoMap[T](xs: Seq[T]) { + assert(xs.toIterable.par == xs.toIterable) + assert(xs.par.toIterable == xs.toIterable) + + assert(xs.toSeq.par == xs.toSeq) + assert(xs.par.toSeq == xs.toSeq) + + assert(xs.toSet.par == xs.toSet) + assert(xs.par.toSet == xs.toSet) } def assertToParIt[K, V](xs: =>Iterator[(K, V)]) { - assert(xs.toParSeq == xs.toSeq) - assert(xs.toParSet == xs.toSet) - assert(xs.toParMap == xs.toMap) + assert(xs.toIterable.par == xs.toIterable) + assert(xs.par.toIterable == xs.toIterable) + + assert(xs.toSeq.par == xs.toSeq) + assert(xs.par.toSeq == xs.toSeq) + + assert(xs.toSet.par == xs.toSet) + assert(xs.par.toSet == xs.toSet) + + assert(xs.toMap.par == xs.toMap) + assert(xs.par.toMap == xs.toMap) } } diff --git a/test/files/run/treePrint.scala b/test/files/run/treePrint.scala index 8a77a3c9dc..ce7dd04499 100644 --- a/test/files/run/treePrint.scala +++ b/test/files/run/treePrint.scala @@ -37,6 +37,6 @@ object Test { val intp = new IMain(settings, new PrintWriter(new NullOutputStream)) val power = new Power(intp) intp.interpret("""def initialize = "Have to interpret something or we get errors." """) - println(power mkTree code) + power trees code foreach println } } |