summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.sbt39
-rw-r--r--build.xml2
-rw-r--r--doc/LICENSE.md4
-rw-r--r--doc/License.rtf4
-rw-r--r--project/ParserUtil.scala54
-rw-r--r--project/PartestUtil.scala92
-rw-r--r--project/ScalaOptionParser.scala128
-rw-r--r--project/VersionUtil.scala2
-rw-r--r--src/intellij/scala-build.iml.SAMPLE109
-rw-r--r--src/intellij/scala.ipr.SAMPLE3
-rw-r--r--src/library/scala/collection/Iterator.scala51
-rw-r--r--src/library/scala/util/Properties.scala2
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala2
-rw-r--r--src/scalap/decoder.properties2
-rw-r--r--test/junit/scala/collection/IteratorTest.scala28
15 files changed, 503 insertions, 19 deletions
diff --git a/build.sbt b/build.sbt
index b31bde8078..6941c8cb7f 100644
--- a/build.sbt
+++ b/build.sbt
@@ -196,7 +196,18 @@ lazy val commonSettings = clearSourceAndResourceDirectories ++ publishSettings +
},
// Remove auto-generated manifest attributes
packageOptions in Compile in packageBin := Seq.empty,
- packageOptions in Compile in packageSrc := Seq.empty
+ packageOptions in Compile in packageSrc := Seq.empty,
+
+ // Lets us CTRL-C partest without exiting SBT entirely
+ cancelable in Global := true,
+ // When we fork subprocesses, use the base directory as the working directory.
+ // This enables `sbt> partest test/files/run/t1.scala` or `sbt> scalac sandbox/test.scala`
+ baseDirectory in Compile := (baseDirectory in ThisBuild).value,
+ baseDirectory in Test := (baseDirectory in ThisBuild).value,
+
+ // Don't log process output (e.g. of forked `compiler/runMain ...Main`), just pass it
+ // directly to stdout
+ outputStrategy in run := Some(StdoutOutput)
)
/** Extra post-processing for the published POM files. These are needed to create POMs that
@@ -409,7 +420,6 @@ lazy val repl = configureAsSubproject(project)
.settings(
connectInput in run := true,
publishArtifact := false,
- outputStrategy in run := Some(StdoutOutput),
run <<= (run in Compile).partialInput(" -usejavacp") // Automatically add this so that `repl/run` works without additional arguments.
)
.dependsOn(compiler, interactive)
@@ -456,7 +466,8 @@ lazy val replJlineEmbedded = Project("repl-jline-embedded", file(".") / "target"
val outdir = (classDirectory in Compile).value
JarJar(inputs, outdir, config)
}),
- publishArtifact := false
+ publishArtifact := false,
+ connectInput in run := true
)
.dependsOn(replJline)
@@ -767,3 +778,25 @@ def generateServiceProviderResources(services: (String, String)*): Setting[_] =
}.taskValue
buildDirectory in ThisBuild := (baseDirectory in ThisBuild).value / "build-sbt"
+
+// Add tab completion to partest
+commands += Command("partest")(_ => PartestUtil.partestParser((baseDirectory in ThisBuild).value, (baseDirectory in ThisBuild).value / "test")) { (state, parsed) =>
+ ("test/it:testOnly -- " + parsed) :: state
+}
+
+// Add tab completion to scalac et al.
+commands ++= {
+ val commands =
+ List(("scalac", "compiler", "scala.tools.nsc.Main"),
+ ("scala", "repl-jline-embedded", "scala.tools.nsc.MainGenericRunner"),
+ ("scaladoc", "scaladoc", "scala.tools.nsc.ScalaDoc"))
+
+ commands.map {
+ case (entryPoint, projectRef, mainClassName) =>
+ Command(entryPoint)(_ => ScalaOptionParser.scalaParser(entryPoint, (baseDirectory in ThisBuild).value)) { (state, parsedOptions) =>
+ (projectRef + "/runMain " + mainClassName + " -usejavacp " + parsedOptions) :: state
+ }
+ }
+}
+
+addCommandAlias("scalap", "scalap/compile:runMain scala.tools.scalap.Main -usejavacp")
diff --git a/build.xml b/build.xml
index 78c7a9a230..04c1052bea 100644
--- a/build.xml
+++ b/build.xml
@@ -183,7 +183,7 @@ TODO:
<property name="dists.dir" value="${basedir}/dists"/>
- <property name="copyright.string" value="Copyright 2002-2015, LAMP/EPFL"/>
+ <property name="copyright.string" value="Copyright 2002-2016, LAMP/EPFL"/>
<!-- These are NOT the flags used to run SuperSabbus, but the ones written
into the script runners created with scala.tools.ant.ScalaTool -->
diff --git a/doc/LICENSE.md b/doc/LICENSE.md
index 5c9310a8db..dc557368cf 100644
--- a/doc/LICENSE.md
+++ b/doc/LICENSE.md
@@ -2,9 +2,9 @@ Scala is licensed under the [BSD 3-Clause License](http://opensource.org/license
## Scala License
-Copyright (c) 2002-2015 EPFL
+Copyright (c) 2002-2016 EPFL
-Copyright (c) 2011-2015 Typesafe, Inc.
+Copyright (c) 2011-2016 Typesafe, Inc.
All rights reserved.
diff --git a/doc/License.rtf b/doc/License.rtf
index d2f37a4bf9..f2258077fa 100644
--- a/doc/License.rtf
+++ b/doc/License.rtf
@@ -10,8 +10,8 @@
\fs48 Scala License
\fs40 \
-\fs26 Copyright (c) 2002-2015 EPFL\
-Copyright (c) 2011-2015 Typesafe, Inc.\
+\fs26 Copyright (c) 2002-2016 EPFL\
+Copyright (c) 2011-2016 Typesafe, Inc.\
All rights reserved.\
\
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\
diff --git a/project/ParserUtil.scala b/project/ParserUtil.scala
new file mode 100644
index 0000000000..f6658b146b
--- /dev/null
+++ b/project/ParserUtil.scala
@@ -0,0 +1,54 @@
+import sbt._
+import sbt.complete.Parser._
+import sbt.complete.Parsers._
+import sbt.complete._
+
+object ParserUtil {
+ def notStartingWith(parser: Parser[String], c: Char): Parser[String] = parser & not(c ~> any.*, "value cannot start with " + c + ".")
+ def concat(p: Parser[(String, String)]): Parser[String] = {
+ p.map(x => x._1 + x._2)
+ }
+
+ def EitherOr(a: Parser[String], b: Parser[String]): Parser[String] = {
+ a.flatMap[String] {
+ case "" => b
+ case x: String =>
+ concat(Space.string ~ b).map[String]((s: String) => x + s)
+ }
+ }
+ def Opt(a: Parser[String]) = a.?.map(_.getOrElse(""))
+
+ val StringBasicNotStartingWithDash = notStartingWith(StringBasic, '-')
+ val IsDirectoryFilter = new SimpleFileFilter(_.isDirectory)
+ val JarOrDirectoryParser = FileParser(GlobFilter("*.jar") || IsDirectoryFilter)
+ def FileParser(filter: FileFilter, dirFilter: FileFilter = AllPassFilter, base: File = file(".")) = {
+ def matching(prefix: String): List[String] = {
+ val preFile = file(prefix)
+ val cwd = base
+ val parent = Option(preFile.getParentFile).getOrElse(cwd)
+ if (preFile.exists) {
+ if (preFile.isDirectory) {
+ preFile.*(IsDirectoryFilter.&&(dirFilter) || filter).get.map(_.getPath).toList
+ } else {
+ List(preFile).filter(filter.accept).map(_.getPath)
+ }
+ }
+ else if (parent != null) {
+ def ensureSuffix(s: String, suffix: String) = if (s.endsWith(suffix)) s else s + suffix
+ def pathOf(f: File): String = if (f.isDirectory && !filter.accept(f)) ensureSuffix(f.getPath, "/") else f.getPath
+ parent.*(GlobFilter(preFile.name + "*") && ((IsDirectoryFilter && dirFilter) || filter)).get.map(x => pathOf(if (parent == cwd) x.relativeTo(cwd).get else x)).toList
+ } else Nil
+ }
+ def displayPath = Completions.single(Completion.displayOnly("<path>"))
+ token(StringBasic, TokenCompletions.fixed((seen, level) => if (seen.isEmpty) displayPath else matching(seen) match {
+ case Nil => displayPath
+ case x :: Nil =>
+ if (filter.accept(file(x)))
+ Completions.strict(Set(Completion.tokenDisplay(x.stripPrefix(seen), x)))
+ else
+ Completions.strict(Set(Completion.suggestion(x.stripPrefix(seen))))
+ case xs =>
+ Completions.strict(xs.map(x => Completion.tokenDisplay(x.stripPrefix(seen), x)).toSet)
+ })).filter(!_.startsWith("-"), x => x)
+ }
+} \ No newline at end of file
diff --git a/project/PartestUtil.scala b/project/PartestUtil.scala
new file mode 100644
index 0000000000..0c0c677a6f
--- /dev/null
+++ b/project/PartestUtil.scala
@@ -0,0 +1,92 @@
+import sbt._
+import sbt.complete._, Parser._, Parsers._
+
+object PartestUtil {
+ private case class TestFiles(srcPath: String, globalBase: File, testBase: File) {
+ private val testCaseDir = new SimpleFileFilter(f => f.isDirectory && f.listFiles.nonEmpty && !(f.getParentFile / (f.name + ".res")).exists)
+ private val testCaseFilter = GlobFilter("*.scala") | GlobFilter("*.java") | GlobFilter("*.res") || testCaseDir
+ private def testCaseFinder = (testBase / srcPath).*(AllPassFilter).*(testCaseFilter)
+ private val basePaths = allTestCases.map(_._2.split('/').take(3).mkString("/") + "/").distinct
+
+ def allTestCases = testCaseFinder.pair(relativeTo(globalBase))
+ def basePathExamples = new FixedSetExamples(basePaths)
+ private def equiv(f1: File, f2: File) = f1.getCanonicalFile == f2.getCanonicalFile
+ def parentChain(f: File): Iterator[File] =
+ if (f == null || !f.exists) Iterator()
+ else Iterator(f) ++ (if (f.getParentFile == null) Nil else parentChain(f.getParentFile))
+ def isParentOf(parent: File, f2: File, maxDepth: Int) =
+ parentChain(f2).take(maxDepth).exists(p1 => equiv(p1, parent))
+ def isTestCase(f: File) = {
+ val grandParent = if (f != null && f.getParentFile != null) f.getParentFile.getParentFile else null
+ grandParent != null && equiv(grandParent, testBase / srcPath) && testCaseFilter.accept(f)
+ }
+ def mayContainTestCase(f: File) = {
+ isParentOf(testBase / srcPath, f, 2) || isParentOf(f, testBase / srcPath, Int.MaxValue)
+ }
+ }
+ /** A parser for the custom `partest` command */
+ def partestParser(globalBase: File, testBase: File): Parser[String] = {
+ val knownUnaryOptions = List(
+ "--pos", "--neg", "--run", "--jvm", "--res", "--ant", "--scalap", "--specialized",
+ "--scalacheck", "--instrumented", "--presentation", "--failed", "--update-check",
+ "--show-diff", "--verbose", "--terse", "--debug", "--version", "--self-test", "--help")
+ val srcPathOption = "--srcpath"
+ val grepOption = "--grep"
+
+ // HACK: if we parse `--srpath scaladoc`, we overwrite this var. The parser for test file paths
+ // then lazily creates the examples based on the current value.
+ // TODO is there a cleaner way to do this with SBT's parser infrastructure?
+ var srcPath = "files"
+ var _testFiles: TestFiles = null
+ def testFiles = {
+ if (_testFiles == null || _testFiles.srcPath != srcPath) _testFiles = new TestFiles(srcPath, globalBase, testBase)
+ _testFiles
+ }
+ val TestPathParser = ParserUtil.FileParser(
+ new SimpleFileFilter(f => testFiles.isTestCase(f)),
+ new SimpleFileFilter(f => testFiles.mayContainTestCase(f)), globalBase)
+
+ // allow `--grep "is unchecked" | --grep *t123*, in the spirit of ./bin/partest-ack
+ // superset of the --grep built into partest itself.
+ val Grep = {
+ def expandGrep(x: String): Seq[String] = {
+ val matchingFileContent = try {
+ val Pattern = ("(?i)" + x).r
+ testFiles.allTestCases.filter {
+ case (testFile, testPath) =>
+ val assocFiles = List(".check", ".flags").map(testFile.getParentFile / _)
+ val sourceFiles = if (testFile.isFile) List(testFile) else testFile.**(AllPassFilter).get.toList
+ val allFiles = testFile :: assocFiles ::: sourceFiles
+ allFiles.exists { f => f.exists && f.isFile && Pattern.findFirstIn(IO.read(f)).isDefined }
+ }
+ } catch {
+ case _: Throwable => Nil
+ }
+ val matchingFileName = try {
+ val filter = GlobFilter("*" + x + "*")
+ testFiles.allTestCases.filter(x => filter.accept(x._1.name))
+ } catch {
+ case t: Throwable => Nil
+ }
+ (matchingFileContent ++ matchingFileName).map(_._2).distinct.sorted
+ }
+
+ val completion = Completions.strict(Set("<filename glob>", "<regex> (for source, flags or checkfile contents)").map(s => Completion.displayOnly(s)))
+ val tokenCompletion = TokenCompletions.fixed((seen, level) => completion)
+
+ val globOrPattern = StringBasic.map(expandGrep).flatMap {
+ case Seq() => failure("no tests match pattern / glob")
+ case x => success(x.mkString(" "))
+ }
+ token(grepOption <~ Space) ~> token(globOrPattern, tokenCompletion)
+ }
+
+ val SrcPath = ((token(srcPathOption) <~ Space) ~ token(StringBasic.examples(Set("files", "pending", "scaladoc")))) map {
+ case opt ~ path =>
+ srcPath = path
+ opt + " " + path
+ }
+ val P = oneOf(knownUnaryOptions.map(x => token(x))) | SrcPath | TestPathParser | Grep
+ (Space ~> repsep(P, oneOrMore(Space))).map(_.mkString(" ")).?.map(_.getOrElse(""))
+ }
+}
diff --git a/project/ScalaOptionParser.scala b/project/ScalaOptionParser.scala
new file mode 100644
index 0000000000..a11bd93d82
--- /dev/null
+++ b/project/ScalaOptionParser.scala
@@ -0,0 +1,128 @@
+import ParserUtil._
+import sbt._
+import sbt.complete.Parser._
+import sbt.complete.Parsers._
+import sbt.complete._
+
+object ScalaOptionParser {
+ /** A SBT parser for the Scala command line runners (scala, scalac, etc) */
+ def scalaParser(entryPoint: String, globalBase: File): Parser[String] = {
+ def BooleanSetting(name: String): Parser[String] =
+ token(name)
+ def StringSetting(name: String): Parser[String] = {
+ val valueParser = name match {
+ case "-d" => JarOrDirectoryParser
+ case _ => token(StringBasic, TokenCompletions.displayOnly("<value>"))
+ }
+ concat(concat(token(name ~ Space.string)) ~ valueParser)
+ }
+ def MultiStringSetting(name: String): Parser[String] =
+ concat(concat(token(name ~ ":")) ~ repsep(token(StringBasicNotStartingWithDash, TokenCompletions.displayOnly("<value>")), token(",")).map(_.mkString))
+ def IntSetting(name: String): Parser[String] =
+ concat(concat(token(name ~ ":")) ~ token(IntBasic.map(_.toString), TokenCompletions.displayOnly("<integer>")))
+ def ChoiceSetting(name: String, choices: List[String]): Parser[String] =
+ concat(token(concat(name ~ ":")) ~ token(StringBasic.examples(choices: _*)).map(_.mkString))
+ def MultiChoiceSetting(name: String, choices: List[String]): Parser[String] =
+ concat(token(concat(name ~ ":")) ~ rep1sep(token(StringBasic.examples(choices: _*)), token(",")).map(_.mkString))
+ def PathSetting(name: String): Parser[String] = {
+ concat(concat(token(name) ~ Space.string) ~ rep1sep(JarOrDirectoryParser.filter(!_.contains(":"), x => x), token(java.io.File.pathSeparator)).map(_.mkString))
+ }
+ def FileSetting(name: String): Parser[String] = {
+ concat(concat(token(name) ~ Space.string) ~ rep1sep(JarOrDirectoryParser.filter(!_.contains(":"), x => x), token(java.io.File.pathSeparator)).map(_.mkString))
+ }
+ val Phase = token(NotSpace.examples(phases: _*))
+ def PhaseSettingParser(name: String): Parser[String] = {
+ MultiChoiceSetting(name, phases)
+ }
+ def ScalaVersionSetting(name: String): Parser[String] = {
+ concat(concat(token(name ~ Space.string)) ~ token(StringBasic, TokenCompletions.displayOnly("<scala version>")))
+ }
+ val Property: Parser[String] = {
+ val PropName = concat(token("-D" ~ oneOrMore(NotSpaceClass & not('=', "not =")).string, TokenCompletions.displayOnly("-D<property name>")))
+ val EqualsValue = concat("=" ~ token(OptNotSpace, TokenCompletions.displayOnly("<property value>")))
+ concat(PropName ~ EqualsValue.?.map(_.getOrElse("")))
+ }
+
+ val sourceFile = FileParser(GlobFilter("*.scala") | GlobFilter("*.java"))
+
+ // TODO Allow JVM settings via -J-... and temporarily add them to the ForkOptions
+ val UniversalOpt = Property | oneOf(pathSettingNames.map(PathSetting) ++ phaseSettings.map(PhaseSettingParser) ++ booleanSettingNames.map(BooleanSetting) ++ stringSettingNames.map(StringSetting) ++ multiStringSettingNames.map(MultiStringSetting) ++ intSettingNames.map(IntSetting) ++ choiceSettingNames.map { case (k, v) => ChoiceSetting(k, v) } ++ multiChoiceSettingNames.map { case (k, v) => MultiChoiceSetting(k, v) } ++ scalaVersionSettings.map(ScalaVersionSetting))
+ val ScalacOpt = sourceFile | UniversalOpt
+
+ val ScalaExtraSettings = oneOf(
+ scalaChoiceSettingNames.map { case (k, v) => ChoiceSetting(k,v)}.toList
+ ++ scalaStringSettingNames.map(StringSetting)
+ ++ scalaBooleanSettingNames.map(BooleanSetting))
+ val ScalaOpt = UniversalOpt | ScalaExtraSettings
+
+ val ScalaDocExtraSettings = oneOf(
+ scalaDocBooleanSettingNames.map(BooleanSetting)
+ ++ scalaDocIntSettingNames.map(IntSetting)
+ ++ scalaDocChoiceSettingNames.map { case (k, v) => ChoiceSetting(k, v)}
+ ++ scaladocStringSettingNames.map(StringSetting)
+ ++ scaladocPathSettingNames.map(PathSetting)
+ ++ scaladocMultiStringSettingNames.map(MultiStringSetting)
+ )
+ val ScalaDocOpt = sourceFile | ScalaOpt | ScalaDocExtraSettings
+
+ entryPoint match {
+ case "scala" =>
+ val runnable = token(StringBasicNotStartingWithDash, TokenCompletions.displayOnly("<script|class|object|jar>")).filter(!_.startsWith("-"), x => x)
+ val runnableAndArgs = concat(runnable ~ Opt(concat(Space.string ~ repsep(token(StringBasic, TokenCompletions.displayOnly("<arg>")), Space).map(_.mkString(" ")))))
+ val options = repsep(ScalaOpt, Space).map(_.mkString(" "))
+ Opt(Space ~> EitherOr(options, runnableAndArgs))
+ case "scaladoc" =>
+ Opt(Space ~> Opt(repsep(ScalaDocOpt, Space).map(_.mkString(" "))))
+ case "scalac" =>
+ Opt(Space ~> repsep(ScalacOpt, Space).map(_.mkString(" ")))
+ }
+ }
+
+ // TODO retrieve this data programatically, ala https://github.com/scala/scala-tool-support/blob/master/bash-completion/src/main/scala/BashCompletion.scala
+ private def booleanSettingNames = List("-X", "-Xcheckinit", "-Xdev", "-Xdisable-assertions", "-Xexperimental", "-Xfatal-warnings", "-Xfull-lubs", "-Xfuture", "-Xlog-free-terms", "-Xlog-free-types", "-Xlog-implicit-conversions", "-Xlog-implicits", "-Xlog-reflective-calls",
+ "-Xno-forwarders", "-Xno-patmat-analysis", "-Xno-uescape", "-Xnojline", "-Xprint-pos", "-Xprint-types", "-Xprompt", "-Xresident", "-Xshow-phases", "-Xstrict-inference", "-Xverify", "-Y",
+ "-Ybreak-cycles", "-Yclosure-elim", "-Yconst-opt", "-Ydead-code", "-Ydebug", "-Ycompact-trees", "-Ydisable-unreachable-prevention", "-YdisableFlatCpCaching", "-Ydoc-debug",
+ "-Yeta-expand-keeps-star", "-Yide-debug", "-Yinfer-argument-types", "-Yinfer-by-name", "-Yinfer-debug", "-Yinline", "-Yinline-handlers",
+ "-Yinline-warnings", "-Yissue-debug", "-Ylog-classpath", "-Ymacro-debug-lite", "-Ymacro-debug-verbose", "-Ymacro-no-expand",
+ "-Yno-completion", "-Yno-generic-signatures", "-Yno-imports", "-Yno-load-impl-class", "-Yno-predef", "-Ynooptimise",
+ "-Yoverride-objects", "-Yoverride-vars", "-Ypatmat-debug", "-Yno-adapted-args", "-Ypos-debug", "-Ypresentation-debug",
+ "-Ypresentation-strict", "-Ypresentation-verbose", "-Yquasiquote-debug", "-Yrangepos", "-Yreify-copypaste", "-Yreify-debug", "-Yrepl-class-based",
+ "-Yrepl-sync", "-Yshow-member-pos", "-Yshow-symkinds", "-Yshow-symowners", "-Yshow-syms", "-Yshow-trees", "-Yshow-trees-compact", "-Yshow-trees-stringified", "-Ytyper-debug",
+ "-Ywarn-adapted-args", "-Ywarn-dead-code", "-Ywarn-inaccessible", "-Ywarn-infer-any", "-Ywarn-nullary-override", "-Ywarn-nullary-unit", "-Ywarn-numeric-widen", "-Ywarn-unused", "-Ywarn-unused-import", "-Ywarn-value-discard",
+ "-deprecation", "-explaintypes", "-feature", "-help", "-no-specialization", "-nobootcp", "-nowarn", "-optimise", "-print", "-unchecked", "-uniqid", "-usejavacp", "-usemanifestcp", "-verbose", "-version")
+ private def stringSettingNames = List("-Xgenerate-phase-graph", "-Xmain-class", "-Xpluginsdir", "-Xshow-class", "-Xshow-object", "-Xsource-reader", "-Ydump-classes", "-Ygen-asmp",
+ "-Ygen-javap", "-Ypresentation-log", "-Ypresentation-replay", "-Yrepl-outdir", "-d", "-dependencyfile", "-encoding", "-Xscript")
+ private def pathSettingNames = List("-bootclasspath", "-classpath", "-extdirs", "-javabootclasspath", "-javaextdirs", "-sourcepath", "-toolcp")
+ private val phases = List("all", "parser", "namer", "packageobjects", "typer", "patmat", "superaccessors", "extmethods", "pickler", "refchecks", "uncurry", "tailcalls", "specialize", "explicitouter", "erasure", "posterasure", "lazyvals", "lambdalift", "constructors", "flatten", "mixin", "cleanup", "delambdafy", "icode", "jvm", "terminal")
+ private val phaseSettings = List("-Xprint-icode", "-Ystop-after", "-Yskip", "-Yshow", "-Ystop-before", "-Ybrowse", "-Ylog", "-Ycheck", "-Xprint")
+ private def multiStringSettingNames = List("-Xmacro-settings", "-Xplugin", "-Xplugin-disable", "-Xplugin-require")
+ private def intSettingNames = List("-Xmax-classfile-name", "-Xelide-below", "-Ypatmat-exhaust-depth", "-Ypresentation-delay", "-Yrecursion")
+ private def choiceSettingNames = Map[String, List[String]](
+ "-Ybackend" -> List("GenASM", "GenBCode"),
+ "-YclasspathImpl" -> List("flat", "recursive"),
+ "-Ydelambdafy" -> List("inline", "method"),
+ "-Ylinearizer" -> List("dfs", "dump", "normal", "rpo"),
+ "-Ymacro-expand" -> List("discard", "none"),
+ "-Yresolve-term-conflict" -> List("error", "object", "package"),
+ "-g" -> List("line", "none", "notailcails", "source", "vars"),
+ "-target" -> List("jvm-1.5", "jvm-1.6", "jvm-1.7", "jvm-1.8"))
+ private def multiChoiceSettingNames = Map[String, List[String]](
+ "-Xlint" -> List("adapted-args", "nullary-unit", "inaccessible", "nullary-override", "infer-any", "missing-interpolator", "doc-detached", "private-shadow", "type-parameter-shadow", "poly-implicit-overload", "option-implicit", "delayedinit-select", "by-name-right-associative", "package-object-classes", "unsound-match", "stars-align"),
+ "-language" -> List("help", "_", "dynamics", "postfixOps", "reflectiveCalls", "implicitConversions", "higherKinds", "existentials", "experimental.macros"),
+ "-Yopt" -> List("l:none", "l:default", "l:method", "l:project", "l:classpath", "unreachable-code", "simplify-jumps", "empty-line-numbers", "empty-labels", "compact-locals", "nullness-tracking", "closure-elimination", "inline-project", "inline-global"),
+ "-Ystatistics" -> List("parser", "typer", "patmat", "erasure", "cleanup", "jvm")
+ )
+ private def scalaVersionSettings = List("-Xmigration", "-Xsource")
+
+ private def scalaChoiceSettingNames = Map("-howtorun" -> List("object", "script", "jar", "guess"))
+ private def scalaStringSettingNames = List("-i", "-e")
+ private def scalaBooleanSettingNames = List("-nc", "-save")
+
+ private def scalaDocBooleanSettingNames = List("-Yuse-stupid-types", "-implicits", "-implicits-debug", "-implicits-show-all", "-implicits-sound-shadowing", "-implicits-hide", "-author", "-diagrams", "-diagrams-debug", "-raw-output", "-no-prefixes", "-no-link-warnings", "-expand-all-types", "-groups")
+ private def scalaDocIntSettingNames = List("-diagrams-max-classes", "-diagrams-max-implicits", "-diagrams-dot-timeout", "-diagrams-dot-restart")
+ private def scalaDocChoiceSettingNames = Map("-doc-format" -> List("html"))
+ private def scaladocStringSettingNames = List("-doc-title", "-doc-version", "-doc-footer", "-doc-no-compile", "-doc-source-url", "-doc-generator", "-skip-packages")
+ private def scaladocPathSettingNames = List("-doc-root-content", "-diagrams-dot-path")
+ private def scaladocMultiStringSettingNames = List("-doc-external-doc")
+
+}
diff --git a/project/VersionUtil.scala b/project/VersionUtil.scala
index f237c35c68..fab22e66d4 100644
--- a/project/VersionUtil.scala
+++ b/project/VersionUtil.scala
@@ -19,7 +19,7 @@ object VersionUtil {
)
lazy val generatePropertiesFileSettings = Seq[Setting[_]](
- copyrightString := "Copyright 2002-2015, LAMP/EPFL",
+ copyrightString := "Copyright 2002-2016, LAMP/EPFL",
resourceGenerators in Compile += generateVersionPropertiesFile.map(file => Seq(file)).taskValue,
generateVersionPropertiesFile := generateVersionPropertiesFileImpl.value
)
diff --git a/src/intellij/scala-build.iml.SAMPLE b/src/intellij/scala-build.iml.SAMPLE
new file mode 100644
index 0000000000..bf722e464f
--- /dev/null
+++ b/src/intellij/scala-build.iml.SAMPLE
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id="scalaz-build" external.linked.project.path="$MODULE_DIR$/../../project" external.root.project.path="$MODULE_DIR$/../.." external.system.id="SBT" sbt.imports="sbt._, Keys._, dsl._, _root_.com.typesafe.sbt.SbtPgp.autoImport._, _root_.sbt.plugins.IvyPlugin, _root_.sbt.plugins.JvmPlugin, _root_.sbt.plugins.CorePlugin, _root_.sbt.plugins.JUnitXmlReportPlugin, _root_.com.typesafe.sbt.SbtPgp" sbt.resolvers="https://repo1.maven.org/maven2/|maven|public, /Users/jason/.ivy2/cache|ivy|Local cache" type="SBT_MODULE" version="4">
+ <component name="NewModuleRootManager" inherit-compiler-output="false">
+ <output url="file://$MODULE_DIR$/../../project/target/idea-classes" />
+ <output-test url="file://$MODULE_DIR$/../../project/target/idea-test-classes" />
+ <exclude-output />
+ <content url="file://$MODULE_DIR$/../../project">
+ <sourceFolder url="file://$MODULE_DIR$/../../project" isTestSource="false" />
+ <excludeFolder url="file://$MODULE_DIR$/../../project/project/target" />
+ <excludeFolder url="file://$MODULE_DIR$/../../project/target" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntry type="module-library">
+ <library name="SBT: sbt-and-plugins">
+ <CLASSES>
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.apache.commons/commons-lang3/jars/commons-lang3-3.3.2.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.pantsbuild/jarjar/jars/jarjar-1.6.0.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.apache.ant/ant/jars/ant-1.9.6.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.apache.ant/ant-launcher/jars/ant-launcher-1.9.6.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.ow2.asm/asm/jars/asm-5.0.4.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.ow2.asm/asm-commons/jars/asm-commons-5.0.4.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.ow2.asm/asm-tree/jars/asm-tree-5.0.4.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.apache.maven/maven-plugin-api/jars/maven-plugin-api-3.3.3.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.apache.maven/maven-model/jars/maven-model-3.3.3.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.codehaus.plexus/plexus-utils/jars/plexus-utils-3.0.20.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.apache.maven/maven-artifact/jars/maven-artifact-3.3.3.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.eclipse.sisu/org.eclipse.sisu.plexus/eclipse-plugins/org.eclipse.sisu.plexus-0.3.0.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/javax.enterprise/cdi-api/jars/cdi-api-1.0.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/javax.annotation/jsr250-api/jars/jsr250-api-1.0.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/javax.inject/javax.inject/jars/javax.inject-1.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.eclipse.sisu/org.eclipse.sisu.inject/eclipse-plugins/org.eclipse.sisu.inject-0.3.0.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.codehaus.plexus/plexus-component-annotations/jars/plexus-component-annotations-1.5.5.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.codehaus.plexus/plexus-classworlds/bundles/plexus-classworlds-2.5.2.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/biz.aQute.bnd/biz.aQute.bnd/jars/biz.aQute.bnd-2.4.1.jar!/" />
+ <root url="jar://$USER_HOME$/.sbt/boot/scala-2.10.5/lib/scala-library.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/sbt/jars/sbt-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/main/jars/main-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/actions/jars/actions-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/classpath/jars/classpath-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.sbt/boot/scala-2.10.5/lib/scala-compiler.jar!/" />
+ <root url="jar://$USER_HOME$/.sbt/boot/scala-2.10.5/lib/scala-reflect.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/interface/jars/interface-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/io/jars/io-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/control/jars/control-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/launcher-interface/jars/launcher-interface-1.0.0-M1.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/completion/jars/completion-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/collections/jars/collections-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/jline/jline/jars/jline-2.11.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/api/jars/api-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/compiler-integration/jars/compiler-integration-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/incremental-compiler/jars/incremental-compiler-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/logging/jars/logging-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/process/jars/process-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/relation/jars/relation-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/compile/jars/compile-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/classfile/jars/classfile-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/persist/jars/persist-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-tools.sbinary/sbinary_2.10/jars/sbinary_2.10-0.4.2.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/compiler-ivy-integration/jars/compiler-ivy-integration-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/ivy/jars/ivy-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/cross/jars/cross-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt.ivy/ivy/jars/ivy-2.3.0-sbt-c5d1b95fdcc1e1007740ffbecf4eb07abc51ec93.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/com.jcraft/jsch/jars/jsch-0.1.46.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/serialization_2.10/jars/serialization_2.10-0.1.1.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-pickling_2.10/jars/scala-pickling_2.10-0.10.0.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scalamacros/quasiquotes_2.10/jars/quasiquotes_2.10-2.0.1.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.json4s/json4s-core_2.10/jars/json4s-core_2.10-3.2.10.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.json4s/json4s-ast_2.10/jars/json4s-ast_2.10-3.2.10.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/com.thoughtworks.paranamer/paranamer/jars/paranamer-2.6.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.spire-math/jawn-parser_2.10/jars/jawn-parser_2.10-0.6.0.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.spire-math/json4s-support_2.10/jars/json4s-support_2.10-0.6.0.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/run/jars/run-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/task-system/jars/task-system-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/tasks/jars/tasks-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/tracking/jars/tracking-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/cache/jars/cache-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/testing/jars/testing-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/test-agent/jars/test-agent-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/test-interface/jars/test-interface-1.0.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/main-settings/jars/main-settings-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/apply-macro/jars/apply-macro-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/command/jars/command-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/logic/jars/logic-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/compiler-interface/jars/compiler-interface-bin-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/compiler-interface/jars/compiler-interface-src-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/precompiled-2_8_2/jars/compiler-interface-bin-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/precompiled-2_9_2/jars/compiler-interface-bin-0.13.9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/precompiled-2_9_3/jars/compiler-interface-bin-0.13.9.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/main/srcs/main-0.13.9-sources.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang/scala-library/srcs/scala-library-2.10.5-sources.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang/scala-reflect/srcs/scala-reflect-2.10.5-sources.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang/scala-compiler/srcs/scala-compiler-2.10.5-sources.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/actions/srcs/actions-0.13.9-sources.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/sbt/srcs/sbt-0.13.9-sources.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/run/srcs/run-0.13.9-sources.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/test-interface/srcs/test-interface-1.0-sources.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/testing/srcs/testing-0.13.9-sources.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/tasks/srcs/tasks-0.13.9-sources.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/ivy/srcs/ivy-0.13.9-sources.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/completion/srcs/completion-0.13.9-sources.jar!/" />
+ </SOURCES>
+ </library>
+ </orderEntry>
+ </component>
+</module> \ No newline at end of file
diff --git a/src/intellij/scala.ipr.SAMPLE b/src/intellij/scala.ipr.SAMPLE
index c4c6a2e44f..e88d6ef257 100644
--- a/src/intellij/scala.ipr.SAMPLE
+++ b/src/intellij/scala.ipr.SAMPLE
@@ -44,6 +44,7 @@
<module fileurl="file://$PROJECT_DIR$/reflect.iml" filepath="$PROJECT_DIR$/reflect.iml" />
<module fileurl="file://$PROJECT_DIR$/repl.iml" filepath="$PROJECT_DIR$/repl.iml" />
<module fileurl="file://$PROJECT_DIR$/scala.iml" filepath="$PROJECT_DIR$/scala.iml" />
+ <module fileurl="file://$PROJECT_DIR$/scala-build.iml" filepath="$PROJECT_DIR$/scala-build.iml" />
<module fileurl="file://$PROJECT_DIR$/scaladoc.iml" filepath="$PROJECT_DIR$/scaladoc.iml" />
<module fileurl="file://$PROJECT_DIR$/scalap.iml" filepath="$PROJECT_DIR$/scalap.iml" />
<module fileurl="file://$PROJECT_DIR$/test.iml" filepath="$PROJECT_DIR$/test.iml" />
@@ -123,4 +124,4 @@
<SOURCES />
</library>
</component>
-</project> \ No newline at end of file
+</project>
diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala
index 17bb83e52e..518bba6b6d 100644
--- a/src/library/scala/collection/Iterator.scala
+++ b/src/library/scala/collection/Iterator.scala
@@ -10,7 +10,7 @@ package scala
package collection
import mutable.ArrayBuffer
-import scala.annotation.migration
+import scala.annotation.{tailrec, migration}
import immutable.Stream
/** The `Iterator` object provides various functions for creating specialized iterators.
@@ -166,8 +166,10 @@ object Iterator {
private[scala] final class ConcatIterator[+A](private[this] var current: Iterator[A], initial: Vector[() => Iterator[A]]) extends Iterator[A] {
@deprecated def this(initial: Vector[() => Iterator[A]]) = this(Iterator.empty, initial) // for binary compatibility
private[this] var queue: Vector[() => Iterator[A]] = initial
+ private[this] var currentHasNextChecked = false
// Advance current to the next non-empty iterator
// current is set to null when all iterators are exhausted
+ @tailrec
private[this] def advance(): Boolean = {
if (queue.isEmpty) {
current = null
@@ -176,20 +178,57 @@ object Iterator {
else {
current = queue.head()
queue = queue.tail
- current.hasNext || advance()
+ if (current.hasNext) {
+ currentHasNextChecked = true
+ true
+ } else advance()
}
}
- def hasNext = (current ne null) && (current.hasNext || advance())
- def next() = if (hasNext) current.next() else Iterator.empty.next()
+ def hasNext =
+ if (currentHasNextChecked) true
+ else if (current eq null) false
+ else if (current.hasNext) {
+ currentHasNextChecked = true
+ true
+ } else advance()
+ def next() =
+ if (hasNext) {
+ currentHasNextChecked = false
+ current.next()
+ } else Iterator.empty.next()
override def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] =
new ConcatIterator(current, queue :+ (() => that.toIterator))
}
private[scala] final class JoinIterator[+A](lhs: Iterator[A], that: => GenTraversableOnce[A]) extends Iterator[A] {
+ private[this] var state = 0 // 0: lhs not checked, 1: lhs has next, 2: switched to rhs
private[this] lazy val rhs: Iterator[A] = that.toIterator
- def hasNext = lhs.hasNext || rhs.hasNext
- def next() = if (lhs.hasNext) lhs.next() else rhs.next()
+ def hasNext = state match {
+ case 0 =>
+ if (lhs.hasNext) {
+ state = 1
+ true
+ } else {
+ state = 2
+ rhs.hasNext
+ }
+ case 1 => true
+ case _ => rhs.hasNext
+ }
+ def next() = state match {
+ case 0 =>
+ if (lhs.hasNext) lhs.next()
+ else {
+ state = 2
+ rhs.next()
+ }
+ case 1 =>
+ state = 0
+ lhs.next()
+ case _ =>
+ rhs.next()
+ }
override def ++[B >: A](that: => GenTraversableOnce[B]) =
new ConcatIterator(this, Vector(() => that.toIterator))
diff --git a/src/library/scala/util/Properties.scala b/src/library/scala/util/Properties.scala
index d4a5e2f0e8..7ea597eac9 100644
--- a/src/library/scala/util/Properties.scala
+++ b/src/library/scala/util/Properties.scala
@@ -105,7 +105,7 @@ private[scala] trait PropertiesTrait {
* or "version (unknown)" if it cannot be determined.
*/
val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
- val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2015, LAMP/EPFL")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2016, LAMP/EPFL")
/** This is the encoding to use reading in source files, overridden with -encoding.
* Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala
index d33b31d8ba..6e87f2b0a9 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala
@@ -284,7 +284,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
{
if (Set("epfl", "EPFL").contains(tpl.universe.settings.docfooter.value))
- <div id="footer">Scala programming documentation. Copyright (c) 2003-2015 <a href="http://www.epfl.ch" target="_top">EPFL</a>, with contributions from <a href="http://typesafe.com" target="_top">Typesafe</a>.</div>
+ <div id="footer">Scala programming documentation. Copyright (c) 2003-2016 <a href="http://www.epfl.ch" target="_top">EPFL</a>, with contributions from <a href="http://typesafe.com" target="_top">Typesafe</a>.</div>
else
<div id="footer"> { tpl.universe.settings.docfooter.value } </div>
}
diff --git a/src/scalap/decoder.properties b/src/scalap/decoder.properties
index 333f6ce715..9bb8d130ea 100644
--- a/src/scalap/decoder.properties
+++ b/src/scalap/decoder.properties
@@ -1,2 +1,2 @@
version.number=2.0.1
-copyright.string=(c) 2002-2015 LAMP/EPFL
+copyright.string=(c) 2002-2016 LAMP/EPFL
diff --git a/test/junit/scala/collection/IteratorTest.scala b/test/junit/scala/collection/IteratorTest.scala
index b0639ef365..4df29e36c0 100644
--- a/test/junit/scala/collection/IteratorTest.scala
+++ b/test/junit/scala/collection/IteratorTest.scala
@@ -186,4 +186,32 @@ class IteratorTest {
assertEquals(1, y.next)
assertFalse(x.hasNext) // was true, after advancing underlying iterator
}
+ // SI-9623
+ @Test def noExcessiveHasNextInJoinIterator: Unit = {
+ var counter = 0
+ val exp = List(1,2,3,1,2,3)
+ def it: Iterator[Int] = new Iterator[Int] {
+ val parent = List(1,2,3).iterator
+ def next(): Int = parent.next
+ def hasNext: Boolean = { counter += 1; parent.hasNext }
+ }
+ // Iterate separately
+ val res = new mutable.ArrayBuffer[Int]
+ it.foreach(res += _)
+ it.foreach(res += _)
+ assertSameElements(exp, res)
+ assertEquals(8, counter)
+ // JoinIterator
+ counter = 0
+ res.clear
+ (it ++ it).foreach(res += _)
+ assertSameElements(exp, res)
+ assertEquals(8, counter) // was 17
+ // ConcatIterator
+ counter = 0
+ res.clear
+ (Iterator.empty ++ it ++ it).foreach(res += _)
+ assertSameElements(exp, res)
+ assertEquals(8, counter) // was 14
+ }
}