summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.sbt5
-rw-r--r--build.xml14
-rw-r--r--project/Osgi.scala13
-rw-r--r--src/compiler/scala/tools/ant/Scalac.scala2
-rw-r--r--src/compiler/scala/tools/nsc/GenericRunnerCommand.scala1
-rw-r--r--src/compiler/scala/tools/nsc/GenericRunnerSettings.scala8
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala108
-rw-r--r--src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala26
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala1
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala41
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala32
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala92
-rw-r--r--src/library/scala/collection/immutable/HashMap.scala2
-rw-r--r--src/library/scala/collection/immutable/Range.scala28
-rw-r--r--src/library/scala/collection/immutable/StringLike.scala22
-rw-r--r--src/library/scala/collection/mutable/OpenHashMap.scala17
-rw-r--r--src/library/scala/native.scala9
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala7
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala1
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala6
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ILoop.scala231
-rw-r--r--src/repl/scala/tools/nsc/interpreter/IMain.scala43
-rw-r--r--src/repl/scala/tools/nsc/interpreter/InteractiveReader.scala95
-rw-r--r--test/benchmarks/.gitignore14
-rw-r--r--test/benchmarks/README.md105
-rw-r--r--test/benchmarks/build.sbt11
-rw-r--r--test/benchmarks/project/plugins.sbt2
-rw-r--r--test/benchmarks/src/main/scala/benchmark/JmhRunner.scala16
-rw-r--r--test/benchmarks/src/main/scala/benchmark/KeySeq.scala24
-rw-r--r--test/benchmarks/src/main/scala/benchmark/KeySeqBuilder.scala33
-rw-r--r--test/benchmarks/src/main/scala/scala/collection/mutable/OpenHashMapBenchmark.scala308
-rw-r--r--test/benchmarks/src/main/scala/scala/collection/mutable/OpenHashMapRunner.scala113
-rw-r--r--test/files/neg/eta-expand-star.check4
-rw-r--r--test/files/neg/macro-invalidusage-badargs.check4
-rw-r--r--test/files/neg/multi-array.check4
-rw-r--r--test/files/neg/protected-constructors.check9
-rw-r--r--test/files/neg/t1112.check4
-rw-r--r--test/files/neg/t1523.check4
-rw-r--r--test/files/neg/t6920.check4
-rw-r--r--test/files/neg/t7157.check48
-rw-r--r--test/files/neg/t8006.check4
-rw-r--r--test/files/neg/t8035-no-adapted-args.check4
-rw-r--r--test/files/neg/t8667.check91
-rw-r--r--test/files/neg/t8667.scala37
-rw-r--r--test/files/neg/t876.check4
-rw-r--r--test/files/neg/trait-no-native.check4
-rw-r--r--test/files/neg/trait-no-native.scala4
-rw-r--r--test/files/pos/t8449/Client.scala (renamed from test/files/t8449/Client.scala)0
-rw-r--r--test/files/pos/t8449/Test.java (renamed from test/files/t8449/Test.java)0
-rw-r--r--test/files/run/repl-paste-b.check14
-rw-r--r--test/files/run/repl-paste-b.scala13
-rwxr-xr-xtest/files/run/repl-paste-parse.check6
-rw-r--r--test/files/run/repl-paste-parse.scala27
-rw-r--r--test/files/run/repl-paste-parse.script1
-rw-r--r--test/files/run/repl-paste-raw-b.pastie8
-rw-r--r--test/files/run/repl-paste-raw-b.scala18
-rw-r--r--test/files/run/repl-paste-raw-c.pastie5
-rw-r--r--test/files/run/repl-paste-raw-c.scala16
-rw-r--r--test/files/run/repl-paste-raw.pastie4
-rw-r--r--test/files/run/repl-paste-raw.scala2
-rw-r--r--test/files/run/t4625.check1
-rw-r--r--test/files/run/t4625.scala7
-rw-r--r--test/files/run/t4625.script5
-rw-r--r--test/files/run/t4625b.check1
-rw-r--r--test/files/run/t4625b.scala7
-rw-r--r--test/files/run/t4625b.script8
-rw-r--r--test/files/run/t4625c.check3
-rw-r--r--test/files/run/t4625c.scala7
-rw-r--r--test/files/run/t4625c.script7
-rw-r--r--test/files/run/t7805-repl-i.check3
-rw-r--r--test/files/run/t9170.scala2
-rw-r--r--test/junit/scala/collection/immutable/HashMapTest.scala48
-rw-r--r--test/junit/scala/collection/immutable/StringLikeTest.scala31
-rw-r--r--test/junit/scala/lang/primitives/NaNTest.scala38
77 files changed, 1634 insertions, 316 deletions
diff --git a/build.sbt b/build.sbt
index 2eb629f923..0194bc08b6 100644
--- a/build.sbt
+++ b/build.sbt
@@ -346,6 +346,7 @@ lazy val library = configureAsSubproject(project)
base ** "*.txt" pair relativeTo(base)
},
Osgi.headers += "Import-Package" -> "sun.misc;resolution:=optional, *",
+ Osgi.jarlist := true,
fixPom(
"/project/name" -> <name>Scala Library</name>,
"/project/description" -> <description>Standard library for the Scala Programming Language</description>,
@@ -412,13 +413,15 @@ lazy val compiler = configureAsSubproject(project)
scalacOptions in Compile in doc ++= Seq(
"-doc-root-content", (sourceDirectory in Compile).value + "/rootdoc.txt"
),
- Osgi.headers +=
+ Osgi.headers ++= Seq(
"Import-Package" -> ("jline.*;resolution:=optional," +
"org.apache.tools.ant.*;resolution:=optional," +
"scala.util.parsing.*;version=\"${range;[====,====];"+versionNumber("scala-parser-combinators")+"}\";resolution:=optional," +
"scala.xml.*;version=\"${range;[====,====];"+versionNumber("scala-xml")+"}\";resolution:=optional," +
"scala.*;version=\"${range;[==,=+);${ver}}\"," +
"*"),
+ "Class-Path" -> "scala-reflect.jar scala-library.jar"
+ ),
// Generate the ScriptEngineFactory service definition. The ant build does this when building
// the JAR but sbt has no support for it and it is easier to do as a resource generator:
generateServiceProviderResources("javax.script.ScriptEngineFactory" -> "scala.tools.nsc.interpreter.IMain$Factory"),
diff --git a/build.xml b/build.xml
index 50ced24247..519d3597cc 100644
--- a/build.xml
+++ b/build.xml
@@ -273,6 +273,10 @@ TODO:
<dependency groupId="org.pantsbuild" artifactId="jarjar" version="1.6.0"/>
</artifact:dependencies>
+ <artifact:dependencies pathId="jarlister.classpath">
+ <dependency groupId="com.github.rjolly" artifactId="jarlister_2.11" version="1.0"/>
+ </artifact:dependencies>
+
<!-- JUnit -->
<property name="junit.version" value="4.12"/>
<artifact:dependencies pathId="junit.classpath" filesetId="junit.fileset">
@@ -787,6 +791,11 @@ TODO:
<path refid="aux.libs"/>
</path>
+ <path id="pack.lib.path">
+ <pathelement location="${library.jar}"/>
+ <path refid="jarlister.classpath"/>
+ </path>
+
<path id="pack.bin.tool.path">
<pathelement location="${library.jar}"/>
<pathelement location="${xml.jar}"/>
@@ -1138,7 +1147,10 @@ TODO:
<!-- ===========================================================================
PACKED QUICK BUILD (PACK)
============================================================================ -->
- <target name="pack.lib" depends="quick.lib"> <staged-pack project="library"/></target>
+ <target name="pack.lib" depends="quick.lib"> <staged-pack project="library"/>
+ <taskdef resource="scala/tools/ant/antlib.xml" classpathref="pack.lib.path"/>
+ <jarlister file="${library.jar}"/>
+ </target>
<target name="pack.reflect" depends="quick.reflect"> <staged-pack project="reflect"/> </target>
diff --git a/project/Osgi.scala b/project/Osgi.scala
index 36803c0e44..9b00379760 100644
--- a/project/Osgi.scala
+++ b/project/Osgi.scala
@@ -1,6 +1,7 @@
import aQute.bnd.osgi.Builder
import aQute.bnd.osgi.Constants._
import java.util.Properties
+import java.util.jar.Attributes
import sbt._
import sbt.Keys._
import collection.JavaConverters._
@@ -16,6 +17,7 @@ object Osgi {
val bundleName = SettingKey[String]("osgiBundleName", "The Bundle-Name for the manifest.")
val bundleSymbolicName = SettingKey[String]("osgiBundleSymbolicName", "The Bundle-SymbolicName for the manifest.")
val headers = SettingKey[Seq[(String, String)]]("osgiHeaders", "Headers and processing instructions for BND.")
+ val jarlist = SettingKey[Boolean]("osgiJarlist", "List classes in manifest.")
def settings: Seq[Setting[_]] = Seq(
bundleName := description.value,
@@ -33,9 +35,10 @@ object Osgi {
"-eclipse" -> "false"
)
},
+ jarlist := false,
bundle <<= Def.task {
val res = (products in Compile in packageBin).value
- bundleTask(headers.value.toMap, (products in Compile in packageBin).value,
+ bundleTask(headers.value.toMap, jarlist.value, (products in Compile in packageBin).value,
(artifactPath in (Compile, packageBin)).value, res, streams.value)
},
packagedArtifact in (Compile, packageBin) <<= (artifact in (Compile, packageBin), bundle).identityMap,
@@ -48,7 +51,7 @@ object Osgi {
)
)
- def bundleTask(headers: Map[String, String], fullClasspath: Seq[File], artifactPath: File,
+ def bundleTask(headers: Map[String, String], jarlist: Boolean, fullClasspath: Seq[File], artifactPath: File,
resourceDirectories: Seq[File], streams: TaskStreams): File = {
val log = streams.log
val builder = new Builder
@@ -63,6 +66,12 @@ object Osgi {
builder.getWarnings.asScala.foreach(s => log.warn(s"bnd: $s"))
builder.getErrors.asScala.foreach(s => log.error(s"bnd: $s"))
IO.createDirectory(artifactPath.getParentFile)
+ if (jarlist) {
+ val entries = jar.getManifest.getEntries
+ for ((name, resource) <- jar.getResources.asScala if name.endsWith(".class")) {
+ entries.put(name, new Attributes)
+ }
+ }
jar.write(artifactPath)
artifactPath
}
diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala
index 930163af36..e9d1dfe4d2 100644
--- a/src/compiler/scala/tools/ant/Scalac.scala
+++ b/src/compiler/scala/tools/ant/Scalac.scala
@@ -575,8 +575,6 @@ class Scalac extends ScalaMatchingTask with ScalacShared {
settings.classpath.value = asString(getClasspath)
if (!sourcepath.isEmpty)
settings.sourcepath.value = asString(getSourcepath)
- else if (origin.get.size() > 0)
- settings.sourcepath.value = origin.get.list()(0)
if (!bootclasspath.isEmpty)
settings.bootclasspath.value = asString(getBootclasspath)
if (!extdirs.isEmpty) settings.extdirs.value = asString(getExtdirs)
diff --git a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala
index 24496fa013..bab612bad5 100644
--- a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala
+++ b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala
@@ -79,6 +79,7 @@ Other startup options:
-howtorun what to run <script|object|jar|guess> (default: guess)
-i <file> preload <file> before starting the repl
+ -I <file> preload <file>, enforcing line-by-line interpretation
-e <string> execute <string> as if entered in the repl
-save save the compiled script in a jar for future use
-nc no compilation daemon: do not use the fsc offline compiler
diff --git a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala
index c82ed68da8..113c02e558 100644
--- a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala
+++ b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala
@@ -21,9 +21,15 @@ class GenericRunnerSettings(error: String => Unit) extends Settings(error) {
val loadfiles =
MultiStringSetting(
+ "-I",
+ "file",
+ "load a file line-by-line")
+
+ val pastefiles =
+ MultiStringSetting(
"-i",
"file",
- "load a file (assumes the code is given interactively)")
+ "paste a file")
val execute =
StringSetting(
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index f59deafe1b..cf66e0a7dc 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -364,12 +364,15 @@ self =>
val stmts = parseStats()
def mainModuleName = newTermName(settings.script.value)
+
/* If there is only a single object template in the file and it has a
* suitable main method, we will use it rather than building another object
* around it. Since objects are loaded lazily the whole script would have
* been a no-op, so we're not taking much liberty.
*/
- def searchForMain(): Option[Tree] = {
+ def searchForMain(): Tree = {
+ import PartialFunction.cond
+
/* Have to be fairly liberal about what constitutes a main method since
* nothing has been typed yet - for instance we can't assume the parameter
* type will look exactly like "Array[String]" as it could have been renamed
@@ -379,11 +382,15 @@ self =>
case DefDef(_, nme.main, Nil, List(_), _, _) => true
case _ => false
}
- /* For now we require there only be one top level object. */
+ def isApp(t: Tree) = t match {
+ case Template(parents, _, _) => parents.exists(cond(_) { case Ident(tpnme.App) => true })
+ case _ => false
+ }
+ /* We allow only one main module. */
var seenModule = false
- val newStmts = stmts collect {
- case t @ Import(_, _) => t
- case md @ ModuleDef(mods, name, template) if !seenModule && (md exists isMainMethod) =>
+ var disallowed = EmptyTree: Tree
+ val newStmts = stmts.map {
+ case md @ ModuleDef(mods, name, template) if !seenModule && (isApp(template) || md.exists(isMainMethod)) =>
seenModule = true
/* This slightly hacky situation arises because we have no way to communicate
* back to the scriptrunner what the name of the program is. Even if we were
@@ -394,50 +401,63 @@ self =>
*/
if (name == mainModuleName) md
else treeCopy.ModuleDef(md, mods, mainModuleName, template)
- case _ =>
+ case md @ ModuleDef(_, _, _) => md
+ case cd @ ClassDef(_, _, _, _) => cd
+ case t @ Import(_, _) => t
+ case t =>
/* If we see anything but the above, fail. */
- return None
+ if (disallowed.isEmpty) disallowed = t
+ EmptyTree
+ }
+ if (disallowed.isEmpty) makeEmptyPackage(0, newStmts)
+ else {
+ if (seenModule)
+ warning(disallowed.pos.point, "Script has a main object but statement is disallowed")
+ EmptyTree
}
- Some(makeEmptyPackage(0, newStmts))
}
- if (mainModuleName == newTermName(ScriptRunner.defaultScriptMain))
- searchForMain() foreach { return _ }
+ def mainModule: Tree =
+ if (mainModuleName == newTermName(ScriptRunner.defaultScriptMain)) searchForMain() else EmptyTree
- /* Here we are building an AST representing the following source fiction,
- * where `moduleName` is from -Xscript (defaults to "Main") and <stmts> are
- * the result of parsing the script file.
- *
- * {{{
- * object moduleName {
- * def main(args: Array[String]): Unit =
- * new AnyRef {
- * stmts
- * }
- * }
- * }}}
- */
- def emptyInit = DefDef(
- NoMods,
- nme.CONSTRUCTOR,
- Nil,
- ListOfNil,
- TypeTree(),
- Block(List(Apply(gen.mkSuperInitCall, Nil)), literalUnit)
- )
-
- // def main
- def mainParamType = AppliedTypeTree(Ident(tpnme.Array), List(Ident(tpnme.String)))
- def mainParameter = List(ValDef(Modifiers(Flags.PARAM), nme.args, mainParamType, EmptyTree))
- def mainDef = DefDef(NoMods, nme.main, Nil, List(mainParameter), scalaDot(tpnme.Unit), gen.mkAnonymousNew(stmts))
-
- // object Main
- def moduleName = newTermName(ScriptRunner scriptMain settings)
- def moduleBody = Template(atInPos(scalaAnyRefConstr) :: Nil, noSelfType, List(emptyInit, mainDef))
- def moduleDef = ModuleDef(NoMods, moduleName, moduleBody)
-
- // package <empty> { ... }
- makeEmptyPackage(0, moduleDef :: Nil)
+ def repackaged: Tree = {
+ /* Here we are building an AST representing the following source fiction,
+ * where `moduleName` is from -Xscript (defaults to "Main") and <stmts> are
+ * the result of parsing the script file.
+ *
+ * {{{
+ * object moduleName {
+ * def main(args: Array[String]): Unit =
+ * new AnyRef {
+ * stmts
+ * }
+ * }
+ * }}}
+ */
+ def emptyInit = DefDef(
+ NoMods,
+ nme.CONSTRUCTOR,
+ Nil,
+ ListOfNil,
+ TypeTree(),
+ Block(List(Apply(gen.mkSuperInitCall, Nil)), literalUnit)
+ )
+
+ // def main
+ def mainParamType = AppliedTypeTree(Ident(tpnme.Array), List(Ident(tpnme.String)))
+ def mainParameter = List(ValDef(Modifiers(Flags.PARAM), nme.args, mainParamType, EmptyTree))
+ def mainDef = DefDef(NoMods, nme.main, Nil, List(mainParameter), scalaDot(tpnme.Unit), gen.mkAnonymousNew(stmts))
+
+ // object Main
+ def moduleName = newTermName(ScriptRunner scriptMain settings)
+ def moduleBody = Template(atInPos(scalaAnyRefConstr) :: Nil, noSelfType, List(emptyInit, mainDef))
+ def moduleDef = ModuleDef(NoMods, moduleName, moduleBody)
+
+ // package <empty> { ... }
+ makeEmptyPackage(0, moduleDef :: Nil)
+ }
+
+ mainModule orElse repackaged
}
/* --------------- PLACEHOLDERS ------------------------------------------- */
diff --git a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala
index 00771b6b8c..dfd5b07a3b 100644
--- a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala
+++ b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala
@@ -61,8 +61,8 @@ abstract class ScalaPrimitives {
final val NE = 43 // x != y
final val LT = 44 // x < y
final val LE = 45 // x <= y
- final val GE = 46 // x > y
- final val GT = 47 // x >= y
+ final val GT = 46 // x > y
+ final val GE = 47 // x >= y
// Boolean unary operations
final val ZNOT = 50 // !x
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
index 5d152ef0e8..d7106ae908 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
@@ -1110,22 +1110,19 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
}
/* Emit code to compare the two top-most stack values using the 'op' operator. */
- private def genCJUMP(success: asm.Label, failure: asm.Label, op: TestOp, tk: BType, targetIfNoJump: asm.Label) {
- if (targetIfNoJump == success) genCJUMP(failure, success, op.negate, tk, targetIfNoJump)
+ private def genCJUMP(success: asm.Label, failure: asm.Label, op: TestOp, tk: BType, targetIfNoJump: asm.Label, negated: Boolean = false) {
+ if (targetIfNoJump == success) genCJUMP(failure, success, op.negate, tk, targetIfNoJump, negated = !negated)
else {
if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
bc.emitIF_ICMP(op, success)
} else if (tk.isRef) { // REFERENCE(_) | ARRAY(_)
bc.emitIF_ACMP(op, success)
} else {
+ def useCmpG = if (negated) op == TestOp.GT || op == TestOp.GE else op == TestOp.LT || op == TestOp.LE
(tk: @unchecked) match {
case LONG => emit(asm.Opcodes.LCMP)
- case FLOAT =>
- if (op == TestOp.LT || op == TestOp.LE) emit(asm.Opcodes.FCMPG)
- else emit(asm.Opcodes.FCMPL)
- case DOUBLE =>
- if (op == TestOp.LT || op == TestOp.LE) emit(asm.Opcodes.DCMPG)
- else emit(asm.Opcodes.DCMPL)
+ case FLOAT => emit(if (useCmpG) asm.Opcodes.FCMPG else asm.Opcodes.FCMPL)
+ case DOUBLE => emit(if (useCmpG) asm.Opcodes.DCMPG else asm.Opcodes.DCMPL)
}
bc.emitIF(op, success)
}
@@ -1134,8 +1131,8 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
}
/* Emits code to compare (and consume) stack-top and zero using the 'op' operator */
- private def genCZJUMP(success: asm.Label, failure: asm.Label, op: TestOp, tk: BType, targetIfNoJump: asm.Label) {
- if (targetIfNoJump == success) genCZJUMP(failure, success, op.negate, tk, targetIfNoJump)
+ private def genCZJUMP(success: asm.Label, failure: asm.Label, op: TestOp, tk: BType, targetIfNoJump: asm.Label, negated: Boolean = false) {
+ if (targetIfNoJump == success) genCZJUMP(failure, success, op.negate, tk, targetIfNoJump, negated = !negated)
else {
if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
bc.emitIF(op, success)
@@ -1145,18 +1142,17 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
case TestOp.NE => bc emitIFNONNULL success
}
} else {
+ def useCmpG = if (negated) op == TestOp.GT || op == TestOp.GE else op == TestOp.LT || op == TestOp.LE
(tk: @unchecked) match {
case LONG =>
emit(asm.Opcodes.LCONST_0)
emit(asm.Opcodes.LCMP)
case FLOAT =>
emit(asm.Opcodes.FCONST_0)
- if (op == TestOp.LT || op == TestOp.LE) emit(asm.Opcodes.FCMPG)
- else emit(asm.Opcodes.FCMPL)
+ emit(if (useCmpG) asm.Opcodes.FCMPG else asm.Opcodes.FCMPL)
case DOUBLE =>
emit(asm.Opcodes.DCONST_0)
- if (op == TestOp.LT || op == TestOp.LE) emit(asm.Opcodes.DCMPG)
- else emit(asm.Opcodes.DCMPL)
+ emit(if (useCmpG) asm.Opcodes.DCMPG else asm.Opcodes.DCMPL)
}
bc.emitIF(op, success)
}
@@ -1171,8 +1167,8 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
case scalaPrimitives.NE => TestOp.NE
case scalaPrimitives.LT => TestOp.LT
case scalaPrimitives.LE => TestOp.LE
- case scalaPrimitives.GE => TestOp.GE
case scalaPrimitives.GT => TestOp.GT
+ case scalaPrimitives.GE => TestOp.GE
}
/** Some useful equality helpers. */
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
index a5744983b2..5a5747c81f 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
@@ -1336,6 +1336,7 @@ object BCodeHelpers {
}
object TestOp {
+ // the order here / op numbers are important to get the correct result when calling opcodeIF
val EQ = new TestOp(0)
val NE = new TestOp(1)
val LT = new TestOp(2)
diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
index 9d02228ab5..f2237a0716 100644
--- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
@@ -192,8 +192,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
extensionDefs(currentOwner.companionModule) = new mutable.ListBuffer[Tree]
currentOwner.primaryConstructor.makeNotPrivate(NoSymbol)
// SI-7859 make param accessors accessible so the erasure can generate unbox operations.
- val paramAccessors = currentOwner.info.decls.filter(sym => sym.isParamAccessor && sym.isMethod)
- paramAccessors.foreach(_.makeNotPrivate(currentOwner))
+ currentOwner.info.decls.foreach(sym => if (sym.isParamAccessor && sym.isMethod) sym.makeNotPrivate(currentOwner))
super.transform(tree)
} else if (currentOwner.isStaticOwner) {
super.transform(tree)
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index d519948a11..81a465ef2f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -539,8 +539,43 @@ trait ContextErrors {
def NamedAndDefaultArgumentsNotSupportedForMacros(tree: Tree, fun: Tree) =
NormalTypeError(tree, "macro applications do not support named and/or default arguments")
- def TooManyArgsNamesDefaultsError(tree: Tree, fun: Tree) =
- NormalTypeError(tree, "too many arguments for "+treeSymTypeMsg(fun))
+ def TooManyArgsNamesDefaultsError(tree: Tree, fun: Tree, formals: List[Type], args: List[Tree], namelessArgs: List[Tree], argPos: Array[Int]) = {
+ val expected = formals.size
+ val supplied = args.size
+ // pick a caret. For f(k=1,i=2,j=3), argPos[0,-1,1] b/c `k=1` taken as arg0
+ val excessive = {
+ val i = argPos.indexWhere(_ >= expected)
+ if (i < 0) tree else args(i min (supplied - 1))
+ }
+ val msg = {
+ val badappl = {
+ val excess = supplied - expected
+ val target = treeSymTypeMsg(fun)
+
+ if (expected == 0) s"no arguments allowed for nullary $target"
+ else if (excess < 3 && expected <= 5) s"too many arguments ($supplied) for $target"
+ else if (expected > 10) s"$supplied arguments but expected $expected for $target"
+ else {
+ val more =
+ if (excess == 1) "one more argument"
+ else if (excess > 0) s"$excess more arguments"
+ else "too many arguments"
+ s"$more than can be applied to $target"
+ }
+ }
+ val unknowns = (namelessArgs zip args) collect {
+ case (_: Assign, AssignOrNamedArg(Ident(name), _)) => name
+ }
+ val suppl =
+ unknowns.size match {
+ case 0 => ""
+ case 1 => s"\nNote that '${unknowns.head}' is not a parameter name of the invoked method."
+ case _ => unknowns.mkString("\nNote that '", "', '", "' are not parameter names of the invoked method.")
+ }
+ s"${badappl}${suppl}"
+ }
+ NormalTypeError(excessive, msg)
+ }
// can it still happen? see test case neg/overloaded-unapply.scala
def OverloadedUnapplyError(tree: Tree) =
@@ -552,7 +587,7 @@ trait ContextErrors {
def MultipleVarargError(tree: Tree) =
NormalTypeError(tree, "when using named arguments, the vararg parameter has to be specified exactly once")
- def ModuleUsingCompanionClassDefaultArgsErrror(tree: Tree) =
+ def ModuleUsingCompanionClassDefaultArgsError(tree: Tree) =
NormalTypeError(tree, "module extending its companion class cannot use default constructor arguments")
def NotEnoughArgsError(tree: Tree, fun: Tree, missing: List[Symbol]) = {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 8943ec810d..2773ee19cf 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -463,7 +463,7 @@ trait Namers extends MethodSynthesis {
// opening up the package object on the classpath at all if one exists in source.
if (m.isPackageObject) {
val packageScope = m.enclosingPackageClass.rawInfo.decls
- packageScope.filter(_.owner != m.enclosingPackageClass).toList.foreach(packageScope unlink _)
+ packageScope.foreach(mem => if (mem.owner != m.enclosingPackageClass) packageScope unlink mem)
}
updatePosFlags(m, tree.pos, moduleFlags)
setPrivateWithin(tree, m)
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 2d454c2fe6..d1764ea482 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -172,12 +172,12 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
// This has become noisy with implicit classes.
if (settings.warnPolyImplicitOverload && settings.developer) {
- clazz.info.decls filter (x => x.isImplicit && x.typeParams.nonEmpty) foreach { sym =>
+ clazz.info.decls.foreach(sym => if (sym.isImplicit && sym.typeParams.nonEmpty) {
// implicit classes leave both a module symbol and a method symbol as residue
val alts = clazz.info.decl(sym.name).alternatives filterNot (_.isModule)
if (alts.size > 1)
alts foreach (x => reporter.warning(x.pos, "parameterized overloaded implicit methods are not visible as view bounds"))
- }
+ })
}
}
@@ -1659,24 +1659,32 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
// inside annotations.
applyRefchecksToAnnotations(tree)
var result: Tree = tree match {
- case DefDef(_, _, _, _, _, EmptyTree) if sym hasAnnotation NativeAttr =>
- sym resetFlag DEFERRED
- transform(deriveDefDef(tree)(_ => typed(gen.mkSysErrorCall("native method stub"))))
-
- case ValDef(_, _, _, _) | DefDef(_, _, _, _, _, _) =>
+ case vod: ValOrDefDef =>
checkDeprecatedOvers(tree)
- checkInfiniteLoop(tree.asInstanceOf[ValOrDefDef])
+ checkInfiniteLoop(vod)
if (settings.warnNullaryUnit)
checkNullaryMethodReturnType(sym)
if (settings.warnInaccessible) {
if (!sym.isConstructor && !sym.isEffectivelyFinalOrNotOverridden && !sym.isSynthetic)
checkAccessibilityOfReferencedTypes(tree)
}
- tree match {
- case dd: DefDef => checkByNameRightAssociativeDef(dd)
- case _ =>
+ vod match {
+ case dd: DefDef =>
+ checkByNameRightAssociativeDef(dd)
+
+ if (sym hasAnnotation NativeAttr) {
+ if (sym.owner.isTrait) {
+ reporter.error(tree.pos, "A trait cannot define a native method.")
+ tree
+ } else if (dd.rhs == EmptyTree) {
+ // pretend it had a stub implementation
+ sym resetFlag DEFERRED
+ deriveDefDef(dd)(_ => typed(gen.mkSysErrorCall("native method stub")))
+ } else tree
+ } else tree
+
+ case _ => tree
}
- tree
case Template(parents, self, body) =>
localTyper = localTyper.atOwner(tree, currentOwner)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index dcf14612c9..9fa3564b2b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2068,35 +2068,39 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case _ =>
(call, Nil)
}
- val (superConstr, superArgs) = decompose(rhs)
- assert(superConstr.symbol ne null, superConstr)//debug
- def superClazz = superConstr.symbol.owner
- def superParamAccessors = superClazz.constrParamAccessors
// associate superclass paramaccessors with their aliases
- if (superConstr.symbol.isPrimaryConstructor && !superClazz.isJavaDefined && sameLength(superParamAccessors, superArgs)) {
- for ((superAcc, superArg @ Ident(name)) <- superParamAccessors zip superArgs) {
- if (mexists(vparamss)(_.symbol == superArg.symbol)) {
- val alias = (
- superAcc.initialize.alias
- orElse (superAcc getterIn superAcc.owner)
- filter (alias => superClazz.info.nonPrivateMember(alias.name) == alias)
- )
- if (alias.exists && !alias.accessed.isVariable && !isRepeatedParamType(alias.accessed.info)) {
- val ownAcc = clazz.info decl name suchThat (_.isParamAccessor) match {
- case acc if !acc.isDeferred && acc.hasAccessorFlag => acc.accessed
- case acc => acc
- }
- ownAcc match {
- case acc: TermSymbol if !acc.isVariable && !isByNameParamType(acc.info) =>
- debuglog(s"$acc has alias ${alias.fullLocationString}")
- acc setAlias alias
- case _ =>
+ val (superConstr, superArgs) = decompose(rhs)
+ if (superConstr.symbol.isPrimaryConstructor) {
+ val superClazz = superConstr.symbol.owner
+ if (!superClazz.isJavaDefined) {
+ val superParamAccessors = superClazz.constrParamAccessors
+ if (sameLength(superParamAccessors, superArgs)) {
+ for ((superAcc, superArg@Ident(name)) <- superParamAccessors zip superArgs) {
+ if (mexists(vparamss)(_.symbol == superArg.symbol)) {
+ val alias = (
+ superAcc.initialize.alias
+ orElse (superAcc getterIn superAcc.owner)
+ filter (alias => superClazz.info.nonPrivateMember(alias.name) == alias)
+ )
+ if (alias.exists && !alias.accessed.isVariable && !isRepeatedParamType(alias.accessed.info)) {
+ val ownAcc = clazz.info decl name suchThat (_.isParamAccessor) match {
+ case acc if !acc.isDeferred && acc.hasAccessorFlag => acc.accessed
+ case acc => acc
+ }
+ ownAcc match {
+ case acc: TermSymbol if !acc.isVariable && !isByNameParamType(acc.info) =>
+ debuglog(s"$acc has alias ${alias.fullLocationString}")
+ acc setAlias alias
+ case _ =>
+ }
+ }
}
}
}
}
}
+
pending.foreach(ErrorUtils.issueTypeError)
}
@@ -2391,19 +2395,20 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
// The block is an anonymous class definitions/instantiation pair
// -> members that are hidden by the type of the block are made private
- val toHide = (
- classDecls filter (member =>
- member.isTerm
- && member.isPossibleInRefinement
- && member.isPublic
- && !matchesVisibleMember(member)
- ) map (member => member
- resetFlag (PROTECTED | LOCAL)
- setFlag (PRIVATE | SYNTHETIC_PRIVATE)
- setPrivateWithin NoSymbol
- )
- )
- syntheticPrivates ++= toHide
+ classDecls foreach { toHide =>
+ if (toHide.isTerm
+ && toHide.isPossibleInRefinement
+ && toHide.isPublic
+ && !matchesVisibleMember(toHide)) {
+ (toHide
+ resetFlag (PROTECTED | LOCAL)
+ setFlag (PRIVATE | SYNTHETIC_PRIVATE)
+ setPrivateWithin NoSymbol)
+
+ syntheticPrivates += toHide
+ }
+ }
+
case _ =>
}
}
@@ -3332,7 +3337,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// #2064
duplErrorTree(WrongNumberOfArgsError(tree, fun))
} else if (lencmp > 0) {
- tryTupleApply orElse duplErrorTree(TooManyArgsNamesDefaultsError(tree, fun))
+ tryTupleApply orElse duplErrorTree {
+ val (namelessArgs, argPos) = removeNames(Typer.this)(args, params)
+ TooManyArgsNamesDefaultsError(tree, fun, formals, args, namelessArgs, argPos)
+ }
} else if (lencmp == 0) {
// we don't need defaults. names were used, so this application is transformed
// into a block (@see transformNamedApplication in NamesDefaults)
@@ -3396,7 +3404,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val lencmp2 = compareLengths(allArgs, formals)
if (!sameLength(allArgs, args) && callToCompanionConstr(context, funSym)) {
- duplErrorTree(ModuleUsingCompanionClassDefaultArgsErrror(tree))
+ duplErrorTree(ModuleUsingCompanionClassDefaultArgsError(tree))
} else if (lencmp2 > 0) {
removeNames(Typer.this)(allArgs, params) // #3818
duplErrTree
@@ -3641,10 +3649,12 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
reportAnnotationError(MultipleArgumentListForAnnotationError(ann))
}
else {
- val annScope = annType.decls
- .filter(sym => sym.isMethod && !sym.isConstructor && sym.isJavaDefined)
+ val annScopeJava =
+ if (isJava) annType.decls.filter(sym => sym.isMethod && !sym.isConstructor && sym.isJavaDefined)
+ else EmptyScope // annScopeJava is only used if isJava
+
val names = mutable.Set[Symbol]()
- names ++= (if (isJava) annScope.iterator
+ names ++= (if (isJava) annScopeJava.iterator
else typedFun.tpe.params.iterator)
def hasValue = names exists (_.name == nme.value)
@@ -3655,7 +3665,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val nvPairs = args map {
case arg @ AssignOrNamedArg(Ident(name), rhs) =>
- val sym = if (isJava) annScope.lookup(name)
+ val sym = if (isJava) annScopeJava.lookup(name)
else findSymbol(typedFun.tpe.params)(_.name == name)
if (sym == NoSymbol) {
reportAnnotationError(UnknownAnnotationNameError(arg, name))
diff --git a/src/library/scala/collection/immutable/HashMap.scala b/src/library/scala/collection/immutable/HashMap.scala
index eac9c14f3f..6b29b084aa 100644
--- a/src/library/scala/collection/immutable/HashMap.scala
+++ b/src/library/scala/collection/immutable/HashMap.scala
@@ -201,7 +201,7 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int {
if (this.value.asInstanceOf[AnyRef] eq value.asInstanceOf[AnyRef]) this
else new HashMap1(key, hash, value, kv)
} else {
- val nkv = merger(this.kv, kv)
+ val nkv = merger(this.ensurePair, if(kv != null) kv else (key, value))
new HashMap1(nkv._1, hash, nkv._2, nkv)
}
} else {
diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala
index 0c24d17c15..2e56750115 100644
--- a/src/library/scala/collection/immutable/Range.scala
+++ b/src/library/scala/collection/immutable/Range.scala
@@ -81,8 +81,7 @@ extends scala.collection.AbstractSeq[Int]
|| (start == end && !isInclusive)
)
- @deprecated("this method will be made private, use `length` instead", "2.11.0")
- final val numRangeElements: Int = {
+ private val numRangeElements: Int = {
if (step == 0) throw new IllegalArgumentException("step cannot be 0.")
else if (isEmpty) 0
else {
@@ -92,21 +91,16 @@ extends scala.collection.AbstractSeq[Int]
}
}
- @deprecated("this method will be made private, use `last` instead", "2.11.0")
- final val lastElement =
- if (isEmpty) start - step
- else step match {
- case 1 => if (isInclusive) end else end-1
- case -1 => if (isInclusive) end else end+1
- case _ =>
- val remainder = (gap % step).toInt
- if (remainder != 0) end - remainder
- else if (isInclusive) end
- else end - step
- }
-
- @deprecated("this method will be made private", "2.11.0")
- final val terminalElement = lastElement + step
+ // This field has a sensible value only for non-empty ranges
+ private val lastElement = step match {
+ case 1 => if (isInclusive) end else end-1
+ case -1 => if (isInclusive) end else end+1
+ case _ =>
+ val remainder = (gap % step).toInt
+ if (remainder != 0) end - remainder
+ else if (isInclusive) end
+ else end - step
+ }
/** The last element of this range. This method will return the correct value
* even if there are too many elements to iterate over.
diff --git a/src/library/scala/collection/immutable/StringLike.scala b/src/library/scala/collection/immutable/StringLike.scala
index b468b09a9d..155d25d933 100644
--- a/src/library/scala/collection/immutable/StringLike.scala
+++ b/src/library/scala/collection/immutable/StringLike.scala
@@ -286,31 +286,39 @@ self =>
def r(groupNames: String*): Regex = new Regex(toString, groupNames: _*)
/**
- * @throws java.lang.IllegalArgumentException - If the string does not contain a parsable boolean.
+ * @throws java.lang.IllegalArgumentException If the string does not contain a parsable `Boolean`.
*/
def toBoolean: Boolean = parseBoolean(toString)
/**
- * @throws java.lang.NumberFormatException - If the string does not contain a parsable byte.
+ * Parse as a `Byte` (string must contain only decimal digits and optional leading `-`).
+ * @throws java.lang.NumberFormatException If the string does not contain a parsable `Byte`.
*/
def toByte: Byte = java.lang.Byte.parseByte(toString)
/**
- * @throws java.lang.NumberFormatException - If the string does not contain a parsable short.
+ * Parse as a `Short` (string must contain only decimal digits and optional leading `-`).
+ * @throws java.lang.NumberFormatException If the string does not contain a parsable `Short`.
*/
def toShort: Short = java.lang.Short.parseShort(toString)
/**
- * @throws java.lang.NumberFormatException - If the string does not contain a parsable int.
+ * Parse as an `Int` (string must contain only decimal digits and optional leading `-`).
+ * @throws java.lang.NumberFormatException If the string does not contain a parsable `Int`.
*/
def toInt: Int = java.lang.Integer.parseInt(toString)
/**
- * @throws java.lang.NumberFormatException - If the string does not contain a parsable long.
+ * Parse as a `Long` (string must contain only decimal digits and optional leading `-`).
+ * @throws java.lang.NumberFormatException If the string does not contain a parsable `Long`.
*/
def toLong: Long = java.lang.Long.parseLong(toString)
/**
- * @throws java.lang.NumberFormatException - If the string does not contain a parsable float.
+ * Parse as a `Float` (surrounding whitespace is removed with a `trim`).
+ * @throws java.lang.NumberFormatException If the string does not contain a parsable `Float`.
+ * @throws java.lang.NullPointerException If the string is null.
*/
def toFloat: Float = java.lang.Float.parseFloat(toString)
/**
- * @throws java.lang.NumberFormatException - If the string does not contain a parsable double.
+ * Parse as a `Double` (surrounding whitespace is removed with a `trim`).
+ * @throws java.lang.NumberFormatException If the string does not contain a parsable `Double`.
+ * @throws java.lang.NullPointerException If the string is null.
*/
def toDouble: Double = java.lang.Double.parseDouble(toString)
diff --git a/src/library/scala/collection/mutable/OpenHashMap.scala b/src/library/scala/collection/mutable/OpenHashMap.scala
index 5bea1634c4..ca08f475ce 100644
--- a/src/library/scala/collection/mutable/OpenHashMap.scala
+++ b/src/library/scala/collection/mutable/OpenHashMap.scala
@@ -115,9 +115,8 @@ extends AbstractMap[Key, Value]
* @param hash hash value for `key`
*/
private[this] def findIndex(key: Key, hash: Int): Int = {
- var j = hash
var index = hash & mask
- var perturb = index
+ var j = 0
/** Index of the first slot containing a deleted entry, or -1 if none found yet. */
var firstDeletedIndex = -1
@@ -130,9 +129,8 @@ extends AbstractMap[Key, Value]
if (firstDeletedIndex == -1 && entry.value == None)
firstDeletedIndex = index
- j = 5 * j + 1 + perturb
- perturb >>= 5
- index = j & mask
+ j += 1
+ index = (index + j) & mask
entry = table(index)
}
@@ -197,20 +195,17 @@ extends AbstractMap[Key, Value]
def get(key : Key) : Option[Value] = {
val hash = hashOf(key)
-
- var j = hash
var index = hash & mask
- var perturb = index
var entry = table(index)
+ var j = 0
while(entry != null){
if (entry.hash == hash &&
entry.key == key){
return entry.value
}
- j = 5 * j + 1 + perturb
- perturb >>= 5
- index = j & mask
+ j += 1
+ index = (index + j) & mask
entry = table(index)
}
None
diff --git a/src/library/scala/native.scala b/src/library/scala/native.scala
index dbacc78618..49d3ced805 100644
--- a/src/library/scala/native.scala
+++ b/src/library/scala/native.scala
@@ -16,8 +16,11 @@ package scala
* @native def f(x: Int, y: List[Long]): String = ...
* }}}
*
- * Method body is not generated if method is marked with `@native`,
- * but it is type checked when present.
+ * A `@native` method is compiled to the platform's native method,
+ * while discarding the method's body (if any). The body will be type checked if present.
*
- * @since 2.6 */
+ * A method marked @native must be a member of a class, not a trait (since 2.12).
+ *
+ * @since 2.6
+ */
class native extends scala.annotation.StaticAnnotation {}
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index ca6c893d13..fe6d88e7c7 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -863,12 +863,13 @@ trait Definitions extends api.StandardDefinitions {
// Scopes()
// must filter out "universal" members (getClass is deferred for some reason)
val deferredMembers = (
- tp membersBasedOnFlags (excludedFlags = BridgeAndPrivateFlags, requiredFlags = METHOD)
- filter (mem => mem.isDeferredNotJavaDefault && !isUniversalMember(mem)) // TODO: test
+ tp.membersBasedOnFlags(excludedFlags = BridgeAndPrivateFlags, requiredFlags = METHOD).toList.filter(
+ mem => mem.isDeferredNotJavaDefault && !isUniversalMember(mem)
+ ) // TODO: test
)
// if there is only one, it's monomorphic and has a single argument list
- if (deferredMembers.size == 1 &&
+ if (deferredMembers.lengthCompare(1) == 0 &&
deferredMembers.head.typeParams.isEmpty &&
deferredMembers.head.info.paramSectionCount == 1)
deferredMembers.head
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index c93ecac3fa..20a485469d 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -240,6 +240,7 @@ trait StdNames {
final val Any: NameType = "Any"
final val AnyVal: NameType = "AnyVal"
+ final val App: NameType = "App"
final val FlagSet: NameType = "FlagSet"
final val Mirror: NameType = "Mirror"
final val Modifiers: NameType = "Modifiers"
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 3b886d357f..ba195363c1 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -2036,11 +2036,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
}
}
- private final def caseFieldAccessorsUnsorted: List[Symbol] =
- (info.decls filter (_.isCaseAccessorMethod)).toList
+ private final def caseFieldAccessorsUnsorted: List[Symbol] = info.decls.toList.filter(_.isCaseAccessorMethod)
- final def constrParamAccessors: List[Symbol] =
- info.decls.filter(sym => !sym.isMethod && sym.isParamAccessor).toList
+ final def constrParamAccessors: List[Symbol] = info.decls.toList.filter(sym => !sym.isMethod && sym.isParamAccessor)
/** The symbol accessed by this accessor (getter or setter) function. */
final def accessed: Symbol = {
diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
index 56d62f3efc..66a5f08e96 100644
--- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
@@ -1,5 +1,5 @@
/* NSC -- new Scala compiler
- * Copyright 2005-2015 LAMP/EPFL
+ * Copyright 2005-2016 LAMP/EPFL
* @author Alexander Spoon
*/
package scala
@@ -15,7 +15,7 @@ import scala.tools.asm.ClassReader
import scala.util.Properties.jdkHome
import scala.tools.nsc.util.{ ClassPath, stringFromStream }
import scala.reflect.classTag
-import scala.reflect.internal.util.{ BatchSourceFile, ScalaClassLoader }
+import scala.reflect.internal.util.{ BatchSourceFile, ScalaClassLoader, NoPosition }
import ScalaClassLoader._
import scala.reflect.io.File
import scala.tools.util._
@@ -174,10 +174,19 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
echo("\n" + msg)
in.redrawLine()
}
- protected def echo(msg: String) = {
+ protected var mum = false
+ protected def echo(msg: String) = if (!mum) {
out println msg
out.flush()
}
+ // turn off intp reporter and our echo
+ def mumly[A](op: => A): A =
+ if (isReplDebug) op
+ else intp beQuietDuring {
+ val saved = mum
+ mum = true
+ try op finally mum = saved
+ }
/** Search the history */
def searchHistory(_cmdline: String) {
@@ -406,12 +415,13 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
* command() for each line of input, and stops when
* command() returns false.
*/
- @tailrec final def loop(): LineResult = {
+ final def loop(): LineResult = loop(readOneLine())
+
+ @tailrec final def loop(line: String): LineResult = {
import LineResults._
- readOneLine() match {
- case null => EOF
- case line => if (try processLine(line) catch crashRecovery) loop() else ERR
- }
+ if (line == null) EOF
+ else if (try processLine(line) catch crashRecovery) loop(readOneLine())
+ else ERR
}
/** interpret all lines from a specified file */
@@ -480,11 +490,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
def editCommand(what: String): Result = editCommand(what, Properties.envOrNone("EDITOR"))
def editCommand(what: String, editor: Option[String]): Result = {
- def diagnose(code: String) = {
- echo("The edited code is incomplete!\n")
- val errless = intp compileSources new BatchSourceFile("<pastie>", s"object pastel {\n$code\n}")
- if (errless) echo("The compiler reports no errors.")
- }
+ def diagnose(code: String): Unit = paste.incomplete("The edited code is incomplete!\n", "<edited>", code)
def edit(text: String): Result = editor match {
case Some(ed) =>
@@ -563,9 +569,9 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
}
}
- def withFile[A](filename: String)(action: File => A): Option[A] = {
+ def withFile[A](filename: String)(action: File => A): Option[A] = intp.withLabel(filename) {
val res = Some(File(filename)) filter (_.exists) map action
- if (res.isEmpty) echo("That file does not exist") // courtesy side-effect
+ if (res.isEmpty) intp.reporter.warning(NoPosition, s"File `$filename' does not exist.") // courtesy side-effect
res
}
@@ -702,6 +708,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
*/
def pasteCommand(arg: String): Result = {
var shouldReplay: Option[String] = None
+ var label = "<pastie>"
def result = Result(keepRunning = true, shouldReplay)
val (raw, file, margin) =
if (arg.isEmpty) (false, None, None)
@@ -722,6 +729,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
}
val code = (file, margin) match {
case (Some(name), None) =>
+ label = name
withFile(name) { f =>
shouldReplay = Some(s":paste $arg")
val s = f.slurp.trim
@@ -744,21 +752,13 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
text
}
def interpretCode() = {
- val res = intp interpret code
- // if input is incomplete, let the compiler try to say why
- if (res == IR.Incomplete) {
- echo("The pasted code is incomplete!\n")
- // Remembrance of Things Pasted in an object
- val errless = intp compileSources new BatchSourceFile("<pastie>", s"object pastel {\n$code\n}")
- if (errless) echo("...but compilation found no error? Good luck with that.")
- }
- }
- def compileCode() = {
- val errless = intp compileSources new BatchSourceFile("<pastie>", code)
- if (!errless) echo("There were compilation errors!")
+ if (intp.withLabel(label)(intp interpret code) == IR.Incomplete)
+ paste.incomplete("The pasted code is incomplete!\n", label, code)
}
+ def compileCode() = paste.compilePaste(label = label, code = code)
+
if (code.nonEmpty) {
- if (raw) compileCode() else interpretCode()
+ if (raw || paste.isPackaged(code)) compileCode() else interpretCode()
}
result
}
@@ -766,6 +766,27 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
private object paste extends Pasted(prompt) {
def interpret(line: String) = intp interpret line
def echo(message: String) = ILoop.this echo message
+
+ val leadingElement = raw"(?s)\s*(package\s|/)".r
+ def isPackaged(code: String): Boolean = {
+ leadingElement.findPrefixMatchOf(code)
+ .map(m => if (m.group(1) == "/") intp.parse.packaged(code) else true)
+ .getOrElse(false)
+ }
+
+ // if input is incomplete, wrap and compile for diagnostics.
+ def incomplete(message: String, label: String, code: String): Boolean = {
+ echo(message)
+ val errless = intp.compileSources(new BatchSourceFile(label, s"object pastel {\n$code\n}"))
+ if (errless) echo("No error found in incomplete source.")
+ errless
+ }
+
+ def compilePaste(label: String, code: String): Boolean = {
+ val errless = intp.compileSources(new BatchSourceFile(label, code))
+ if (!errless) echo("There were compilation errors!")
+ errless
+ }
}
private object invocation {
@@ -826,19 +847,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
}
}
- // runs :load `file` on any files passed via -i
- def loadFiles(settings: Settings) = settings match {
- case settings: GenericRunnerSettings =>
- for (filename <- settings.loadfiles.value) {
- val cmd = ":load " + filename
- command(cmd)
- addReplay(cmd)
- echo("")
- }
- case _ =>
- }
-
- /** Tries to create a JLineReader, falling back to SimpleReader,
+ /** Tries to create a jline.InteractiveReader, falling back to SimpleReader,
* unless settings or properties are such that it should start with SimpleReader.
* The constructor of the InteractiveReader must take a Completion strategy,
* supplied as a `() => Completion`; the Completion object provides a concrete Completer.
@@ -877,49 +886,115 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
}
}
- private def loopPostInit() {
- // Bind intp somewhere out of the regular namespace where
- // we can get at it in generated code.
- intp.quietBind(NamedParam[IMain]("$intp", intp)(tagOfIMain, classTag[IMain]))
- // Auto-run code via some setting.
- ( replProps.replAutorunCode.option
- flatMap (f => io.File(f).safeSlurp())
- foreach (intp quietRun _)
- )
- // classloader and power mode setup
- intp.setContextClassLoader()
- if (isReplPower) {
- replProps.power setValue true
- unleashAndSetPhase()
- asyncMessage(power.banner)
- }
- // SI-7418 Now, and only now, can we enable TAB completion.
- in.postInit()
- }
-
- // start an interpreter with the given settings
+ /** Start an interpreter with the given settings.
+ * @return true if successful
+ */
def process(settings: Settings): Boolean = savingContextLoader {
- this.settings = settings
- createInterpreter()
+ def newReader = in0.fold(chooseReader(settings))(r => SimpleReader(r, out, interactive = true))
- // sets in to some kind of reader depending on environmental cues
- in = in0.fold(chooseReader(settings))(r => SimpleReader(r, out, interactive = true))
- globalFuture = Future {
- intp.initializeSynchronous()
- loopPostInit()
- !intp.reporter.hasErrors
+ /** Reader to use before interpreter is online. */
+ def preLoop = {
+ val sr = SplashReader(newReader) { r =>
+ in = r
+ in.postInit()
+ }
+ in = sr
+ SplashLoop(sr, prompt)
}
- loadFiles(settings)
- printWelcome()
- try loop() match {
- case LineResults.EOF => out print Properties.shellInterruptedString
- case _ =>
+ /* Actions to cram in parallel while collecting first user input at prompt.
+ * Run with output muted both from ILoop and from the intp reporter.
+ */
+ def loopPostInit(): Unit = mumly {
+ // Bind intp somewhere out of the regular namespace where
+ // we can get at it in generated code.
+ intp.quietBind(NamedParam[IMain]("$intp", intp)(tagOfIMain, classTag[IMain]))
+
+ // Auto-run code via some setting.
+ ( replProps.replAutorunCode.option
+ flatMap (f => File(f).safeSlurp())
+ foreach (intp quietRun _)
+ )
+ // power mode setup
+ if (isReplPower) {
+ replProps.power setValue true
+ unleashAndSetPhase()
+ asyncMessage(power.banner)
+ }
+ loadInitFiles()
+ // SI-7418 Now, and only now, can we enable TAB completion.
+ in.postInit()
+ }
+ def loadInitFiles(): Unit = settings match {
+ case settings: GenericRunnerSettings =>
+ for (f <- settings.loadfiles.value) {
+ loadCommand(f)
+ addReplay(s":load $f")
+ }
+ for (f <- settings.pastefiles.value) {
+ pasteCommand(f)
+ addReplay(s":paste $f")
+ }
+ case _ =>
+ }
+ // wait until after startup to enable noisy settings
+ def withSuppressedSettings[A](body: => A): A = {
+ val ss = this.settings
+ import ss._
+ val noisy = List(Xprint, Ytyperdebug)
+ val noisesome = noisy.exists(!_.isDefault)
+ val current = (Xprint.value, Ytyperdebug.value)
+ if (isReplDebug || !noisesome) body
+ else {
+ this.settings.Xprint.value = List.empty
+ this.settings.Ytyperdebug.value = false
+ try body
+ finally {
+ Xprint.value = current._1
+ Ytyperdebug.value = current._2
+ intp.global.printTypings = current._2
+ }
+ }
}
- catch AbstractOrMissingHandler()
- finally closeInterpreter()
+ def startup(): String = withSuppressedSettings {
+ // starting
+ printWelcome()
+
+ // let them start typing
+ val splash = preLoop
+ splash.start()
- true
+ // while we go fire up the REPL
+ try {
+ createInterpreter()
+ intp.initializeSynchronous()
+ globalFuture = Future successful true
+ if (intp.reporter.hasErrors) {
+ echo("Interpreter encountered errors during initialization!")
+ null
+ } else {
+ loopPostInit()
+ val line = splash.line // what they typed in while they were waiting
+ if (line == null) { // they ^D
+ try out print Properties.shellInterruptedString
+ finally closeInterpreter()
+ }
+ line
+ }
+ } finally splash.stop()
+ }
+ this.settings = settings
+ startup() match {
+ case null => false
+ case line =>
+ try loop(line) match {
+ case LineResults.EOF => out print Properties.shellInterruptedString
+ case _ =>
+ }
+ catch AbstractOrMissingHandler()
+ finally closeInterpreter()
+ true
+ }
}
@deprecated("Use `process` instead", "2.9.0")
diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala
index 763a8ccd1b..44784aa953 100644
--- a/src/repl/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala
@@ -1,5 +1,5 @@
/* NSC -- new Scala compiler
- * Copyright 2005-2013 LAMP/EPFL
+ * Copyright 2005-2016 LAMP/EPFL
* @author Martin Odersky
*/
@@ -69,13 +69,14 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
lazy val isClassBased: Boolean = settings.Yreplclassbased.value
- private[nsc] var printResults = true // whether to print result lines
- private[nsc] var totalSilence = false // whether to print anything
- private var _initializeComplete = false // compiler is initialized
- private var _isInitialized: Future[Boolean] = null // set up initialization future
- private var bindExceptions = true // whether to bind the lastException variable
- private var _executionWrapper = "" // code to be wrapped around all lines
- var partialInput: String = "" // code accumulated in multi-line REPL input
+ private[nsc] var printResults = true // whether to print result lines
+ private[nsc] var totalSilence = false // whether to print anything
+ private var _initializeComplete = false // compiler is initialized
+ private var _isInitialized: Future[Boolean] = null // set up initialization future
+ private var bindExceptions = true // whether to bind the lastException variable
+ private var _executionWrapper = "" // code to be wrapped around all lines
+ var partialInput: String = "" // code accumulated in multi-line REPL input
+ private var label = "<console>" // compilation unit name for reporting
/** We're going to go to some trouble to initialize the compiler asynchronously.
* It's critical that nothing call into it until it's been initialized or we will
@@ -103,6 +104,12 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
try body
finally if (!saved) settings.nowarn.value = false
}
+ // Apply a temporary label for compilation (for example, script name)
+ def withLabel[A](temp: String)(body: => A): A = {
+ val saved = label
+ label = temp
+ try body finally label = saved
+ }
// the expanded prompt but without color escapes and without leading newline, for purposes of indenting
lazy val formatting = Formatting.forPrompt(replProps.promptText)
@@ -749,7 +756,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
case Right(result) => Right(result)
}
- def compile(source: String): Boolean = compileAndSaveRun("<console>", source)
+ def compile(source: String): Boolean = compileAndSaveRun(label, source)
/** The innermost object inside the wrapper, found by
* following accessPath into the outer one.
@@ -1094,17 +1101,27 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
case class Incomplete(trees: List[Tree]) extends Result
case class Success(trees: List[Tree]) extends Result
- def apply(line: String): Result = debugging(s"""parse("$line")""") {
+ def apply(line: String): Result = debugging(s"""parse("$line")""") {
var isIncomplete = false
def parse = {
reporter.reset()
- val trees = newUnitParser(line).parseStats()
+ val trees = newUnitParser(line, label).parseStats()
if (reporter.hasErrors) Error(trees)
else if (isIncomplete) Incomplete(trees)
else Success(trees)
}
- currentRun.parsing.withIncompleteHandler((_, _) => isIncomplete = true) {parse}
-
+ currentRun.parsing.withIncompleteHandler((_, _) => isIncomplete = true)(parse)
+ }
+ // code has a named package
+ def packaged(line: String): Boolean = {
+ def parses = {
+ reporter.reset()
+ val tree = newUnitParser(line).parse()
+ !reporter.hasErrors && {
+ tree match { case PackageDef(Ident(id), _) => id != nme.EMPTY_PACKAGE_NAME case _ => false }
+ }
+ }
+ beSilentDuring(parses)
}
}
diff --git a/src/repl/scala/tools/nsc/interpreter/InteractiveReader.scala b/src/repl/scala/tools/nsc/interpreter/InteractiveReader.scala
index 71753a3e39..1f81d9965c 100644
--- a/src/repl/scala/tools/nsc/interpreter/InteractiveReader.scala
+++ b/src/repl/scala/tools/nsc/interpreter/InteractiveReader.scala
@@ -50,3 +50,98 @@ object InteractiveReader {
def createDefault(): InteractiveReader = apply() // used by sbt
}
+/** Collect one line of user input from the supplied reader.
+ * Runs on a new thread while the REPL is initializing on the main thread.
+ *
+ * The user can enter text or a `:paste` command.
+ */
+class SplashLoop(reader: InteractiveReader, prompt: String) extends Runnable {
+ import java.util.concurrent.SynchronousQueue
+ import scala.compat.Platform.EOL
+
+ private val result = new SynchronousQueue[Option[String]]
+ @volatile private var running: Boolean = _
+ private var thread: Thread = _
+
+ /** Read one line of input which can be retrieved with `line`. */
+ def run(): Unit = {
+ var line = ""
+ try
+ do {
+ line = reader.readLine(prompt)
+ if (line != null) {
+ line = process(line.trim)
+ }
+ } while (line != null && line.isEmpty && running)
+ finally {
+ result.put(Option(line))
+ }
+ }
+
+ /** Check for `:paste` command. */
+ private def process(line: String): String = {
+ def isPrefix(s: String, p: String, n: Int) = (
+ //s != null && p.inits.takeWhile(_.length >= n).exists(s == _)
+ s != null && s.length >= n && s.length <= p.length && s == p.take(s.length)
+ )
+ if (isPrefix(line, ":paste", 3)) {
+ // while collecting lines, check running flag
+ var help = f"// Entering paste mode (ctrl-D to finish)%n%n"
+ def readWhile(cond: String => Boolean) = {
+ Iterator continually reader.readLine(help) takeWhile { x =>
+ help = ""
+ x != null && cond(x)
+ }
+ }
+ val text = (readWhile(_ => running) mkString EOL).trim
+ val next =
+ if (text.isEmpty) "// Nothing pasted, nothing gained."
+ else "// Exiting paste mode, now interpreting."
+ Console println f"%n${next}%n"
+ text
+ } else {
+ line
+ }
+ }
+
+ def start(): Unit = result.synchronized {
+ require(thread == null, "Already started")
+ thread = new Thread(this)
+ running = true
+ thread.start()
+ }
+
+ def stop(): Unit = result.synchronized {
+ running = false
+ if (thread != null) thread.interrupt()
+ thread = null
+ }
+
+ /** Block for the result line, or null on ctl-D. */
+ def line: String = result.take getOrElse null
+}
+object SplashLoop {
+ def apply(reader: SplashReader, prompt: String): SplashLoop = new SplashLoop(reader, prompt)
+}
+
+/** Reader during splash. Handles splash-completion with a stub, otherwise delegates. */
+class SplashReader(reader: InteractiveReader, postIniter: InteractiveReader => Unit) extends InteractiveReader {
+ /** Invoke the postInit action with the underlying reader. */
+ override def postInit(): Unit = postIniter(reader)
+
+ override val interactive: Boolean = reader.interactive
+
+ override def reset(): Unit = reader.reset()
+ override def history: History = reader.history
+ override val completion: Completion = NoCompletion
+ override def redrawLine(): Unit = reader.redrawLine()
+
+ override protected[interpreter] def readOneLine(prompt: String): String = ??? // unused
+ override protected[interpreter] def readOneKey(prompt: String): Int = ??? // unused
+
+ override def readLine(prompt: String): String = reader.readLine(prompt)
+}
+object SplashReader {
+ def apply(reader: InteractiveReader)(postIniter: InteractiveReader => Unit) =
+ new SplashReader(reader, postIniter)
+}
diff --git a/test/benchmarks/.gitignore b/test/benchmarks/.gitignore
new file mode 100644
index 0000000000..ce4d893417
--- /dev/null
+++ b/test/benchmarks/.gitignore
@@ -0,0 +1,14 @@
+/project/project/
+/project/target/
+/target/
+
+# what appears to be a Scala IDE-generated file
+.cache-main
+
+# standard Eclipse output directory
+/bin/
+
+# sbteclipse-generated Eclipse files
+/.classpath
+/.project
+/.settings/
diff --git a/test/benchmarks/README.md b/test/benchmarks/README.md
new file mode 100644
index 0000000000..370d610bc4
--- /dev/null
+++ b/test/benchmarks/README.md
@@ -0,0 +1,105 @@
+# Scala library benchmarks
+
+This directory is a standalone SBT project, within the Scala project,
+that makes use of the [SBT plugin](https://github.com/ktoso/sbt-jmh) for [JMH](http://openjdk.java.net/projects/code-tools/jmh/).
+
+## Running a benchmark
+
+The benchmarks require first building Scala into `../../build/pack` with `ant`.
+If you want to build with `sbt dist/mkPack` instead,
+you'll need to change `scalaHome` in this project.
+
+You'll then need to know the fully-qualified name of the benchmark runner class.
+The benchmarking classes are organized under `src/main/scala`,
+in the same package hierarchy as the classes that they test.
+Assuming that we're benchmarking `scala.collection.mutable.OpenHashMap`,
+the benchmark runner would likely be named `scala.collection.mutable.OpenHashMapRunner`.
+Using this example, one would simply run
+
+ jmh:runMain scala.collection.mutable.OpenHashMapRunner
+
+in SBT.
+SBT should be run _from this directory_.
+
+The JMH results can be found under `target/jmh-results/`.
+`target` gets deleted on an SBT `clean`,
+so you should copy these files out of `target` if you wish to preserve them.
+
+## Creating a benchmark and runner
+
+The benchmarking classes use the same package hierarchy as the classes that they test
+in order to make it easy to expose, in package scope, members of the class under test,
+should that be necessary for benchmarking.
+
+There are two types of classes in the source directory:
+those suffixed `Benchmark` and those suffixed `Runner`.
+The former are benchmarks that can be run directly using `jmh:run`;
+however, they are normally run from a corresponding class of the latter type,
+which is run using `jmh:runMain` (as described above).
+This …`Runner` class is useful for setting appropriate JMH command options,
+and for processing the JMH results into files that can be read by other tools, such as Gnuplot.
+
+The `benchmark.JmhRunner` trait should be woven into any runner class, for the standard behavior that it provides.
+This includes creating output files in a subdirectory of `target/jmh-results`
+derived from the fully-qualified package name of the `Runner` class.
+
+## Some useful HotSpot options
+Adding these to the `jmh:run` or `jmh:runMain` command line may help if you're using the HotSpot (Oracle, OpenJDK) compiler.
+They require prefixing with `-jvmArgs`.
+See [the Java documentation](http://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html) for more options.
+
+### Viewing JIT compilation events
+Adding `-XX:+PrintCompilation` shows when Java methods are being compiled or deoptimized.
+At the most basic level,
+these messages will tell you whether the code that you're measuring is still being tuned,
+so that you know whether you're running enough warm-up iterations.
+See [Kris Mok's notes](https://gist.github.com/rednaxelafx/1165804#file-notes-md) to interpret the output in detail.
+
+### Consider GC events
+If you're not explicitly performing `System.gc()` calls outside of your benchmarking code,
+you should add the JVM option `-verbose:gc` to understand the effect that GCs may be having on your tests.
+
+### "Diagnostic" options
+These require the `-XX:+UnlockDiagnosticVMOptions` JVM option.
+
+#### Viewing inlining events
+Add `-XX:+PrintInlining`.
+
+#### Viewing the disassembled code
+If you're running OpenJDK or Oracle JVM,
+you may need to install the disassembler library (`hsdis-amd64.so` for the `amd64` architecture).
+In Debian, this is available in
+<a href="https://packages.debian.org/search?keywords=libhsdis0-fcml">the `libhsdis0-fcml` package</a>.
+For an Oracle (or other compatible) JVM not set up by your distribution,
+you may also need to copy or link the disassembler library
+to the `jre/lib/`_`architecture`_ directory inside your JVM installation directory.
+
+To show the assembly code corresponding to the code generated by the JIT compiler for specific methods,
+add `-XX:CompileCommand=print,scala.collection.mutable.OpenHashMap::*`,
+for example, to show all of the methods in the `scala.collection.mutable.OpenHashMap` class.
+
+To show it for _all_ methods, add `-XX:+PrintAssembly`.
+(This is usually excessive.)
+
+## Useful reading
+* [OpenJDK advice on microbenchmarks](https://wiki.openjdk.java.net/display/HotSpot/MicroBenchmarks)
+* Brian Goetz's "Java theory and practice" articles:
+ * "[Dynamic compilation and performance measurement](http://www.ibm.com/developerworks/java/library/j-jtp12214/)"
+ * "[Anatomy of a flawed benchmark](http://www.ibm.com/developerworks/java/library/j-jtp02225/)"
+* [Doug Lea's JSR 166 benchmarks](http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/test/loops/)
+* "[Measuring performance](http://docs.scala-lang.org/overviews/parallel-collections/performance.html)" of Scala parallel collections
+
+## Legacy frameworks
+
+An older version of the benchmarking framework is still present in this directory, in the following locations:
+
+<dl>
+<dt><code>bench</code></dt>
+<dd>A script to run the old benchmarks.</dd>
+<dt><code>source.list</code></dt>
+<dd>A temporary file used by <code>bench</code>.</dd>
+<dt><code>src/scala/</code></dt>
+<dd>The older benchmarks, including the previous framework.</dd>
+</dl>
+
+Another, older set of benchmarks is present in `../benchmarking/`.
diff --git a/test/benchmarks/build.sbt b/test/benchmarks/build.sbt
new file mode 100644
index 0000000000..31cee701ad
--- /dev/null
+++ b/test/benchmarks/build.sbt
@@ -0,0 +1,11 @@
+scalaHome := Some(file("../../build/pack"))
+scalaVersion := "2.12.0-dev"
+scalacOptions ++= Seq("-feature", "-Yopt:l:classpath")
+
+lazy val root = (project in file(".")).
+ enablePlugins(JmhPlugin).
+ settings(
+ name := "test-benchmarks",
+ version := "0.0.1",
+ libraryDependencies += "org.openjdk.jol" % "jol-core" % "0.4"
+ )
diff --git a/test/benchmarks/project/plugins.sbt b/test/benchmarks/project/plugins.sbt
new file mode 100644
index 0000000000..e11aa29f3b
--- /dev/null
+++ b/test/benchmarks/project/plugins.sbt
@@ -0,0 +1,2 @@
+addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "4.0.0")
+addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.2.6")
diff --git a/test/benchmarks/src/main/scala/benchmark/JmhRunner.scala b/test/benchmarks/src/main/scala/benchmark/JmhRunner.scala
new file mode 100644
index 0000000000..cc75be529d
--- /dev/null
+++ b/test/benchmarks/src/main/scala/benchmark/JmhRunner.scala
@@ -0,0 +1,16 @@
+package benchmark
+
+import java.io.File
+
+/** Common code for JMH runner objects. */
+trait JmhRunner {
+ private[this] val parentDirectory = new File("target", "jmh-results")
+
+ /** Return the output directory for this class, creating the directory if necessary. */
+ protected def outputDirectory: File = {
+ val subdir = getClass.getPackage.getName.replace('.', File.separatorChar)
+ val dir = new File(parentDirectory, subdir)
+ if (!dir.isDirectory) dir.mkdirs()
+ dir
+ }
+}
diff --git a/test/benchmarks/src/main/scala/benchmark/KeySeq.scala b/test/benchmarks/src/main/scala/benchmark/KeySeq.scala
new file mode 100644
index 0000000000..126b92b3b6
--- /dev/null
+++ b/test/benchmarks/src/main/scala/benchmark/KeySeq.scala
@@ -0,0 +1,24 @@
+package benchmark
+
+/** A sequence of keys.
+ *
+ * Tests of maps and sets require a sequence of keys that can be used
+ * to add entries and possibly to find them again.
+ * This type provides such a sequence.
+ *
+ * Note that this needn't be a "sequence" in the full sense of [[collection.Seq]],
+ * particularly in that it needn't extend [[PartialFunction]].
+ *
+ * @tparam K the type of the keys
+ */
+trait KeySeq[K] {
+ /** Selects a key by its index in the sequence.
+ * Repeated calls with the same index return the same key (by reference equality).
+ *
+ * @param idx The index to select. Should be non-negative and less than `size`.
+ */
+ def apply(idx: Int): K
+
+ /** The size of this sequence. */
+ def size: Int
+}
diff --git a/test/benchmarks/src/main/scala/benchmark/KeySeqBuilder.scala b/test/benchmarks/src/main/scala/benchmark/KeySeqBuilder.scala
new file mode 100644
index 0000000000..95f6c7afd7
--- /dev/null
+++ b/test/benchmarks/src/main/scala/benchmark/KeySeqBuilder.scala
@@ -0,0 +1,33 @@
+package benchmark
+
+/** Builder of a [[KeySeq]]
+ *
+ * @tparam K the type of the keys
+ */
+trait KeySeqBuilder[K] {
+ /** Return a [[KeySeq]] having at least the given size. */
+ def build(size: Int): KeySeq[K]
+}
+
+object KeySeqBuilder {
+ /** Builder of a sequence of `Int` keys.
+ * Simply maps the sequence index to itself.
+ */
+ implicit object IntKeySeqBuilder extends KeySeqBuilder[Int] {
+ def build(_size: Int) = new KeySeq[Int] {
+ def apply(idx: Int) = idx
+ def size = _size
+ }
+ }
+
+ /** Builder of a sequence of `AnyRef` keys. */
+ implicit object AnyRefKeySeqBuilder extends KeySeqBuilder[AnyRef] {
+ def build(_size: Int) = new KeySeq[AnyRef] {
+ private[this] val arr = new Array[AnyRef](size)
+ for (i <- 0 until size) arr(i) = new AnyRef()
+
+ def apply(idx: Int) = arr(idx)
+ def size = _size
+ }
+ }
+}
diff --git a/test/benchmarks/src/main/scala/scala/collection/mutable/OpenHashMapBenchmark.scala b/test/benchmarks/src/main/scala/scala/collection/mutable/OpenHashMapBenchmark.scala
new file mode 100644
index 0000000000..64e2244499
--- /dev/null
+++ b/test/benchmarks/src/main/scala/scala/collection/mutable/OpenHashMapBenchmark.scala
@@ -0,0 +1,308 @@
+package scala.collection.mutable;
+
+import org.openjdk.jmh.annotations._
+import org.openjdk.jmh.infra._
+import org.openjdk.jmh.runner.IterationType
+import org.openjdk.jol.info.GraphLayout
+
+import benchmark._
+import java.util.concurrent.TimeUnit
+
+/** Utilities for the [[OpenHashMapBenchmark]].
+ *
+ * The method calls are tested by looping to the size desired for the map;
+ * instead of using the JMH harness, which iterates for a fixed length of time.
+ */
+private object OpenHashMapBenchmark {
+
+ /** Abstract state container for the `put()` bulk calling tests.
+ *
+ * Provides an array of adequately-sized, empty maps to each invocation,
+ * so that hash table allocation won't be done during measurement.
+ * Provides enough maps to make each invocation long enough to avoid timing artifacts.
+ * Performs a GC after re-creating the empty maps before every invocation,
+ * so that only the GCs caused by the invocation contribute to the measurement.
+ *
+ * Records the memory used by all the maps in the last invocation of each iteration.
+ *
+ * @tparam K type of the map keys to be used in the test
+ */
+ @State(Scope.Thread)
+ private[this] abstract class BulkPutState[K](implicit keyBuilder: KeySeqBuilder[K]) {
+ /** A lower-bound estimate of the number of nanoseconds per `put()` call */
+ private[this] val nanosPerPut: Double = 5
+
+ /** Minimum number of nanoseconds per invocation, so as to avoid timing artifacts. */
+ private[this] val minNanosPerInvocation = 1000000 // one millisecond
+
+ /** Size of the maps created in this trial. */
+ private[this] var size: Int = _
+
+ /** Total number of entries in all of the `maps` combined. */
+ private[this] var _mapEntries: Int = _
+ protected def mapEntries = _mapEntries
+
+ /** Number of operations performed in the current invocation. */
+ private[this] var _operations: Int = _
+ protected def operations = _operations
+
+ /** Bytes of memory used in the object graphs of all the maps. */
+ private[this] var _memory: Long = _
+ protected def memory = _memory
+
+ /** The sequence of keys to store into a map. */
+ private[this] var _keys: KeySeq[K] = _
+ def keys() = _keys
+
+ var maps: Array[OpenHashMap[K,Int]] = null
+
+ @Setup
+ def threadSetup(params: BenchmarkParams) {
+ size = params.getParam("size").toInt
+ val n = math.ceil(minNanosPerInvocation / (nanosPerPut * size)).toInt
+ _mapEntries = size * n
+ _keys = keyBuilder.build(size)
+ maps = new Array(n)
+ }
+
+ @Setup(Level.Iteration)
+ def iterationSetup {
+ _operations = 0
+ }
+
+ @Setup(Level.Invocation)
+ def setup(params: IterationParams) {
+ for (i <- 0 until maps.length) maps(i) = new OpenHashMap[K,Int](size)
+
+ if (params.getType == IterationType.MEASUREMENT) {
+ _operations += _mapEntries
+ System.gc() // clean up after last invocation
+ }
+ }
+
+ @TearDown(Level.Iteration)
+ def iterationTeardown(params: IterationParams) {
+ if (params.getType == IterationType.MEASUREMENT) {
+ // limit to smaller cases to avoid OOM
+ _memory =
+ if (_mapEntries <= 1000000) GraphLayout.parseInstance(maps(0), maps.tail).totalSize
+ else 0
+ }
+ }
+ }
+
+ /** Abstract state container for the `get()` bulk calling tests.
+ *
+ * Provides a thread-scoped map of the expected size.
+ * Performs a GC after loading the map.
+ *
+ * @tparam K type of the map keys to be used in the test
+ */
+ @State(Scope.Thread)
+ private[this] abstract class BulkGetState[K](implicit keyBuilder: KeySeqBuilder[K]) {
+ /** The sequence of keys to store into a map. */
+ private[this] var _keys: KeySeq[K] = _
+ def keys() = _keys
+
+ val map = new OpenHashMap[K,Int].empty
+
+ /** Load the map with keys from `1` to `size`. */
+ @Setup
+ def setup(params: BenchmarkParams) {
+ val size = params.getParam("size").toInt
+ _keys = keyBuilder.build(size)
+ put(map, keys, 0, size)
+ System.gc()
+ }
+ }
+
+ /** Abstract state container for the `get()` bulk calling tests with deleted entries.
+ *
+ * Provides a thread-scoped map of the expected size, from which entries have been removed.
+ * Performs a GC after loading the map.
+ *
+ * @tparam K type of the map keys to be used in the test
+ */
+ @State(Scope.Thread)
+ private[this] abstract class BulkRemovedGetState[K](implicit keyBuilder: KeySeqBuilder[K]) {
+ /** The sequence of keys to store into a map. */
+ private[this] var _keys: KeySeq[K] = _
+ def keys() = _keys
+
+ val map = new OpenHashMap[K,Int].empty
+
+ /** Load the map with keys from `1` to `size`, removing half of them. */
+ @Setup
+ def setup(params: BenchmarkParams) {
+ val size = params.getParam("size").toInt
+ _keys = keyBuilder.build(size)
+ put_remove(map, keys)
+ System.gc()
+ }
+ }
+
+ /* In order to use `@AuxCounters` on a class hierarchy (as of JMH 1.11.3),
+ * it's necessary to place it on the injected (sub)class, and to make the
+ * counters visible as explicit public members of the that class. JMH doesn't
+ * scan the ancestor classes for counters.
+ */
+
+ @AuxCounters
+ private class IntBulkPutState extends BulkPutState[Int] {
+ override def mapEntries = super.mapEntries
+ override def operations = super.operations
+ override def memory = super.memory
+ }
+ private class IntBulkGetState extends BulkGetState[Int]
+ private class IntBulkRemovedGetState extends BulkRemovedGetState[Int]
+
+ @AuxCounters
+ private class AnyRefBulkPutState extends BulkPutState[AnyRef] {
+ override def mapEntries = super.mapEntries
+ override def operations = super.operations
+ override def memory = super.memory
+ }
+ private class AnyRefBulkGetState extends BulkGetState[AnyRef]
+ private class AnyRefBulkRemovedGetState extends BulkRemovedGetState[AnyRef]
+
+
+ /** Put entries into the given map.
+ * Adds entries using a range of keys from the given list.
+ *
+ * @param from lowest index in the range of keys to add
+ * @param to highest index in the range of keys to add, plus one
+ */
+ private[this] def put[K](map: OpenHashMap[K,Int], keys: KeySeq[K], from: Int, to: Int) {
+ var i = from
+ while (i < to) { // using a `for` expression instead adds significant overhead
+ map.put(keys(i), i)
+ i += 1
+ }
+ }
+
+ /** Put entries into the given map.
+ * Adds entries using all of the keys from the given list.
+ */
+ private def put[K](map: OpenHashMap[K,Int], keys: KeySeq[K]): Unit =
+ put(map, keys, 0, keys.size)
+
+ /** Put entries into the given map, removing half of them as they're added.
+ *
+ * @param keys list of keys to use
+ */
+ private def put_remove[K](map: OpenHashMap[K,Int], keys: KeySeq[K]) {
+ val blocks = 25 // should be a non-trivial factor of `size`
+ val size = keys.size
+ val blockSize: Int = size / blocks
+ var base = 0
+ while (base < size) {
+ put(map, keys, base, base + blockSize)
+
+ // remove every other entry
+ var i = base
+ while (i < base + blockSize) {
+ map.remove(keys(i))
+ i += 2
+ }
+
+ base += blockSize
+ }
+ }
+
+ /** Get elements from the given map. */
+ private def get[K](map: OpenHashMap[K,Int], keys: KeySeq[K]) = {
+ val size = keys.size
+ var i = 0
+ var sum = 0
+ while (i < size) {
+ sum += map.get(keys(i)).getOrElse(0)
+ i += 1
+ }
+ sum
+ }
+}
+
+/** Benchmark for the library's [[OpenHashMap]]. */
+@BenchmarkMode(Array(Mode.AverageTime))
+@Fork(5)
+@Threads(1)
+@Warmup(iterations = 20)
+@Measurement(iterations = 5)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+@State(Scope.Benchmark)
+class OpenHashMapBenchmark {
+ import OpenHashMapBenchmark._
+
+ @Param(Array("50", "100", "1000", "10000", "100000", "1000000", "2500000",
+ "5000000", "7500000", "10000000", "25000000"))
+ var size: Int = _
+
+ // Tests with Int keys
+
+ /** Test putting elements to a map of `Int` to `Int`. */
+ @Benchmark
+ def put_Int(state: IntBulkPutState) {
+ var i = 0
+ while (i < state.maps.length) {
+ put(state.maps(i), state.keys)
+ i += 1
+ }
+ }
+
+ /** Test putting and removing elements to a growing map of `Int` to `Int`. */
+ @Benchmark
+ def put_remove_Int(state: IntBulkPutState) {
+ var i = 0
+ while (i < state.maps.length) {
+ put_remove(state.maps(i), state.keys)
+ i += 1
+ }
+ }
+
+ /** Test getting elements from a map of `Int` to `Int`. */
+ @Benchmark
+ def get_Int_after_put(state: IntBulkGetState) =
+ get(state.map, state.keys)
+
+ /** Test getting elements from a map of `Int` to `Int` from which elements have been removed.
+ * Note that half of these queries will fail to find their keys, which have been removed.
+ */
+ @Benchmark
+ def get_Int_after_put_remove(state: IntBulkRemovedGetState) =
+ get(state.map, state.keys)
+
+
+ // Tests with AnyRef keys
+
+ /** Test putting elements to a map of `AnyRef` to `Int`. */
+ @Benchmark
+ def put_AnyRef(state: AnyRefBulkPutState) {
+ var i = 0
+ while (i < state.maps.length) {
+ put(state.maps(i), state.keys)
+ i += 1
+ }
+ }
+
+ /** Test putting and removing elements to a growing map of `AnyRef` to `Int`. */
+ @Benchmark
+ def put_remove_AnyRef(state: AnyRefBulkPutState) {
+ var i = 0
+ while (i < state.maps.length) {
+ put_remove(state.maps(i), state.keys)
+ i += 1
+ }
+ }
+
+ /** Test getting elements from a map of `AnyRef` to `Int`. */
+ @Benchmark
+ def get_AnyRef_after_put(state: AnyRefBulkGetState) =
+ get(state.map, state.keys)
+
+ /** Test getting elements from a map of `AnyRef` to `Int` from which elements have been removed.
+ * Note that half of these queries will fail to find their keys, which have been removed.
+ */
+ @Benchmark
+ def get_AnyRef_after_put_remove(state: AnyRefBulkRemovedGetState) =
+ get(state.map, state.keys)
+}
diff --git a/test/benchmarks/src/main/scala/scala/collection/mutable/OpenHashMapRunner.scala b/test/benchmarks/src/main/scala/scala/collection/mutable/OpenHashMapRunner.scala
new file mode 100644
index 0000000000..b14b733a81
--- /dev/null
+++ b/test/benchmarks/src/main/scala/scala/collection/mutable/OpenHashMapRunner.scala
@@ -0,0 +1,113 @@
+package scala.collection.mutable
+
+import java.io.File
+import java.io.PrintWriter
+
+import scala.language.existentials
+
+import org.openjdk.jmh.results.Result
+import org.openjdk.jmh.results.RunResult
+import org.openjdk.jmh.runner.Runner
+import org.openjdk.jmh.runner.options.CommandLineOptions
+import org.openjdk.jmh.runner.options.OptionsBuilder
+import org.openjdk.jmh.runner.options.VerboseMode
+
+import benchmark.JmhRunner
+
+/** Replacement JMH application that runs the [[OpenHashMap]] benchmark.
+ *
+ * Outputs the results in a form consumable by a Gnuplot script.
+ */
+object OpenHashMapRunner extends JmhRunner {
+ /** File that will be created for the output data set. */
+ private[this] val outputFile = new File(outputDirectory, "OpenHashMap.dat")
+
+ /** Qualifier to add to the name of a memory usage data set. */
+ private[this] val memoryDatasetQualifier = "-memory"
+
+ /** Adapter to the JMH result class that simplifies our method calls. */
+ private[this] implicit class MyRunResult(r: RunResult) {
+ /** Return the dataset label. */
+ def label = r.getPrimaryResult.getLabel
+
+ /** Return the value of the JMH parameter for the number of map entries per invocation. */
+ def size: String = r.getParams.getParam("size")
+
+ /** Return the operation counts. Not every test tracks this. */
+ def operations = Option(r.getSecondaryResults.get("operations"))
+
+ /** Return the number of map entries. */
+ def entries = r.getSecondaryResults.get("mapEntries")
+
+ /** Return the memory usage. Only defined if memory usage was measured. */
+ def memory = Option(r.getSecondaryResults.get("memory"))
+ }
+
+ /** Return the statistics of the given result as a string. */
+ private[this] def stats(r: Result[_]) = r.getScore + " " + r.getStatistics.getStandardDeviation
+
+
+ def main(args: Array[String]) {
+ import scala.collection.JavaConversions._
+
+ val opts = new CommandLineOptions(args: _*)
+ var builder = new OptionsBuilder().parent(opts).jvmArgsPrepend("-Xmx6000m")
+ if (!opts.verbosity.hasValue) builder = builder.verbosity(VerboseMode.SILENT)
+
+ val results = new Runner(builder.build).run()
+
+ /* Sort the JMH results into "data sets", each representing a complete test of one feature.
+ * Some results only measure CPU performance; while others also measure memory usage, and
+ * thus are split into two data sets. A data set is distinguished by its label, which is
+ * the label of the JMH result, for CPU performance, or that with an added suffix, for memory
+ * usage.
+ */
+
+ /** Map from data set name to data set. */
+ val datasetByName = Map.empty[String, Set[RunResult]]
+
+ /** Ordering for the results within a data set. Orders by increasing number of map entries. */
+ val ordering = Ordering.by[RunResult, Int](_.size.toInt)
+
+ def addToDataset(key: String, result: RunResult): Unit =
+ datasetByName.getOrElseUpdate(key, SortedSet.empty(ordering)) += result
+
+ results.foreach { result =>
+ addToDataset(result.label, result)
+
+ // Create another data set for trials that track memory usage
+ if (result.memory.isDefined)
+ addToDataset(result.label + memoryDatasetQualifier, result)
+ }
+
+ //TODO Write out test parameters
+ // val jvm = params.getJvm
+ // val jvmArgs = params.getJvmArgs.mkString(" ")
+
+ val f = new PrintWriter(outputFile, "UTF-8")
+ try {
+ datasetByName.foreach(_ match {
+ case (label: String, dataset: Iterable[RunResult]) =>
+ outputDataset(f, label, dataset)
+ })
+ } finally {
+ f.close()
+ }
+ }
+
+ private[this] def outputDataset(f: PrintWriter, label: String, dataset: Iterable[RunResult]) {
+ f.println(s"# [$label]")
+
+ val isMemoryUsageDataset = label.endsWith(memoryDatasetQualifier)
+ dataset.foreach { r =>
+ f.println(r.size + " " + (
+ if (isMemoryUsageDataset && !r.memory.get.getScore.isInfinite)
+ stats(r.entries) + " " + stats(r.memory.get)
+ else
+ stats(r.operations getOrElse r.getPrimaryResult)
+ ))
+ }
+
+ f.println(); f.println() // data set separator
+ }
+}
diff --git a/test/files/neg/eta-expand-star.check b/test/files/neg/eta-expand-star.check
index 6765d504fc..eba1721014 100644
--- a/test/files/neg/eta-expand-star.check
+++ b/test/files/neg/eta-expand-star.check
@@ -1,4 +1,4 @@
-eta-expand-star.scala:6: error: too many arguments for method apply: (v1: Seq[T])Unit in trait Function1
+eta-expand-star.scala:6: error: too many arguments (2) for method apply: (v1: Seq[T])Unit in trait Function1
g(1, 2)
- ^
+ ^
one error found
diff --git a/test/files/neg/macro-invalidusage-badargs.check b/test/files/neg/macro-invalidusage-badargs.check
index 19ac6528d3..ee549c45cb 100644
--- a/test/files/neg/macro-invalidusage-badargs.check
+++ b/test/files/neg/macro-invalidusage-badargs.check
@@ -13,7 +13,7 @@ Macros_Test_2.scala:8: error: not enough arguments for macro method foo: (x: Int
Unspecified value parameter x.
foo()
^
-Macros_Test_2.scala:9: error: too many arguments for macro method foo: (x: Int)Int
+Macros_Test_2.scala:9: error: too many arguments (2) for macro method foo: (x: Int)Int
foo(4, 2)
- ^
+ ^
5 errors found
diff --git a/test/files/neg/multi-array.check b/test/files/neg/multi-array.check
index 511caa126f..06ffdc9fbc 100644
--- a/test/files/neg/multi-array.check
+++ b/test/files/neg/multi-array.check
@@ -1,4 +1,4 @@
-multi-array.scala:7: error: too many arguments for constructor Array: (_length: Int)Array[T]
+multi-array.scala:7: error: too many arguments (2) for constructor Array: (_length: Int)Array[T]
val a: Array[Int] = new Array(10, 10)
- ^
+ ^
one error found
diff --git a/test/files/neg/protected-constructors.check b/test/files/neg/protected-constructors.check
index f44d7db9b9..0279f5815d 100644
--- a/test/files/neg/protected-constructors.check
+++ b/test/files/neg/protected-constructors.check
@@ -1,6 +1,6 @@
-protected-constructors.scala:17: error: too many arguments for constructor Foo1: ()dingus.Foo1
+protected-constructors.scala:17: error: no arguments allowed for nullary constructor Foo1: ()dingus.Foo1
val foo1 = new Foo1("abc")
- ^
+ ^
protected-constructors.scala:18: error: constructor Foo2 in class Foo2 cannot be accessed in object P
Access to protected constructor Foo2 not permitted because
enclosing object P in package hungus is not a subclass of
@@ -19,4 +19,7 @@ protected-constructors.scala:15: error: class Foo3 in object Ding cannot be acce
object Ding in package dingus where target is defined
class Bar3 extends Ding.Foo3("abc")
^
-four errors found
+protected-constructors.scala:15: error: no arguments allowed for nullary constructor Object: ()Object
+ class Bar3 extends Ding.Foo3("abc")
+ ^
+5 errors found
diff --git a/test/files/neg/t1112.check b/test/files/neg/t1112.check
index 5e3821b153..e6058bf176 100644
--- a/test/files/neg/t1112.check
+++ b/test/files/neg/t1112.check
@@ -1,4 +1,4 @@
-t1112.scala:12: error: too many arguments for method call: (p: Int)(f: => Test.this.Type1)Unit
+t1112.scala:12: error: too many arguments (2) for method call: (p: Int)(f: => Test.this.Type1)Unit
call(0,() => System.out.println("here we are"))
- ^
+ ^
one error found
diff --git a/test/files/neg/t1523.check b/test/files/neg/t1523.check
index d2489f2602..273d0f8cf7 100644
--- a/test/files/neg/t1523.check
+++ b/test/files/neg/t1523.check
@@ -1,4 +1,4 @@
-t1523.scala:4: error: too many arguments for method bug: (x: Any)Any
+t1523.scala:4: error: 25 more arguments than can be applied to method bug: (x: Any)Any
def go() = bug("a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a")
- ^
+ ^
one error found
diff --git a/test/files/neg/t6920.check b/test/files/neg/t6920.check
index ee4eafb83e..d10abff03c 100644
--- a/test/files/neg/t6920.check
+++ b/test/files/neg/t6920.check
@@ -1,6 +1,6 @@
-t6920.scala:9: error: too many arguments for method applyDynamicNamed: (values: Seq[(String, Any)])String
+t6920.scala:9: error: too many arguments (2) for method applyDynamicNamed: (values: Seq[(String, Any)])String
error after rewriting to CompilerError.this.test.applyDynamicNamed("crushTheCompiler")(scala.Tuple2("a", 1), scala.Tuple2("b", 2))
possible cause: maybe a wrong Dynamic method signature?
test.crushTheCompiler(a = 1, b = 2)
- ^
+ ^
one error found
diff --git a/test/files/neg/t7157.check b/test/files/neg/t7157.check
index 3988460d4b..0b81394946 100644
--- a/test/files/neg/t7157.check
+++ b/test/files/neg/t7157.check
@@ -1,22 +1,22 @@
-Test_2.scala:5: error: too many arguments for macro method m1_0_0: ()Unit
+Test_2.scala:5: error: no arguments allowed for nullary macro method m1_0_0: ()Unit
m1_0_0(1)
- ^
-Test_2.scala:6: error: too many arguments for macro method m1_0_0: ()Unit
+ ^
+Test_2.scala:6: error: no arguments allowed for nullary macro method m1_0_0: ()Unit
m1_0_0(1, 2)
- ^
-Test_2.scala:7: error: too many arguments for macro method m1_0_0: ()Unit
+ ^
+Test_2.scala:7: error: no arguments allowed for nullary macro method m1_0_0: ()Unit
m1_0_0(1, 2, 3)
- ^
+ ^
Test_2.scala:9: error: not enough arguments for macro method m1_1_1: (x: Int)Unit.
Unspecified value parameter x.
m1_1_1()
^
-Test_2.scala:11: error: too many arguments for macro method m1_1_1: (x: Int)Unit
+Test_2.scala:11: error: too many arguments (2) for macro method m1_1_1: (x: Int)Unit
m1_1_1(1, 2)
- ^
-Test_2.scala:12: error: too many arguments for macro method m1_1_1: (x: Int)Unit
+ ^
+Test_2.scala:12: error: too many arguments (3) for macro method m1_1_1: (x: Int)Unit
m1_1_1(1, 2, 3)
- ^
+ ^
Test_2.scala:14: error: not enough arguments for macro method m1_2_2: (x: Int, y: Int)Unit.
Unspecified value parameters x, y.
m1_2_2()
@@ -25,9 +25,9 @@ Test_2.scala:15: error: not enough arguments for macro method m1_2_2: (x: Int, y
Unspecified value parameter y.
m1_2_2(1)
^
-Test_2.scala:17: error: too many arguments for macro method m1_2_2: (x: Int, y: Int)Unit
+Test_2.scala:17: error: too many arguments (3) for macro method m1_2_2: (x: Int, y: Int)Unit
m1_2_2(1, 2, 3)
- ^
+ ^
Test_2.scala:24: error: not enough arguments for macro method m1_1_inf: (x: Int, y: Int*)Unit.
Unspecified value parameters x, y.
m1_1_inf()
@@ -40,25 +40,25 @@ Test_2.scala:30: error: not enough arguments for macro method m1_2_inf: (x: Int,
Unspecified value parameters y, z.
m1_2_inf(1)
^
-Test_2.scala:35: error: too many arguments for macro method m2_0_0: ()Unit
+Test_2.scala:35: error: no arguments allowed for nullary macro method m2_0_0: ()Unit
m2_0_0()(1)
- ^
-Test_2.scala:36: error: too many arguments for macro method m2_0_0: ()Unit
+ ^
+Test_2.scala:36: error: no arguments allowed for nullary macro method m2_0_0: ()Unit
m2_0_0()(1, 2)
- ^
-Test_2.scala:37: error: too many arguments for macro method m2_0_0: ()Unit
+ ^
+Test_2.scala:37: error: no arguments allowed for nullary macro method m2_0_0: ()Unit
m2_0_0()(1, 2, 3)
- ^
+ ^
Test_2.scala:39: error: not enough arguments for macro method m2_1_1: (x: Int)Unit.
Unspecified value parameter x.
m2_1_1()()
^
-Test_2.scala:41: error: too many arguments for macro method m2_1_1: (x: Int)Unit
+Test_2.scala:41: error: too many arguments (2) for macro method m2_1_1: (x: Int)Unit
m2_1_1()(1, 2)
- ^
-Test_2.scala:42: error: too many arguments for macro method m2_1_1: (x: Int)Unit
+ ^
+Test_2.scala:42: error: too many arguments (3) for macro method m2_1_1: (x: Int)Unit
m2_1_1()(1, 2, 3)
- ^
+ ^
Test_2.scala:44: error: not enough arguments for macro method m2_2_2: (x: Int, y: Int)Unit.
Unspecified value parameters x, y.
m2_2_2()()
@@ -67,9 +67,9 @@ Test_2.scala:45: error: not enough arguments for macro method m2_2_2: (x: Int, y
Unspecified value parameter y.
m2_2_2()(1)
^
-Test_2.scala:47: error: too many arguments for macro method m2_2_2: (x: Int, y: Int)Unit
+Test_2.scala:47: error: too many arguments (3) for macro method m2_2_2: (x: Int, y: Int)Unit
m2_2_2()(1, 2, 3)
- ^
+ ^
Test_2.scala:54: error: not enough arguments for macro method m2_1_inf: (x: Int, y: Int*)Unit.
Unspecified value parameters x, y.
m2_1_inf()()
diff --git a/test/files/neg/t8006.check b/test/files/neg/t8006.check
index fbac26e3ad..6152d0fba3 100644
--- a/test/files/neg/t8006.check
+++ b/test/files/neg/t8006.check
@@ -1,6 +1,6 @@
-t8006.scala:3: error: too many arguments for method applyDynamicNamed: (value: (String, Any))String
+t8006.scala:3: error: too many arguments (2) for method applyDynamicNamed: (value: (String, Any))String
error after rewriting to X.this.d.applyDynamicNamed("meth")(scala.Tuple2("value1", 10), scala.Tuple2("value2", 100))
possible cause: maybe a wrong Dynamic method signature?
d.meth(value1 = 10, value2 = 100) // two arguments here, but only one is allowed
- ^
+ ^
one error found
diff --git a/test/files/neg/t8035-no-adapted-args.check b/test/files/neg/t8035-no-adapted-args.check
index 43637b2c1f..0115dddc91 100644
--- a/test/files/neg/t8035-no-adapted-args.check
+++ b/test/files/neg/t8035-no-adapted-args.check
@@ -4,9 +4,9 @@ t8035-no-adapted-args.scala:4: warning: No automatic adaptation here: use explic
after adaptation: Test.f((1, 2, 3): (Int, Int, Int))
f(1, 2, 3)
^
-t8035-no-adapted-args.scala:4: error: too many arguments for method f: (x: (Int, Int, Int))Int
+t8035-no-adapted-args.scala:4: error: too many arguments (3) for method f: (x: (Int, Int, Int))Int
f(1, 2, 3)
- ^
+ ^
t8035-no-adapted-args.scala:5: warning: No automatic adaptation here: use explicit parentheses.
signature: Test.f[T](x: T): Int
given arguments: <none>
diff --git a/test/files/neg/t8667.check b/test/files/neg/t8667.check
new file mode 100644
index 0000000000..82451ee5d6
--- /dev/null
+++ b/test/files/neg/t8667.check
@@ -0,0 +1,91 @@
+t8667.scala:6: error: too many arguments (3) for constructor C: (a: Int, b: Int)C
+Note that 'c' is not a parameter name of the invoked method.
+ def c2 = new C(a = 42, b = 17, c = 5)
+ ^
+t8667.scala:7: error: unknown parameter name: c
+ def c3 = new C(b = 42, a = 17, c = 5)
+ ^
+t8667.scala:7: error: too many arguments (3) for constructor C: (a: Int, b: Int)C
+ def c3 = new C(b = 42, a = 17, c = 5)
+ ^
+t8667.scala:8: error: positional after named argument.
+ def c4 = new C(b = 42, a = 17, 5)
+ ^
+t8667.scala:8: error: too many arguments (3) for constructor C: (a: Int, b: Int)C
+ def c4 = new C(b = 42, a = 17, 5)
+ ^
+t8667.scala:9: error: not found: value c
+ def c5 = new C(a = 42, c = 17)
+ ^
+t8667.scala:10: error: parameter 'b' is already specified at parameter position 2
+Note that 'c' is not a parameter name of the invoked method.
+ def c6 = new C(a = 42, c = 17, b = 5)
+ ^
+t8667.scala:10: error: too many arguments (3) for constructor C: (a: Int, b: Int)C
+Note that 'c' is not a parameter name of the invoked method.
+ def c6 = new C(a = 42, c = 17, b = 5)
+ ^
+t8667.scala:11: error: parameter 'a' is already specified at parameter position 1
+Note that 'c' is not a parameter name of the invoked method.
+ def c7 = new C(c = 42, a = 17, b = 5)
+ ^
+t8667.scala:11: error: too many arguments (3) for constructor C: (a: Int, b: Int)C
+Note that 'c' is not a parameter name of the invoked method.
+ def c7 = new C(c = 42, a = 17, b = 5)
+ ^
+t8667.scala:12: error: parameter 'b' is already specified at parameter position 2
+ def c8 = new C(42, 17, b = 5)
+ ^
+t8667.scala:12: error: too many arguments (3) for constructor C: (a: Int, b: Int)C
+ def c8 = new C(42, 17, b = 5)
+ ^
+t8667.scala:13: error: parameter 'b' is already specified at parameter position 2
+Note that 'c' is not a parameter name of the invoked method.
+ def c9 = new C(a = 42, c = 17, d = 3, b = 5)
+ ^
+t8667.scala:13: error: too many arguments (4) for constructor C: (a: Int, b: Int)C
+Note that 'c', 'd' are not parameter names of the invoked method.
+ def c9 = new C(a = 42, c = 17, d = 3, b = 5)
+ ^
+t8667.scala:14: error: too many arguments (4) for constructor C: (a: Int, b: Int)C
+Note that 'd', 'c' are not parameter names of the invoked method.
+ def c0 = new C(42, 17, d = 3, c = 5)
+ ^
+t8667.scala:25: error: no arguments allowed for nullary method f0: ()Int
+ f0(1)
+ ^
+t8667.scala:26: error: too many arguments (2) for method f1: (i: Int)Int
+ f1(1, 2)
+ ^
+t8667.scala:27: error: too many arguments (3) for method f1: (i: Int)Int
+ f1(1, 2, 3)
+ ^
+t8667.scala:28: error: 3 more arguments than can be applied to method f1: (i: Int)Int
+ f1(1, 2, 3, 4)
+ ^
+t8667.scala:29: error: 3 more arguments than can be applied to method f1: (i: Int)Int
+Note that 'j' is not a parameter name of the invoked method.
+ f1(1, j = 2, 3, 4)
+ ^
+t8667.scala:30: error: 3 more arguments than can be applied to method f1: (i: Int)Int
+Note that 'j', 'k' are not parameter names of the invoked method.
+ f1(1, j = 2, k = 3, 4)
+ ^
+t8667.scala:31: error: parameter 'i' is already specified at parameter position 1
+Note that 'k' is not a parameter name of the invoked method.
+ f2(k = 1, i = 2, j = 3)
+ ^
+t8667.scala:31: error: too many arguments (3) for method f2: (i: Int, j: Int)Int
+Note that 'k' is not a parameter name of the invoked method.
+ f2(k = 1, i = 2, j = 3)
+ ^
+t8667.scala:32: error: one more argument than can be applied to method f6: (i: Int, j: Int, k: Int, l: Int, m: Int, n: Int)Int
+ f6(1, 2, 3, 4, 5, 6, 7)
+ ^
+t8667.scala:33: error: 2 more arguments than can be applied to method f6: (i: Int, j: Int, k: Int, l: Int, m: Int, n: Int)Int
+ f6(1, 2, 3, 4, 5, 6, 7, 8)
+ ^
+t8667.scala:34: error: 15 arguments but expected 12 for method f12: (i: Int, j: Int, k: Int, l: Int, m: Int, n: Int, o: Int, p: Int, q: Int, r: Int, s: Int, t: Int)Int
+ f12(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
+ ^
+26 errors found
diff --git a/test/files/neg/t8667.scala b/test/files/neg/t8667.scala
new file mode 100644
index 0000000000..d55582ca6b
--- /dev/null
+++ b/test/files/neg/t8667.scala
@@ -0,0 +1,37 @@
+
+class C(a: Int, b: Int)
+
+trait T {
+ def c1 = new C(a = 42, b = 17)
+ def c2 = new C(a = 42, b = 17, c = 5)
+ def c3 = new C(b = 42, a = 17, c = 5)
+ def c4 = new C(b = 42, a = 17, 5)
+ def c5 = new C(a = 42, c = 17)
+ def c6 = new C(a = 42, c = 17, b = 5)
+ def c7 = new C(c = 42, a = 17, b = 5)
+ def c8 = new C(42, 17, b = 5)
+ def c9 = new C(a = 42, c = 17, d = 3, b = 5)
+ def c0 = new C(42, 17, d = 3, c = 5)
+}
+
+trait X {
+ def f0() = 42
+ def f1(i: Int) = 42
+ def f2(i: Int, j: Int) = 42
+ def f6(i: Int, j: Int, k: Int, l: Int, m: Int, n: Int) = 42
+ def f12(i: Int, j: Int, k: Int, l: Int, m: Int, n: Int, o: Int, p: Int, q: Int, r: Int, s: Int, t: Int) = 42
+
+ def g() = {
+ f0(1)
+ f1(1, 2)
+ f1(1, 2, 3)
+ f1(1, 2, 3, 4)
+ f1(1, j = 2, 3, 4)
+ f1(1, j = 2, k = 3, 4)
+ f2(k = 1, i = 2, j = 3)
+ f6(1, 2, 3, 4, 5, 6, 7)
+ f6(1, 2, 3, 4, 5, 6, 7, 8)
+ f12(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
+ ()
+ }
+}
diff --git a/test/files/neg/t876.check b/test/files/neg/t876.check
index 04c5c8f22e..7df2e126a6 100644
--- a/test/files/neg/t876.check
+++ b/test/files/neg/t876.check
@@ -1,4 +1,4 @@
-t876.scala:25: error: too many arguments for method apply: (key: AssertionError.A)manager.B in class HashMap
+t876.scala:25: error: too many arguments (2) for method apply: (key: AssertionError.A)manager.B in class HashMap
assert(manager.map(A2) == List(manager.map(A2, A1)))
- ^
+ ^
one error found
diff --git a/test/files/neg/trait-no-native.check b/test/files/neg/trait-no-native.check
new file mode 100644
index 0000000000..12bce4042d
--- /dev/null
+++ b/test/files/neg/trait-no-native.check
@@ -0,0 +1,4 @@
+trait-no-native.scala:3: error: A trait cannot define a native method.
+ @native def foo = ???
+ ^
+one error found
diff --git a/test/files/neg/trait-no-native.scala b/test/files/neg/trait-no-native.scala
new file mode 100644
index 0000000000..463e604a48
--- /dev/null
+++ b/test/files/neg/trait-no-native.scala
@@ -0,0 +1,4 @@
+trait T {
+ // should not compile, because it would result in a VerifyError
+ @native def foo = ???
+}
diff --git a/test/files/t8449/Client.scala b/test/files/pos/t8449/Client.scala
index 5d273f06b2..5d273f06b2 100644
--- a/test/files/t8449/Client.scala
+++ b/test/files/pos/t8449/Client.scala
diff --git a/test/files/t8449/Test.java b/test/files/pos/t8449/Test.java
index ecb1711b24..ecb1711b24 100644
--- a/test/files/t8449/Test.java
+++ b/test/files/pos/t8449/Test.java
diff --git a/test/files/run/repl-paste-b.check b/test/files/run/repl-paste-b.check
new file mode 100644
index 0000000000..2e205d48d6
--- /dev/null
+++ b/test/files/run/repl-paste-b.check
@@ -0,0 +1,14 @@
+
+scala> :paste < EOF
+// Entering paste mode (EOF to finish)
+
+object X
+EOF
+
+// Exiting paste mode, now interpreting.
+
+defined object X
+
+scala> assert(X.getClass.getName.contains("line"))
+
+scala> :quit
diff --git a/test/files/run/repl-paste-b.scala b/test/files/run/repl-paste-b.scala
new file mode 100644
index 0000000000..718f7d9e17
--- /dev/null
+++ b/test/files/run/repl-paste-b.scala
@@ -0,0 +1,13 @@
+import scala.tools.partest.ReplTest
+
+// confirm X not in empty package
+object Test extends ReplTest {
+ def code =
+ """
+:paste < EOF
+object X
+EOF
+assert(X.getClass.getName.contains("line"))
+"""
+
+}
diff --git a/test/files/run/repl-paste-parse.check b/test/files/run/repl-paste-parse.check
new file mode 100755
index 0000000000..7b2148dc74
--- /dev/null
+++ b/test/files/run/repl-paste-parse.check
@@ -0,0 +1,6 @@
+Type in expressions for evaluation. Or try :help.
+
+scala> repl-paste-parse.script:1: error: illegal start of simple pattern
+val case = 9
+ ^
+:quit
diff --git a/test/files/run/repl-paste-parse.scala b/test/files/run/repl-paste-parse.scala
new file mode 100644
index 0000000000..e93ad4d02b
--- /dev/null
+++ b/test/files/run/repl-paste-parse.scala
@@ -0,0 +1,27 @@
+
+import java.io.{ BufferedReader, StringReader, StringWriter, PrintWriter }
+
+import scala.tools.partest.DirectTest
+import scala.tools.nsc.interpreter.ILoop
+import scala.tools.nsc.GenericRunnerSettings
+
+object Test extends DirectTest {
+ override def extraSettings = s"-usejavacp -i $scriptPath"
+ def scriptPath = testPath.changeExtension("script")
+ override def newSettings(args: List[String]) = {
+ val ss = new GenericRunnerSettings(Console.println)
+ ss.processArguments(args, true)
+ ss
+ }
+ def code = ""
+ def show() = {
+ val r = new BufferedReader(new StringReader(""))
+ val w = new StringWriter
+ val p = new PrintWriter(w, true)
+ new ILoop(r, p).process(settings)
+ w.toString.lines foreach { s =>
+ if (!s.startsWith("Welcome to Scala")) println(s)
+ }
+ }
+}
+
diff --git a/test/files/run/repl-paste-parse.script b/test/files/run/repl-paste-parse.script
new file mode 100644
index 0000000000..903f6e7b0c
--- /dev/null
+++ b/test/files/run/repl-paste-parse.script
@@ -0,0 +1 @@
+val case = 9
diff --git a/test/files/run/repl-paste-raw-b.pastie b/test/files/run/repl-paste-raw-b.pastie
new file mode 100644
index 0000000000..f13b4bcf8b
--- /dev/null
+++ b/test/files/run/repl-paste-raw-b.pastie
@@ -0,0 +1,8 @@
+
+// a raw paste is not a script
+// hence it can be packaged
+
+package brown_paper
+
+// these are a few of my favorite things
+case class Gift (hasString: Boolean)
diff --git a/test/files/run/repl-paste-raw-b.scala b/test/files/run/repl-paste-raw-b.scala
new file mode 100644
index 0000000000..d1c7692f2f
--- /dev/null
+++ b/test/files/run/repl-paste-raw-b.scala
@@ -0,0 +1,18 @@
+
+import scala.tools.partest.SessionTest
+
+object Test extends SessionTest {
+ def session =
+s"""|
+ |scala> :paste $pastie
+ |Pasting file $pastie...
+ |
+ |scala> val favoriteThing = brown_paper.Gift(true)
+ |favoriteThing: brown_paper.Gift = Gift(true)
+ |
+ |scala> favoriteThing.hasString
+ |res0: Boolean = true
+ |
+ |scala> :quit"""
+ def pastie = testPath changeExtension "pastie"
+}
diff --git a/test/files/run/repl-paste-raw-c.pastie b/test/files/run/repl-paste-raw-c.pastie
new file mode 100644
index 0000000000..364d8cef4b
--- /dev/null
+++ b/test/files/run/repl-paste-raw-c.pastie
@@ -0,0 +1,5 @@
+
+// not actually a candidate for raw paste
+
+val nope = 42
+
diff --git a/test/files/run/repl-paste-raw-c.scala b/test/files/run/repl-paste-raw-c.scala
new file mode 100644
index 0000000000..600ac4d2f0
--- /dev/null
+++ b/test/files/run/repl-paste-raw-c.scala
@@ -0,0 +1,16 @@
+
+import scala.tools.partest.SessionTest
+
+object Test extends SessionTest {
+ def session =
+s"""|
+ |scala> :paste -raw $pastie
+ |Pasting file $pastie...
+ |$pastie:3: error: expected class or object definition
+ |val nope = 42
+ |^
+ |There were compilation errors!
+ |
+ |scala> :quit"""
+ def pastie = testPath changeExtension "pastie"
+}
diff --git a/test/files/run/repl-paste-raw.pastie b/test/files/run/repl-paste-raw.pastie
index f13b4bcf8b..a4a570aaa2 100644
--- a/test/files/run/repl-paste-raw.pastie
+++ b/test/files/run/repl-paste-raw.pastie
@@ -1,8 +1,8 @@
+package brown_paper
+
// a raw paste is not a script
// hence it can be packaged
-package brown_paper
-
// these are a few of my favorite things
case class Gift (hasString: Boolean)
diff --git a/test/files/run/repl-paste-raw.scala b/test/files/run/repl-paste-raw.scala
index 9bd5e8e63e..d1c7692f2f 100644
--- a/test/files/run/repl-paste-raw.scala
+++ b/test/files/run/repl-paste-raw.scala
@@ -4,7 +4,7 @@ import scala.tools.partest.SessionTest
object Test extends SessionTest {
def session =
s"""|
- |scala> :paste -raw $pastie
+ |scala> :paste $pastie
|Pasting file $pastie...
|
|scala> val favoriteThing = brown_paper.Gift(true)
diff --git a/test/files/run/t4625.check b/test/files/run/t4625.check
new file mode 100644
index 0000000000..e4a4d15b87
--- /dev/null
+++ b/test/files/run/t4625.check
@@ -0,0 +1 @@
+Test ran.
diff --git a/test/files/run/t4625.scala b/test/files/run/t4625.scala
new file mode 100644
index 0000000000..44f6225220
--- /dev/null
+++ b/test/files/run/t4625.scala
@@ -0,0 +1,7 @@
+
+import scala.tools.partest.ScriptTest
+
+object Test extends ScriptTest {
+ // must be called Main to get probing treatment in parser
+ override def testmain = "Main"
+}
diff --git a/test/files/run/t4625.script b/test/files/run/t4625.script
new file mode 100644
index 0000000000..600ceacbb6
--- /dev/null
+++ b/test/files/run/t4625.script
@@ -0,0 +1,5 @@
+
+object Main extends Runnable with App {
+ def run() = println("Test ran.")
+ run()
+}
diff --git a/test/files/run/t4625b.check b/test/files/run/t4625b.check
new file mode 100644
index 0000000000..e79539a5c4
--- /dev/null
+++ b/test/files/run/t4625b.check
@@ -0,0 +1 @@
+Misc top-level detritus
diff --git a/test/files/run/t4625b.scala b/test/files/run/t4625b.scala
new file mode 100644
index 0000000000..44f6225220
--- /dev/null
+++ b/test/files/run/t4625b.scala
@@ -0,0 +1,7 @@
+
+import scala.tools.partest.ScriptTest
+
+object Test extends ScriptTest {
+ // must be called Main to get probing treatment in parser
+ override def testmain = "Main"
+}
diff --git a/test/files/run/t4625b.script b/test/files/run/t4625b.script
new file mode 100644
index 0000000000..f21a553dd1
--- /dev/null
+++ b/test/files/run/t4625b.script
@@ -0,0 +1,8 @@
+
+trait X { def x = "Misc top-level detritus" }
+
+object Bumpkus
+
+object Main extends X with App {
+ println(x)
+}
diff --git a/test/files/run/t4625c.check b/test/files/run/t4625c.check
new file mode 100644
index 0000000000..6acb1710b9
--- /dev/null
+++ b/test/files/run/t4625c.check
@@ -0,0 +1,3 @@
+newSource1.scala:2: warning: Script has a main object but statement is disallowed
+val x = "value x"
+ ^
diff --git a/test/files/run/t4625c.scala b/test/files/run/t4625c.scala
new file mode 100644
index 0000000000..44f6225220
--- /dev/null
+++ b/test/files/run/t4625c.scala
@@ -0,0 +1,7 @@
+
+import scala.tools.partest.ScriptTest
+
+object Test extends ScriptTest {
+ // must be called Main to get probing treatment in parser
+ override def testmain = "Main"
+}
diff --git a/test/files/run/t4625c.script b/test/files/run/t4625c.script
new file mode 100644
index 0000000000..16159208e0
--- /dev/null
+++ b/test/files/run/t4625c.script
@@ -0,0 +1,7 @@
+
+val x = "value x"
+val y = "value y"
+
+object Main extends App {
+ println(s"Test ran with $x.")
+}
diff --git a/test/files/run/t7805-repl-i.check b/test/files/run/t7805-repl-i.check
index 24512c0067..70f024605c 100644
--- a/test/files/run/t7805-repl-i.check
+++ b/test/files/run/t7805-repl-i.check
@@ -1,6 +1,3 @@
-Loading t7805-repl-i.script...
-import util._
-
Welcome to Scala
Type in expressions for evaluation. Or try :help.
diff --git a/test/files/run/t9170.scala b/test/files/run/t9170.scala
index f39467bc25..87471fb129 100644
--- a/test/files/run/t9170.scala
+++ b/test/files/run/t9170.scala
@@ -44,7 +44,7 @@ object Y {
// Exiting paste mode, now interpreting.
-<console>:13: error: double definition:
+<pastie>:13: error: double definition:
def f[A](a: => A): Int at line 12 and
def f[A](a: => Either[Exception,A]): Int at line 13
have same type after erasure: (a: Function0)Int
diff --git a/test/junit/scala/collection/immutable/HashMapTest.scala b/test/junit/scala/collection/immutable/HashMapTest.scala
new file mode 100644
index 0000000000..a970786455
--- /dev/null
+++ b/test/junit/scala/collection/immutable/HashMapTest.scala
@@ -0,0 +1,48 @@
+package scala.collection.immutable
+
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(classOf[JUnit4])
+class HashMapTest {
+
+ private val computeHashF = {
+ HashMap.empty.computeHash _
+ }
+
+ @Test
+ def canMergeIdenticalHashMap1sWithNullKvs() {
+ def m = new HashMap.HashMap1(1, computeHashF(1), 1, null)
+ val merged = m.merged(m)(null)
+ assertEquals(m, merged)
+ }
+
+ @Test
+ def canMergeIdenticalHashMap1sWithNullKvsCustomMerge() {
+ def m = new HashMap.HashMap1(1, computeHashF(1), 1, null)
+ val merged = m.merged(m) {
+ case ((k1, v1), (k2, v2)) =>
+ (k1, v1 + v2)
+ }
+ assertEquals(new HashMap.HashMap1(1, computeHashF(1), 2, null), merged)
+ }
+
+ @Test
+ def canMergeHashMap1sWithNullKvsHashCollision() {
+ val key1 = 1000L * 1000 * 1000 * 10
+ val key2 = key1.##.toLong
+ assert(key1.## == key2.##)
+
+ val m1 = new HashMap.HashMap1(key1, computeHashF(key1.##), 1, null)
+ val m2 = new HashMap.HashMap1(key2, computeHashF(key2.##), 1, null)
+ val expected = HashMap(key1 -> 1, key2 -> 1)
+ val merged = m1.merged(m2)(null)
+ assertEquals(expected, merged)
+ val mergedWithMergeFunction = m1.merged(m2) { (kv1, kv2) =>
+ throw new RuntimeException("Should not be reached.")
+ }
+ assertEquals(expected, mergedWithMergeFunction)
+ }
+} \ No newline at end of file
diff --git a/test/junit/scala/collection/immutable/StringLikeTest.scala b/test/junit/scala/collection/immutable/StringLikeTest.scala
index 50be638b89..44bade860e 100644
--- a/test/junit/scala/collection/immutable/StringLikeTest.scala
+++ b/test/junit/scala/collection/immutable/StringLikeTest.scala
@@ -1,5 +1,6 @@
package scala.collection.immutable
+import org.junit.Assert._
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -40,4 +41,34 @@ class StringLikeTest {
AssertUtil.assertSameElements("--ch--omp--".split("-"), Array("", "", "ch", "", "omp")) // All the cases!
AssertUtil.assertSameElements(twopairs.split(high), Array(twopairs)) //don't split on characters that are half a surrogate pair
}
+
+ /* Test for SI-9767 */
+ @Test
+ def testNumericConversion: Unit = {
+ val sOne = " \t\n 1 \n\r\t "
+ val sOk = "2"
+ val sNull:String = null
+
+ AssertUtil.assertThrows[java.lang.NumberFormatException](sOne.toInt)
+ AssertUtil.assertThrows[java.lang.NumberFormatException](sOne.toLong)
+ AssertUtil.assertThrows[java.lang.NumberFormatException](sOne.toShort)
+ AssertUtil.assertThrows[java.lang.NumberFormatException](sOne.toByte)
+ assertTrue("trim toDouble", sOne.toDouble == 1.0d)
+ assertTrue("trim toFloat", sOne.toFloat == 1.0f)
+
+ assertTrue("no trim toInt", sOk.toInt == 2)
+ assertTrue("no trim toLong", sOk.toLong == 2L)
+ assertTrue("no trim toShort", sOk.toShort == 2.toShort)
+ assertTrue("no trim toByte", sOk.toByte == 2.toByte)
+ assertTrue("no trim toDouble", sOk.toDouble == 2.0d)
+ assertTrue("no trim toFloat", sOk.toFloat == 2.0f)
+
+ AssertUtil.assertThrows[java.lang.NumberFormatException](sNull.toInt, {s => s == "null"})
+ AssertUtil.assertThrows[java.lang.NumberFormatException](sNull.toLong, {s => s == "null"})
+ AssertUtil.assertThrows[java.lang.NumberFormatException](sNull.toShort, {s => s == "null"})
+ AssertUtil.assertThrows[java.lang.NumberFormatException](sNull.toByte, {s => s == "null"})
+
+ AssertUtil.assertThrows[java.lang.NullPointerException](sNull.toDouble)
+ AssertUtil.assertThrows[java.lang.NullPointerException](sNull.toFloat)
+ }
}
diff --git a/test/junit/scala/lang/primitives/NaNTest.scala b/test/junit/scala/lang/primitives/NaNTest.scala
new file mode 100644
index 0000000000..f4c4258395
--- /dev/null
+++ b/test/junit/scala/lang/primitives/NaNTest.scala
@@ -0,0 +1,38 @@
+package scala.lang.primitives
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.tools.testing.RunTesting
+
+@RunWith(classOf[JUnit4])
+class NaNTest extends RunTesting {
+
+ @Test
+ def compNaNFalse(): Unit = {
+ def code(tp: String) =
+ s"""val n = $tp.NaN
+ |def ne(x: $tp, y: $tp) = x != y
+ |val fs: List[($tp, $tp) => Boolean] = List(_ < _, _ <= _, _ > _, _ >= _, _ == _, (x, y) => !ne(x, y))
+ |val vs = List[$tp](n, 1, -1, 0)
+ |for (f <- fs; v <- vs; (x, y) <- List((n, v), (v, n))) yield f(x, y)
+ """.stripMargin
+
+ runner.run[List[Boolean]](code("Double")).foreach(assertFalse)
+ runner.run[List[Boolean]](code("Float")).foreach(assertFalse)
+ }
+
+ @Test
+ def genericEqNe(): Unit = {
+ def code(tp: String) =
+ s"""def a[T](x: T, y: T) = x == y
+ |def b[T](x: T, y: T) = x != y
+ |val n = $tp.NaN
+ |a(n, n) :: a(n, 0) :: a (0, n) :: !b(n, n) :: !b(n, 0) :: !b(0, n) :: Nil
+ """.stripMargin
+ runner.run[List[Boolean]](code("Double")).foreach(assertFalse)
+ runner.run[List[Boolean]](code("Float")).foreach(assertFalse)
+ }
+}