summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bincompat-backward.whitelist.conf4
-rw-r--r--bincompat-forward.whitelist.conf4
-rw-r--r--build-ant-macros.xml5
-rw-r--r--build.number2
-rwxr-xr-xbuild.xml32
-rw-r--r--src/build/bnd/scala-actors.bnd2
-rw-r--r--src/build/bnd/scala-compiler-doc.bnd3
-rw-r--r--src/build/bnd/scala-compiler-interactive.bnd3
-rw-r--r--src/build/bnd/scala-compiler.bnd4
-rw-r--r--src/build/bnd/scala-continuations-library.bnd4
-rw-r--r--src/build/bnd/scala-continuations-plugin.bnd4
-rw-r--r--src/build/bnd/scala-library.bnd1
-rw-r--r--src/build/bnd/scala-parser-combinators.bnd4
-rw-r--r--src/build/bnd/scala-reflect.bnd5
-rw-r--r--src/build/bnd/scala-swing.bnd4
-rw-r--r--src/build/bnd/scala-xml.bnd4
-rw-r--r--src/build/maven/scala-dist-pom.xml5
-rw-r--r--src/compiler/scala/tools/nsc/CompilerCommand.scala11
-rw-r--r--src/compiler/scala/tools/nsc/Driver.scala21
-rw-r--r--src/compiler/scala/tools/nsc/GenericRunnerCommand.scala27
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala13
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala8
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala96
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala718
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala96
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala139
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala25
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala17
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala171
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala417
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala7
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala11
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala48
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala12
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala20
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala11
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala1
-rw-r--r--src/interactive/scala/tools/nsc/interactive/Main.scala7
-rwxr-xr-xsrc/library/scala/collection/IndexedSeqOptimized.scala2
-rw-r--r--src/library/scala/collection/Iterator.scala17
-rw-r--r--src/library/scala/collection/immutable/HashSet.scala7
-rw-r--r--src/library/scala/collection/immutable/ListSet.scala7
-rw-r--r--src/library/scala/collection/immutable/Set.scala16
-rw-r--r--src/library/scala/collection/mutable/AVLTree.scala2
-rw-r--r--src/library/scala/concurrent/Channel.scala17
-rw-r--r--src/library/scala/concurrent/ExecutionContext.scala4
-rw-r--r--src/library/scala/concurrent/Lock.scala2
-rw-r--r--src/library/scala/concurrent/SyncVar.scala16
-rw-r--r--src/library/scala/concurrent/package.scala5
-rw-r--r--src/library/scala/util/Properties.scala7
-rw-r--r--src/reflect/scala/reflect/internal/Names.scala106
-rw-r--r--src/reflect/scala/reflect/internal/Scopes.scala24
-rw-r--r--src/reflect/scala/reflect/internal/util/SourceFile.scala2
-rw-r--r--src/reflect/scala/reflect/runtime/SymbolLoaders.scala2
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedOps.scala3
-rw-r--r--src/reflect/scala/reflect/runtime/package.scala3
-rw-r--r--src/repl/scala/tools/nsc/MainGenericRunner.scala128
-rw-r--r--test/files/neg/double-def-top-level.check7
-rw-r--r--test/files/neg/double-def-top-level/A_1.scala4
-rw-r--r--test/files/neg/double-def-top-level/B_2.scala2
-rw-r--r--test/files/neg/double-def-top-level/C_3.scala2
-rw-r--r--test/files/neg/double-def-top-level/D_3.scala2
-rw-r--r--test/files/neg/t6289.check2
-rw-r--r--test/files/neg/t8630.check7
-rw-r--r--test/files/neg/t8630.scala1
-rw-r--r--test/files/pos/t8596.flags1
-rw-r--r--test/files/pos/t8596.scala7
-rw-r--r--test/files/pos/t8617.flags1
-rw-r--r--test/files/pos/t8617.scala10
-rw-r--r--test/files/pos/t8625.scala5
-rw-r--r--test/files/presentation/ide-bug-1000531.check111
-rw-r--r--test/files/presentation/ide-bug-1000531/src/CrashOnLoad.scala15
-rw-r--r--test/files/presentation/ide-bug-1000531/src/TestIterable.java7
-rw-r--r--test/files/presentation/t7915.check20
-rw-r--r--test/files/presentation/t7915/src/Foo.scala4
-rw-r--r--test/files/run/analyzerPlugins.check13
-rw-r--r--test/files/run/icode-reader-dead-code.check19
-rw-r--r--test/files/run/icode-reader-dead-code.scala82
-rw-r--r--test/files/run/repl-javap-app.check39
-rw-r--r--test/files/run/repl-javap-app.scala11
-rw-r--r--test/files/run/t7974.check29
-rw-r--r--test/files/run/t7974/Test.scala2
-rw-r--r--test/files/run/t8346.check6
-rw-r--r--test/files/run/t8346.scala34
-rw-r--r--test/files/run/t8607.scala36
-rw-r--r--test/files/run/t8637.check0
-rw-r--r--test/files/run/t8637.scala9
-rw-r--r--test/junit/scala/collection/IndexedSeqOptimizedTest.scala16
-rw-r--r--test/junit/scala/collection/IteratorTest.scala28
-rw-r--r--test/junit/scala/reflect/internal/NamesTest.scala95
-rw-r--r--test/junit/scala/reflect/internal/ScopeTest.scala54
-rw-r--r--test/junit/scala/reflect/internal/util/SourceFileTest.scala5
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala104
-rw-r--r--test/junit/scala/tools/testing/AssertUtil.scala17
-rw-r--r--versions.properties12
99 files changed, 1730 insertions, 1435 deletions
diff --git a/bincompat-backward.whitelist.conf b/bincompat-backward.whitelist.conf
index 703c5add42..ffacbf0442 100644
--- a/bincompat-backward.whitelist.conf
+++ b/bincompat-backward.whitelist.conf
@@ -181,6 +181,10 @@ filter {
{
matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticExistentialType"
problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.reflect.runtime.SynchronizedOps.newNestedScope"
+ problemName=MissingMethodProblem
}
]
}
diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf
index ca8f7468eb..3cd985aeae 100644
--- a/bincompat-forward.whitelist.conf
+++ b/bincompat-forward.whitelist.conf
@@ -230,6 +230,10 @@ filter {
{
matchName="scala.reflect.runtime.JavaMirrors#JavaMirror.scala$reflect$runtime$JavaMirrors$JavaMirror$$followStatic"
problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.reflect.runtime.SynchronizedOps.newNestedScope"
+ problemName=MissingMethodProblem
}
]
}
diff --git a/build-ant-macros.xml b/build-ant-macros.xml
index bd0e723b9b..609f106d09 100644
--- a/build-ant-macros.xml
+++ b/build-ant-macros.xml
@@ -467,6 +467,11 @@
<filter token="SCALA_FULL_VERSION" value="${scala.full.version}"/>
<filter token="SCALA_COMPILER_DOC_VERSION" value="${scala-compiler-doc.version.number}"/>
<filter token="SCALA_COMPILER_INTERACTIVE_VERSION" value="${scala-compiler-interactive.version.number}"/>
+ <filter token="XML_VERSION" value="${scala-xml.version.number}" />
+ <filter token="PARSER_COMBINATORS_VERSION" value="${scala-parser-combinators.version.number}" />
+ <filter token="CONTINUATIONS_PLUGIN_VERSION" value="${scala-continuations-plugin.version.number}" />
+ <filter token="CONTINUATIONS_LIBRARY_VERSION" value="${scala-continuations-library.version.number}" />
+ <filter token="SCALA_SWING_VERSION" value="${scala-swing.version.number}" />
</filterset>
</copy>
<bnd classpath="${@{project}.jar}" eclipse="false" failok="false" exceptions="true" files="${build-osgi.dir}/${@{project}.name}.bnd" output="${build-osgi.dir}"/>
diff --git a/build.number b/build.number
index 63a55339b9..4a0898529e 100644
--- a/build.number
+++ b/build.number
@@ -1,7 +1,7 @@
#Tue Sep 11 19:21:09 CEST 2007
version.major=2
version.minor=11
-version.patch=1
+version.patch=2
# This is the -N part of a version. if it's 0, it's dropped from maven versions.
version.bnum=0
diff --git a/build.xml b/build.xml
index ed12eb06d2..c407c8d797 100755
--- a/build.xml
+++ b/build.xml
@@ -1357,20 +1357,24 @@ TODO:
</target>
<target name="test.osgi" depends="test.osgi.comp">
- <stopwatch name="test.osgi.timer"/>
- <mkdir dir="${test.osgi.classes}"/>
-
- <echo message="Running OSGi JUnit tests. Output in ${build-osgi.dir}"/>
- <junit fork="yes" haltonfailure="yes">
- <classpath refid="test.osgi.compiler.build.path"/>
- <batchtest fork="yes" todir="${build-osgi.dir}">
- <fileset dir="${test.osgi.classes}">
- <include name="**/*Test.class"/>
- </fileset>
- </batchtest>
- <formatter type="xml" /> <!-- silenced by having it use a file; I tried for an hour to use other formatters but classpath issues drove me to this usefile="false" -->
- </junit>
- <stopwatch name="test.osgi.timer" action="total"/>
+ <if><isset property="has.java8"/><then>
+ <echo message="Skipping OSGi JUnit tests on Java 8. See SI-8642"/>
+ </then><else>
+ <echo message="Running OSGi JUnit tests. Output in ${build-osgi.dir}"/>
+ <stopwatch name="test.osgi.timer"/>
+ <mkdir dir="${test.osgi.classes}"/>
+
+ <junit fork="yes" haltonfailure="yes">
+ <classpath refid="test.osgi.compiler.build.path"/>
+ <batchtest fork="yes" todir="${build-osgi.dir}">
+ <fileset dir="${test.osgi.classes}">
+ <include name="**/*Test.class"/>
+ </fileset>
+ </batchtest>
+ <formatter type="xml" /> <!-- silenced by having it use a file; I tried for an hour to use other formatters but classpath issues drove me to this usefile="false" -->
+ </junit>
+ <stopwatch name="test.osgi.timer" action="total"/>
+ </else></if>
</target>
diff --git a/src/build/bnd/scala-actors.bnd b/src/build/bnd/scala-actors.bnd
index 8d0555777f..69885fc2bf 100644
--- a/src/build/bnd/scala-actors.bnd
+++ b/src/build/bnd/scala-actors.bnd
@@ -3,3 +3,5 @@ Bundle-SymbolicName: org.scala-lang.scala-actors
ver: @VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
+Import-Package: scala.*;version="${range;[==,=+);${ver}}",*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-compiler-doc.bnd b/src/build/bnd/scala-compiler-doc.bnd
index 4910e5fcb0..9d6d0304d1 100644
--- a/src/build/bnd/scala-compiler-doc.bnd
+++ b/src/build/bnd/scala-compiler-doc.bnd
@@ -3,4 +3,5 @@ Bundle-SymbolicName: org.scala-lang.modules.scala-compiler-doc_@SCALA_BINARY_VER
ver: @SCALA_COMPILER_DOC_VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
-Import-Package: *
+Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-compiler-interactive.bnd b/src/build/bnd/scala-compiler-interactive.bnd
index 34d2f2956d..07e3de35b0 100644
--- a/src/build/bnd/scala-compiler-interactive.bnd
+++ b/src/build/bnd/scala-compiler-interactive.bnd
@@ -3,4 +3,5 @@ Bundle-SymbolicName: org.scala-lang.modules.scala-compiler-interactive_@SCALA_BI
ver: @SCALA_COMPILER_INTERACTIVE_VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
-Import-Package: *
+Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-compiler.bnd b/src/build/bnd/scala-compiler.bnd
index dc30513db4..2bd24d780d 100644
--- a/src/build/bnd/scala-compiler.bnd
+++ b/src/build/bnd/scala-compiler.bnd
@@ -5,4 +5,8 @@ Bundle-Version: ${ver}
Export-Package: *;version=${ver}
Import-Package: jline.*;resolution:=optional, \
org.apache.tools.ant.*;resolution:=optional, \
+ scala.util.parsing.*;version="${range;[====,====];@PARSER_COMBINATORS_VERSION@}";resolution:=optional, \
+ scala.xml.*;version="${range;[====,====];@XML_VERSION@}";resolution:=optional, \
+ scala.*;version="${range;[==,=+);${ver}}", \
*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-continuations-library.bnd b/src/build/bnd/scala-continuations-library.bnd
index bb505b60a9..b36718cc5b 100644
--- a/src/build/bnd/scala-continuations-library.bnd
+++ b/src/build/bnd/scala-continuations-library.bnd
@@ -1,5 +1,7 @@
Bundle-Name: Scala Delimited Continuations Library
Bundle-SymbolicName: org.scala-lang.plugins.scala-continuations-library
-ver: @VERSION@
+ver: @CONTINUATIONS_LIBRARY_VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
+Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-continuations-plugin.bnd b/src/build/bnd/scala-continuations-plugin.bnd
index cd66614a22..2f2464b452 100644
--- a/src/build/bnd/scala-continuations-plugin.bnd
+++ b/src/build/bnd/scala-continuations-plugin.bnd
@@ -1,5 +1,7 @@
Bundle-Name: Scala Delimited Continuations Compiler Plugin
Bundle-SymbolicName: org.scala-lang.plugins.scala-continuations-plugin
-ver: @VERSION@
+ver: @CONTINUATIONS_PLUGIN_VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
+Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-library.bnd b/src/build/bnd/scala-library.bnd
index 03aff45672..7eb4fa4b2a 100644
--- a/src/build/bnd/scala-library.bnd
+++ b/src/build/bnd/scala-library.bnd
@@ -4,3 +4,4 @@ ver: @VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
Import-Package: sun.misc;resolution:=optional, *
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-parser-combinators.bnd b/src/build/bnd/scala-parser-combinators.bnd
index 6ffc3b2760..ef8646cbd0 100644
--- a/src/build/bnd/scala-parser-combinators.bnd
+++ b/src/build/bnd/scala-parser-combinators.bnd
@@ -1,5 +1,7 @@
Bundle-Name: Scala Parser Combinators Library
Bundle-SymbolicName: org.scala-lang.modules.scala-parser-combinators
-ver: @VERSION@
+ver: @PARSER_COMBINATORS_VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
+Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-reflect.bnd b/src/build/bnd/scala-reflect.bnd
index 6cda346d3a..e4bc54e52e 100644
--- a/src/build/bnd/scala-reflect.bnd
+++ b/src/build/bnd/scala-reflect.bnd
@@ -3,4 +3,7 @@ Bundle-SymbolicName: org.scala-lang.scala-reflect
ver: @VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
-Import-Package: scala.tools.nsc;resolution:=optional, *
+Import-Package: scala.*;version="${range;[==,=+);${ver}}", \
+ scala.tools.nsc;resolution:=optional;version="${range;[==,=+);${ver}}", \
+ *
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-swing.bnd b/src/build/bnd/scala-swing.bnd
index 7cccb1343b..f8b50baa91 100644
--- a/src/build/bnd/scala-swing.bnd
+++ b/src/build/bnd/scala-swing.bnd
@@ -1,5 +1,7 @@
Bundle-Name: Scala Swing
Bundle-SymbolicName: org.scala-lang.modules.scala-swing
-ver: @VERSION@
+ver: @SCALA_SWING_VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
+Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6,JavaSE-1.7
diff --git a/src/build/bnd/scala-xml.bnd b/src/build/bnd/scala-xml.bnd
index 5d64c05e65..01bf0144eb 100644
--- a/src/build/bnd/scala-xml.bnd
+++ b/src/build/bnd/scala-xml.bnd
@@ -1,5 +1,7 @@
Bundle-Name: Scala XML Library
Bundle-SymbolicName: org.scala-lang.modules.scala-xml
-ver: @VERSION@
+ver: @XML_VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
+Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/maven/scala-dist-pom.xml b/src/build/maven/scala-dist-pom.xml
index 22a24dea21..9477e14285 100644
--- a/src/build/maven/scala-dist-pom.xml
+++ b/src/build/maven/scala-dist-pom.xml
@@ -40,6 +40,11 @@
<version>@VERSION@</version>
</dependency>
<dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scalap</artifactId>
+ <version>@VERSION@</version>
+ </dependency>
+ <dependency>
<groupId>org.scala-lang.plugins</groupId>
<!-- plugins are fully cross-versioned. But, we don't publish with 2.11.0-SNAPSHOT, instead use full version of the last non-snapshot version -->
<artifactId>scala-continuations-plugin_@SCALA_FULL_VERSION@</artifactId>
diff --git a/src/compiler/scala/tools/nsc/CompilerCommand.scala b/src/compiler/scala/tools/nsc/CompilerCommand.scala
index bab0768ca9..a1d0d52dcf 100644
--- a/src/compiler/scala/tools/nsc/CompilerCommand.scala
+++ b/src/compiler/scala/tools/nsc/CompilerCommand.scala
@@ -20,9 +20,12 @@ class CompilerCommand(arguments: List[String], val settings: Settings) {
def ok = processArgumentsResult._1
def files = processArgumentsResult._2
- /** The name of the command */
+ /** The name of the command. */
def cmdName = "scalac"
+ /** A descriptive alias for version and help messages. */
+ def cmdDesc = "compiler"
+
private def explainAdvanced = "\n" + """
|-- Notes on option parsing --
|Boolean settings are always false unless set.
@@ -85,7 +88,11 @@ class CompilerCommand(arguments: List[String], val settings: Settings) {
def getInfoMessage(global: Global): String = {
import settings._
- if (help) usageMsg + global.pluginOptionsHelp
+ import Properties.{ versionString, copyrightString } //versionFor
+ def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ if (version) versionFor(cmdDesc)
+ else if (help) usageMsg + global.pluginOptionsHelp
else if (Xhelp) xusageMsg
else if (Yhelp) yusageMsg
else if (showPlugins) global.pluginDescriptions
diff --git a/src/compiler/scala/tools/nsc/Driver.scala b/src/compiler/scala/tools/nsc/Driver.scala
index 3ac27a42e8..6befa76b3f 100644
--- a/src/compiler/scala/tools/nsc/Driver.scala
+++ b/src/compiler/scala/tools/nsc/Driver.scala
@@ -2,26 +2,24 @@ package scala
package tools.nsc
import scala.tools.nsc.reporters.ConsoleReporter
-import Properties.{ versionString, copyrightString, residentPromptString }
+import Properties.{ versionMsg, residentPromptString }
import scala.reflect.internal.util.FakePos
abstract class Driver {
val prompt = residentPromptString
- val versionMsg = "Scala compiler " +
- versionString + " -- " +
- copyrightString
-
var reporter: ConsoleReporter = _
protected var command: CompilerCommand = _
protected var settings: Settings = _
- protected def scalacError(msg: String) {
+ protected def scalacError(msg: String): Unit = {
reporter.error(FakePos("scalac"), msg + "\n scalac -help gives more information")
}
- protected def processSettingsHook(): Boolean = true
+ protected def processSettingsHook(): Boolean = {
+ if (settings.version) { reporter echo versionMsg ; false } else true
+ }
protected def newCompiler(): Global
@@ -37,14 +35,12 @@ abstract class Driver {
}
def process(args: Array[String]) {
- val ss = new Settings(scalacError)
- reporter = new ConsoleReporter(ss)
+ val ss = new Settings(scalacError)
+ reporter = new ConsoleReporter(ss)
command = new CompilerCommand(args.toList, ss)
settings = command.settings
- if (settings.version) {
- reporter.echo(versionMsg)
- } else if (processSettingsHook()) {
+ if (processSettingsHook()) {
val compiler = newCompiler()
try {
if (reporter.hasErrors)
@@ -68,5 +64,4 @@ abstract class Driver {
process(args)
sys.exit(if (reporter.hasErrors) 1 else 0)
}
-
}
diff --git a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala
index e710222285..dbdeec809f 100644
--- a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala
+++ b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala
@@ -19,9 +19,10 @@ extends CompilerCommand(args, settings) {
def this(args: List[String]) =
this(args, str => Console.println("Error: " + str))
- /** name of the associated compiler command */
override def cmdName = "scala"
- def compCmdName = "scalac"
+ override def cmdDesc = "code runner"
+
+ def compCmdName = "scalac" // super.cmdName
// change CompilerCommand behavior
override def shouldProcessArguments: Boolean = false
@@ -50,17 +51,16 @@ extends CompilerCommand(args, settings) {
case Nil => AsRepl
case hd :: _ => waysToRun find (_.name == settings.howtorun.value) getOrElse guessHowToRun(hd)
}
- private def interpolate(s: String) = s.trim.replaceAll("@cmd@", cmdName).replaceAll("@compileCmd@", compCmdName) + "\n"
-
- def shortUsageMsg = interpolate("""
-Usage: @cmd@ <options> [<script|class|object|jar> <arguments>]
- or @cmd@ -help
-All options to @compileCmd@ (see @compileCmd@ -help) are also allowed.
-""")
+ def shortUsageMsg =
+s"""|Usage: $cmdName <options> [<script|class|object|jar> <arguments>]
+ | or $cmdName -help
+ |
+ |All options to $compCmdName (see $compCmdName -help) are also allowed.
+""".stripMargin
- override def usageMsg = shortUsageMsg + interpolate("""
-The first given argument other than options to @cmd@ designates
+ override def usageMsg = f"""$shortUsageMsg
+The first given argument other than options to $cmdName designates
what to run. Runnable targets are:
- a file containing scala source
@@ -68,7 +68,7 @@ what to run. Runnable targets are:
- a runnable jar file with a valid Main-Class attribute
- or if no argument is given, the repl (interactive shell) is started
-Options to @cmd@ which reach the java runtime:
+Options to $cmdName which reach the java runtime:
-Dname=prop passed directly to java to set system properties
-J<arg> -J is stripped and <arg> passed to java as-is
@@ -86,8 +86,7 @@ A file argument will be run as a scala script unless it contains only
self-contained compilation units (classes and objects) and exactly one
runnable main method. In that case the file will be compiled and the
main method invoked. This provides a bridge between scripts and standard
-scala source.
- """) + "\n"
+scala source.%n"""
}
object GenericRunnerCommand {
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 0da66d43f7..0ad3c2c76b 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -1424,11 +1424,18 @@ abstract class GenICode extends SubComponent {
def genZandOrZor(and: Boolean): Boolean = {
val ctxInterm = ctx.newBlock()
- val branchesReachable = if (and) genCond(lhs, ctx, ctxInterm, elseCtx)
+ val lhsBranchesReachable = if (and) genCond(lhs, ctx, ctxInterm, elseCtx)
else genCond(lhs, ctx, thenCtx, ctxInterm)
- ctxInterm.bb killUnless branchesReachable
+ // If lhs is known to throw, we can kill the just created ctxInterm.
+ ctxInterm.bb killUnless lhsBranchesReachable
- genCond(rhs, ctxInterm, thenCtx, elseCtx)
+ val rhsBranchesReachable = genCond(rhs, ctxInterm, thenCtx, elseCtx)
+
+ // Reachable means "it does not always throw", i.e. "it might not throw".
+ // In an expression (a && b) or (a || b), the b branch might not be evaluated.
+ // Such an expression is therefore known to throw only if both expressions throw. Or,
+ // successors are reachable if either of the two is reachable (SI-8625).
+ lhsBranchesReachable || rhsBranchesReachable
}
def genRefEq(isEq: Boolean) = {
val f = genEqEqPrimitive(lhs, rhs, ctx) _
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
index 856f85d9e3..2af2037fec 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
@@ -8,6 +8,7 @@ package scala.tools.nsc.backend.jvm
import scala.tools.asm.tree.{ClassNode, MethodNode}
import java.io.PrintWriter
import scala.tools.asm.util.{TraceClassVisitor, TraceMethodVisitor, Textifier}
+import scala.tools.asm.ClassReader
object AsmUtils {
@@ -50,4 +51,11 @@ object AsmUtils {
w.flush()
}
+ def traceClass(bytes: Array[Byte]): Unit = traceClass(readClass(bytes))
+
+ def readClass(bytes: Array[Byte]): ClassNode = {
+ val node = new ClassNode()
+ new ClassReader(bytes).accept(node, 0)
+ node
+ }
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
index 3d1b646069..bffa4bc51d 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
@@ -24,6 +24,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
import global._
import definitions._
import bCodeICodeCommon._
+ import bTypes._
/*
* Functionality to build the body of ASM MethodNode, except for `synchronized` and `try` expressions.
@@ -46,16 +47,16 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
def emit(opc: Int) { mnode.visitInsn(opc) }
def emitZeroOf(tk: BType) {
- (tk.sort: @switch) match {
- case asm.Type.BOOLEAN => bc.boolconst(false)
- case asm.Type.BYTE |
- asm.Type.SHORT |
- asm.Type.CHAR |
- asm.Type.INT => bc.iconst(0)
- case asm.Type.LONG => bc.lconst(0)
- case asm.Type.FLOAT => bc.fconst(0)
- case asm.Type.DOUBLE => bc.dconst(0)
- case asm.Type.VOID => ()
+ tk match {
+ case BOOL => bc.boolconst(false)
+ case BYTE |
+ SHORT |
+ CHAR |
+ INT => bc.iconst(0)
+ case LONG => bc.lconst(0)
+ case FLOAT => bc.fconst(0)
+ case DOUBLE => bc.dconst(0)
+ case UNIT => ()
case _ => emit(asm.Opcodes.ACONST_NULL)
}
}
@@ -166,7 +167,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
// load argument on stack
assert(args.length == 1, s"Too many arguments for array get operation: $tree");
genLoad(args.head, INT)
- generatedType = k.getComponentType
+ generatedType = k.asArrayBType.componentType
bc.aload(elementType)
}
else if (scalaPrimitives.isArraySet(code)) {
@@ -320,7 +321,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
generatedType =
if (tree.symbol == ArrayClass) ObjectReference
- else brefType(thisName) // inner class (if any) for claszSymbol already tracked.
+ else ClassBType(thisName) // inner class (if any) for claszSymbol already tracked.
}
case Select(Ident(nme.EMPTY_PACKAGE_NAME), module) =>
@@ -418,7 +419,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
if (hostClass == null) internalName(field.owner)
else internalName(hostClass)
val fieldJName = field.javaSimpleName.toString
- val fieldDescr = symInfoTK(field).getDescriptor
+ val fieldDescr = symInfoTK(field).descriptor
val isStatic = field.isStaticMember
val opc =
if (isLoad) { if (isStatic) asm.Opcodes.GETSTATIC else asm.Opcodes.GETFIELD }
@@ -459,7 +460,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
case ClazzTag =>
val toPush: BType = {
val kind = toTypeKind(const.typeValue)
- if (kind.isValueType) classLiteral(kind)
+ if (kind.isPrimitive) classLiteral(kind)
else kind
}
mnode.visitLdcInsn(toPush.toASMType)
@@ -468,7 +469,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
val sym = const.symbolValue
val ownerName = internalName(sym.owner)
val fieldName = sym.javaSimpleName.toString
- val fieldDesc = toTypeKind(sym.tpe.underlying).getDescriptor
+ val fieldDesc = toTypeKind(sym.tpe.underlying).descriptor
mnode.visitFieldInsn(
asm.Opcodes.GETSTATIC,
ownerName,
@@ -540,26 +541,28 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
def genTypeApply(): BType = {
genLoadQualifier(fun)
- if (l.isValueType && r.isValueType)
+ // TODO @lry make pattern match
+ if (l.isPrimitive && r.isPrimitive)
genConversion(l, r, cast)
- else if (l.isValueType) {
+ else if (l.isPrimitive) {
bc drop l
if (cast) {
- mnode.visitTypeInsn(asm.Opcodes.NEW, classCastExceptionReference.getInternalName)
+ mnode.visitTypeInsn(asm.Opcodes.NEW, classCastExceptionReference.internalName)
bc dup ObjectReference
emit(asm.Opcodes.ATHROW)
} else {
bc boolconst false
}
}
- else if (r.isValueType && cast) {
+ else if (r.isPrimitive && cast) {
abort(s"Erasure should have added an unboxing operation to prevent this cast. Tree: $app")
}
- else if (r.isValueType) {
+ else if (r.isPrimitive) {
bc isInstance classLiteral(r)
}
else {
- genCast(r, cast)
+ assert(r.isRef, r) // ensure that it's not a method
+ genCast(r.asRefBType, cast)
}
if (cast) r else BOOL
@@ -579,7 +582,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
genLoadArguments(args, paramTKs(app))
genCallMethod(fun.symbol, invokeStyle, pos = app.pos)
- generatedType = asmMethodType(fun.symbol).getReturnType
+ generatedType = asmMethodType(fun.symbol).returnType
// 'new' constructor call: Note: since constructors are
// thought to return an instance of what they construct,
@@ -590,13 +593,13 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
assert(ctor.isClassConstructor, s"'new' call to non-constructor: ${ctor.name}")
generatedType = tpeTK(tpt)
- assert(generatedType.isRefOrArrayType, s"Non reference type cannot be instantiated: $generatedType")
+ assert(generatedType.isRef, s"Non reference type cannot be instantiated: $generatedType")
generatedType match {
- case arr if generatedType.isArray =>
+ case arr @ ArrayBType(componentType) =>
genLoadArguments(args, paramTKs(app))
- val dims = arr.getDimensions
- var elemKind = arr.getElementType
+ val dims = arr.dimension
+ var elemKind = arr.elementType
val argsSize = args.length
if (argsSize > dims) {
cunit.error(app.pos, s"too many arguments for array constructor: found ${args.length} but array has only $dims dimension(s)")
@@ -606,18 +609,18 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
* elemKind = new BType(BType.ARRAY, arr.off + argsSize, arr.len - argsSize)
* however the above does not enter a TypeName for each nested arrays in chrs.
*/
- for (i <- args.length until dims) elemKind = arrayOf(elemKind)
+ for (i <- args.length until dims) elemKind = ArrayBType(elemKind)
}
(argsSize : @switch) match {
case 1 => bc newarray elemKind
case _ =>
- val descr = ('[' * argsSize) + elemKind.getDescriptor // denotes the same as: arrayN(elemKind, argsSize).getDescriptor
+ val descr = ('[' * argsSize) + elemKind.descriptor // denotes the same as: arrayN(elemKind, argsSize).descriptor
mnode.visitMultiANewArrayInsn(descr, argsSize)
}
- case rt if generatedType.hasObjectSort =>
+ case rt: ClassBType =>
assert(exemplar(ctor.owner).c == rt, s"Symbol ${ctor.owner.fullName} is different from $rt")
- mnode.visitTypeInsn(asm.Opcodes.NEW, rt.getInternalName)
+ mnode.visitTypeInsn(asm.Opcodes.NEW, rt.internalName)
bc dup generatedType
genLoadArguments(args, paramTKs(app))
genCallMethod(ctor, icodes.opcodes.Static(onInstance = true))
@@ -630,7 +633,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
val nativeKind = tpeTK(expr)
genLoad(expr, nativeKind)
val MethodNameAndType(mname, mdesc) = asmBoxTo(nativeKind)
- bc.invokestatic(BoxesRunTime.getInternalName, mname, mdesc)
+ bc.invokestatic(BoxesRunTime.internalName, mname, mdesc)
generatedType = boxResultType(fun.symbol) // was toTypeKind(fun.symbol.tpe.resultType)
case Apply(fun @ _, List(expr)) if currentRun.runDefinitions.isUnbox(fun.symbol) =>
@@ -638,7 +641,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
val boxType = unboxResultType(fun.symbol) // was toTypeKind(fun.symbol.owner.linkedClassOfClass.tpe)
generatedType = boxType
val MethodNameAndType(mname, mdesc) = asmUnboxTo(boxType)
- bc.invokestatic(BoxesRunTime.getInternalName, mname, mdesc)
+ bc.invokestatic(BoxesRunTime.internalName, mname, mdesc)
case app @ Apply(fun, args) =>
val sym = fun.symbol
@@ -683,7 +686,12 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
case _ =>
}
if ((targetTypeKind != null) && (sym == definitions.Array_clone) && invokeStyle.isDynamic) {
- val target: String = targetTypeKind.getInternalName
+ // An invokevirtual points to a CONSTANT_Methodref_info which in turn points to a
+ // CONSTANT_Class_info of the receiver type.
+ // The JVMS is not explicit about this, but that receiver type may be an array type
+ // descriptor (instead of a class internal name):
+ // invokevirtual #2; //Method "[I".clone:()Ljava/lang/Object
+ val target: String = targetTypeKind.asRefBType.classOrArrayType
bc.invokevirtual(target, "clone", "()Ljava/lang/Object;")
}
else {
@@ -694,7 +702,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
genNormalMethodCall()
- generatedType = asmMethodType(sym).getReturnType
+ generatedType = asmMethodType(sym).returnType
}
}
@@ -706,7 +714,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
val ArrayValue(tpt @ TypeTree(), elems) = av
val elmKind = tpeTK(tpt)
- val generatedType = arrayOf(elmKind)
+ val generatedType = ArrayBType(elmKind)
lineNumber(av)
bc iconst elems.length
@@ -876,12 +884,12 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
if (claszSymbol == module.moduleClass && jMethodName != "readResolve" && !inStaticMethod) {
mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
} else {
- val mbt = symInfoTK(module)
+ val mbt = symInfoTK(module).asClassBType
mnode.visitFieldInsn(
asm.Opcodes.GETSTATIC,
- mbt.getInternalName /* + "$" */ ,
+ mbt.internalName /* + "$" */ ,
strMODULE_INSTANCE_FIELD,
- mbt.getDescriptor // for nostalgics: toTypeKind(module.tpe).getDescriptor
+ mbt.descriptor // for nostalgics: toTypeKind(module.tpe).descriptor
)
}
}
@@ -894,7 +902,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
}
}
- def genCast(to: BType, cast: Boolean) {
+ def genCast(to: RefBType, cast: Boolean) {
if (cast) { bc checkCast to }
else { bc isInstance to }
}
@@ -959,10 +967,10 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
)
val receiver = if (useMethodOwner) methodOwner else hostSymbol
val bmOwner = asmClassType(receiver)
- val jowner = bmOwner.getInternalName
+ val jowner = bmOwner.internalName
val jname = method.javaSimpleName.toString
val bmType = asmMethodType(method)
- val mdescr = bmType.getDescriptor
+ val mdescr = bmType.descriptor
def initModule() {
// we initialize the MODULE$ field immediately after the super ctor
@@ -1025,7 +1033,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
private def genCJUMP(success: asm.Label, failure: asm.Label, op: TestOp, tk: BType) {
if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
bc.emitIF_ICMP(op, success)
- } else if (tk.isRefOrArrayType) { // REFERENCE(_) | ARRAY(_)
+ } else if (tk.isRef) { // REFERENCE(_) | ARRAY(_)
bc.emitIF_ACMP(op, success)
} else {
(tk: @unchecked) match {
@@ -1046,7 +1054,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
private def genCZJUMP(success: asm.Label, failure: asm.Label, op: TestOp, tk: BType) {
if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
bc.emitIF(op, success)
- } else if (tk.isRefOrArrayType) { // REFERENCE(_) | ARRAY(_)
+ } else if (tk.isRef) { // REFERENCE(_) | ARRAY(_)
// @unchecked because references aren't compared with GT, GE, LT, LE.
(op : @unchecked) match {
case icodes.EQ => bc emitIFNULL success
@@ -1131,7 +1139,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
case ZOR => genZandOrZor(and = false)
case code =>
// TODO !!!!!!!!!! isReferenceType, in the sense of TypeKind? (ie non-array, non-boxed, non-nothing, may be null)
- if (scalaPrimitives.isUniversalEqualityOp(code) && tpeTK(lhs).hasObjectSort) {
+ if (scalaPrimitives.isUniversalEqualityOp(code) && tpeTK(lhs).isClass) {
// `lhs` has reference type
if (code == EQ) genEqEqPrimitive(lhs, rhs, success, failure)
else genEqEqPrimitive(lhs, rhs, failure, success)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala
deleted file mode 100644
index aa7e73a36b..0000000000
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala
+++ /dev/null
@@ -1,718 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2012 LAMP/EPFL
- * @author Martin Odersky
- */
-
-package scala
-package tools.nsc
-package backend.jvm
-
-import scala.tools.asm
-import scala.annotation.switch
-import scala.collection.{ immutable, mutable }
-
-/*
- * Immutable representations of bytecode-level types.
- *
- * @author Miguel Garcia, http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded
- * @version 1.0
- *
- */
-abstract class BCodeGlue extends SubComponent {
-
- import global._
-
- protected val bCodeICodeCommon: BCodeICodeCommon[global.type] = new BCodeICodeCommon(global)
-
- object BType {
-
- import global.chrs
-
- // ------------- sorts -------------
-
- val VOID : Int = 0
- val BOOLEAN: Int = 1
- val CHAR : Int = 2
- val BYTE : Int = 3
- val SHORT : Int = 4
- val INT : Int = 5
- val FLOAT : Int = 6
- val LONG : Int = 7
- val DOUBLE : Int = 8
- val ARRAY : Int = 9
- val OBJECT : Int = 10
- val METHOD : Int = 11
-
- // ------------- primitive types -------------
-
- val VOID_TYPE = new BType(VOID, ('V' << 24) | (5 << 16) | (0 << 8) | 0, 1)
- val BOOLEAN_TYPE = new BType(BOOLEAN, ('Z' << 24) | (0 << 16) | (5 << 8) | 1, 1)
- val CHAR_TYPE = new BType(CHAR, ('C' << 24) | (0 << 16) | (6 << 8) | 1, 1)
- val BYTE_TYPE = new BType(BYTE, ('B' << 24) | (0 << 16) | (5 << 8) | 1, 1)
- val SHORT_TYPE = new BType(SHORT, ('S' << 24) | (0 << 16) | (7 << 8) | 1, 1)
- val INT_TYPE = new BType(INT, ('I' << 24) | (0 << 16) | (0 << 8) | 1, 1)
- val FLOAT_TYPE = new BType(FLOAT, ('F' << 24) | (2 << 16) | (2 << 8) | 1, 1)
- val LONG_TYPE = new BType(LONG, ('J' << 24) | (1 << 16) | (1 << 8) | 2, 1)
- val DOUBLE_TYPE = new BType(DOUBLE, ('D' << 24) | (3 << 16) | (3 << 8) | 2, 1)
-
- /*
- * Returns the Java type corresponding to the given type descriptor.
- *
- * @param off the offset of this descriptor in the chrs buffer.
- * @return the Java type corresponding to the given type descriptor.
- *
- * can-multi-thread
- */
- def getType(off: Int): BType = {
- var len = 0
- chrs(off) match {
- case 'V' => VOID_TYPE
- case 'Z' => BOOLEAN_TYPE
- case 'C' => CHAR_TYPE
- case 'B' => BYTE_TYPE
- case 'S' => SHORT_TYPE
- case 'I' => INT_TYPE
- case 'F' => FLOAT_TYPE
- case 'J' => LONG_TYPE
- case 'D' => DOUBLE_TYPE
- case '[' =>
- len = 1
- while (chrs(off + len) == '[') {
- len += 1
- }
- if (chrs(off + len) == 'L') {
- len += 1
- while (chrs(off + len) != ';') {
- len += 1
- }
- }
- new BType(ARRAY, off, len + 1)
- case 'L' =>
- len = 1
- while (chrs(off + len) != ';') {
- len += 1
- }
- new BType(OBJECT, off + 1, len - 1)
- // case '(':
- case _ =>
- assert(chrs(off) == '(')
- var resPos = off + 1
- while (chrs(resPos) != ')') { resPos += 1 }
- val resType = getType(resPos + 1)
- val len = resPos - off + 1 + resType.len;
- new BType(
- METHOD,
- off,
- if (resType.hasObjectSort) {
- len + 2 // "+ 2" accounts for the "L ... ;" in a descriptor for a non-array reference.
- } else {
- len
- }
- )
- }
- }
-
- /* Params denote an internal name.
- * can-multi-thread
- */
- def getObjectType(index: Int, length: Int): BType = {
- val sort = if (chrs(index) == '[') ARRAY else OBJECT;
- new BType(sort, index, length)
- }
-
- /*
- * @param methodDescriptor a method descriptor.
- *
- * must-single-thread
- */
- def getMethodType(methodDescriptor: String): BType = {
- val n = global.newTypeName(methodDescriptor)
- new BType(BType.METHOD, n.start, n.length) // TODO assert isValidMethodDescriptor
- }
-
- /*
- * Returns the Java method type corresponding to the given argument and return types.
- *
- * @param returnType the return type of the method.
- * @param argumentTypes the argument types of the method.
- * @return the Java type corresponding to the given argument and return types.
- *
- * must-single-thread
- */
- def getMethodType(returnType: BType, argumentTypes: Array[BType]): BType = {
- val n = global.newTypeName(getMethodDescriptor(returnType, argumentTypes))
- new BType(BType.METHOD, n.start, n.length)
- }
-
- /*
- * Returns the Java types corresponding to the argument types of method descriptor whose first argument starts at idx0.
- *
- * @param idx0 index into chrs of the first argument.
- * @return the Java types corresponding to the argument types of the given method descriptor.
- *
- * can-multi-thread
- */
- private def getArgumentTypes(idx0: Int): Array[BType] = {
- assert(chrs(idx0 - 1) == '(', "doesn't look like a method descriptor.")
- val args = new Array[BType](getArgumentCount(idx0))
- var off = idx0
- var size = 0
- while (chrs(off) != ')') {
- args(size) = getType(off)
- off += args(size).len
- if (args(size).sort == OBJECT) { off += 2 }
- // debug: assert("LVZBSCIJFD[)".contains(chrs(off)))
- size += 1
- }
- // debug: var check = 0; while (check < args.length) { assert(args(check) != null); check += 1 }
- args
- }
-
- /*
- * Returns the number of argument types of this method type, whose first argument starts at idx0.
- *
- * @param idx0 index into chrs of the first argument.
- * @return the number of argument types of this method type.
- *
- * can-multi-thread
- */
- private def getArgumentCount(idx0: Int): Int = {
- assert(chrs(idx0 - 1) == '(', "doesn't look like a method descriptor.")
- var off = idx0
- var size = 0
- var keepGoing = true
- while (keepGoing) {
- val car = chrs(off)
- off += 1
- if (car == ')') {
- keepGoing = false
- } else if (car == 'L') {
- while (chrs(off) != ';') { off += 1 }
- off += 1
- size += 1
- } else if (car != '[') {
- size += 1
- }
- }
-
- size
- }
-
- /*
- * Returns the Java type corresponding to the return type of the given
- * method descriptor.
- *
- * @param methodDescriptor a method descriptor.
- * @return the Java type corresponding to the return type of the given method descriptor.
- *
- * must-single-thread
- */
- def getReturnType(methodDescriptor: String): BType = {
- val n = global.newTypeName(methodDescriptor)
- val delta = n.pos(')') // `delta` is relative to the Name's zero-based start position, not a valid index into chrs.
- assert(delta < n.length, s"not a valid method descriptor: $methodDescriptor")
- getType(n.start + delta + 1)
- }
-
- /*
- * Returns the descriptor corresponding to the given argument and return types.
- * Note: no BType is created here for the resulting method descriptor,
- * if that's desired the invoker is responsible for that.
- *
- * @param returnType the return type of the method.
- * @param argumentTypes the argument types of the method.
- * @return the descriptor corresponding to the given argument and return types.
- *
- * can-multi-thread
- */
- def getMethodDescriptor(
- returnType: BType,
- argumentTypes: Array[BType]): String =
- {
- val buf = new StringBuffer()
- buf.append('(')
- var i = 0
- while (i < argumentTypes.length) {
- argumentTypes(i).getDescriptor(buf)
- i += 1
- }
- buf.append(')')
- returnType.getDescriptor(buf)
- buf.toString()
- }
-
- } // end of object BType
-
- /*
- * Based on ASM's Type class. Namer's chrs is used in this class for the same purposes as the `buf` char array in asm.Type.
- *
- * All methods of this classs can-multi-thread
- */
- final class BType(val sort: Int, val off: Int, val len: Int) {
-
- import global.chrs
-
- /*
- * can-multi-thread
- */
- def toASMType: scala.tools.asm.Type = {
- import scala.tools.asm
- // using `asm.Type.SHORT` instead of `BType.SHORT` because otherwise "warning: could not emit switch for @switch annotated match"
- (sort: @switch) match {
- case asm.Type.VOID => asm.Type.VOID_TYPE
- case asm.Type.BOOLEAN => asm.Type.BOOLEAN_TYPE
- case asm.Type.CHAR => asm.Type.CHAR_TYPE
- case asm.Type.BYTE => asm.Type.BYTE_TYPE
- case asm.Type.SHORT => asm.Type.SHORT_TYPE
- case asm.Type.INT => asm.Type.INT_TYPE
- case asm.Type.FLOAT => asm.Type.FLOAT_TYPE
- case asm.Type.LONG => asm.Type.LONG_TYPE
- case asm.Type.DOUBLE => asm.Type.DOUBLE_TYPE
- case asm.Type.ARRAY |
- asm.Type.OBJECT => asm.Type.getObjectType(getInternalName)
- case asm.Type.METHOD => asm.Type.getMethodType(getDescriptor)
- }
- }
-
- /*
- * Unlike for ICode's REFERENCE, isBoxedType(t) implies isReferenceType(t)
- * Also, `isReferenceType(RT_NOTHING) == true` , similarly for RT_NULL.
- * Use isNullType() , isNothingType() to detect Nothing and Null.
- *
- * can-multi-thread
- */
- def hasObjectSort = (sort == BType.OBJECT)
-
- /*
- * Returns the number of dimensions of this array type. This method should
- * only be used for an array type.
- *
- * @return the number of dimensions of this array type.
- *
- * can-multi-thread
- */
- def getDimensions: Int = {
- var i = 1
- while (chrs(off + i) == '[') {
- i += 1
- }
- i
- }
-
- /*
- * Returns the (ultimate) element type of this array type.
- * This method should only be used for an array type.
- *
- * @return Returns the type of the elements of this array type.
- *
- * can-multi-thread
- */
- def getElementType: BType = {
- assert(isArray, s"Asked for the element type of a non-array type: $this")
- BType.getType(off + getDimensions)
- }
-
- /*
- * Returns the internal name of the class corresponding to this object or
- * array type. The internal name of a class is its fully qualified name (as
- * returned by Class.getName(), where '.' are replaced by '/'. This method
- * should only be used for an object or array type.
- *
- * @return the internal name of the class corresponding to this object type.
- *
- * can-multi-thread
- */
- def getInternalName: String = {
- new String(chrs, off, len)
- }
-
- /*
- * @return the suffix of the internal name until the last '/' (if '/' present), internal name otherwise.
- *
- * can-multi-thread
- */
- def getSimpleName: String = {
- assert(hasObjectSort, s"not of object sort: $toString")
- val iname = getInternalName
- val idx = iname.lastIndexOf('/')
- if (idx == -1) iname
- else iname.substring(idx + 1)
- }
-
- /*
- * Returns the argument types of methods of this type.
- * This method should only be used for method types.
- *
- * @return the argument types of methods of this type.
- *
- * can-multi-thread
- */
- def getArgumentTypes: Array[BType] = {
- BType.getArgumentTypes(off + 1)
- }
-
- /*
- * Returns the return type of methods of this type.
- * This method should only be used for method types.
- *
- * @return the return type of methods of this type.
- *
- * can-multi-thread
- */
- def getReturnType: BType = {
- assert(chrs(off) == '(', s"doesn't look like a method descriptor: $toString")
- var resPos = off + 1
- while (chrs(resPos) != ')') { resPos += 1 }
- BType.getType(resPos + 1)
- }
-
- // ------------------------------------------------------------------------
- // Inspector methods
- // ------------------------------------------------------------------------
-
- def isPrimitiveOrVoid = (sort < BType.ARRAY) // can-multi-thread
- def isValueType = (sort < BType.ARRAY) // can-multi-thread
- def isArray = (sort == BType.ARRAY) // can-multi-thread
- def isUnitType = (sort == BType.VOID) // can-multi-thread
-
- def isRefOrArrayType = { hasObjectSort || isArray } // can-multi-thread
- def isNonUnitValueType = { isValueType && !isUnitType } // can-multi-thread
-
- def isNonSpecial = { !isValueType && !isArray && !isPhantomType } // can-multi-thread
- def isNothingType = { (this == RT_NOTHING) || (this == CT_NOTHING) } // can-multi-thread
- def isNullType = { (this == RT_NULL) || (this == CT_NULL) } // can-multi-thread
- def isPhantomType = { isNothingType || isNullType } // can-multi-thread
-
- /*
- * can-multi-thread
- */
- def isBoxed = {
- this match {
- case BOXED_UNIT | BOXED_BOOLEAN | BOXED_CHAR |
- BOXED_BYTE | BOXED_SHORT | BOXED_INT |
- BOXED_FLOAT | BOXED_LONG | BOXED_DOUBLE
- => true
- case _
- => false
- }
- }
-
- /* On the JVM,
- * BOOL, BYTE, CHAR, SHORT, and INT
- * are like Ints for the purpose of lub calculation.
- *
- * can-multi-thread
- */
- def isIntSizedType = {
- (sort : @switch) match {
- case BType.BOOLEAN | BType.CHAR |
- BType.BYTE | BType.SHORT | BType.INT
- => true
- case _
- => false
- }
- }
-
- /* On the JVM, similar to isIntSizedType except that BOOL isn't integral while LONG is.
- *
- * can-multi-thread
- */
- def isIntegralType = {
- (sort : @switch) match {
- case BType.CHAR |
- BType.BYTE | BType.SHORT | BType.INT |
- BType.LONG
- => true
- case _
- => false
- }
- }
-
- /* On the JVM, FLOAT and DOUBLE.
- *
- * can-multi-thread
- */
- def isRealType = { (sort == BType.FLOAT ) || (sort == BType.DOUBLE) }
-
- def isNumericType = (isIntegralType || isRealType) // can-multi-thread
-
- /* Is this type a category 2 type in JVM terms? (ie, is it LONG or DOUBLE?)
- *
- * can-multi-thread
- */
- def isWideType = (getSize == 2)
-
- /*
- * Element vs. Component type of an array:
- * Quoting from the JVMS, Sec. 2.4 "Reference Types and Values"
- *
- * An array type consists of a component type with a single dimension (whose
- * length is not given by the type). The component type of an array type may itself be
- * an array type. If, starting from any array type, one considers its component type,
- * and then (if that is also an array type) the component type of that type, and so on,
- * eventually one must reach a component type that is not an array type; this is called
- * the element type of the array type. The element type of an array type is necessarily
- * either a primitive type, or a class type, or an interface type.
- *
- */
-
- /* The type of items this array holds.
- *
- * can-multi-thread
- */
- def getComponentType: BType = {
- assert(isArray, s"Asked for the component type of a non-array type: $this")
- BType.getType(off + 1)
- }
-
- // ------------------------------------------------------------------------
- // Conversion to type descriptors
- // ------------------------------------------------------------------------
-
- /*
- * @return the descriptor corresponding to this Java type.
- *
- * can-multi-thread
- */
- def getDescriptor: String = {
- val buf = new StringBuffer()
- getDescriptor(buf)
- buf.toString()
- }
-
- /*
- * Appends the descriptor corresponding to this Java type to the given string buffer.
- *
- * @param buf the string buffer to which the descriptor must be appended.
- *
- * can-multi-thread
- */
- private def getDescriptor(buf: StringBuffer) {
- if (isPrimitiveOrVoid) {
- // descriptor is in byte 3 of 'off' for primitive types (buf == null)
- buf.append(((off & 0xFF000000) >>> 24).asInstanceOf[Char])
- } else if (sort == BType.OBJECT) {
- buf.append('L')
- buf.append(chrs, off, len)
- buf.append(';')
- } else { // sort == ARRAY || sort == METHOD
- buf.append(chrs, off, len)
- }
- }
-
- // ------------------------------------------------------------------------
- // Corresponding size and opcodes
- // ------------------------------------------------------------------------
-
- /*
- * Returns the size of values of this type.
- * This method must not be used for method types.
- *
- * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
- * <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise.
- *
- * can-multi-thread
- */
- def getSize: Int = {
- // the size is in byte 0 of 'off' for primitive types (buf == null)
- if (isPrimitiveOrVoid) (off & 0xFF) else 1
- }
-
- /*
- * Returns a JVM instruction opcode adapted to this Java type. This method
- * must not be used for method types.
- *
- * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD,
- * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL,
- * ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
- * @return an opcode that is similar to the given opcode, but adapted to
- * this Java type. For example, if this type is <tt>float</tt> and
- * <tt>opcode</tt> is IRETURN, this method returns FRETURN.
- *
- * can-multi-thread
- */
- def getOpcode(opcode: Int): Int = {
- import scala.tools.asm.Opcodes
- if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
- // the offset for IALOAD or IASTORE is in byte 1 of 'off' for
- // primitive types (buf == null)
- opcode + (if (isPrimitiveOrVoid) (off & 0xFF00) >> 8 else 4)
- } else {
- // the offset for other instructions is in byte 2 of 'off' for
- // primitive types (buf == null)
- opcode + (if (isPrimitiveOrVoid) (off & 0xFF0000) >> 16 else 4)
- }
- }
-
- // ------------------------------------------------------------------------
- // Equals, hashCode and toString
- // ------------------------------------------------------------------------
-
- /*
- * Tests if the given object is equal to this type.
- *
- * @param o the object to be compared to this type.
- * @return <tt>true</tt> if the given object is equal to this type.
- *
- * can-multi-thread
- */
- override def equals(o: Any): Boolean = {
- if (!(o.isInstanceOf[BType])) {
- return false
- }
- val t = o.asInstanceOf[BType]
- if (this eq t) {
- return true
- }
- if (sort != t.sort) {
- return false
- }
- if (sort >= BType.ARRAY) {
- if (len != t.len) {
- return false
- }
- // sort checked already
- if (off == t.off) {
- return true
- }
- var i = 0
- while (i < len) {
- if (chrs(off + i) != chrs(t.off + i)) {
- return false
- }
- i += 1
- }
- // If we reach here, we could update the largest of (this.off, t.off) to match the other, so as to simplify future == comparisons.
- // But that would require a var rather than val.
- }
- true
- }
-
- /*
- * @return a hash code value for this type.
- *
- * can-multi-thread
- */
- override def hashCode(): Int = {
- var hc = 13 * sort;
- if (sort >= BType.ARRAY) {
- var i = off
- val end = i + len
- while (i < end) {
- hc = 17 * (hc + chrs(i))
- i += 1
- }
- }
- hc
- }
-
- /*
- * @return the descriptor of this type.
- *
- * can-multi-thread
- */
- override def toString: String = { getDescriptor }
-
- }
-
- /*
- * Creates a TypeName and the BType token for it.
- * This method does not add to `innerClassBufferASM`, use `internalName()` or `asmType()` or `toTypeKind()` for that.
- *
- * must-single-thread
- */
- def brefType(iname: String): BType = { brefType(newTypeName(iname.toCharArray(), 0, iname.length())) }
-
- /*
- * Creates a BType token for the TypeName received as argument.
- * This method does not add to `innerClassBufferASM`, use `internalName()` or `asmType()` or `toTypeKind()` for that.
- *
- * can-multi-thread
- */
- def brefType(iname: TypeName): BType = { BType.getObjectType(iname.start, iname.length) }
-
- // due to keyboard economy only
- val UNIT = BType.VOID_TYPE
- val BOOL = BType.BOOLEAN_TYPE
- val CHAR = BType.CHAR_TYPE
- val BYTE = BType.BYTE_TYPE
- val SHORT = BType.SHORT_TYPE
- val INT = BType.INT_TYPE
- val LONG = BType.LONG_TYPE
- val FLOAT = BType.FLOAT_TYPE
- val DOUBLE = BType.DOUBLE_TYPE
-
- val BOXED_UNIT = brefType("java/lang/Void")
- val BOXED_BOOLEAN = brefType("java/lang/Boolean")
- val BOXED_BYTE = brefType("java/lang/Byte")
- val BOXED_SHORT = brefType("java/lang/Short")
- val BOXED_CHAR = brefType("java/lang/Character")
- val BOXED_INT = brefType("java/lang/Integer")
- val BOXED_LONG = brefType("java/lang/Long")
- val BOXED_FLOAT = brefType("java/lang/Float")
- val BOXED_DOUBLE = brefType("java/lang/Double")
-
- /*
- * RT_NOTHING and RT_NULL exist at run-time only.
- * They are the bytecode-level manifestation (in method signatures only) of what shows up as NothingClass resp. NullClass in Scala ASTs.
- * Therefore, when RT_NOTHING or RT_NULL are to be emitted,
- * a mapping is needed: the internal names of NothingClass and NullClass can't be emitted as-is.
- */
- val RT_NOTHING = brefType("scala/runtime/Nothing$")
- val RT_NULL = brefType("scala/runtime/Null$")
- val CT_NOTHING = brefType("scala/Nothing") // TODO needed?
- val CT_NULL = brefType("scala/Null") // TODO needed?
-
- val srBooleanRef = brefType("scala/runtime/BooleanRef")
- val srByteRef = brefType("scala/runtime/ByteRef")
- val srCharRef = brefType("scala/runtime/CharRef")
- val srIntRef = brefType("scala/runtime/IntRef")
- val srLongRef = brefType("scala/runtime/LongRef")
- val srFloatRef = brefType("scala/runtime/FloatRef")
- val srDoubleRef = brefType("scala/runtime/DoubleRef")
-
- /* Map from type kinds to the Java reference types.
- * Useful when pushing class literals onto the operand stack (ldc instruction taking a class literal).
- * @see Predef.classOf
- * @see genConstant()
- */
- val classLiteral = immutable.Map[BType, BType](
- UNIT -> BOXED_UNIT,
- BOOL -> BOXED_BOOLEAN,
- BYTE -> BOXED_BYTE,
- SHORT -> BOXED_SHORT,
- CHAR -> BOXED_CHAR,
- INT -> BOXED_INT,
- LONG -> BOXED_LONG,
- FLOAT -> BOXED_FLOAT,
- DOUBLE -> BOXED_DOUBLE
- )
-
- case class MethodNameAndType(mname: String, mdesc: String)
-
- val asmBoxTo: Map[BType, MethodNameAndType] = {
- Map(
- BOOL -> MethodNameAndType("boxToBoolean", "(Z)Ljava/lang/Boolean;" ) ,
- BYTE -> MethodNameAndType("boxToByte", "(B)Ljava/lang/Byte;" ) ,
- CHAR -> MethodNameAndType("boxToCharacter", "(C)Ljava/lang/Character;") ,
- SHORT -> MethodNameAndType("boxToShort", "(S)Ljava/lang/Short;" ) ,
- INT -> MethodNameAndType("boxToInteger", "(I)Ljava/lang/Integer;" ) ,
- LONG -> MethodNameAndType("boxToLong", "(J)Ljava/lang/Long;" ) ,
- FLOAT -> MethodNameAndType("boxToFloat", "(F)Ljava/lang/Float;" ) ,
- DOUBLE -> MethodNameAndType("boxToDouble", "(D)Ljava/lang/Double;" )
- )
- }
-
- val asmUnboxTo: Map[BType, MethodNameAndType] = {
- Map(
- BOOL -> MethodNameAndType("unboxToBoolean", "(Ljava/lang/Object;)Z") ,
- BYTE -> MethodNameAndType("unboxToByte", "(Ljava/lang/Object;)B") ,
- CHAR -> MethodNameAndType("unboxToChar", "(Ljava/lang/Object;)C") ,
- SHORT -> MethodNameAndType("unboxToShort", "(Ljava/lang/Object;)S") ,
- INT -> MethodNameAndType("unboxToInt", "(Ljava/lang/Object;)I") ,
- LONG -> MethodNameAndType("unboxToLong", "(Ljava/lang/Object;)J") ,
- FLOAT -> MethodNameAndType("unboxToFloat", "(Ljava/lang/Object;)F") ,
- DOUBLE -> MethodNameAndType("unboxToDouble", "(Ljava/lang/Object;)D")
- )
- }
-}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
index 3fdb38ce0e..51bfdf0027 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
@@ -20,8 +20,8 @@ import scala.tools.nsc.io.AbstractFile
*
*/
abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
-
import global._
+ import bTypes._
/*
* must-single-thread
@@ -56,7 +56,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
/*
* can-multi-thread
*/
- def firstCommonSuffix(as: List[Tracked], bs: List[Tracked]): BType = {
+ def firstCommonSuffix(as: List[Tracked], bs: List[Tracked]): ClassBType = {
var chainA = as
var chainB = bs
var fcs: Tracked = null
@@ -77,17 +77,18 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
*/
final class CClassWriter(flags: Int) extends asm.ClassWriter(flags) {
- /*
- * This method is thread re-entrant because chrs never grows during its operation (that's because all TypeNames being looked up have already been entered).
- * To stress this point, rather than using `newTypeName()` we use `lookupTypeName()`
+ /**
+ * This method is thread re-entrant because chrs never grows during its operation (that's
+ * because all TypeNames being looked up have already been entered).
+ * To stress this point, rather than using `newTypeName()` we use `lookupTypeName()`
*
- * can-multi-thread
+ * can-multi-thread
*/
override def getCommonSuperClass(inameA: String, inameB: String): String = {
- val a = brefType(lookupTypeName(inameA.toCharArray))
- val b = brefType(lookupTypeName(inameB.toCharArray))
+ val a = ClassBType(lookupTypeName(inameA.toCharArray))
+ val b = ClassBType(lookupTypeName(inameB.toCharArray))
val lca = jvmWiseLUB(a, b)
- val lcaName = lca.getInternalName // don't call javaName because that side-effects innerClassBuffer.
+ val lcaName = lca.internalName // don't call javaName because that side-effects innerClassBuffer.
assert(lcaName != "scala/Any")
lcaName // ASM caches the answer during the lifetime of a ClassWriter. We outlive that. Not sure whether caching on our side would improve things.
@@ -95,16 +96,17 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
}
- /*
- * Finding the least upper bound in agreement with the bytecode verifier (given two internal names handed out by ASM)
- * Background:
- * http://gallium.inria.fr/~xleroy/publi/bytecode-verification-JAR.pdf
- * http://comments.gmane.org/gmane.comp.java.vm.languages/2293
- * https://issues.scala-lang.org/browse/SI-3872
+ /**
+ * Finding the least upper bound in agreement with the bytecode verifier (given two internal names
+ * handed out by ASM)
+ * Background:
+ * http://gallium.inria.fr/~xleroy/publi/bytecode-verification-JAR.pdf
+ * http://comments.gmane.org/gmane.comp.java.vm.languages/2293
+ * https://issues.scala-lang.org/browse/SI-3872
*
- * can-multi-thread
+ * can-multi-thread
*/
- def jvmWiseLUB(a: BType, b: BType): BType = {
+ def jvmWiseLUB(a: ClassBType, b: ClassBType): ClassBType = {
assert(a.isNonSpecial, s"jvmWiseLUB() received a non-plain-class $a")
assert(b.isNonSpecial, s"jvmWiseLUB() received a non-plain-class $b")
@@ -401,14 +403,14 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
*
* must-single-thread
*/
- final def internalName(sym: Symbol): String = { asmClassType(sym).getInternalName }
+ final def internalName(sym: Symbol): String = asmClassType(sym).internalName
/*
* Tracks (if needed) the inner class given by `sym`.
*
* must-single-thread
*/
- final def asmClassType(sym: Symbol): BType = {
+ final def asmClassType(sym: Symbol): ClassBType = {
assert(
hasInternalName(sym),
{
@@ -514,17 +516,18 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
case _: ConstantType => toTypeKind(t.underlying)
case TypeRef(_, sym, args) =>
- if (sym == ArrayClass) arrayOf(toTypeKind(args.head))
+ if (sym == ArrayClass) ArrayBType(toTypeKind(args.head))
else primitiveOrRefType2(sym)
case ClassInfoType(_, _, sym) =>
assert(sym != ArrayClass, "ClassInfoType to ArrayClass!")
primitiveOrRefType(sym)
+ // TODO @lry check below comments / todo's
// !!! Iulian says types which make no sense after erasure should not reach here, which includes the ExistentialType, AnnotatedType, RefinedType.
case ExistentialType(_, t) => toTypeKind(t) // TODO shouldn't get here but the following does: akka-actor/src/main/scala/akka/util/WildcardTree.scala
case AnnotatedType(_, w) => toTypeKind(w) // TODO test/files/jvm/annotations.scala causes an AnnotatedType to reach here.
- case RefinedType(parents, _) => parents map toTypeKind reduceLeft jvmWiseLUB
+ case RefinedType(parents, _) => parents.map(toTypeKind(_).asClassBType) reduceLeft jvmWiseLUB
// For sure WildcardTypes shouldn't reach here either, but when debugging such situations this may come in handy.
// case WildcardType => REFERENCE(ObjectClass)
@@ -538,12 +541,12 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
/*
* must-single-thread
*/
- def asmMethodType(msym: Symbol): BType = {
+ def asmMethodType(msym: Symbol): MethodBType = {
assert(msym.isMethod, s"not a method-symbol: $msym")
val resT: BType =
- if (msym.isClassConstructor || msym.isConstructor) BType.VOID_TYPE
- else toTypeKind(msym.tpe.resultType);
- BType.getMethodType( resT, mkArray(msym.tpe.paramTypes map toTypeKind) )
+ if (msym.isClassConstructor || msym.isConstructor) UNIT
+ else toTypeKind(msym.tpe.resultType)
+ MethodBType(msym.tpe.paramTypes map toTypeKind, resT)
}
/*
@@ -577,14 +580,14 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
*
* must-single-thread
*/
- final def descriptor(t: Type): String = { toTypeKind(t).getDescriptor }
+ final def descriptor(t: Type): String = { toTypeKind(t).descriptor }
/*
* Tracks (if needed) the inner class given by `sym`.
*
* must-single-thread
*/
- final def descriptor(sym: Symbol): String = { asmClassType(sym).getDescriptor }
+ final def descriptor(sym: Symbol): String = { asmClassType(sym).descriptor }
} // end of trait BCInnerClassGen
@@ -800,7 +803,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
val thrownExceptions: List[String] = getExceptions(throws)
val jReturnType = toTypeKind(methodInfo.resultType)
- val mdesc = BType.getMethodType(jReturnType, mkArray(paramJavaTypes)).getDescriptor
+ val mdesc = MethodBType(paramJavaTypes, jReturnType).descriptor
val mirrorMethodName = m.javaSimpleName.toString
val mirrorMethod: asm.MethodVisitor = jclass.visitMethod(
flags,
@@ -819,13 +822,13 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
var index = 0
for(jparamType <- paramJavaTypes) {
- mirrorMethod.visitVarInsn(jparamType.getOpcode(asm.Opcodes.ILOAD), index)
- assert(jparamType.sort != BType.METHOD, jparamType)
- index += jparamType.getSize
+ mirrorMethod.visitVarInsn(jparamType.typedOpcode(asm.Opcodes.ILOAD), index)
+ assert(!jparamType.isInstanceOf[MethodBType], jparamType)
+ index += jparamType.size
}
- mirrorMethod.visitMethodInsn(asm.Opcodes.INVOKEVIRTUAL, moduleName, mirrorMethodName, asmMethodType(m).getDescriptor, false)
- mirrorMethod.visitInsn(jReturnType.getOpcode(asm.Opcodes.IRETURN))
+ mirrorMethod.visitMethodInsn(asm.Opcodes.INVOKEVIRTUAL, moduleName, mirrorMethodName, asmMethodType(m).descriptor, false)
+ mirrorMethod.visitInsn(jReturnType.typedOpcode(asm.Opcodes.IRETURN))
mirrorMethod.visitMaxs(0, 0) // just to follow protocol, dummy arguments
mirrorMethod.visitEnd()
@@ -993,7 +996,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
flags,
mirrorName,
null /* no java-generic-signature */,
- JAVA_LANG_OBJECT.getInternalName,
+ JAVA_LANG_OBJECT.internalName,
EMPTY_STRING_ARRAY
)
@@ -1085,12 +1088,11 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
EMPTY_STRING_ARRAY // no throwable exceptions
)
- val stringArrayJType: BType = arrayOf(JAVA_LANG_STRING)
- val conJType: BType =
- BType.getMethodType(
- BType.VOID_TYPE,
- Array(exemplar(definitions.ClassClass).c, stringArrayJType, stringArrayJType)
- )
+ val stringArrayJType: BType = ArrayBType(JAVA_LANG_STRING)
+ val conJType: BType = MethodBType(
+ exemplar(definitions.ClassClass).c :: stringArrayJType :: stringArrayJType :: Nil,
+ UNIT
+ )
def push(lst: List[String]) {
var fi = 0
@@ -1099,7 +1101,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
constructor.visitLdcInsn(new java.lang.Integer(fi))
if (f == null) { constructor.visitInsn(asm.Opcodes.ACONST_NULL) }
else { constructor.visitLdcInsn(f) }
- constructor.visitInsn(JAVA_LANG_STRING.getOpcode(asm.Opcodes.IASTORE))
+ constructor.visitInsn(JAVA_LANG_STRING.typedOpcode(asm.Opcodes.IASTORE))
fi += 1
}
}
@@ -1112,17 +1114,17 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
// push the string array of field information
constructor.visitLdcInsn(new java.lang.Integer(fieldList.length))
- constructor.visitTypeInsn(asm.Opcodes.ANEWARRAY, JAVA_LANG_STRING.getInternalName)
+ constructor.visitTypeInsn(asm.Opcodes.ANEWARRAY, JAVA_LANG_STRING.internalName)
push(fieldList)
// push the string array of method information
constructor.visitLdcInsn(new java.lang.Integer(methodList.length))
- constructor.visitTypeInsn(asm.Opcodes.ANEWARRAY, JAVA_LANG_STRING.getInternalName)
+ constructor.visitTypeInsn(asm.Opcodes.ANEWARRAY, JAVA_LANG_STRING.internalName)
push(methodList)
// invoke the superclass constructor, which will do the
// necessary java reflection and create Method objects.
- constructor.visitMethodInsn(asm.Opcodes.INVOKESPECIAL, "scala/beans/ScalaBeanInfo", INSTANCE_CONSTRUCTOR_NAME, conJType.getDescriptor, false)
+ constructor.visitMethodInsn(asm.Opcodes.INVOKESPECIAL, "scala/beans/ScalaBeanInfo", INSTANCE_CONSTRUCTOR_NAME, conJType.descriptor, false)
constructor.visitInsn(asm.Opcodes.RETURN)
constructor.visitMaxs(0, 0) // just to follow protocol, dummy arguments
@@ -1161,7 +1163,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
def legacyAddCreatorCode(clinit: asm.MethodVisitor, cnode: asm.tree.ClassNode, thisName: String) {
// this tracks the inner class in innerClassBufferASM, if needed.
val androidCreatorType = asmClassType(AndroidCreatorClass)
- val tdesc_creator = androidCreatorType.getDescriptor
+ val tdesc_creator = androidCreatorType.descriptor
cnode.visitField(
PublicStaticFinal,
@@ -1182,12 +1184,12 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
)
// INVOKEVIRTUAL `moduleName`.CREATOR() : android.os.Parcelable$Creator;
- val bt = BType.getMethodType(androidCreatorType, Array.empty[BType])
+ val bt = MethodBType(Nil, androidCreatorType)
clinit.visitMethodInsn(
asm.Opcodes.INVOKEVIRTUAL,
moduleName,
"CREATOR",
- bt.getDescriptor,
+ bt.descriptor,
false
)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
index f9f6e7c3ff..9b7c975960 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
@@ -9,8 +9,7 @@ package backend.jvm
import scala.tools.asm
import scala.annotation.switch
-import scala.collection.{ immutable, mutable }
-import collection.convert.Wrappers.JListWrapper
+import scala.collection.mutable
/*
* A high-level facade to the ASM API for bytecode generation.
@@ -19,9 +18,17 @@ import collection.convert.Wrappers.JListWrapper
* @version 1.0
*
*/
-abstract class BCodeIdiomatic extends BCodeGlue {
+abstract class BCodeIdiomatic extends SubComponent {
+ protected val bCodeICodeCommon: BCodeICodeCommon[global.type] = new BCodeICodeCommon(global)
+
+ val bTypes = new BTypes[global.type](global) {
+ def chrs = global.chrs
+ override type BTypeName = global.TypeName
+ override def createNewName(s: String) = global.newTypeName(s)
+ }
import global._
+ import bTypes._
val classfileVersion: Int = settings.target.value match {
case "jvm-1.5" => asm.Opcodes.V1_5
@@ -44,12 +51,12 @@ abstract class BCodeIdiomatic extends BCodeGlue {
val CLASS_CONSTRUCTOR_NAME = "<clinit>"
val INSTANCE_CONSTRUCTOR_NAME = "<init>"
- val ObjectReference = brefType("java/lang/Object")
+ val ObjectReference = ClassBType("java/lang/Object")
val AnyRefReference = ObjectReference
- val objArrayReference = arrayOf(ObjectReference)
+ val objArrayReference = ArrayBType(ObjectReference)
val JAVA_LANG_OBJECT = ObjectReference
- val JAVA_LANG_STRING = brefType("java/lang/String")
+ val JAVA_LANG_STRING = ClassBType("java/lang/String")
var StringBuilderReference: BType = null
@@ -108,17 +115,6 @@ abstract class BCodeIdiomatic extends BCodeGlue {
a
}
- /*
- * The type of 1-dimensional arrays of `elem` type.
- * The invoker is responsible for tracking (if needed) the inner class given by the elem BType.
- *
- * must-single-thread
- */
- final def arrayOf(elem: BType): BType = {
- assert(!(elem.isUnitType), s"The element type of an array can't be: $elem")
- brefType("[" + elem.getDescriptor)
- }
-
/* Just a namespace for utilities that encapsulate MethodVisitor idioms.
* In the ASM world, org.objectweb.asm.commons.InstructionAdapter plays a similar role,
* but the methods here allow choosing when to transition from ICode to ASM types
@@ -242,12 +238,12 @@ abstract class BCodeIdiomatic extends BCodeGlue {
final def genStringConcat(el: BType) {
val jtype =
- if (el.isArray || el.hasObjectSort) JAVA_LANG_OBJECT
- else el;
+ if (el.isArray || el.isClass) JAVA_LANG_OBJECT
+ else el
- val bt = BType.getMethodType(StringBuilderReference, Array(jtype))
+ val bt = MethodBType(List(jtype), StringBuilderReference)
- invokevirtual(StringBuilderClassName, "append", bt.getDescriptor)
+ invokevirtual(StringBuilderClassName, "append", bt.descriptor)
}
/*
@@ -268,7 +264,7 @@ abstract class BCodeIdiomatic extends BCodeGlue {
final def emitT2T(from: BType, to: BType) {
assert(
- from.isNonUnitValueType && to.isNonUnitValueType,
+ from.isNonVoidPrimitiveType && to.isNonVoidPrimitiveType,
s"Cannot emit primitive conversion from $from to $to"
)
@@ -290,37 +286,37 @@ abstract class BCodeIdiomatic extends BCodeGlue {
assert(from != BOOL && to != BOOL, s"inconvertible types : $from -> $to")
// We're done with BOOL already
- (from.sort: @switch) match {
+ from match {
// using `asm.Type.SHORT` instead of `BType.SHORT` because otherwise "warning: could not emit switch for @switch annotated match"
- case asm.Type.BYTE => pickOne(JCodeMethodN.fromByteT2T)
- case asm.Type.SHORT => pickOne(JCodeMethodN.fromShortT2T)
- case asm.Type.CHAR => pickOne(JCodeMethodN.fromCharT2T)
- case asm.Type.INT => pickOne(JCodeMethodN.fromIntT2T)
+ case BYTE => pickOne(JCodeMethodN.fromByteT2T)
+ case SHORT => pickOne(JCodeMethodN.fromShortT2T)
+ case CHAR => pickOne(JCodeMethodN.fromCharT2T)
+ case INT => pickOne(JCodeMethodN.fromIntT2T)
- case asm.Type.FLOAT =>
+ case FLOAT =>
import asm.Opcodes.{ F2L, F2D, F2I }
- (to.sort: @switch) match {
- case asm.Type.LONG => emit(F2L)
- case asm.Type.DOUBLE => emit(F2D)
- case _ => emit(F2I); emitT2T(INT, to)
+ to match {
+ case LONG => emit(F2L)
+ case DOUBLE => emit(F2D)
+ case _ => emit(F2I); emitT2T(INT, to)
}
- case asm.Type.LONG =>
+ case LONG =>
import asm.Opcodes.{ L2F, L2D, L2I }
- (to.sort: @switch) match {
- case asm.Type.FLOAT => emit(L2F)
- case asm.Type.DOUBLE => emit(L2D)
- case _ => emit(L2I); emitT2T(INT, to)
+ to match {
+ case FLOAT => emit(L2F)
+ case DOUBLE => emit(L2D)
+ case _ => emit(L2I); emitT2T(INT, to)
}
- case asm.Type.DOUBLE =>
+ case DOUBLE =>
import asm.Opcodes.{ D2L, D2F, D2I }
- (to.sort: @switch) match {
- case asm.Type.FLOAT => emit(D2F)
- case asm.Type.LONG => emit(D2L)
- case _ => emit(D2I); emitT2T(INT, to)
+ to match {
+ case FLOAT => emit(D2F)
+ case LONG => emit(D2L)
+ case _ => emit(D2I); emitT2T(INT, to)
}
}
} // end of emitT2T()
@@ -372,24 +368,26 @@ abstract class BCodeIdiomatic extends BCodeGlue {
// can-multi-thread
final def newarray(elem: BType) {
- if (elem.isRefOrArrayType || elem.isPhantomType ) {
- /* phantom type at play in `Array(null)`, SI-1513. On the other hand, Array(()) has element type `scala.runtime.BoxedUnit` which hasObjectSort. */
- jmethod.visitTypeInsn(Opcodes.ANEWARRAY, elem.getInternalName)
- } else {
- val rand = {
- // using `asm.Type.SHORT` instead of `BType.SHORT` because otherwise "warning: could not emit switch for @switch annotated match"
- (elem.sort: @switch) match {
- case asm.Type.BOOLEAN => Opcodes.T_BOOLEAN
- case asm.Type.BYTE => Opcodes.T_BYTE
- case asm.Type.SHORT => Opcodes.T_SHORT
- case asm.Type.CHAR => Opcodes.T_CHAR
- case asm.Type.INT => Opcodes.T_INT
- case asm.Type.LONG => Opcodes.T_LONG
- case asm.Type.FLOAT => Opcodes.T_FLOAT
- case asm.Type.DOUBLE => Opcodes.T_DOUBLE
+ elem match {
+ case c: RefBType =>
+ /* phantom type at play in `Array(null)`, SI-1513. On the other hand, Array(()) has element type `scala.runtime.BoxedUnit` which isObject. */
+ jmethod.visitTypeInsn(Opcodes.ANEWARRAY, c.classOrArrayType)
+ case _ =>
+ assert(elem.isNonVoidPrimitiveType)
+ val rand = {
+ // using `asm.Type.SHORT` instead of `BType.SHORT` because otherwise "warning: could not emit switch for @switch annotated match"
+ elem match {
+ case BOOL => Opcodes.T_BOOLEAN
+ case BYTE => Opcodes.T_BYTE
+ case SHORT => Opcodes.T_SHORT
+ case CHAR => Opcodes.T_CHAR
+ case INT => Opcodes.T_INT
+ case LONG => Opcodes.T_LONG
+ case FLOAT => Opcodes.T_FLOAT
+ case DOUBLE => Opcodes.T_DOUBLE
+ }
}
- }
- jmethod.visitIntInsn(Opcodes.NEWARRAY, rand)
+ jmethod.visitIntInsn(Opcodes.NEWARRAY, rand)
}
}
@@ -529,7 +527,7 @@ abstract class BCodeIdiomatic extends BCodeGlue {
// can-multi-thread
final def emitVarInsn(opc: Int, idx: Int, tk: BType) {
assert((opc == Opcodes.ILOAD) || (opc == Opcodes.ISTORE), opc)
- jmethod.visitVarInsn(tk.getOpcode(opc), idx)
+ jmethod.visitVarInsn(tk.typedOpcode(opc), idx)
}
// ---------------- array load and store ----------------
@@ -538,7 +536,7 @@ abstract class BCodeIdiomatic extends BCodeGlue {
final def emitTypeBased(opcs: Array[Int], tk: BType) {
assert(tk != UNIT, tk)
val opc = {
- if (tk.isRefOrArrayType) { opcs(0) }
+ if (tk.isRef) { opcs(0) }
else if (tk.isIntSizedType) {
(tk: @unchecked) match {
case BOOL | BYTE => opcs(1)
@@ -563,11 +561,11 @@ abstract class BCodeIdiomatic extends BCodeGlue {
final def emitPrimitive(opcs: Array[Int], tk: BType) {
val opc = {
// using `asm.Type.SHORT` instead of `BType.SHORT` because otherwise "warning: could not emit switch for @switch annotated match"
- (tk.sort: @switch) match {
- case asm.Type.LONG => opcs(1)
- case asm.Type.FLOAT => opcs(2)
- case asm.Type.DOUBLE => opcs(3)
- case _ => opcs(0)
+ tk match {
+ case LONG => opcs(1)
+ case FLOAT => opcs(2)
+ case DOUBLE => opcs(3)
+ case _ => opcs(0)
}
}
emit(opc)
@@ -582,15 +580,14 @@ abstract class BCodeIdiomatic extends BCodeGlue {
// ---------------- type checks and casts ----------------
// can-multi-thread
- final def isInstance(tk: BType) {
- jmethod.visitTypeInsn(Opcodes.INSTANCEOF, tk.getInternalName)
+ final def isInstance(tk: RefBType): Unit = {
+ jmethod.visitTypeInsn(Opcodes.INSTANCEOF, tk.classOrArrayType)
}
// can-multi-thread
- final def checkCast(tk: BType) {
- assert(tk.isRefOrArrayType, s"checkcast on primitive type: $tk")
+ final def checkCast(tk: RefBType): Unit = {
// TODO ICode also requires: but that's too much, right? assert(!isBoxedType(tk), "checkcast on boxed type: " + tk)
- jmethod.visitTypeInsn(Opcodes.CHECKCAST, tk.getInternalName)
+ jmethod.visitTypeInsn(Opcodes.CHECKCAST, tk.classOrArrayType)
}
} // end of class JCodeMethodN
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
index a76fa4d7ba..effc68c5e3 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
@@ -25,6 +25,7 @@ import java.io.PrintWriter
*/
abstract class BCodeSkelBuilder extends BCodeHelpers {
import global._
+ import bTypes._
/*
* There's a dedicated PlainClassBuilder for each CompilationUnit,
@@ -133,7 +134,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
private def initJClass(jclass: asm.ClassVisitor) {
val ps = claszSymbol.info.parents
- val superClass: String = if (ps.isEmpty) JAVA_LANG_OBJECT.getInternalName else internalName(ps.head.typeSymbol);
+ val superClass: String = if (ps.isEmpty) JAVA_LANG_OBJECT.internalName else internalName(ps.head.typeSymbol);
val ifaces: Array[String] = {
val arrIfacesTr: Array[Tracked] = exemplar(claszSymbol).ifaces
val arrIfaces = new Array[String](arrIfacesTr.length)
@@ -142,7 +143,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val ifaceTr = arrIfacesTr(i)
val bt = ifaceTr.c
if (ifaceTr.isInnerClass) { innerClassBufferASM += bt }
- arrIfaces(i) = bt.getInternalName
+ arrIfaces(i) = bt.internalName
i += 1
}
arrIfaces
@@ -166,7 +167,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val enclM = getEnclosingMethodAttribute(claszSymbol)
if (enclM != null) {
val EnclMethodEntry(className, methodName, methodType) = enclM
- cnode.visitOuterClass(className, methodName, methodType.getDescriptor)
+ cnode.visitOuterClass(className, methodName, methodType.descriptor)
}
val ssa = getAnnotPickle(thisName, claszSymbol)
@@ -261,7 +262,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val jfield = new asm.tree.FieldNode(
flags,
f.javaSimpleName.toString,
- symInfoTK(f).getDescriptor,
+ symInfoTK(f).descriptor,
javagensig,
null // no initial value
)
@@ -397,8 +398,8 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
assert(nxtIdx != -1, "not a valid start index")
val loc = Local(tk, sym.javaSimpleName.toString, nxtIdx, sym.isSynthetic)
slots += (sym -> loc)
- assert(tk.getSize > 0, "makeLocal called for a symbol whose type is Unit.")
- nxtIdx += tk.getSize
+ assert(tk.size > 0, "makeLocal called for a symbol whose type is Unit.")
+ nxtIdx += tk.size
loc
}
@@ -531,7 +532,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
if (isMethSymStaticCtor) CLASS_CONSTRUCTOR_NAME
else jMethodName
- val mdesc = asmMethodType(methSymbol).getDescriptor
+ val mdesc = asmMethodType(methSymbol).descriptor
mnode = cnode.visitMethod(
flags,
bytecodeName,
@@ -555,7 +556,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
methSymbol = dd.symbol
jMethodName = methSymbol.javaSimpleName.toString
- returnType = asmMethodType(dd.symbol).getReturnType
+ returnType = asmMethodType(dd.symbol).returnType
isMethSymStaticCtor = methSymbol.isStaticConstructor
resetMethodBookkeeping(dd)
@@ -685,7 +686,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val callee = methSymbol.enclClass.primaryConstructor
val jname = callee.javaSimpleName.toString
val jowner = internalName(callee.owner)
- val jtype = asmMethodType(callee).getDescriptor
+ val jtype = asmMethodType(callee).descriptor
insnModB = new asm.tree.MethodInsnNode(asm.Opcodes.INVOKESPECIAL, jowner, jname, jtype, false)
}
@@ -694,7 +695,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
// android creator code
if (isCZParcelable) {
// add a static field ("CREATOR") to this class to cache android.os.Parcelable$Creator
- val andrFieldDescr = asmClassType(AndroidCreatorClass).getDescriptor
+ val andrFieldDescr = asmClassType(AndroidCreatorClass).descriptor
cnode.visitField(
asm.Opcodes.ACC_STATIC | asm.Opcodes.ACC_FINAL,
"CREATOR",
@@ -706,7 +707,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val callee = definitions.getMember(claszSymbol.companionModule, androidFieldName)
val jowner = internalName(callee.owner)
val jname = callee.javaSimpleName.toString
- val jtype = asmMethodType(callee).getDescriptor
+ val jtype = asmMethodType(callee).descriptor
insnParcA = new asm.tree.MethodInsnNode(asm.Opcodes.INVOKESTATIC, jowner, jname, jtype, false)
// PUTSTATIC `thisName`.CREATOR;
insnParcB = new asm.tree.FieldInsnNode(asm.Opcodes.PUTSTATIC, thisName, "CREATOR", andrFieldDescr)
@@ -723,7 +724,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
def emitLocalVarScope(sym: Symbol, start: asm.Label, end: asm.Label, force: Boolean = false) {
val Local(tk, name, idx, isSynth) = locals(sym)
if (force || !isSynth) {
- mnode.visitLocalVariable(name, tk.getDescriptor, null, start, end, idx)
+ mnode.visitLocalVariable(name, tk.descriptor, null, start, end, idx)
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala
index 9ddb7a3ce8..c271e7b129 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala
@@ -9,9 +9,7 @@ package tools.nsc
package backend
package jvm
-import scala.collection.{ mutable, immutable }
-import scala.annotation.switch
-
+import scala.collection.immutable
import scala.tools.asm
/*
@@ -22,6 +20,7 @@ import scala.tools.asm
*/
abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
import global._
+ import bTypes._
/*
@@ -184,7 +183,7 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
val caseHandlers: List[EHClause] =
for (CaseDef(pat, _, caseBody) <- catches) yield {
pat match {
- case Typed(Ident(nme.WILDCARD), tpt) => NamelessEH(tpeTK(tpt), caseBody)
+ case Typed(Ident(nme.WILDCARD), tpt) => NamelessEH(tpeTK(tpt).asClassBType, caseBody)
case Ident(nme.WILDCARD) => NamelessEH(ThrowableReference, caseBody)
case Bind(_, _) => BoundEH (pat.symbol, caseBody)
}
@@ -250,7 +249,7 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
// (2.a) emit case clause proper
val startHandler = currProgramPoint()
var endHandler: asm.Label = null
- var excType: BType = null
+ var excType: ClassBType = null
registerCleanup(finCleanup)
ch match {
case NamelessEH(typeToDrop, caseBody) =>
@@ -269,7 +268,7 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
nopIfNeeded(startHandler)
endHandler = currProgramPoint()
emitLocalVarScope(patSymbol, startHandler, endHandler)
- excType = patTK
+ excType = patTK.asClassBType
}
unregisterCleanup(finCleanup)
// (2.b) mark the try-body as protected by this case clause.
@@ -357,10 +356,10 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
}
}
- def protect(start: asm.Label, end: asm.Label, handler: asm.Label, excType: BType) {
+ def protect(start: asm.Label, end: asm.Label, handler: asm.Label, excType: ClassBType) {
val excInternalName: String =
if (excType == null) null
- else excType.getInternalName
+ else excType.internalName
assert(start != end, "protecting a range of zero instructions leads to illegal class format. Solution: add a NOP to that range.")
mnode.visitTryCatchBlock(start, end, handler, excInternalName)
}
@@ -387,7 +386,7 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
def mayCleanStack(tree: Tree): Boolean = tree exists { t => t.isInstanceOf[Try] }
trait EHClause
- case class NamelessEH(typeToDrop: BType, caseBody: Tree) extends EHClause
+ case class NamelessEH(typeToDrop: ClassBType, caseBody: Tree) extends EHClause
case class BoundEH (patSymbol: Symbol, caseBody: Tree) extends EHClause
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala
index 1eca69936a..62dfb4917d 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala
@@ -18,27 +18,25 @@ import scala.collection.{ immutable, mutable }
*
*/
abstract class BCodeTypes extends BCodeIdiomatic {
-
import global._
+ import bTypes._
// when compiling the Scala library, some assertions don't hold (e.g., scala.Boolean has null superClass although it's not an interface)
val isCompilingStdLib = !(settings.sourcepath.isDefault)
- val srBoxedUnit = brefType("scala/runtime/BoxedUnit")
-
// special names
- var StringReference : BType = null
- var ThrowableReference : BType = null
- var jlCloneableReference : BType = null // java/lang/Cloneable
- var jlNPEReference : BType = null // java/lang/NullPointerException
- var jioSerializableReference : BType = null // java/io/Serializable
- var scalaSerializableReference : BType = null // scala/Serializable
- var classCastExceptionReference : BType = null // java/lang/ClassCastException
+ var StringReference : ClassBType = null
+ var ThrowableReference : ClassBType = null
+ var jlCloneableReference : ClassBType = null // java/lang/Cloneable
+ var jlNPEReference : ClassBType = null // java/lang/NullPointerException
+ var jioSerializableReference : ClassBType = null // java/io/Serializable
+ var scalaSerializableReference : ClassBType = null // scala/Serializable
+ var classCastExceptionReference : ClassBType = null // java/lang/ClassCastException
/* A map from scala primitive type-symbols to BTypes */
var primitiveTypeMap: Map[Symbol, BType] = null
/* A map from scala type-symbols for Nothing and Null to (runtime version) BTypes */
- var phantomTypeMap: Map[Symbol, BType] = null
+ var phantomTypeMap: Map[Symbol, ClassBType] = null
/* Maps the method symbol for a box method to the boxed type of the result.
* For example, the method symbol for `Byte.box()`) is mapped to the BType `Ljava/lang/Integer;`. */
var boxResultType: Map[Symbol, BType] = null
@@ -63,10 +61,10 @@ abstract class BCodeTypes extends BCodeIdiomatic {
val AbstractFunctionReference = new Array[Tracked](definitions.MaxFunctionArity + 1)
val abstractFunctionArityMap = mutable.Map.empty[BType, Int]
- var PartialFunctionReference: BType = null // scala.PartialFunction
- var AbstractPartialFunctionReference: BType = null // scala.runtime.AbstractPartialFunction
+ var PartialFunctionReference: ClassBType = null // scala.PartialFunction
+ var AbstractPartialFunctionReference: ClassBType = null // scala.runtime.AbstractPartialFunction
- var BoxesRunTime: BType = null
+ var BoxesRunTime: ClassBType = null
/*
* must-single-thread
@@ -107,7 +105,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
// Other than that, they aren't needed there (e.g., `isSubtypeOf()` special-cases boxed classes, similarly for others).
val boxedClasses = List(BoxedBooleanClass, BoxedCharacterClass, BoxedByteClass, BoxedShortClass, BoxedIntClass, BoxedLongClass, BoxedFloatClass, BoxedDoubleClass)
for(csym <- boxedClasses) {
- val key = brefType(csym.javaBinaryName.toTypeName)
+ val key = ClassBType(csym.javaBinaryName.toTypeName)
val tr = buildExemplar(key, csym)
symExemplars.put(csym, tr)
exemplars.put(tr.c, tr)
@@ -147,16 +145,6 @@ abstract class BCodeTypes extends BCodeIdiomatic {
scalaSerializableReference = exemplar(SerializableClass).c
classCastExceptionReference = exemplar(ClassCastExceptionClass).c
- /*
- * The bytecode emitter special-cases String concatenation, in that three methods of `JCodeMethodN`
- * ( `genStartConcat()` , `genStringConcat()` , and `genEndConcat()` )
- * don't obtain the method descriptor of the callee via `asmMethodType()` (as normally done)
- * but directly emit callsites on StringBuilder using literal constant for method descriptors.
- * In order to make sure those method descriptors are available as BTypes, they are initialized here.
- */
- BType.getMethodType("()V") // necessary for JCodeMethodN.genStartConcat
- BType.getMethodType("()Ljava/lang/String;") // necessary for JCodeMethodN.genEndConcat
-
PartialFunctionReference = exemplar(PartialFunctionClass).c
for(idx <- 0 to definitions.MaxFunctionArity) {
FunctionReference(idx) = exemplar(FunctionClass(idx))
@@ -165,12 +153,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
AbstractPartialFunctionReference = exemplar(AbstractPartialFunctionClass).c
}
- // later a few analyses (e.g. refreshInnerClasses) will look up BTypes based on descriptors in instructions
- // we make sure those BTypes can be found via lookup as opposed to creating them on the fly.
- BoxesRunTime = brefType("scala/runtime/BoxesRunTime")
- asmBoxTo.values foreach { mnat: MethodNameAndType => BType.getMethodType(mnat.mdesc) }
- asmUnboxTo.values foreach { mnat: MethodNameAndType => BType.getMethodType(mnat.mdesc) }
-
+ BoxesRunTime = ClassBType("scala/runtime/BoxesRunTime")
}
/*
@@ -191,28 +174,41 @@ abstract class BCodeTypes extends BCodeIdiomatic {
// allowing answering `conforms()` without resorting to typer.
// ------------------------------------------------
- val exemplars = new java.util.concurrent.ConcurrentHashMap[BType, Tracked]
- val symExemplars = new java.util.concurrent.ConcurrentHashMap[Symbol, Tracked]
+ /**
+ * TODO @lry should probably be a map form ClassBType to Tracked
+ */
+ val exemplars = new java.util.concurrent.ConcurrentHashMap[BType, Tracked]
- /*
- * Typically, a question about a BType can be answered only by using the BType as lookup key in one or more maps.
- * A `Tracked` object saves time by holding together information required to answer those questions:
+ /**
+ * Maps class symbols to their corresponding `Tracked` instance.
+ */
+ val symExemplars = new java.util.concurrent.ConcurrentHashMap[Symbol, Tracked]
+
+ /**
+ * A `Tracked` instance stores information about a BType. This allows ansering type questions
+ * without resolving to the compiler, in a thread-safe manner, in particular isSubtypeOf.
*
- * - `sc` denotes the bytecode-level superclass if any, null otherwise
+ * @param c the BType described by this `Tracked`
+ * @param flags the java flags for the type, computed by BCodeTypes#javaFlags
+ * @param sc the bytecode-level superclass if any, null otherwise
+ * @param ifaces the interfaces explicitly declared. Not included are those transitively
+ * supported, but the utility method `allLeafIfaces()` can be used for that.
+ * @param innersChain the containing classes for a non-package-level class `c`, null otherwise.
*
- * - `ifaces` denotes the interfaces explicitly declared.
- * Not included are those transitively supported, but the utility method `allLeafIfaces()` can be used for that.
+ * Note: the optimizer may inline anonymous closures, thus eliding those inner classes (no
+ * physical class file is emitted for elided classes). Before committing `innersChain` to
+ * bytecode, cross-check with the list of elided classes (SI-6546).
*
- * - `innersChain` denotes the containing classes for a non-package-level class `c`, null otherwise.
- * Note: the optimizer may inline anonymous closures, thus eliding those inner classes
- * (no physical class file is emitted for elided classes).
- * Before committing `innersChain` to bytecode, cross-check with the list of elided classes (SI-6546).
+ * All methods of this class can-multi-thread
*
- * All methods of this class can-multi-thread
+ * TODO @lry c: ClassBType. rename to ClassBTypeInfo
*/
- case class Tracked(c: BType, flags: Int, sc: Tracked, ifaces: Array[Tracked], innersChain: Array[InnerClassEntry]) {
+ case class Tracked(c: ClassBType, flags: Int, sc: Tracked, ifaces: Array[Tracked], innersChain: Array[InnerClassEntry]) {
// not a case-field because we initialize it only for JVM classes we emit.
+ // TODO @lry make it an Option[List[BType]]
+ // TODO: this is currently not used. a commit in the optimizer branch uses this field to
+ // re-compute inner classes (ee4c185). leaving it in for now.
private var _directMemberClasses: List[BType] = null
def directMemberClasses: List[BType] = {
@@ -223,9 +219,9 @@ abstract class BCodeTypes extends BCodeIdiomatic {
def directMemberClasses_=(bs: List[BType]) {
if (_directMemberClasses != null) {
// TODO we enter here when both mirror class and plain class are emitted for the same ModuleClassSymbol.
- assert(_directMemberClasses == bs.sortBy(_.off))
+ assert(_directMemberClasses.sameElements(bs))
}
- _directMemberClasses = bs.sortBy(_.off)
+ _directMemberClasses = bs
}
/* `isCompilingStdLib` saves the day when compiling:
@@ -247,7 +243,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
def isInnerClass = { innersChain != null }
def isLambda = {
// ie isLCC || isTraditionalClosureClass
- isFinal && (c.getSimpleName.contains(tpnme.ANON_FUN_NAME.toString)) && isFunctionType(c)
+ isFinal && (c.simpleName.contains(tpnme.ANON_FUN_NAME.toString)) && isFunctionType(c)
}
/* can-multi-thread */
@@ -350,8 +346,8 @@ abstract class BCodeTypes extends BCodeIdiomatic {
val superInterfaces0: List[Symbol] = csym.mixinClasses
val superInterfaces = existingSymbols(superInterfaces0 ++ csym.annotations.map(newParentForAttr)).distinct
- assert(!superInterfaces.contains(NoSymbol), s"found NoSymbol among: ${superInterfaces.mkString}")
- assert(superInterfaces.forall(s => s.isInterface || s.isTrait), s"found non-interface among: ${superInterfaces.mkString}")
+ assert(!superInterfaces.contains(NoSymbol), s"found NoSymbol among: ${superInterfaces.mkString(", ")}")
+ assert(superInterfaces.forall(s => s.isInterface || s.isTrait), s"found non-interface among: ${superInterfaces.mkString(", ")}")
minimizeInterfaces(superInterfaces)
}
@@ -380,8 +376,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
if (opt != null) {
return opt
}
-
- val key = brefType(csym.javaBinaryName.toTypeName)
+ val key = new ClassBType(csym.javaBinaryName.toTypeName)
assert(key.isNonSpecial || isCompilingStdLib, s"Not a class to track: ${csym.fullName}")
// TODO accomodate the fix for SI-5031 of https://github.com/scala/scala/commit/0527b2549bcada2fda2201daa630369b377d0877
@@ -395,12 +390,10 @@ abstract class BCodeTypes extends BCodeIdiomatic {
tr
}
- val EMPTY_TRACKED_ARRAY = Array.empty[Tracked]
-
/*
* must-single-thread
*/
- private def buildExemplar(key: BType, csym: Symbol): Tracked = {
+ private def buildExemplar(key: ClassBType, csym: Symbol): Tracked = {
val sc =
if (csym.isImplClass) definitions.ObjectClass
else csym.superClass
@@ -413,14 +406,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
((sc != NoSymbol) && !sc.isInterface) || isCompilingStdLib,
"superClass out of order"
)
- val ifaces = getSuperInterfaces(csym) map exemplar;
- val ifacesArr =
- if (ifaces.isEmpty) EMPTY_TRACKED_ARRAY
- else {
- val arr = new Array[Tracked](ifaces.size)
- ifaces.copyToArray(arr)
- arr
- }
+ val ifacesArr = getSuperInterfaces(csym).map(exemplar).toArray
val flags = mkFlags(
javaFlags(csym),
@@ -476,29 +462,30 @@ abstract class BCodeTypes extends BCodeIdiomatic {
if ((b == jlCloneableReference) ||
(b == jioSerializableReference) ||
(b == AnyRefReference)) { true }
- else if (b.isArray) { conforms(a.getComponentType, b.getComponentType) }
+ else if (b.isArray) { conforms(a.asArrayBType.componentType, // TODO @lry change to pattern match, get rid of casts
+ b.asArrayBType.componentType) }
else { false }
}
else if (a.isBoxed) { // may be null
if (b.isBoxed) { a == b }
else if (b == AnyRefReference) { true }
- else if (!(b.hasObjectSort)) { false }
+ else if (!(b.isClass)) { false }
else { exemplars.get(a).isSubtypeOf(b) } // e.g., java/lang/Double conforms to java/lang/Number
}
else if (a.isNullType) { // known to be null
if (b.isNothingType) { false }
- else if (b.isValueType) { false }
+ else if (b.isPrimitive) { false }
else { true }
}
else if (a.isNothingType) { // known to be Nothing
true
}
- else if (a.isUnitType) {
- b.isUnitType
+ else if (a == UNIT) {
+ b == UNIT
}
- else if (a.hasObjectSort) { // may be null
+ else if (a.isClass) { // may be null
if (a.isNothingType) { true }
- else if (b.hasObjectSort) { exemplars.get(a).isSubtypeOf(b) }
+ else if (b.isClass) { exemplars.get(a).isSubtypeOf(b) }
else if (b.isArray) { a.isNullType } // documentation only, because `if(a.isNullType)` (above) covers this case already.
else { false }
}
@@ -506,8 +493,8 @@ abstract class BCodeTypes extends BCodeIdiomatic {
def msg = s"(a: $a, b: $b)"
- assert(a.isNonUnitValueType, s"a isn't a non-Unit value type. $msg")
- assert(b.isValueType, s"b isn't a value type. $msg")
+ assert(a.isNonVoidPrimitiveType, s"a isn't a non-Unit value type. $msg")
+ assert(b.isPrimitive, s"b isn't a value type. $msg")
(a eq b) || (a match {
case BOOL | BYTE | SHORT | CHAR => b == INT || b == LONG // TODO Actually, BOOL does NOT conform to LONG. Even with adapt().
@@ -521,7 +508,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
* can-multi-thread
*/
def maxValueType(a: BType, other: BType): BType = {
- assert(a.isValueType, "maxValueType() is defined only for 1st arg valuetypes (2nd arg doesn't matter).")
+ assert(a.isPrimitive, "maxValueType() is defined only for 1st arg valuetypes (2nd arg doesn't matter).")
def uncomparable: Nothing = {
abort(s"Uncomparable BTypes: $a with $other")
@@ -537,30 +524,30 @@ abstract class BCodeTypes extends BCodeIdiomatic {
case BOOL => uncomparable
case BYTE =>
- if (other == CHAR) INT
+ if (other == CHAR) INT
else if (other.isNumericType) other
else uncomparable
case SHORT =>
other match {
- case BYTE => SHORT
- case CHAR => INT
+ case BYTE => SHORT
+ case CHAR => INT
case INT | LONG | FLOAT | DOUBLE => other
- case _ => uncomparable
+ case _ => uncomparable
}
case CHAR =>
other match {
- case BYTE | SHORT => INT
+ case BYTE | SHORT => INT
case INT | LONG | FLOAT | DOUBLE => other
- case _ => uncomparable
+ case _ => uncomparable
}
case INT =>
other match {
case BYTE | SHORT | CHAR => INT
case LONG | FLOAT | DOUBLE => other
- case _ => uncomparable
+ case _ => uncomparable
}
case LONG =>
@@ -569,7 +556,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
else uncomparable
case FLOAT =>
- if (other == DOUBLE) DOUBLE
+ if (other == DOUBLE) DOUBLE
else if (other.isNumericType) FLOAT
else uncomparable
@@ -586,18 +573,18 @@ abstract class BCodeTypes extends BCodeIdiomatic {
* can-multi-thread
*/
final def maxType(a: BType, other: BType): BType = {
- if (a.isValueType) { maxValueType(a, other) }
+ if (a.isPrimitive) { maxValueType(a, other) }
else {
if (a.isNothingType) return other;
if (other.isNothingType) return a;
if (a == other) return a;
// Approximate `lub`. The common type of two references is always AnyRef.
// For 'real' least upper bound wrt to subclassing use method 'lub'.
- assert(a.isArray || a.isBoxed || a.hasObjectSort, s"This is not a valuetype and it's not something else, what is it? $a")
+ assert(a.isArray || a.isBoxed || a.isClass, s"This is not a valuetype and it's not something else, what is it? $a")
// TODO For some reason, ICode thinks `REFERENCE(...).maxType(BOXED(whatever))` is `uncomparable`. Here, that has maxType AnyRefReference.
// BTW, when swapping arguments, ICode says BOXED(whatever).maxType(REFERENCE(...)) == AnyRefReference, so I guess the above was an oversight in REFERENCE.maxType()
- if (other.isRefOrArrayType) { AnyRefReference }
- else { abort(s"Uncomparable BTypes: $a with $other") }
+ if (other.isRef) { AnyRefReference }
+ else { abort(s"Uncomparable BTypes: $a with $other") }
}
}
@@ -609,7 +596,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
* can-multi-thread
*/
def isPartialFunctionType(t: BType): Boolean = {
- (t.hasObjectSort) && exemplars.get(t).isSubtypeOf(PartialFunctionReference)
+ (t.isClass) && exemplars.get(t).isSubtypeOf(PartialFunctionReference)
}
/*
@@ -618,7 +605,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
* can-multi-thread
*/
def isFunctionType(t: BType): Boolean = {
- if (!t.hasObjectSort) return false
+ if (!t.isClass) return false
var idx = 0
val et: Tracked = exemplars.get(t)
while (idx <= definitions.MaxFunctionArity) {
@@ -724,14 +711,8 @@ abstract class BCodeTypes extends BCodeIdiomatic {
}
}
- // now that we have all of `ics` , `csym` , and soon the inner-classes-chain, it's too tempting not to cache.
- if (chain.isEmpty) { null }
- else {
- val arr = new Array[InnerClassEntry](chain.size)
- (chain map toInnerClassEntry).copyToArray(arr)
-
- arr
- }
+ if (chain.isEmpty) null
+ else chain.map(toInnerClassEntry).toArray
}
/*
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
new file mode 100644
index 0000000000..5b0fa6f7a8
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
@@ -0,0 +1,417 @@
+package scala.tools.nsc
+package backend.jvm
+
+import scala.collection.immutable
+import scala.annotation.switch
+import scala.tools.asm
+import asm.Opcodes
+import scala.collection.mutable.ListBuffer
+
+/**
+ * BTypes is a backend component that defines the class BType, a number of basic instances and
+ * some utilities.
+ *
+ * A BType is essentially an slice of the array `chrs` denoting the name of the type, and a field
+ * denoting the kind (object, array, method, or one of the primitive types).
+ *
+ * BTypes depends on Global just because it re-uses hash-consing of Name. It would be cleaner to
+ * create an interface for BTypeName and extend it in scala.reflect.internal.Names#Name, that
+ * would simplify testing BTypes (no Global needed).
+ */
+abstract class BTypes[G <: Global](val __global_dont_use: G) {
+ def chrs: Array[Char]
+
+ /**
+ * Interface for names stored in `chrs`
+ */
+ type BTypeName <: __global_dont_use.Name
+
+ /**
+ * Create a new name in `chrs`. Names are assumed to be hash-consed. Equality on BType will use
+ * reference equality to compare the names.
+ */
+ def createNewName(s: String): BTypeName
+
+ /*sealed*/ trait BType { // Not sealed for now due to SI-8546
+ final override def toString: String = this match {
+ case UNIT => "V"
+ case BOOL => "Z"
+ case CHAR => "C"
+ case BYTE => "B"
+ case SHORT => "S"
+ case INT => "I"
+ case FLOAT => "F"
+ case LONG => "J"
+ case DOUBLE => "D"
+ case c @ ClassBType(_, _) => "L" + c.internalName + ";"
+ case ArrayBType(component) => "[" + component
+ case MethodBType(args, res) => "(" + args.mkString + ")" + res
+ }
+
+ /**
+ * @return The Java descriptor of this type. Examples:
+ * - int: I
+ * - java.lang.String: Ljava/lang/String;
+ * - int[]: [I
+ * - Object m(String s, double d): (Ljava/lang/String;D)Ljava/lang/Object;
+ */
+ final def descriptor = toString
+
+ /**
+ * @return 0 for void, 2 for long and double, 1 otherwise
+ */
+ final def size: Int = this match {
+ case UNIT => 0
+ case LONG | DOUBLE => 2
+ case _ => 1
+ }
+
+ final def isPrimitive: Boolean = this.isInstanceOf[PrimitiveBType]
+ final def isRef: Boolean = this.isInstanceOf[RefBType]
+ final def isArray: Boolean = this.isInstanceOf[ArrayBType]
+ final def isClass: Boolean = this.isInstanceOf[ClassBType]
+ final def isMethod: Boolean = this.isInstanceOf[MethodBType]
+
+ final def isNonVoidPrimitiveType = isPrimitive && this != UNIT
+ // TODO @lry should also include !isMethod in isNonSpecial? in this case it would be equivalent to isClass, so we could get rid of it.
+ final def isNonSpecial = !isPrimitive && !isArray && !isPhantomType
+ final def isNullType = this == RT_NULL || this == CT_NULL
+ final def isNothingType = this == RT_NOTHING || this == CT_NOTHING
+ final def isPhantomType = isNullType || isNothingType
+
+ final def isBoxed = this match {
+ case BOXED_UNIT | BOXED_BOOLEAN | BOXED_CHAR |
+ BOXED_BYTE | BOXED_SHORT | BOXED_INT |
+ BOXED_FLOAT | BOXED_LONG | BOXED_DOUBLE => true
+ case _ => false
+ }
+
+ final def isIntSizedType = this == BOOL || this == CHAR || this == BYTE ||
+ this == SHORT || this == INT
+ final def isIntegralType = this == INT || this == BYTE || this == LONG ||
+ this == CHAR || this == SHORT
+ final def isRealType = this == FLOAT || this == DOUBLE
+ final def isNumericType = isIntegralType || isRealType
+ final def isWideType = size == 2
+
+ /**
+ * See documentation of [[typedOpcode]].
+ * The numbers are taken from asm.Type.VOID_TYPE ff., the values are those shifted by << 8.
+ */
+ private def loadStoreOpcodeOffset: Int = this match {
+ case UNIT | INT => 0
+ case BOOL | BYTE => 5
+ case CHAR => 6
+ case SHORT => 7
+ case FLOAT => 2
+ case LONG => 1
+ case DOUBLE => 3
+ case _ => 4
+ }
+
+ /**
+ * See documentation of [[typedOpcode]].
+ * The numbers are taken from asm.Type.VOID_TYPE ff., the values are those shifted by << 16.
+ */
+ private def typedOpcodeOffset: Int = this match {
+ case UNIT => 5
+ case BOOL | CHAR | BYTE | SHORT | INT => 0
+ case FLOAT => 2
+ case LONG => 1
+ case DOUBLE => 3
+ case _ => 4
+ }
+
+ /**
+ * Some JVM opcodes have typed variants. This method returns the correct opcode according to
+ * the type.
+ *
+ * @param opcode A JVM instruction opcode. This opcode must be one of ILOAD, ISTORE, IALOAD,
+ * IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL, ISHR, IUSHR, IAND, IOR
+ * IXOR and IRETURN.
+ * @return The opcode adapted to this java type. For example, if this type is `float` and
+ * `opcode` is `IRETURN`, this method returns `FRETURN`.
+ */
+ final def typedOpcode(opcode: Int): Int = {
+ if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE)
+ opcode + loadStoreOpcodeOffset
+ else
+ opcode + typedOpcodeOffset
+ }
+
+ /**
+ * The asm.Type corresponding to this BType.
+ *
+ * Note about asm.Type.getObjectType (*): For class types, the method expects the internal
+ * name, i.e. without the surrounding 'L' and ';'. For array types on the other hand, the
+ * method expects a full descriptor, for example "[Ljava/lang/String;".
+ *
+ * See method asm.Type.getType that creates a asm.Type from a type descriptor
+ * - for an OBJECT type, the 'L' and ';' are not part of the range of the created Type
+ * - for an ARRAY type, the full descriptor is part of the range
+ */
+ def toASMType: asm.Type = this match {
+ case UNIT => asm.Type.VOID_TYPE
+ case BOOL => asm.Type.BOOLEAN_TYPE
+ case CHAR => asm.Type.CHAR_TYPE
+ case BYTE => asm.Type.BYTE_TYPE
+ case SHORT => asm.Type.SHORT_TYPE
+ case INT => asm.Type.INT_TYPE
+ case FLOAT => asm.Type.FLOAT_TYPE
+ case LONG => asm.Type.LONG_TYPE
+ case DOUBLE => asm.Type.DOUBLE_TYPE
+ case c @ ClassBType(_, _) => asm.Type.getObjectType(c.internalName) // (*)
+ case a @ ArrayBType(_) => asm.Type.getObjectType(a.descriptor)
+ case m @ MethodBType(_, _) => asm.Type.getMethodType(m.descriptor)
+ }
+
+ def asRefBType : RefBType = this.asInstanceOf[RefBType]
+ def asArrayBType: ArrayBType = this.asInstanceOf[ArrayBType]
+ def asClassBType: ClassBType = this.asInstanceOf[ClassBType]
+ }
+
+ object BType {
+ /**
+ * @param chars The character array containing the descriptor
+ * @param start The position where the descriptor starts
+ * @return The BType and the index of the first character after the consumed descriptor
+ */
+ private[BTypes] def fromNonMethodDescriptor(chars: Array[Char], start: Int): (BType, Int) = {
+ chars(start) match {
+ case 'L' =>
+ var i = start
+ while (chars(i) != ';') { i += 1 }
+ // Example: chars = "IILpkg/Cls;I"
+ // ^ ^
+ // start=2 i=10
+ // `start + 1` to exclude the 'L', `i - start - 1` excludes the ';'
+ (new ClassBType(new String(chars, start + 1, i - start - 1)), i + 1)
+ case '[' =>
+ val (res, next) = fromNonMethodDescriptor(chars, start + 1)
+ (ArrayBType(res), next)
+ case 'V' => (UNIT, start + 1)
+ case 'Z' => (BOOL, start + 1)
+ case 'C' => (CHAR, start + 1)
+ case 'B' => (BYTE, start + 1)
+ case 'S' => (SHORT, start + 1)
+ case 'I' => (INT, start + 1)
+ case 'F' => (FLOAT, start + 1)
+ case 'J' => (LONG, start + 1)
+ case 'D' => (DOUBLE, start + 1)
+ }
+ }
+ }
+
+ sealed trait PrimitiveBType extends BType
+
+ case object UNIT extends PrimitiveBType
+ case object BOOL extends PrimitiveBType
+ case object CHAR extends PrimitiveBType
+ case object BYTE extends PrimitiveBType
+ case object SHORT extends PrimitiveBType
+ case object INT extends PrimitiveBType
+ case object FLOAT extends PrimitiveBType
+ case object LONG extends PrimitiveBType
+ case object DOUBLE extends PrimitiveBType
+
+ sealed trait RefBType extends BType {
+ /**
+ * The class or array type of this reference type. Used for ANEWARRAY, MULTIANEWARRAY,
+ * INSTANCEOF and CHECKCAST instructions. Also used for emitting invokevirtual calls to
+ * (a: Array[T]).clone() for any T, see genApply.
+ *
+ * In contrast to the descriptor, this string does not contain the surrounding 'L' and ';' for
+ * class types, for example "java/lang/String".
+ * However, for array types, the full descriptor is used, for example "[Ljava/lang/String;".
+ *
+ * This can be verified for example using javap or ASMifier.
+ */
+ def classOrArrayType: String = this match {
+ case c: ClassBType => c.internalName
+ case a: ArrayBType => a.descriptor
+ }
+ }
+
+ /**
+ * Class or Interface type.
+ *
+ * Classes are represented using their name as a slice of the `chrs` array. This representation is
+ * efficient because the JVM class name is initially created using `classSymbol.javaBinaryName`.
+ * This already adds the necessary string to the `chrs` array, so it makes sense to reuse the same
+ * name table in the backend.
+ *
+ * Not a case class because that would expose the (Int, Int) constructor (didn't find a way to
+ * make it private, also the factory in the companion).
+ */
+ class ClassBType private(val offset: Int, val length: Int) extends RefBType {
+ /**
+ * Construct a ClassBType for a given (intenred) class name.
+ *
+ * @param n The class name as a slice of the `chrs` array, without the surrounding 'L' and ';'.
+ * Note that `classSymbol.javaBinaryName` returns exactly such a name.
+ */
+ def this(n: BTypeName) = this(n.start, n.length)
+
+ /**
+ * Construct a ClassBType for a given java class name.
+ *
+ * @param s A class name of the form "java/lang/String", without the surrounding 'L' and ';'.
+ */
+ def this(s: String) = this({
+ assert(!(s.head == 'L' && s.last == ';'), s"Descriptor instead of internal name: $s")
+ createNewName(s)
+ })
+
+ /**
+ * The internal name of a class is the string returned by java.lang.Class.getName, with all '.'
+ * replaced by '/'. For example "java/lang/String".
+ */
+ def internalName: String = new String(chrs, offset, length)
+
+ /**
+ * @return The class name without the package prefix
+ */
+ def simpleName: String = internalName.split("/").last
+
+ /**
+ * Custom equals / hashCode are needed because this is not a case class.
+ */
+ override def equals(o: Any): Boolean = (this eq o.asInstanceOf[Object]) || (o match {
+ case ClassBType(`offset`, `length`) => true
+ case _ => false
+ })
+
+ override def hashCode: Int = {
+ import scala.runtime.Statics
+ var acc: Int = -889275714
+ acc = Statics.mix(acc, offset)
+ acc = Statics.mix(acc, length)
+ Statics.finalizeHash(acc, 2)
+ }
+ }
+
+ object ClassBType {
+ def apply(n: BTypeName): ClassBType = new ClassBType(n)
+ def apply(s: String): ClassBType = new ClassBType(s)
+
+ def unapply(c: ClassBType): Option[(Int, Int)] =
+ if (c == null) None
+ else Some((c.offset, c.length))
+ }
+
+ case class ArrayBType(componentType: BType) extends RefBType {
+ def dimension: Int = componentType match {
+ case a: ArrayBType => 1 + a.dimension
+ case _ => 1
+ }
+
+ def elementType: BType = componentType match {
+ case a: ArrayBType => a.elementType
+ case t => t
+ }
+ }
+
+ case class MethodBType(argumentTypes: List[BType], returnType: BType) extends BType {
+ private def this(types: (List[BType], BType)) = this(types._1, types._2)
+ def this(descriptor: String) = this(MethodBType.decomposeMethodDescriptor(descriptor))
+ }
+
+ object MethodBType {
+ private def decomposeMethodDescriptor(descriptor: String): (List[BType], BType) = {
+ val chars = descriptor.toCharArray
+ assert(chars(0) == '(', s"Not a valid method descriptor: $descriptor")
+ var i = 1
+ val argTypes = new ListBuffer[BType]
+ while (chars(i) != ')') {
+ val (argType, next) = BType.fromNonMethodDescriptor(chars, i)
+ argTypes += argType
+ i = next
+ }
+ val (resType, _) = BType.fromNonMethodDescriptor(chars, i + 1) // `i + 1` to skip the ')'
+ (argTypes.toList, resType)
+ }
+ def apply(descriptor: String) = {
+ val (argTypes, resType) = decomposeMethodDescriptor(descriptor)
+ new MethodBType(argTypes, resType)
+ }
+ }
+
+ val BOXED_UNIT = ClassBType("java/lang/Void")
+ val BOXED_BOOLEAN = ClassBType("java/lang/Boolean")
+ val BOXED_BYTE = ClassBType("java/lang/Byte")
+ val BOXED_SHORT = ClassBType("java/lang/Short")
+ val BOXED_CHAR = ClassBType("java/lang/Character")
+ val BOXED_INT = ClassBType("java/lang/Integer")
+ val BOXED_LONG = ClassBType("java/lang/Long")
+ val BOXED_FLOAT = ClassBType("java/lang/Float")
+ val BOXED_DOUBLE = ClassBType("java/lang/Double")
+
+ /*
+ * RT_NOTHING and RT_NULL exist at run-time only. They are the bytecode-level manifestation (in
+ * method signatures only) of what shows up as NothingClass resp. NullClass in Scala ASTs.
+ *
+ * Therefore, when RT_NOTHING or RT_NULL are to be emitted, a mapping is needed: the internal
+ * names of NothingClass and NullClass can't be emitted as-is.
+ */
+ val RT_NOTHING = ClassBType("scala/runtime/Nothing$")
+ val RT_NULL = ClassBType("scala/runtime/Null$")
+ val CT_NOTHING = ClassBType("scala/Nothing")
+ val CT_NULL = ClassBType("scala/Null")
+
+ val srBooleanRef = ClassBType("scala/runtime/BooleanRef")
+ val srByteRef = ClassBType("scala/runtime/ByteRef")
+ val srCharRef = ClassBType("scala/runtime/CharRef")
+ val srIntRef = ClassBType("scala/runtime/IntRef")
+ val srLongRef = ClassBType("scala/runtime/LongRef")
+ val srFloatRef = ClassBType("scala/runtime/FloatRef")
+ val srDoubleRef = ClassBType("scala/runtime/DoubleRef")
+
+ /**
+ * Map from type kinds to the Java reference types.
+ * Useful when pushing class literals onto the operand stack (ldc instruction taking a class
+ * literal).
+ * @see Predef.classOf
+ * @see genConstant()
+ *
+ * TODO @lry rename to "boxedClassOfPrimitive" or so, check usages
+ */
+ val classLiteral = immutable.Map[BType, ClassBType](
+ UNIT -> BOXED_UNIT,
+ BOOL -> BOXED_BOOLEAN,
+ BYTE -> BOXED_BYTE,
+ SHORT -> BOXED_SHORT,
+ CHAR -> BOXED_CHAR,
+ INT -> BOXED_INT,
+ LONG -> BOXED_LONG,
+ FLOAT -> BOXED_FLOAT,
+ DOUBLE -> BOXED_DOUBLE
+ )
+
+ case class MethodNameAndType(name: String, descriptor: String)
+
+ val asmBoxTo: immutable.Map[BType, MethodNameAndType] = {
+ Map(
+ BOOL -> MethodNameAndType("boxToBoolean", "(Z)Ljava/lang/Boolean;" ) ,
+ BYTE -> MethodNameAndType("boxToByte", "(B)Ljava/lang/Byte;" ) ,
+ CHAR -> MethodNameAndType("boxToCharacter", "(C)Ljava/lang/Character;") ,
+ SHORT -> MethodNameAndType("boxToShort", "(S)Ljava/lang/Short;" ) ,
+ INT -> MethodNameAndType("boxToInteger", "(I)Ljava/lang/Integer;" ) ,
+ LONG -> MethodNameAndType("boxToLong", "(J)Ljava/lang/Long;" ) ,
+ FLOAT -> MethodNameAndType("boxToFloat", "(F)Ljava/lang/Float;" ) ,
+ DOUBLE -> MethodNameAndType("boxToDouble", "(D)Ljava/lang/Double;" )
+ )
+ }
+
+ val asmUnboxTo: immutable.Map[BType, MethodNameAndType] = {
+ Map(
+ BOOL -> MethodNameAndType("unboxToBoolean", "(Ljava/lang/Object;)Z") ,
+ BYTE -> MethodNameAndType("unboxToByte", "(Ljava/lang/Object;)B") ,
+ CHAR -> MethodNameAndType("unboxToChar", "(Ljava/lang/Object;)C") ,
+ SHORT -> MethodNameAndType("unboxToShort", "(Ljava/lang/Object;)S") ,
+ INT -> MethodNameAndType("unboxToInt", "(Ljava/lang/Object;)I") ,
+ LONG -> MethodNameAndType("unboxToLong", "(Ljava/lang/Object;)J") ,
+ FLOAT -> MethodNameAndType("unboxToFloat", "(Ljava/lang/Object;)F") ,
+ DOUBLE -> MethodNameAndType("unboxToDouble", "(Ljava/lang/Object;)D")
+ )
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index 13a5c6413d..988c04f514 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -1401,7 +1401,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
// TODO param names: (m.params map (p => javaName(p.sym)))
- // typestate: entering mode with valid call sequences:
+ // typestate: entering mode with valid call sequences: (see ASM Guide, 3.2.1)
// [ visitAnnotationDefault ] ( visitAnnotation | visitParameterAnnotation | visitAttribute )*
emitAnnotations(jmethod, others)
@@ -1446,7 +1446,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
val hasStaticBitSet = ((flags & asm.Opcodes.ACC_STATIC) != 0)
genCode(m, emitVars, hasStaticBitSet)
- jmethod.visitMaxs(0, 0) // just to follow protocol, dummy arguments
+ // visitMaxs needs to be called according to the protocol. The arguments will be ignored
+ // since maximums (and stack map frames) are computed. See ASM Guide, Section 3.2.1,
+ // section "ClassWriter options"
+ jmethod.visitMaxs(0, 0)
}
jmethod.visitEnd()
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
index 61cf76f524..9b292fee7f 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
@@ -244,14 +244,9 @@ abstract class GenBCode extends BCodeSyncAndTry {
val beanC = if (bean == null) null else SubItem3(bean.name, getByteArray(bean))
if (AsmUtils.traceSerializedClassEnabled && plain.name.contains(AsmUtils.traceSerializedClassPattern)) {
- def readClass(bytes: Array[Byte]): asm.tree.ClassNode = {
- val node = new asm.tree.ClassNode()
- new asm.ClassReader(bytes).accept(node, 0)
- node
- }
- if (mirrorC != null) AsmUtils.traceClass(readClass(mirrorC.jclassBytes))
- AsmUtils.traceClass(readClass(plainC.jclassBytes))
- if (beanC != null) AsmUtils.traceClass(readClass(beanC.jclassBytes))
+ if (mirrorC != null) AsmUtils.traceClass(mirrorC.jclassBytes)
+ AsmUtils.traceClass(plainC.jclassBytes)
+ if (beanC != null) AsmUtils.traceClass(beanC.jclassBytes)
}
q3 add Item3(arrivalPos, mirrorC, plainC, beanC, outFolder)
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 20ccc30ff6..d22dcacad6 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -42,7 +42,7 @@ trait ScalaSettings extends AbsScalaSettings
def optimiseSettings = List[BooleanSetting](inline, inlineHandlers, Xcloselim, Xdce, YconstOptimization)
/** If any of these settings is enabled, the compiler should print a message and exit. */
- def infoSettings = List[Setting](help, Xhelp, Yhelp, showPlugins, showPhases, genPhaseGraph)
+ def infoSettings = List[Setting](version, help, Xhelp, Yhelp, showPlugins, showPhases, genPhaseGraph)
/** Is an info setting set? */
def isInfo = infoSettings exists (_.isSetByUser)
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
index 6ca2205881..149b4fe446 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
@@ -780,32 +780,40 @@ abstract class ICodeReader extends ClassfileParser {
bb = otherBlock
// Console.println("\t> entering bb: " + bb)
}
- instr match {
- case LJUMP(target) =>
- otherBlock = blocks(target)
- bb.emitOnly(JUMP(otherBlock))
- case LCJUMP(success, failure, cond, kind) =>
- otherBlock = blocks(success)
- val failBlock = blocks(failure)
- bb.emitOnly(CJUMP(otherBlock, failBlock, cond, kind))
+ if (bb.closed) {
+ // the basic block is closed, i.e. the previous instruction was a jump, return or throw,
+ // but the next instruction is not a jump target. this means that the next instruction is
+ // dead code. we can therefore advance until the next jump target.
+ debuglog(s"ICode reader skipping dead instruction $instr in classfile $instanceCode")
+ } else {
+ instr match {
+ case LJUMP(target) =>
+ otherBlock = blocks(target)
+ bb.emitOnly(JUMP(otherBlock))
+
+ case LCJUMP(success, failure, cond, kind) =>
+ otherBlock = blocks(success)
+ val failBlock = blocks(failure)
+ bb.emitOnly(CJUMP(otherBlock, failBlock, cond, kind))
- case LCZJUMP(success, failure, cond, kind) =>
- otherBlock = blocks(success)
- val failBlock = blocks(failure)
- bb.emitOnly(CZJUMP(otherBlock, failBlock, cond, kind))
+ case LCZJUMP(success, failure, cond, kind) =>
+ otherBlock = blocks(success)
+ val failBlock = blocks(failure)
+ bb.emitOnly(CZJUMP(otherBlock, failBlock, cond, kind))
- case LSWITCH(tags, targets) =>
- bb.emitOnly(SWITCH(tags, targets map blocks))
+ case LSWITCH(tags, targets) =>
+ bb.emitOnly(SWITCH(tags, targets map blocks))
- case RETURN(_) =>
- bb emitOnly instr
+ case RETURN(_) =>
+ bb emitOnly instr
- case THROW(clasz) =>
- bb emitOnly instr
+ case THROW(clasz) =>
+ bb emitOnly instr
- case _ =>
- bb emit instr
+ case _ =>
+ bb emit instr
+ }
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index e036035397..2f2142027f 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -1050,20 +1050,18 @@ abstract class Erasure extends AddInterfaces
}
}
- def isAccessible(sym: Symbol) = localTyper.context.isAccessible(sym, sym.owner.thisType)
- if (!isAccessible(owner) && qual.tpe != null) {
+ def isJvmAccessible(sym: Symbol) = (sym.isClass && !sym.isJavaDefined) || localTyper.context.isAccessible(sym, sym.owner.thisType)
+ if (!isJvmAccessible(owner) && qual.tpe != null) {
qual match {
case Super(_, _) =>
- // Insert a cast here at your peril -- see SI-5162. Bail out if the target method is defined in
- // Java, otherwise, we'd get an IllegalAccessError at runtime. If the target method is defined in
- // Scala, however, we should have access.
- if (owner.isJavaDefined) unit.error(tree.pos, s"Unable to access ${tree.symbol.fullLocationString} with a super reference.")
+ // Insert a cast here at your peril -- see SI-5162.
+ unit.error(tree.pos, s"Unable to access ${tree.symbol.fullLocationString} with a super reference.")
tree
case _ =>
// Todo: Figure out how qual.tpe could be null in the check above (it does appear in build where SwingWorker.this
// has a null type).
val qualSym = qual.tpe.widen.typeSymbol
- if (isAccessible(qualSym) && !qualSym.isPackageClass && !qualSym.isPackageObjectClass) {
+ if (isJvmAccessible(qualSym) && !qualSym.isPackageClass && !qualSym.isPackageObjectClass) {
// insert cast to prevent illegal access error (see #4283)
// util.trace("insert erasure cast ") (*/
treeCopy.Select(tree, gen.mkAttributedCast(qual, qual.tpe.widen), name) //)
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 33e8e47c76..313d0a6e61 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -391,7 +391,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
else {
sourceModule setPos sym.pos
if (sourceModule.flags != MODULE) {
- log("!!! Directly setting sourceModule flags from %s to MODULE".format(sourceModule.flagString))
+ log(s"!!! Directly setting sourceModule flags for $sourceModule from ${sourceModule.flagString} to MODULE")
sourceModule.flags = MODULE
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index d87090fa46..73c3e6f016 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -1306,7 +1306,7 @@ trait Implicits {
}
def wrapResult(tree: Tree): SearchResult =
- if (tree == EmptyTree) SearchFailure else new SearchResult(tree, EmptyTreeTypeSubstituter, Nil)
+ if (tree == EmptyTree) SearchFailure else new SearchResult(atPos(pos.focus)(tree), EmptyTreeTypeSubstituter, Nil)
/** Materializes implicits of predefined types (currently, manifests and tags).
* Will be replaced by implicit macros once we fix them.
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 4382a2c6f7..099031d536 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -1040,10 +1040,10 @@ trait Namers extends MethodSynthesis {
* so the resulting type is a valid external method type, it does not contain (references to) skolems.
*/
def thisMethodType(restpe: Type) = {
- val checkDependencies = new DependentTypeChecker(context)(this)
- checkDependencies check vparamSymss
- // DEPMETTODO: check not needed when they become on by default
- checkDependencies(restpe)
+ if (vparamSymss.lengthCompare(0) > 0) { // OPT fast path for methods of 0-1 parameter lists
+ val checkDependencies = new DependentTypeChecker(context)(this)
+ checkDependencies check vparamSymss
+ }
val makeMethodType = (vparams: List[Symbol], restpe: Type) => {
// TODODEPMET: check that we actually don't need to do anything here
@@ -1177,7 +1177,13 @@ trait Namers extends MethodSynthesis {
}
}
- addDefaultGetters(meth, ddef, vparamss, tparams, overriddenSymbol(methResTp))
+ val overridden = {
+ val isConstr = meth.isConstructor
+ if (isConstr || !methOwner.isClass) NoSymbol else overriddenSymbol(methResTp)
+ }
+ val hasDefaults = mexists(vparamss)(_.symbol.hasDefault) || mexists(overridden.paramss)(_.hasDefault)
+ if (hasDefaults)
+ addDefaultGetters(meth, ddef, vparamss, tparams, overridden)
// fast track macros, i.e. macros defined inside the compiler, are hardcoded
// hence we make use of that and let them have whatever right-hand side they need
@@ -1219,7 +1225,7 @@ trait Namers extends MethodSynthesis {
* typechecked, the corresponding param would not yet have the "defaultparam"
* flag.
*/
- private def addDefaultGetters(meth: Symbol, ddef: DefDef, vparamss: List[List[ValDef]], tparams: List[TypeDef], overriddenSymbol: => Symbol) {
+ private def addDefaultGetters(meth: Symbol, ddef: DefDef, vparamss: List[List[ValDef]], tparams: List[TypeDef], overridden: Symbol) {
val DefDef(_, _, rtparams0, rvparamss0, _, _) = resetAttrs(ddef.duplicate)
// having defs here is important to make sure that there's no sneaky tree sharing
// in methods with multiple default parameters
@@ -1227,7 +1233,6 @@ trait Namers extends MethodSynthesis {
def rvparamss = rvparamss0.map(_.map(_.duplicate))
val methOwner = meth.owner
val isConstr = meth.isConstructor
- val overridden = if (isConstr || !methOwner.isClass) NoSymbol else overriddenSymbol
val overrides = overridden != NoSymbol && !overridden.isOverloaded
// value parameters of the base class (whose defaults might be overridden)
var baseParamss = (vparamss, overridden.tpe.paramss) match {
@@ -1745,7 +1750,6 @@ trait Namers extends MethodSynthesis {
for (p <- vps)
this(p.info)
// can only refer to symbols in earlier parameter sections
- // (if the extension is enabled)
okParams ++= vps
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index dceb0a47d8..284ab2f6f9 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -174,8 +174,8 @@ trait NamesDefaults { self: Analyzer =>
// assigning the correct method symbol, typedSelect will just assign the type. the reason
// to still call 'typed' is to correctly infer singleton types, SI-5259.
val selectPos =
- if(qual.pos.isRange && baseFun.pos.isRange) qual.pos.union(baseFun.pos).withStart(Math.min(qual.pos.end, baseFun.pos.end))
- else baseFun.pos
+ if(qual.pos.isRange && baseFun1.pos.isRange) qual.pos.union(baseFun1.pos).withStart(Math.min(qual.pos.end, baseFun1.pos.end))
+ else baseFun1.pos
val f = blockTyper.typedOperator(Select(newQual, selected).setSymbol(baseFun1.symbol).setPos(selectPos))
if (funTargs.isEmpty) f
else TypeApply(f, funTargs).setType(baseFun.tpe)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 9fe693ce2a..66b1c2d87a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -3022,7 +3022,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
|| (looker.hasAccessorFlag && !accessed.hasAccessorFlag && accessed.isPrivate)
)
- def checkNoDoubleDefs(stats: List[Tree]): Unit = {
+ def checkNoDoubleDefs: Unit = {
val scope = if (inBlock) context.scope else context.owner.info.decls
var e = scope.elems
while ((e ne null) && e.owner == scope) {
@@ -3057,8 +3057,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// the corresponding synthetics to the package class, only to the package object class.
def shouldAdd(sym: Symbol) =
inBlock || !context.isInPackageObject(sym, context.owner)
- for (sym <- scope if shouldAdd(sym))
- for (tree <- context.unit.synthetics get sym) {
+ for (sym <- scope)
+ for (tree <- context.unit.synthetics get sym if shouldAdd(sym)) { // OPT: shouldAdd is usually true. Call it here, rather than in the outer loop
newStats += typedStat(tree) // might add even more synthetics to the scope
context.unit.synthetics -= sym
}
@@ -3104,7 +3104,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val stats1 = stats mapConserve typedStat
if (phase.erasedTypes) stats1
else {
- checkNoDoubleDefs(stats1)
+ // As packages are open, it doesn't make sense to check double definitions here. Furthermore,
+ // it is expensive if the package is large. Instead, such double defininitions are checked in `Namers.enterInScope`
+ if (!context.owner.isPackageClass)
+ checkNoDoubleDefs
addSynthetics(stats1)
}
}
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
index 3b12086cc7..923297bafb 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -141,6 +141,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
val run = new Run
run.symSource(ownerClass) = NoAbstractFile // need to set file to something different from null, so that currentRun.defines works
phase = run.typerPhase // need to set a phase to something <= typerPhase, otherwise implicits in typedSelect will be disabled
+ globalPhase = run.typerPhase // amazing... looks like phase and globalPhase are different things, so we need to set them separately
currentTyper.context.setReportErrors() // need to manually set context mode, otherwise typer.silent will throw exceptions
reporter.reset()
diff --git a/src/interactive/scala/tools/nsc/interactive/Main.scala b/src/interactive/scala/tools/nsc/interactive/Main.scala
index c838606f02..7796c65670 100644
--- a/src/interactive/scala/tools/nsc/interactive/Main.scala
+++ b/src/interactive/scala/tools/nsc/interactive/Main.scala
@@ -12,7 +12,7 @@ package interactive
*/
object Main extends nsc.MainClass {
override def processSettingsHook(): Boolean = {
- if (this.settings.Yidedebug) {
+ def run(): Unit = {
this.settings.Xprintpos.value = true
this.settings.Yrangepos.value = true
val compiler = new interactive.Global(this.settings, this.reporter)
@@ -27,8 +27,9 @@ object Main extends nsc.MainClass {
case None => reporter.reset() // Causes other compiler errors to be ignored
}
askShutdown
- false
}
- else true
+ super.processSettingsHook() && (
+ if (this.settings.Yidedebug) { run() ; false } else true
+ )
}
}
diff --git a/src/library/scala/collection/IndexedSeqOptimized.scala b/src/library/scala/collection/IndexedSeqOptimized.scala
index ade04e4de8..42cb37aa24 100755
--- a/src/library/scala/collection/IndexedSeqOptimized.scala
+++ b/src/library/scala/collection/IndexedSeqOptimized.scala
@@ -206,7 +206,7 @@ trait IndexedSeqOptimized[+A, +Repr] extends Any with IndexedSeqLike[A, Repr] {
override /*SeqLike*/
def lastIndexWhere(p: A => Boolean, end: Int): Int = {
- var i = end
+ var i = math.min(end, length - 1)
while (i >= 0 && !p(this(i))) i -= 1
i
}
diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala
index 1b496383a3..f6f46e158f 100644
--- a/src/library/scala/collection/Iterator.scala
+++ b/src/library/scala/collection/Iterator.scala
@@ -922,11 +922,16 @@ trait Iterator[+A] extends TraversableOnce[A] {
/** For reasons which remain to be determined, calling
* self.take(n).toSeq cause an infinite loop, so we have
* a slight variation on take for local usage.
+ * NB: self.take.toSeq is slice.toStream, lazily built on self,
+ * so a subsequent self.hasNext would not test self after the
+ * group was consumed.
*/
private def takeDestructively(size: Int): Seq[A] = {
val buf = new ArrayBuffer[A]
var i = 0
- while (self.hasNext && i < size) {
+ // The order of terms in the following condition is important
+ // here as self.hasNext could be blocking
+ while (i < size && self.hasNext) {
buf += self.next
i += 1
}
@@ -943,12 +948,10 @@ trait Iterator[+A] extends TraversableOnce[A] {
// so the rest of the code can be oblivious
val xs: Seq[B] = {
val res = takeDestructively(count)
- // extra checks so we don't calculate length unless there's reason
- if (pad.isDefined && !self.hasNext) {
- val shortBy = count - res.length
- if (shortBy > 0) res ++ padding(shortBy) else res
- }
- else res
+ // was: extra checks so we don't calculate length unless there's reason
+ // but since we took the group eagerly, just use the fast length
+ val shortBy = count - res.length
+ if (shortBy > 0 && pad.isDefined) res ++ padding(shortBy) else res
}
lazy val len = xs.length
lazy val incomplete = len < count
diff --git a/src/library/scala/collection/immutable/HashSet.scala b/src/library/scala/collection/immutable/HashSet.scala
index 726937efd9..e4b7371ed4 100644
--- a/src/library/scala/collection/immutable/HashSet.scala
+++ b/src/library/scala/collection/immutable/HashSet.scala
@@ -162,6 +162,13 @@ class HashSet[A] extends AbstractSet[A]
def - (e: A): HashSet[A] =
nullToEmpty(removed0(e, computeHash(e), 0))
+ /** Returns this $coll as an immutable set.
+ *
+ * A new set will not be built; lazy collections will stay lazy.
+ */
+ @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0")
+ override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]]
+
override def filter(p: A => Boolean) = {
val buffer = new Array[HashSet[A]](bufferSize(size))
nullToEmpty(filter0(p, false, 0, buffer, 0))
diff --git a/src/library/scala/collection/immutable/ListSet.scala b/src/library/scala/collection/immutable/ListSet.scala
index 1bb07eb02d..89d1a9640e 100644
--- a/src/library/scala/collection/immutable/ListSet.scala
+++ b/src/library/scala/collection/immutable/ListSet.scala
@@ -138,6 +138,13 @@ class ListSet[A] extends AbstractSet[A]
override def stringPrefix = "ListSet"
+ /** Returns this $coll as an immutable set.
+ *
+ * A new set will not be built; lazy collections will stay lazy.
+ */
+ @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0")
+ override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]]
+
/** Represents an entry in the `ListSet`.
*/
protected class Node(override val head: A) extends ListSet[A] with Serializable {
diff --git a/src/library/scala/collection/immutable/Set.scala b/src/library/scala/collection/immutable/Set.scala
index 0fbf7942d4..7725ad9ee3 100644
--- a/src/library/scala/collection/immutable/Set.scala
+++ b/src/library/scala/collection/immutable/Set.scala
@@ -35,12 +35,7 @@ trait Set[A] extends Iterable[A]
override def companion: GenericCompanion[Set] = Set
- /** Returns this $coll as an immutable map.
- *
- * A new map will not be built; lazy collections will stay lazy.
- */
- @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0")
- override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]]
+ override def toSet[B >: A]: Set[B] = to[({type l[a] = immutable.Set[B]})#l] // for bincompat; remove in dev
override def seq: Set[A] = this
protected override def parCombiner = ParSet.newCombiner[A] // if `immutable.SetLike` gets introduced, please move this there!
@@ -62,6 +57,7 @@ object Set extends ImmutableSetFactory[Set] {
def - (elem: Any): Set[Any] = this
def iterator: Iterator[Any] = Iterator.empty
override def foreach[U](f: Any => U): Unit = {}
+ override def toSet[B >: Any]: Set[B] = this.asInstanceOf[Set[B]]
}
private[collection] def emptyInstance: Set[Any] = EmptySet
@@ -92,6 +88,8 @@ object Set extends ImmutableSetFactory[Set] {
if (f(elem1)) Some(elem1)
else None
}
+ @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0")
+ override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]]
}
/** An optimized representation for immutable sets of size 2 */
@@ -123,6 +121,8 @@ object Set extends ImmutableSetFactory[Set] {
else if (f(elem2)) Some(elem2)
else None
}
+ @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0")
+ override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]]
}
/** An optimized representation for immutable sets of size 3 */
@@ -156,6 +156,8 @@ object Set extends ImmutableSetFactory[Set] {
else if (f(elem3)) Some(elem3)
else None
}
+ @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0")
+ override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]]
}
/** An optimized representation for immutable sets of size 4 */
@@ -191,6 +193,8 @@ object Set extends ImmutableSetFactory[Set] {
else if (f(elem4)) Some(elem4)
else None
}
+ @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0")
+ override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]]
}
}
diff --git a/src/library/scala/collection/mutable/AVLTree.scala b/src/library/scala/collection/mutable/AVLTree.scala
index de09bb2040..cc2acb74d4 100644
--- a/src/library/scala/collection/mutable/AVLTree.scala
+++ b/src/library/scala/collection/mutable/AVLTree.scala
@@ -14,8 +14,8 @@ package mutable
* An immutable AVL Tree implementation formerly used by mutable.TreeSet
*
* @author Lucien Pereira
- * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.0")
*/
+@deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.2")
private[mutable] sealed trait AVLTree[+A] extends Serializable {
def balance: Int
diff --git a/src/library/scala/concurrent/Channel.scala b/src/library/scala/concurrent/Channel.scala
index 067244bd1c..89ad7d8c0e 100644
--- a/src/library/scala/concurrent/Channel.scala
+++ b/src/library/scala/concurrent/Channel.scala
@@ -10,8 +10,10 @@
package scala.concurrent
-/** This class ...
+/** This class provides a simple FIFO queue of data objects,
+ * which are read by one or more reader threads.
*
+ * @tparam A type of data exchanged
* @author Martin Odersky
* @version 1.0, 10/03/2003
*/
@@ -20,11 +22,14 @@ class Channel[A] {
var elem: A = _
var next: LinkedList[A] = null
}
- private var written = new LinkedList[A] // FIFO buffer, realized through
+ private var written = new LinkedList[A] // FIFO queue, realized through
private var lastWritten = written // aliasing of a linked list
private var nreaders = 0
- /**
+ /** Append a value to the FIFO queue to be read by `read`.
+ * This operation is nonblocking and can be executed by any thread.
+ *
+ * @param x object to enqueue to this channel
*/
def write(x: A) = synchronized {
lastWritten.elem = x
@@ -33,6 +38,11 @@ class Channel[A] {
if (nreaders > 0) notify()
}
+ /** Retrieve the next waiting object from the FIFO queue,
+ * blocking if necessary until an object is available.
+ *
+ * @return next object dequeued from this channel
+ */
def read: A = synchronized {
while (written.next == null) {
try {
@@ -45,5 +55,4 @@ class Channel[A] {
written = written.next
x
}
-
}
diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala
index a1e94c8876..4674c9174b 100644
--- a/src/library/scala/concurrent/ExecutionContext.scala
+++ b/src/library/scala/concurrent/ExecutionContext.scala
@@ -77,12 +77,12 @@ trait ExecutionContext {
}
/**
- * Union interface since Java does not support union types
+ * An [[ExecutionContext]] that is also a Java [[Executor]].
*/
trait ExecutionContextExecutor extends ExecutionContext with Executor
/**
- * Union interface since Java does not support union types
+ * An [[ExecutionContext]] that is also a Java [[ExecutorService]].
*/
trait ExecutionContextExecutorService extends ExecutionContextExecutor with ExecutorService
diff --git a/src/library/scala/concurrent/Lock.scala b/src/library/scala/concurrent/Lock.scala
index 1c00c0e91f..8d18da2d38 100644
--- a/src/library/scala/concurrent/Lock.scala
+++ b/src/library/scala/concurrent/Lock.scala
@@ -14,8 +14,8 @@ package scala.concurrent
*
* @author Martin Odersky
* @version 1.0, 10/03/2003
- * @deprecated("Use java.util.concurrent.locks.Lock", "2.11.0")
*/
+@deprecated("Use java.util.concurrent.locks.Lock", "2.11.2")
class Lock {
var available = true
diff --git a/src/library/scala/concurrent/SyncVar.scala b/src/library/scala/concurrent/SyncVar.scala
index d5dc3d7e3f..494c955833 100644
--- a/src/library/scala/concurrent/SyncVar.scala
+++ b/src/library/scala/concurrent/SyncVar.scala
@@ -13,6 +13,7 @@ import java.util.concurrent.TimeUnit
/** A class to provide safe concurrent access to a mutable cell.
* All methods are synchronized.
*
+ * @tparam A type of the contained value
* @author Martin Odersky
* @version 1.0, 10/03/2003
*/
@@ -20,6 +21,12 @@ class SyncVar[A] {
private var isDefined: Boolean = false
private var value: Option[A] = None
+ /**
+ * Waits for this SyncVar to become defined and returns
+ * the result, without modifying the stored value.
+ *
+ * @return value that is held in this container
+ */
def get: A = synchronized {
while (!isDefined) wait()
value.get
@@ -57,8 +64,12 @@ class SyncVar[A] {
value
}
- /** Waits for this SyncVar to become defined and returns
- * the result */
+ /**
+ * Waits for this SyncVar to become defined and returns
+ * the result, unsetting the stored value before returning.
+ *
+ * @return value that was held in this container
+ */
def take(): A = synchronized {
try get
finally unsetVal()
@@ -129,4 +140,3 @@ class SyncVar[A] {
}
}
-
diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala
index cc1350f5a9..4d88253de4 100644
--- a/src/library/scala/concurrent/package.scala
+++ b/src/library/scala/concurrent/package.scala
@@ -55,6 +55,11 @@ package object concurrent {
}
package concurrent {
+ /**
+ * This marker trait is used by [[Await]] to ensure that [[Awaitable.ready]] and [[Awaitable.result]]
+ * are not directly called by user code. An implicit instance of this trait is only available when
+ * user code is currently calling the methods on [[Await]].
+ */
@implicitNotFound("Don't call `Awaitable` methods directly, use the `Await` object.")
sealed trait CanAwait
diff --git a/src/library/scala/util/Properties.scala b/src/library/scala/util/Properties.scala
index d597feb898..2daa4de9a6 100644
--- a/src/library/scala/util/Properties.scala
+++ b/src/library/scala/util/Properties.scala
@@ -155,9 +155,12 @@ private[scala] trait PropertiesTrait {
// This is looking for javac, tools.jar, etc.
// Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
// and finally the system property based javaHome.
- def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
- def versionMsg = "Scala %s %s -- %s".format(propCategory, versionString, copyrightString)
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
def scalaCmd = if (isWin) "scala.bat" else "scala"
def scalacCmd = if (isWin) "scalac.bat" else "scalac"
diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala
index ae9f2da4e5..b50f324074 100644
--- a/src/reflect/scala/reflect/internal/Names.scala
+++ b/src/reflect/scala/reflect/internal/Names.scala
@@ -40,7 +40,10 @@ trait Names extends api.Names {
/** Hashtable for finding type names quickly. */
private val typeHashtable = new Array[TypeName](HASH_SIZE)
- /** The hashcode of a name. */
+ /**
+ * The hashcode of a name depends on the first, the last and the middle character,
+ * and the length of the name.
+ */
private def hashValue(cs: Array[Char], offset: Int, len: Int): Int =
if (len > 0)
(len * (41 * 41 * 41) +
@@ -104,10 +107,21 @@ trait Names extends api.Names {
// The logic order here is future-proofing against the possibility
// that name.toString will become an eager val, in which case the call
// to enterChars cannot follow the construction of the TermName.
- val ncStart = nc
- enterChars(cs, offset, len)
- if (cachedString ne null) new TermName_S(ncStart, len, h, cachedString)
- else new TermName_R(ncStart, len, h)
+ var startIndex = 0
+ if (cs == chrs) {
+ // Optimize for subName, the new name is already stored in chrs
+ startIndex = offset
+ } else {
+ startIndex = nc
+ enterChars(cs, offset, len)
+ }
+ val next = termHashtable(h)
+ val termName =
+ if (cachedString ne null) new TermName_S(startIndex, len, next, cachedString)
+ else new TermName_R(startIndex, len, next)
+ // Add the new termName to the hashtable only after it's been fully constructed
+ termHashtable(h) = termName
+ termName
}
}
if (synchronizeNames) nameLock.synchronized(body) else body
@@ -145,40 +159,20 @@ trait Names extends api.Names {
newTermName(bs, offset, len).toTypeName
/**
- * Used only by the GenBCode backend, to represent bytecode-level types in a way that makes equals() and hashCode() efficient.
- * For bytecode-level types of OBJECT sort, its internal name (not its descriptor) is stored.
- * For those of ARRAY sort, its descriptor is stored ie has a leading '['
- * For those of METHOD sort, its descriptor is stored ie has a leading '('
+ * Used by the GenBCode backend to lookup type names that are known to already exist. This method
+ * might be invoked in a multi-threaded setting. Invoking newTypeName instead might be unsafe.
*
- * can-multi-thread
- * TODO SI-6240 !!! JZ Really? the constructors TermName and TypeName publish unconstructed `this` references
- * into the hash tables; we could observe them here before the subclass constructor completes.
+ * can-multi-thread: names are added to the hash tables only after they are fully constructed.
*/
- final def lookupTypeName(cs: Array[Char]): TypeName = { lookupTypeNameIfExisting(cs, true) }
-
- final def lookupTypeNameIfExisting(cs: Array[Char], failOnNotFound: Boolean): TypeName = {
-
- val hterm = hashValue(cs, 0, cs.size) & HASH_MASK
- var nterm = termHashtable(hterm)
- while ((nterm ne null) && (nterm.length != cs.size || !equals(nterm.start, cs, 0, cs.size))) {
- nterm = nterm.next
- }
- if (nterm eq null) {
- if (failOnNotFound) { assert(false, "TermName not yet created: " + new String(cs)) }
- return null
- }
+ final def lookupTypeName(cs: Array[Char]): TypeName = {
+ val hash = hashValue(cs, 0, cs.length) & HASH_MASK
+ var typeName = typeHashtable(hash)
- val htype = hashValue(chrs, nterm.start, nterm.length) & HASH_MASK
- var ntype = typeHashtable(htype)
- while ((ntype ne null) && ntype.start != nterm.start) {
- ntype = ntype.next
+ while ((typeName ne null) && (typeName.length != cs.length || !equals(typeName.start, cs, 0, cs.length))) {
+ typeName = typeName.next
}
- if (ntype eq null) {
- if (failOnNotFound) { assert(false, "TypeName not yet created: " + new String(cs)) }
- return null
- }
-
- ntype
+ assert(typeName != null, s"TypeName ${new String(cs)} not yet created.")
+ typeName
}
// Classes ----------------------------------------------------------------------
@@ -515,43 +509,47 @@ trait Names extends api.Names {
/** TermName_S and TypeName_S have fields containing the string version of the name.
* TermName_R and TypeName_R recreate it each time toString is called.
*/
- private final class TermName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TermName(index0, len0, hash) {
- protected def createCompanionName(h: Int): TypeName = new TypeName_S(index, len, h, toString)
+ private final class TermName_S(index0: Int, len0: Int, next0: TermName, override val toString: String) extends TermName(index0, len0, next0) {
+ protected def createCompanionName(next: TypeName): TypeName = new TypeName_S(index, len, next, toString)
override def newName(str: String): TermName = newTermNameCached(str)
}
- private final class TypeName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TypeName(index0, len0, hash) {
- protected def createCompanionName(h: Int): TermName = new TermName_S(index, len, h, toString)
+ private final class TypeName_S(index0: Int, len0: Int, next0: TypeName, override val toString: String) extends TypeName(index0, len0, next0) {
override def newName(str: String): TypeName = newTypeNameCached(str)
}
- private final class TermName_R(index0: Int, len0: Int, hash: Int) extends TermName(index0, len0, hash) {
- protected def createCompanionName(h: Int): TypeName = new TypeName_R(index, len, h)
+ private final class TermName_R(index0: Int, len0: Int, next0: TermName) extends TermName(index0, len0, next0) {
+ protected def createCompanionName(next: TypeName): TypeName = new TypeName_R(index, len, next)
override def toString = new String(chrs, index, len)
}
- private final class TypeName_R(index0: Int, len0: Int, hash: Int) extends TypeName(index0, len0, hash) {
- protected def createCompanionName(h: Int): TermName = new TermName_R(index, len, h)
+ private final class TypeName_R(index0: Int, len0: Int, next0: TypeName) extends TypeName(index0, len0, next0) {
override def toString = new String(chrs, index, len)
}
// SYNCNOTE: caller to constructor must synchronize if `synchronizeNames` is enabled
- sealed abstract class TermName(index0: Int, len0: Int, hash: Int) extends Name(index0, len0) with TermNameApi {
+ sealed abstract class TermName(index0: Int, len0: Int, val next: TermName) extends Name(index0, len0) with TermNameApi {
type ThisNameType = TermName
protected[this] def thisName: TermName = this
- val next: TermName = termHashtable(hash)
- termHashtable(hash) = this
+
def isTermName: Boolean = true
def isTypeName: Boolean = false
def toTermName: TermName = this
def toTypeName: TypeName = {
def body = {
+ // Re-computing the hash saves a field for storing it in the TermName
val h = hashValue(chrs, index, len) & HASH_MASK
var n = typeHashtable(h)
while ((n ne null) && n.start != index)
n = n.next
if (n ne null) n
- else createCompanionName(h)
+ else {
+ val next = typeHashtable(h)
+ val typeName = createCompanionName(next)
+ // Add the new typeName to the hashtable only after it's been fully constructed
+ typeHashtable(h) = typeName
+ typeName
+ }
}
if (synchronizeNames) nameLock.synchronized(body) else body
}
@@ -562,7 +560,7 @@ trait Names extends api.Names {
def nameKind = "term"
/** SYNCNOTE: caller must synchronize if `synchronizeNames` is enabled */
- protected def createCompanionName(h: Int): TypeName
+ protected def createCompanionName(next: TypeName): TypeName
}
implicit val TermNameTag = ClassTag[TermName](classOf[TermName])
@@ -572,24 +570,22 @@ trait Names extends api.Names {
def unapply(name: TermName): Option[String] = Some(name.toString)
}
- sealed abstract class TypeName(index0: Int, len0: Int, hash: Int) extends Name(index0, len0) with TypeNameApi {
+ sealed abstract class TypeName(index0: Int, len0: Int, val next: TypeName) extends Name(index0, len0) with TypeNameApi {
type ThisNameType = TypeName
protected[this] def thisName: TypeName = this
- val next: TypeName = typeHashtable(hash)
- typeHashtable(hash) = this
-
def isTermName: Boolean = false
def isTypeName: Boolean = true
def toTermName: TermName = {
def body = {
+ // Re-computing the hash saves a field for storing it in the TypeName
val h = hashValue(chrs, index, len) & HASH_MASK
var n = termHashtable(h)
while ((n ne null) && n.start != index)
n = n.next
- if (n ne null) n
- else createCompanionName(h)
+ assert (n ne null, s"TypeName $this is missing its correspondent")
+ n
}
if (synchronizeNames) nameLock.synchronized(body) else body
}
@@ -601,8 +597,6 @@ trait Names extends api.Names {
def nameKind = "type"
override def decode = if (nameDebug) super.decode + "!" else super.decode
- /** SYNCNOTE: caller must synchronize if `synchronizeNames` is enabled */
- protected def createCompanionName(h: Int): TermName
}
implicit val TypeNameTag = ClassTag[TypeName](classOf[TypeName])
diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala
index cf3f356daa..103f885ad4 100644
--- a/src/reflect/scala/reflect/internal/Scopes.scala
+++ b/src/reflect/scala/reflect/internal/Scopes.scala
@@ -48,22 +48,17 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
* This is necessary because when run from reflection every scope needs to have a
* SynchronizedScope as mixin.
*/
- class Scope protected[Scopes] (initElems: ScopeEntry = null, initFingerPrints: Long = 0L) extends ScopeApi with MemberScopeApi {
+ class Scope protected[Scopes]() extends ScopeApi with MemberScopeApi {
- protected[Scopes] def this(base: Scope) = {
- this(base.elems)
- nestinglevel = base.nestinglevel + 1
- }
-
- private[scala] var elems: ScopeEntry = initElems
+ private[scala] var elems: ScopeEntry = _
/** The number of times this scope is nested in another
*/
- private var nestinglevel = 0
+ private[Scopes] var nestinglevel = 0
/** the hash table
*/
- private var hashtable: Array[ScopeEntry] = null
+ private[Scopes] var hashtable: Array[ScopeEntry] = null
/** a cache for all elements, to be used by symbol iterator.
*/
@@ -84,8 +79,6 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
*/
private val MIN_HASH = 8
- if (size >= MIN_HASH) createHash()
-
/** Returns a new scope with the same content as this one. */
def cloneScope: Scope = newScopeWith(this.toList: _*)
@@ -435,7 +428,14 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
}
/** Create a new scope nested in another one with which it shares its elements */
- def newNestedScope(outer: Scope): Scope = new Scope(outer)
+ final def newNestedScope(outer: Scope): Scope = {
+ val nested = newScope // not `new Scope`, we must allow the runtime reflection universe to mixin SynchronizedScopes!
+ nested.elems = outer.elems
+ nested.nestinglevel = outer.nestinglevel + 1
+ if (outer.hashtable ne null)
+ nested.hashtable = java.util.Arrays.copyOf(outer.hashtable, outer.hashtable.length)
+ nested
+ }
/** Create a new scope with given initial elements */
def newScopeWith(elems: Symbol*): Scope = {
diff --git a/src/reflect/scala/reflect/internal/util/SourceFile.scala b/src/reflect/scala/reflect/internal/util/SourceFile.scala
index 4fccad74ac..a2642628a4 100644
--- a/src/reflect/scala/reflect/internal/util/SourceFile.scala
+++ b/src/reflect/scala/reflect/internal/util/SourceFile.scala
@@ -40,7 +40,7 @@ abstract class SourceFile {
def lineToString(index: Int): String = {
val start = lineToOffset(index)
var end = start
- while (!isEndOfLine(end) && end <= length) end += 1
+ while (end < length && !isEndOfLine(end)) end += 1
new String(content, start, end - start)
}
diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
index c56bc28d90..7ba68b8733 100644
--- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
+++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
@@ -91,7 +91,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
//
// Short of significantly changing SymbolLoaders I see no other way than just
// to slap a global lock on materialization in runtime reflection.
- class PackageScope(pkgClass: Symbol) extends Scope(initFingerPrints = -1L) // disable fingerprinting as we do not know entries beforehand
+ class PackageScope(pkgClass: Symbol) extends Scope
with SynchronizedScope {
assert(pkgClass.isType)
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
index c90901410a..4a8585d616 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
@@ -37,8 +37,7 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable
// Scopes
- override def newScope = new Scope() with SynchronizedScope
- override def newNestedScope(outer: Scope): Scope = new Scope(outer) with SynchronizedScope
+ override def newScope = new Scope with SynchronizedScope
trait SynchronizedScope extends Scope {
// we can keep this lock fine-grained, because methods of Scope don't do anything extraordinary, which makes deadlocks impossible
diff --git a/src/reflect/scala/reflect/runtime/package.scala b/src/reflect/scala/reflect/runtime/package.scala
index 3c9bbccba3..e240bed0a7 100644
--- a/src/reflect/scala/reflect/runtime/package.scala
+++ b/src/reflect/scala/reflect/runtime/package.scala
@@ -30,7 +30,8 @@ package runtime {
import c.universe._
val runtimeClass = c.reifyEnclosingRuntimeClass
if (runtimeClass.isEmpty) c.abort(c.enclosingPosition, "call site does not have an enclosing class")
- val runtimeUniverse = Select(Select(Select(Ident(newTermName("scala")), newTermName("reflect")), newTermName("runtime")), newTermName("universe"))
+ val scalaPackage = Select(Ident(newTermName("_root_")), newTermName("scala"))
+ val runtimeUniverse = Select(Select(Select(scalaPackage, newTermName("reflect")), newTermName("runtime")), newTermName("universe"))
val currentMirror = Apply(Select(runtimeUniverse, newTermName("runtimeMirror")), List(Select(runtimeClass, newTermName("getClassLoader"))))
c.Expr[Nothing](currentMirror)(c.WeakTypeTag.Nothing)
}
diff --git a/src/repl/scala/tools/nsc/MainGenericRunner.scala b/src/repl/scala/tools/nsc/MainGenericRunner.scala
index 43f0ea1256..34057ed341 100644
--- a/src/repl/scala/tools/nsc/MainGenericRunner.scala
+++ b/src/repl/scala/tools/nsc/MainGenericRunner.scala
@@ -8,7 +8,6 @@ package tools.nsc
import io.{ File }
import util.{ ClassPath, ScalaClassLoader }
-import Properties.{ versionString, copyrightString }
import GenericRunnerCommand._
object JarRunner extends CommonRunner {
@@ -28,79 +27,78 @@ object JarRunner extends CommonRunner {
}
/** An object that runs Scala code. It has three possible
- * sources for the code to run: pre-compiled code, a script file,
- * or interactive entry.
- */
+ * sources for the code to run: pre-compiled code, a script file,
+ * or interactive entry.
+ */
class MainGenericRunner {
- def errorFn(ex: Throwable): Boolean = {
- ex.printStackTrace()
- false
- }
- def errorFn(str: String): Boolean = {
- Console.err println str
- false
+ def errorFn(str: String, e: Option[Throwable] = None, isFailure: Boolean = true): Boolean = {
+ if (str.nonEmpty) Console.err println str
+ e foreach (_.printStackTrace())
+ !isFailure
}
def process(args: Array[String]): Boolean = {
val command = new GenericRunnerCommand(args.toList, (x: String) => errorFn(x))
- import command.{ settings, howToRun, thingToRun }
- def sampleCompiler = new Global(settings) // def so its not created unless needed
-
- if (!command.ok) return errorFn("\n" + command.shortUsageMsg)
- else if (settings.version) return errorFn("Scala code runner %s -- %s".format(versionString, copyrightString))
- else if (command.shouldStopWithInfo) return errorFn(command getInfoMessage sampleCompiler)
-
- def isE = !settings.execute.isDefault
- def dashe = settings.execute.value
-
- def isI = !settings.loadfiles.isDefault
- def dashi = settings.loadfiles.value
-
- // Deadlocks on startup under -i unless we disable async.
- if (isI)
- settings.Yreplsync.value = true
-
- def combinedCode = {
- val files = if (isI) dashi map (file => File(file).slurp()) else Nil
- val str = if (isE) List(dashe) else Nil
-
- files ++ str mkString "\n\n"
- }
-
- def runTarget(): Either[Throwable, Boolean] = howToRun match {
- case AsObject =>
- ObjectRunner.runAndCatch(settings.classpathURLs, thingToRun, command.arguments)
- case AsScript =>
- ScriptRunner.runScriptAndCatch(settings, thingToRun, command.arguments)
- case AsJar =>
- JarRunner.runJar(settings, thingToRun, command.arguments)
- case Error =>
- Right(false)
- case _ =>
- // We start the repl when no arguments are given.
- Right(new interpreter.ILoop process settings)
+ import command.{ settings, howToRun, thingToRun, shortUsageMsg, shouldStopWithInfo }
+ def sampleCompiler = new Global(settings) // def so it's not created unless needed
+
+ def run(): Boolean = {
+ def isE = !settings.execute.isDefault
+ def dashe = settings.execute.value
+
+ def isI = !settings.loadfiles.isDefault
+ def dashi = settings.loadfiles.value
+
+ // Deadlocks on startup under -i unless we disable async.
+ if (isI)
+ settings.Yreplsync.value = true
+
+ def combinedCode = {
+ val files = if (isI) dashi map (file => File(file).slurp()) else Nil
+ val str = if (isE) List(dashe) else Nil
+
+ files ++ str mkString "\n\n"
+ }
+
+ def runTarget(): Either[Throwable, Boolean] = howToRun match {
+ case AsObject =>
+ ObjectRunner.runAndCatch(settings.classpathURLs, thingToRun, command.arguments)
+ case AsScript =>
+ ScriptRunner.runScriptAndCatch(settings, thingToRun, command.arguments)
+ case AsJar =>
+ JarRunner.runJar(settings, thingToRun, command.arguments)
+ case Error =>
+ Right(false)
+ case _ =>
+ // We start the repl when no arguments are given.
+ Right(new interpreter.ILoop process settings)
+ }
+
+ /** If -e and -i were both given, we want to execute the -e code after the
+ * -i files have been included, so they are read into strings and prepended to
+ * the code given in -e. The -i option is documented to only make sense
+ * interactively so this is a pretty reasonable assumption.
+ *
+ * This all needs a rewrite though.
+ */
+ if (isE) {
+ ScriptRunner.runCommand(settings, combinedCode, thingToRun +: command.arguments)
+ }
+ else runTarget() match {
+ case Left(ex) => errorFn("", Some(ex)) // there must be a useful message of hope to offer here
+ case Right(b) => b
+ }
}
- /** If -e and -i were both given, we want to execute the -e code after the
- * -i files have been included, so they are read into strings and prepended to
- * the code given in -e. The -i option is documented to only make sense
- * interactively so this is a pretty reasonable assumption.
- *
- * This all needs a rewrite though.
- */
- if (isE) {
- ScriptRunner.runCommand(settings, combinedCode, thingToRun +: command.arguments)
- }
- else runTarget() match {
- case Left(ex) => errorFn(ex)
- case Right(b) => b
- }
+ if (!command.ok)
+ errorFn(f"%n$shortUsageMsg")
+ else if (shouldStopWithInfo)
+ errorFn(command getInfoMessage sampleCompiler, isFailure = false)
+ else
+ run()
}
}
object MainGenericRunner extends MainGenericRunner {
- def main(args: Array[String]) {
- if (!process(args))
- sys.exit(1)
- }
+ def main(args: Array[String]): Unit = if (!process(args)) sys.exit(1)
}
diff --git a/test/files/neg/double-def-top-level.check b/test/files/neg/double-def-top-level.check
new file mode 100644
index 0000000000..85b16e81e5
--- /dev/null
+++ b/test/files/neg/double-def-top-level.check
@@ -0,0 +1,7 @@
+D_3.scala:1: error: C is already defined as class C
+class C
+ ^
+D_3.scala:2: error: O is already defined as object O
+object O
+ ^
+two errors found
diff --git a/test/files/neg/double-def-top-level/A_1.scala b/test/files/neg/double-def-top-level/A_1.scala
new file mode 100644
index 0000000000..c3d68d9d05
--- /dev/null
+++ b/test/files/neg/double-def-top-level/A_1.scala
@@ -0,0 +1,4 @@
+package p
+
+class C
+object O
diff --git a/test/files/neg/double-def-top-level/B_2.scala b/test/files/neg/double-def-top-level/B_2.scala
new file mode 100644
index 0000000000..c328e8c964
--- /dev/null
+++ b/test/files/neg/double-def-top-level/B_2.scala
@@ -0,0 +1,2 @@
+class C /* noerror */
+object O /* noerror */ \ No newline at end of file
diff --git a/test/files/neg/double-def-top-level/C_3.scala b/test/files/neg/double-def-top-level/C_3.scala
new file mode 100644
index 0000000000..e1c327c15a
--- /dev/null
+++ b/test/files/neg/double-def-top-level/C_3.scala
@@ -0,0 +1,2 @@
+class C
+object O \ No newline at end of file
diff --git a/test/files/neg/double-def-top-level/D_3.scala b/test/files/neg/double-def-top-level/D_3.scala
new file mode 100644
index 0000000000..518e0d1c54
--- /dev/null
+++ b/test/files/neg/double-def-top-level/D_3.scala
@@ -0,0 +1,2 @@
+class C
+object O
diff --git a/test/files/neg/t6289.check b/test/files/neg/t6289.check
index f6f43cabd3..989932750f 100644
--- a/test/files/neg/t6289.check
+++ b/test/files/neg/t6289.check
@@ -3,7 +3,7 @@ t6289/J.java:2: method does not override or implement a method from a supertype
@Override public void foo() { }
^
1 error
-#partest java7
+#partest !java6
t6289/J.java:2: error: method does not override or implement a method from a supertype
@Override public void foo() { }
^
diff --git a/test/files/neg/t8630.check b/test/files/neg/t8630.check
new file mode 100644
index 0000000000..98b084b153
--- /dev/null
+++ b/test/files/neg/t8630.check
@@ -0,0 +1,7 @@
+t8630.scala:1: error: '{' expected but 'abstract' found.
+package bobsdelights abstract class Fruit( val name: String, val color: String ) object Fruits { object Apple extends Fruit("apple", "red") object Orange extends Fruit("orange", "orange") object Pear extends Fruit("pear", "yellowish") val menu = List(Apple, Orange, Pear) }
+ ^
+t8630.scala:1: error: '}' expected but eof found.
+package bobsdelights abstract class Fruit( val name: String, val color: String ) object Fruits { object Apple extends Fruit("apple", "red") object Orange extends Fruit("orange", "orange") object Pear extends Fruit("pear", "yellowish") val menu = List(Apple, Orange, Pear) }
+ ^
+two errors found
diff --git a/test/files/neg/t8630.scala b/test/files/neg/t8630.scala
new file mode 100644
index 0000000000..ea25227452
--- /dev/null
+++ b/test/files/neg/t8630.scala
@@ -0,0 +1 @@
+package bobsdelights abstract class Fruit( val name: String, val color: String ) object Fruits { object Apple extends Fruit("apple", "red") object Orange extends Fruit("orange", "orange") object Pear extends Fruit("pear", "yellowish") val menu = List(Apple, Orange, Pear) } \ No newline at end of file
diff --git a/test/files/pos/t8596.flags b/test/files/pos/t8596.flags
new file mode 100644
index 0000000000..281f0a10cd
--- /dev/null
+++ b/test/files/pos/t8596.flags
@@ -0,0 +1 @@
+-Yrangepos
diff --git a/test/files/pos/t8596.scala b/test/files/pos/t8596.scala
new file mode 100644
index 0000000000..bfed58eadf
--- /dev/null
+++ b/test/files/pos/t8596.scala
@@ -0,0 +1,7 @@
+class TypeTreeObjects {
+ class Container {
+ def typeParamAndDefaultArg[C](name: String = ""): String = ""
+ }
+ // crashed under -Yrangepos
+ new Container().typeParamAndDefaultArg[Any]()
+}
diff --git a/test/files/pos/t8617.flags b/test/files/pos/t8617.flags
new file mode 100644
index 0000000000..281f0a10cd
--- /dev/null
+++ b/test/files/pos/t8617.flags
@@ -0,0 +1 @@
+-Yrangepos
diff --git a/test/files/pos/t8617.scala b/test/files/pos/t8617.scala
new file mode 100644
index 0000000000..fc825bbcba
--- /dev/null
+++ b/test/files/pos/t8617.scala
@@ -0,0 +1,10 @@
+object Test {
+ def foo[A] = implicitly[OptManifest[A]] // was "unpositioned tree" under -Yrangepos
+
+ // These did not crash, but testing for good measure.
+ implicitly[OptManifest[String]]
+ implicitly[Manifest[String]]
+
+ implicitly[reflect.ClassTag[String]]
+ implicitly[reflect.runtime.universe.TypeTag[String]]
+}
diff --git a/test/files/pos/t8625.scala b/test/files/pos/t8625.scala
new file mode 100644
index 0000000000..95c4b0dbcd
--- /dev/null
+++ b/test/files/pos/t8625.scala
@@ -0,0 +1,5 @@
+object Test {
+ def f1(a: Boolean, b: Boolean) = (a || ???) && (b || ???)
+ def f2(a: Boolean, b: Boolean) = (a || ???) && b
+ def f3(a: Boolean, b: Boolean) = (a && ???) || b
+}
diff --git a/test/files/presentation/ide-bug-1000531.check b/test/files/presentation/ide-bug-1000531.check
index d8c7a369f7..12eafcd6de 100644
--- a/test/files/presentation/ide-bug-1000531.check
+++ b/test/files/presentation/ide-bug-1000531.check
@@ -1,111 +1,24 @@
-reload: CrashOnLoad.scala
+reload: CrashOnLoad.scala, TestIterable.java
-askTypeCompletion at CrashOnLoad.scala(6,12)
+askTypeCompletion at CrashOnLoad.scala(6,11)
================================================================================
-[response] askTypeCompletion at (6,12)
-retrieved 117 members
+[response] askTypeCompletion at (6,11)
+retrieved 30 members
[inaccessible] protected[package lang] def clone(): Object
[inaccessible] protected[package lang] def finalize(): Unit
-[inaccessible] protected[this] def reversed: List[B]
-class GroupedIterator[B >: A] extends AbstractIterator[Seq[B]] with Iterator[Seq[B]]
def +(other: String): String
-def ++[B >: B](that: => scala.collection.GenTraversableOnce[B]): Iterator[B]
-def ->[B](y: B): (java.util.Iterator[B], B)
-def /:[B](z: B)(op: (B, B) => B): B
-def :\[B](z: B)(op: (B, B) => B): B
-def addString(b: StringBuilder): StringBuilder
-def addString(b: StringBuilder,sep: String): StringBuilder
-def addString(b: StringBuilder,start: String,sep: String,end: String): StringBuilder
-def aggregate[B](z: => B)(seqop: (B, B) => B,combop: (B, B) => B): B
-def buffered: scala.collection.BufferedIterator[B]
-def collectFirst[B](pf: PartialFunction[B,B]): Option[B]
-def collect[B](pf: PartialFunction[B,B]): Iterator[B]
-def contains(elem: Any): Boolean
-def copyToArray[B >: B](xs: Array[B]): Unit
-def copyToArray[B >: B](xs: Array[B],start: Int): Unit
-def copyToArray[B >: B](xs: Array[B],start: Int,len: Int): Unit
-def copyToBuffer[B >: B](dest: scala.collection.mutable.Buffer[B]): Unit
-def corresponds[B](that: scala.collection.GenTraversableOnce[B])(p: (B, B) => Boolean): Boolean
-def count(p: B => Boolean): Int
-def drop(n: Int): Iterator[B]
-def dropWhile(p: B => Boolean): Iterator[B]
-def duplicate: (Iterator[B], Iterator[B])
-def ensuring(cond: Boolean): java.util.Iterator[B]
-def ensuring(cond: Boolean,msg: => Any): java.util.Iterator[B]
-def ensuring(cond: java.util.Iterator[B] => Boolean): java.util.Iterator[B]
-def ensuring(cond: java.util.Iterator[B] => Boolean,msg: => Any): java.util.Iterator[B]
+def ->[B](y: B): (other.TestIterator[Nothing], B)
+def ensuring(cond: Boolean): other.TestIterator[Nothing]
+def ensuring(cond: Boolean,msg: => Any): other.TestIterator[Nothing]
+def ensuring(cond: other.TestIterator[Nothing] => Boolean): other.TestIterator[Nothing]
+def ensuring(cond: other.TestIterator[Nothing] => Boolean,msg: => Any): other.TestIterator[Nothing]
def equals(x$1: Any): Boolean
-def exists(p: B => Boolean): Boolean
-def filter(p: B => Boolean): Iterator[B]
-def filterNot(p: B => Boolean): Iterator[B]
-def find(p: B => Boolean): Option[B]
-def flatMap[B](f: B => scala.collection.GenTraversableOnce[B]): Iterator[B]
-def foldLeft[B](z: B)(op: (B, B) => B): B
-def foldRight[B](z: B)(op: (B, B) => B): B
-def fold[A1 >: B](z: A1)(op: (A1, A1) => A1): A1
-def forall(p: B => Boolean): Boolean
-def foreach[U](f: B => U): Unit
def formatted(fmtstr: String): String
-def grouped[B >: B](size: Int): Iterator[B]#GroupedIterator[B]
-def hasDefiniteSize: Boolean
-def hasNext(): Boolean
+def hasNext: Boolean
def hashCode(): Int
-def indexOf[B >: B](elem: B): Int
-def indexWhere(p: B => Boolean): Int
-def isEmpty: Boolean
-def isTraversableAgain: Boolean
-def length: Int
-def map[B](f: B => B): Iterator[B]
-def maxBy[B](f: B => B)(implicit cmp: Ordering[B]): B
-def max[B >: B](implicit cmp: Ordering[B]): B
-def minBy[B](f: B => B)(implicit cmp: Ordering[B]): B
-def min[B >: B](implicit cmp: Ordering[B]): B
-def mkString(sep: String): String
-def mkString(start: String,sep: String,end: String): String
-def mkString: String
-def next(): B
-def nonEmpty: Boolean
-def padTo[A1 >: B](len: Int,elem: A1): Iterator[A1]
-def partition(p: B => Boolean): (Iterator[B], Iterator[B])
-def patch[B >: B](from: Int,patchElems: Iterator[B],replaced: Int): Iterator[B]
-def product[B >: B](implicit num: Numeric[B]): B
-def reduceLeftOption[B >: B](op: (B, B) => B): Option[B]
-def reduceLeft[B >: B](op: (B, B) => B): B
-def reduceOption[A1 >: B](op: (A1, A1) => A1): Option[A1]
-def reduceRightOption[B >: B](op: (B, B) => B): Option[B]
-def reduceRight[B >: B](op: (B, B) => B): B
-def reduce[A1 >: B](op: (A1, A1) => A1): A1
-def remove(): Unit
-def sameElements(that: Iterator[_]): Boolean
-def scanLeft[B](z: B)(op: (B, B) => B): Iterator[B]
-def scanRight[B](z: B)(op: (B, B) => B): Iterator[B]
-def seq: Iterator[B]
-def size: Int
-def slice(from: Int,until: Int): Iterator[B]
-def sliding[B >: B](size: Int,step: Int): Iterator[B]#GroupedIterator[B]
-def span(p: B => Boolean): (Iterator[B], Iterator[B])
-def sum[B >: B](implicit num: Numeric[B]): B
-def take(n: Int): Iterator[B]
-def takeWhile(p: B => Boolean): Iterator[B]
-def toArray[B >: B](implicit evidence$1: scala.reflect.ClassTag[B]): Array[B]
-def toBuffer[B >: B]: scala.collection.mutable.Buffer[B]
-def toIndexedSeq: scala.collection.immutable.IndexedSeq[B]
-def toIterable: Iterable[B]
-def toIterator: Iterator[B]
-def toList: List[B]
-def toMap[T, U](implicit ev: <:<[B,(T, U)]): scala.collection.immutable.Map[T,U]
-def toSeq: Seq[B]
-def toSet[B >: B]: scala.collection.immutable.Set[B]
-def toStream: scala.collection.immutable.Stream[B]
+def next: T
def toString(): String
-def toTraversable: Traversable[B]
-def toVector: Vector[B]
-def to[Col[_]](implicit cbf: scala.collection.generic.CanBuildFrom[Nothing,B,Col[B]]): Col[B]
-def withFilter(p: B => Boolean): Iterator[B]
-def zipAll[B, A1 >: B, B1 >: B](that: Iterator[B],thisElem: A1,thatElem: B1): Iterator[(A1, B1)]
-def zipWithIndex: Iterator[(B, Int)]
-def zip[B](that: Iterator[B]): Iterator[(B, B)]
-def →[B](y: B): (java.util.Iterator[B], B)
+def →[B](y: B): (other.TestIterator[Nothing], B)
final def !=(x$1: Any): Boolean
final def ##(): Int
final def ==(x$1: Any): Boolean
diff --git a/test/files/presentation/ide-bug-1000531/src/CrashOnLoad.scala b/test/files/presentation/ide-bug-1000531/src/CrashOnLoad.scala
index 878bbfa19e..3f59282083 100644
--- a/test/files/presentation/ide-bug-1000531/src/CrashOnLoad.scala
+++ b/test/files/presentation/ide-bug-1000531/src/CrashOnLoad.scala
@@ -1,7 +1,14 @@
/** When this files is opened within the IDE, a typing error is reported. */
-class A[B] extends java.lang.Iterable[B] {
+class A[B] extends TestIterable[B] {
import scala.collection.JavaConversions._
- def iterator = Iterator.empty
+ def iterator: other.TestIterator[Nothing] = ???
- iterator. /*!*/
-} \ No newline at end of file
+ iterator./*!*/
+}
+
+object other {
+ trait TestIterator[T] {
+ def hasNext: Boolean
+ def next: T
+ }
+}
diff --git a/test/files/presentation/ide-bug-1000531/src/TestIterable.java b/test/files/presentation/ide-bug-1000531/src/TestIterable.java
new file mode 100644
index 0000000000..84a6fe77f1
--- /dev/null
+++ b/test/files/presentation/ide-bug-1000531/src/TestIterable.java
@@ -0,0 +1,7 @@
+public abstract class TestIterable<T> {
+ public abstract TestIterator<T> iterator();
+ public static abstract class TestIterator<T> {
+ public abstract T next();
+ public abstract boolean hasNext();
+ }
+}
diff --git a/test/files/presentation/t7915.check b/test/files/presentation/t7915.check
index b18b4ddb55..0849aaa82b 100644
--- a/test/files/presentation/t7915.check
+++ b/test/files/presentation/t7915.check
@@ -9,3 +9,23 @@ askHyperlinkPos for `bar` at (7,22) Foo.scala
================================================================================
[response] found askHyperlinkPos for `bar` at (2,7) Foo.scala
================================================================================
+
+askHyperlinkPos for `Bar` at (8,11) Foo.scala
+================================================================================
+[response] found askHyperlinkPos for `Bar` at (1,7) Foo.scala
+================================================================================
+
+askHyperlinkPos for `baz` at (8,22) Foo.scala
+================================================================================
+[response] found askHyperlinkPos for `baz` at (2,31) Foo.scala
+================================================================================
+
+askHyperlinkPos for `Bar` at (9,11) Foo.scala
+================================================================================
+[response] found askHyperlinkPos for `Bar` at (1,7) Foo.scala
+================================================================================
+
+askHyperlinkPos for `baz` at (9,22) Foo.scala
+================================================================================
+[response] found askHyperlinkPos for `baz` at (2,31) Foo.scala
+================================================================================
diff --git a/test/files/presentation/t7915/src/Foo.scala b/test/files/presentation/t7915/src/Foo.scala
index a4166ae5b4..5c9ca36a6e 100644
--- a/test/files/presentation/t7915/src/Foo.scala
+++ b/test/files/presentation/t7915/src/Foo.scala
@@ -1,9 +1,11 @@
class Bar {
- def bar(b: Int = 2) {}
+ def bar(b: Int = 2) {}; def baz[X](b: Int = 2) {}
}
class Foo {
def foo() {
new Bar/*#*/().bar/*#*/()
+ new Bar/*#*/().baz/*#*/[Any]()
+ new Bar/*#*/().baz/*#*/()
}
}
diff --git a/test/files/run/analyzerPlugins.check b/test/files/run/analyzerPlugins.check
index e3ab554d4c..9803465ddc 100644
--- a/test/files/run/analyzerPlugins.check
+++ b/test/files/run/analyzerPlugins.check
@@ -19,7 +19,7 @@ canAdaptAnnotations(Trees$Typed, Any) [1]
canAdaptAnnotations(Trees$Typed, Int) [1]
lub(List(Int @testAnn, Int)) [1]
pluginsPt(?, Trees$Annotated) [7]
-pluginsPt(?, Trees$Apply) [9]
+pluginsPt(?, Trees$Apply) [8]
pluginsPt(?, Trees$ApplyImplicitView) [2]
pluginsPt(?, Trees$Assign) [7]
pluginsPt(?, Trees$Block) [4]
@@ -31,13 +31,13 @@ pluginsPt(?, Trees$Literal) [16]
pluginsPt(?, Trees$New) [5]
pluginsPt(?, Trees$PackageDef) [1]
pluginsPt(?, Trees$Return) [1]
-pluginsPt(?, Trees$Select) [48]
+pluginsPt(?, Trees$Select) [47]
pluginsPt(?, Trees$Super) [2]
pluginsPt(?, Trees$This) [20]
-pluginsPt(?, Trees$TypeApply) [4]
+pluginsPt(?, Trees$TypeApply) [3]
pluginsPt(?, Trees$TypeBoundsTree) [2]
pluginsPt(?, Trees$TypeDef) [1]
-pluginsPt(?, Trees$TypeTree) [39]
+pluginsPt(?, Trees$TypeTree) [38]
pluginsPt(?, Trees$Typed) [1]
pluginsPt(?, Trees$ValDef) [21]
pluginsPt(Any, Trees$Literal) [2]
@@ -98,7 +98,6 @@ pluginsTyped(()String, Trees$Ident) [1]
pluginsTyped(()String, Trees$TypeApply) [1]
pluginsTyped(()scala.annotation.Annotation, Trees$Select) [1]
pluginsTyped(()testAnn, Trees$Select) [10]
-pluginsTyped(()type, Trees$TypeApply) [1]
pluginsTyped((str: String)A <and> (param: Double)A, Trees$Select) [1]
pluginsTyped((x$1: Any)Boolean <and> (x: Double)Boolean <and> (x: Float)Boolean <and> (x: Long)Boolean <and> (x: Int)Boolean <and> (x: Char)Boolean <and> (x: Short)Boolean <and> (x: Byte)Boolean, Trees$Select) [1]
pluginsTyped((x$1: Int)Unit, Trees$Select) [1]
@@ -173,7 +172,7 @@ pluginsTyped(Unit, Trees$Literal) [5]
pluginsTyped(Unit, Trees$TypeTree) [1]
pluginsTyped([A](xs: A*)List[A], Trees$Select) [1]
pluginsTyped([T <: Int]=> Int, Trees$Select) [1]
-pluginsTyped([T0]()T0, Trees$Select) [2]
+pluginsTyped([T0]()T0, Trees$Select) [1]
pluginsTyped([T](xs: Array[T])scala.collection.mutable.WrappedArray[T], Trees$Select) [1]
pluginsTyped(annotation.type, Trees$Select) [4]
pluginsTyped(math.type, Trees$Select) [9]
@@ -190,7 +189,5 @@ pluginsTyped(testAnn, Trees$New) [5]
pluginsTyped(testAnn, Trees$This) [1]
pluginsTyped(testAnn, Trees$TypeTree) [2]
pluginsTyped(testAnn.super.type, Trees$Super) [1]
-pluginsTyped(type, Trees$Apply) [1]
pluginsTyped(type, Trees$Select) [1]
-pluginsTyped(type, Trees$TypeTree) [1]
pluginsTypedReturn(return f, String) [1]
diff --git a/test/files/run/icode-reader-dead-code.check b/test/files/run/icode-reader-dead-code.check
new file mode 100644
index 0000000000..d1739fed3b
--- /dev/null
+++ b/test/files/run/icode-reader-dead-code.check
@@ -0,0 +1,19 @@
+Bytecode for method f
+ L0
+ LINENUMBER 4 L0
+ ICONST_1
+ IRETURN
+ L1
+ LOCALVARIABLE this Lp/A; L0 L1 0
+ MAXSTACK = 1
+ MAXLOCALS = 1
+Bytecode for method f
+ L0
+ LINENUMBER 4 L0
+ ICONST_1
+ ATHROW
+ IRETURN
+ L1
+ LOCALVARIABLE this Lp/A; L0 L1 0
+ MAXSTACK = 1
+ MAXLOCALS = 1
diff --git a/test/files/run/icode-reader-dead-code.scala b/test/files/run/icode-reader-dead-code.scala
new file mode 100644
index 0000000000..00ba58829f
--- /dev/null
+++ b/test/files/run/icode-reader-dead-code.scala
@@ -0,0 +1,82 @@
+import java.io.{FileOutputStream, FileInputStream}
+
+import scala.tools.asm.{ClassWriter, Opcodes, ClassReader}
+import scala.tools.asm.tree.{InsnNode, ClassNode}
+import scala.tools.nsc.backend.jvm.AsmUtils
+import scala.tools.partest.DirectTest
+import scala.collection.JavaConverters._
+
+/**
+ * Test that the ICodeReader does not crash if the bytecode of a method has unreachable code.
+ */
+object Test extends DirectTest {
+ def code: String = ???
+
+ def show(): Unit = {
+ // The bytecode of f will be modified using ASM by `addDeadCode`
+ val aCode =
+ """
+ |package p
+ |class A {
+ | @inline final def f = 1
+ |}
+ """.stripMargin
+
+ val bCode =
+ """
+ |package p
+ |class B {
+ | def g = (new A()).f
+ |}
+ """.stripMargin
+
+ compileString(newCompiler("-usejavacp"))(aCode)
+
+ addDeadCode()
+
+ // If inlining fails, the compiler will issue an inliner warning that is not present in the
+ // check file
+ compileString(newCompiler("-usejavacp", "-optimise"))(bCode)
+ }
+
+ def readClass(file: String) = {
+ val cnode = new ClassNode()
+ val is = new FileInputStream(file)
+ val reader = new ClassReader(is)
+ reader.accept(cnode, 0)
+ is.close()
+ cnode
+ }
+
+ def writeClass(file: String, cnode: ClassNode): Unit = {
+ val writer = new ClassWriter(0)
+ cnode.accept(writer)
+
+ val os = new FileOutputStream(file)
+ os.write(writer.toByteArray)
+ os.close()
+ }
+
+ def addDeadCode() {
+ val file = (testOutput / "p" / "A.class").path
+ val cnode = readClass(file)
+ val method = cnode.methods.asScala.find(_.name == "f").head
+
+ AsmUtils.traceMethod(method)
+
+ val insns = method.instructions
+ val it = insns.iterator()
+ while (it.hasNext) {
+ val in = it.next()
+ if (in.getOpcode == Opcodes.IRETURN) {
+ // Insert an ATHROW before the IRETURN. The IRETURN will then be dead code.
+ // The ICodeReader should not crash if there's dead code.
+ insns.insert(in.getPrevious, new InsnNode(Opcodes.ATHROW))
+ }
+ }
+
+ AsmUtils.traceMethod(method)
+
+ writeClass(file, cnode)
+ }
+}
diff --git a/test/files/run/repl-javap-app.check b/test/files/run/repl-javap-app.check
index 490860585c..1136b415d7 100644
--- a/test/files/run/repl-javap-app.check
+++ b/test/files/run/repl-javap-app.check
@@ -1,4 +1,5 @@
#partest java6
+Welcome to Scala
Type in expressions to have them evaluated.
Type :help for more information.
@@ -6,16 +7,17 @@ scala> :javap -app MyApp$
public final void delayedEndpoint$MyApp$1();
Code:
Stack=2, Locals=1, Args_size=1
- 0: getstatic #61; //Field scala/Console$.MODULE$:Lscala/Console$;
- 3: ldc #63; //String Hello, delayed world.
- 5: invokevirtual #67; //Method scala/Console$.println:(Ljava/lang/Object;)V
+ 0: getstatic #XX; //Field scala/Console$.MODULE$:Lscala/Console$;
+ 3: ldc #XX; //String Hello, delayed world.
+ 5: invokevirtual #XX; //Method scala/Console$.println:(Ljava/lang/Object;)V
8: return
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this LMyApp$;
scala>
-#partest !java6
+#partest java7
+Welcome to Scala
Type in expressions to have them evaluated.
Type :help for more information.
@@ -24,9 +26,9 @@ scala> :javap -app MyApp$
flags: ACC_PUBLIC, ACC_FINAL
Code:
stack=2, locals=1, args_size=1
- 0: getstatic #61 // Field scala/Console$.MODULE$:Lscala/Console$;
- 3: ldc #63 // String Hello, delayed world.
- 5: invokevirtual #67 // Method scala/Console$.println:(Ljava/lang/Object;)V
+ 0: getstatic #XX // Field scala/Console$.MODULE$:Lscala/Console$;
+ 3: ldc #XX // String Hello, delayed world.
+ 5: invokevirtual #XX // Method scala/Console$.println:(Ljava/lang/Object;)V
8: return
LocalVariableTable:
Start Length Slot Name Signature
@@ -36,3 +38,26 @@ scala> :javap -app MyApp$
}
scala>
+#partest java8
+Welcome to Scala
+Type in expressions to have them evaluated.
+Type :help for more information.
+
+scala> :javap -app MyApp$
+ public final void delayedEndpoint$MyApp$1();
+ descriptor: ()V
+ flags: ACC_PUBLIC, ACC_FINAL
+ Code:
+ stack=2, locals=1, args_size=1
+ 0: getstatic #XX // Field scala/Console$.MODULE$:Lscala/Console$;
+ 3: ldc #XX // String Hello, delayed world.
+ 5: invokevirtual #XX // Method scala/Console$.println:(Ljava/lang/Object;)V
+ 8: return
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 9 0 this LMyApp$;
+ LineNumberTable:
+ line 5: 0
+}
+
+scala>
diff --git a/test/files/run/repl-javap-app.scala b/test/files/run/repl-javap-app.scala
index be04920be1..ad6076c2d5 100644
--- a/test/files/run/repl-javap-app.scala
+++ b/test/files/run/repl-javap-app.scala
@@ -7,4 +7,15 @@ object MyApp extends App {
object Test extends ReplTest {
def code = ":javap -app MyApp$"
+
+ override def welcoming = true
+
+ // The constant pool indices are not the same for GenASM / GenBCode, so
+ // replacing the exact numbers by XX.
+ lazy val hasConstantPoolRef = """(.*)(#\d\d)(.*)""".r
+
+ override def normalize(s: String) = s match {
+ case hasConstantPoolRef(start, ref, end) => start + "#XX" + end
+ case _ => super.normalize(s)
+ }
}
diff --git a/test/files/run/t7974.check b/test/files/run/t7974.check
index 0be496d8d0..d8152d3286 100644
--- a/test/files/run/t7974.check
+++ b/test/files/run/t7974.check
@@ -1,6 +1,5 @@
public class Symbols {
- // compiled from: Symbols.scala
@@ -18,20 +17,14 @@ public class Symbols {
// access flags 0x9
public static <clinit>()V
- L0
- LINENUMBER 2 L0
GETSTATIC scala/Symbol$.MODULE$ : Lscala/Symbol$;
LDC "Symbolic1"
INVOKEVIRTUAL scala/Symbol$.apply (Ljava/lang/String;)Lscala/Symbol;
PUTSTATIC Symbols.symbol$1 : Lscala/Symbol;
- L1
- LINENUMBER 3 L1
GETSTATIC scala/Symbol$.MODULE$ : Lscala/Symbol$;
LDC "Symbolic2"
INVOKEVIRTUAL scala/Symbol$.apply (Ljava/lang/String;)Lscala/Symbol;
PUTSTATIC Symbols.symbol$2 : Lscala/Symbol;
- L2
- LINENUMBER 5 L2
GETSTATIC scala/Symbol$.MODULE$ : Lscala/Symbol$;
LDC "Symbolic3"
INVOKEVIRTUAL scala/Symbol$.apply (Ljava/lang/String;)Lscala/Symbol;
@@ -42,63 +35,41 @@ public class Symbols {
// access flags 0x1
public someSymbol1()Lscala/Symbol;
- L0
- LINENUMBER 2 L0
GETSTATIC Symbols.symbol$1 : Lscala/Symbol;
ARETURN
- L1
- LOCALVARIABLE this LSymbols; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1
public someSymbol2()Lscala/Symbol;
- L0
- LINENUMBER 3 L0
GETSTATIC Symbols.symbol$2 : Lscala/Symbol;
ARETURN
- L1
- LOCALVARIABLE this LSymbols; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1
public sameSymbol1()Lscala/Symbol;
- L0
- LINENUMBER 4 L0
GETSTATIC Symbols.symbol$1 : Lscala/Symbol;
ARETURN
- L1
- LOCALVARIABLE this LSymbols; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1
public someSymbol3()Lscala/Symbol;
- L0
- LINENUMBER 5 L0
ALOAD 0
GETFIELD Symbols.someSymbol3 : Lscala/Symbol;
ARETURN
- L1
- LOCALVARIABLE this LSymbols; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1
public <init>()V
- L0
- LINENUMBER 6 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
- L1
- LINENUMBER 5 L1
ALOAD 0
GETSTATIC Symbols.symbol$3 : Lscala/Symbol;
PUTFIELD Symbols.someSymbol3 : Lscala/Symbol;
RETURN
- L2
- LOCALVARIABLE this LSymbols; L0 L2 0
MAXSTACK = 2
MAXLOCALS = 1
}
diff --git a/test/files/run/t7974/Test.scala b/test/files/run/t7974/Test.scala
index 433d9061a7..29d2b9cb64 100644
--- a/test/files/run/t7974/Test.scala
+++ b/test/files/run/t7974/Test.scala
@@ -6,7 +6,7 @@ import scala.tools.nsc.util.stringFromWriter
object Test extends BytecodeTest {
def show {
- val classNode = loadClassNode("Symbols", skipDebugInfo = false)
+ val classNode = loadClassNode("Symbols", skipDebugInfo = true)
val textifier = new Textifier
classNode.accept(new TraceClassVisitor(null, textifier, null))
diff --git a/test/files/run/t8346.check b/test/files/run/t8346.check
new file mode 100644
index 0000000000..1ba5c31abe
--- /dev/null
+++ b/test/files/run/t8346.check
@@ -0,0 +1,6 @@
+BitSet: List(invariant, invariant, invariant, invariant)
+HashSet: List(covariant (true), covariant (true), covariant (true), covariant (true))
+ListSet: List(covariant (true), covariant (true), covariant (true), covariant (true))
+SortedSet: List(invariant, invariant, invariant, invariant)
+TreeSet: List(invariant, invariant, invariant, invariant)
+ValueSet: invariant
diff --git a/test/files/run/t8346.scala b/test/files/run/t8346.scala
new file mode 100644
index 0000000000..5f3df84174
--- /dev/null
+++ b/test/files/run/t8346.scala
@@ -0,0 +1,34 @@
+object Test extends App {
+ import reflect.ClassTag
+
+ object SomeEnum extends Enumeration {
+ val one, two, three, four = Value
+ }
+
+ def sctor[A <: Set[Int]](f: Int => A)(implicit A: ClassTag[A])
+ : (String, Int => Set[Int]) =
+ (A.runtimeClass.getSimpleName, f)
+
+ val inits: Seq[(String, Int => Set[Int])] = {
+ import collection.immutable.{Seq => _, _}
+ Seq(sctor(BitSet(_)),
+ sctor(HashSet(_)),
+ sctor(ListSet(_)),
+ sctor(SortedSet(_)),
+ sctor(TreeSet(_)))
+ }
+
+ def sVarInfo[A](sa: Set[A]): String = {
+ val saa = sa.toSet[Any]
+ if (sa eq saa) s"""covariant (${(saa + "hi") contains "hi"})"""
+ else "invariant"
+ }
+
+ inits foreach {case (name, singleton) =>
+ print(s"${name}: ")
+ val one = singleton(1)
+ println(Seq(2,3,4).scanLeft(one)(_ + _) map sVarInfo toList)
+ }
+
+ println(s"ValueSet: ${sVarInfo(SomeEnum.values)}")
+}
diff --git a/test/files/run/t8607.scala b/test/files/run/t8607.scala
new file mode 100644
index 0000000000..1b8ef9bbd0
--- /dev/null
+++ b/test/files/run/t8607.scala
@@ -0,0 +1,36 @@
+package p1 {
+ private[p1] trait B extends Any {
+ def a: Any = ""
+ }
+
+ class C(val value: Int) extends AnyVal with B {
+ // def b = ""
+ }
+}
+
+object Test {
+ def main(args: Array[String]) {
+ val c = new p1.C(42)
+ c.a
+ /*
+ new p1.C.<init>(
+ c.$asInstanceOf[scala.this.Int]()
+ ).a();
+
+
+ new p1.C.<init>(
+ new p1.C.<init>(
+ c.$asInstanceOf[scala.this.Int]()
+ ).$asInstanceOf[ErasedValueType(class C, scala.this.Int)]()
+ .$asInstanceOf[scala.this.Int]()
+ ).a();
+
+ new p1.C.<init>(
+ new p1.C.<init>(c)
+ .$asInstanceOf[scala.this.Int]()
+ .$asInstanceOf[scala.this.Int]()
+ ).a();
+
+ */
+ }
+}
diff --git a/test/files/run/t8637.check b/test/files/run/t8637.check
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/files/run/t8637.check
diff --git a/test/files/run/t8637.scala b/test/files/run/t8637.scala
new file mode 100644
index 0000000000..99c8d4c413
--- /dev/null
+++ b/test/files/run/t8637.scala
@@ -0,0 +1,9 @@
+import scala.reflect.runtime.universe._
+import scala.reflect.runtime.currentMirror
+import scala.tools.reflect.ToolBox
+
+object Test extends App {
+ val tb = currentMirror.mkToolBox()
+ tb.compile(q"true > true")
+ tb.typecheck(q"true > true")
+} \ No newline at end of file
diff --git a/test/junit/scala/collection/IndexedSeqOptimizedTest.scala b/test/junit/scala/collection/IndexedSeqOptimizedTest.scala
new file mode 100644
index 0000000000..e5382907af
--- /dev/null
+++ b/test/junit/scala/collection/IndexedSeqOptimizedTest.scala
@@ -0,0 +1,16 @@
+package scala.collection
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Assert._
+import org.junit.Test
+
+@RunWith(classOf[JUnit4])
+class IndexedSeqOptimizedTest {
+
+ @Test
+ def notThrowsAnExceptionInLastIndexOf() {
+ assertEquals(0, (Array(2): collection.mutable.WrappedArray[Int]).lastIndexWhere(_ => true, 1))
+ assertEquals(2, "abc123".lastIndexWhere(_.isLetter, 6))
+ }
+}
diff --git a/test/junit/scala/collection/IteratorTest.scala b/test/junit/scala/collection/IteratorTest.scala
new file mode 100644
index 0000000000..b7a9805c9f
--- /dev/null
+++ b/test/junit/scala/collection/IteratorTest.scala
@@ -0,0 +1,28 @@
+
+package scala.collection
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(classOf[JUnit4])
+class IteratorTest {
+
+ @Test
+ def groupedIteratorShouldNotAskForUnneededElement(): Unit = {
+ var counter = 0
+ val it = new Iterator[Int] { var i = 0 ; def hasNext = { counter = i; true } ; def next = { i += 1; i } }
+ val slidingIt = it sliding 2
+ slidingIt.next
+ assertEquals("Counter should be one, that means we didn't look further than needed", 1, counter)
+ }
+
+ @Test def groupedIteratorIsLazyWhenPadded(): Unit = {
+ var counter = 0
+ def it = new Iterator[Int] { var i = 0 ; def hasNext = { counter = i; true } ; def next = { i += 1; i } }
+ val slidingIt = it sliding 2 withPadding -1
+ slidingIt.next
+ assertEquals("Counter should be one, that means we didn't look further than needed", 1, counter)
+ }
+}
diff --git a/test/junit/scala/reflect/internal/NamesTest.scala b/test/junit/scala/reflect/internal/NamesTest.scala
new file mode 100644
index 0000000000..549c10abed
--- /dev/null
+++ b/test/junit/scala/reflect/internal/NamesTest.scala
@@ -0,0 +1,95 @@
+package scala.reflect.internal
+
+import scala.tools.testing.AssertUtil._
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Test
+import org.junit.Assert._
+import scala.tools.nsc.symtab.SymbolTableForUnitTesting
+
+@RunWith(classOf[JUnit4])
+class NamesTest {
+ object symbolTable extends SymbolTableForUnitTesting
+ import symbolTable._
+
+ val h1 = newTermName("hai")
+ val h2 = newTermName("hai")
+ val f = newTermName("fisch")
+
+ val h1y = h1.toTypeName
+ val h2y = newTypeName("hai")
+ val fy = newTypeName("fisch")
+
+ val uy = newTypeName("uhu")
+ val u = uy.toTermName // calling toTermName after constructing a typeName. This tests the fact
+ // that creating a typeName always also first creates a termName. There is
+ // an assertion for that in toTermName.
+
+ @Test
+ def termNamesAreHashConsed() {
+ assertTrue(h1 eq h2)
+ assertEquals(h1, h2)
+ assertTrue(h1 ne f)
+ assertTrue(h1 != f)
+ }
+
+ @Test
+ def termNamesNotEqualsTypeNames() {
+ assert(h1 ne h1y)
+ assert(h1 != h1y)
+ assert(h2 ne h2y)
+ assert(h2 != h2y)
+ }
+
+ @Test
+ def termNamesTypeNamesSameRange() {
+ assert(h1.start == h1y.start && h1.length == h1y.length)
+ assert(h2.start == h2y.start && h2.length == h2y.length)
+ assert(u.start == uy.start && u.length == uy.length)
+ }
+
+ @Test
+ def testLookupTypeName() {
+ assert(lookupTypeName("hai".toCharArray) eq h1y)
+ assert(lookupTypeName("fisch".toCharArray) eq fy)
+ assert(lookupTypeName("uhu".toCharArray) eq uy)
+
+ assertThrows[AssertionError](lookupTypeName("dog".toCharArray), _ contains "not yet created")
+ val d = newTermName("dog")
+ assertThrows[AssertionError](lookupTypeName("dog".toCharArray), _ contains "not yet created")
+ val dy = d.toTypeName
+ assert(lookupTypeName("dog".toCharArray) eq dy)
+ }
+
+ @Test
+ def emptyName() {
+ val z = newTermName("")
+ val zy = z.toTypeName
+ assertEquals(z.toString, "")
+ assertEquals(zy.toString, "")
+ assert(z eq newTermName(""))
+ assert(zy eq newTypeName(""))
+ }
+
+ @Test
+ def subNameTest() {
+ val i = f.subName(1, f.length)
+ assert(i.start == (f.start + 1) && i.length == (f.length - 1))
+ assert(f.subName(0, f.length) eq f)
+
+ val iy = fy.subName(1, fy.length)
+ assert(iy.start == (fy.start + 1) && iy.length == (fy.length - 1))
+ assert(fy.subName(0, fy.length) eq fy)
+
+ assert(f.subName(1,1) eq newTermName(""))
+ assert(f.subName(1, 0) eq newTermName(""))
+
+ assertThrows[IllegalArgumentException](f.subName(0 - f.start - 1, 1))
+ }
+
+ @Test
+ def stringEqualsTest() {
+ assert(h1 string_== h2)
+ assert(h1 string_== h1y)
+ }
+}
diff --git a/test/junit/scala/reflect/internal/ScopeTest.scala b/test/junit/scala/reflect/internal/ScopeTest.scala
new file mode 100644
index 0000000000..5166620189
--- /dev/null
+++ b/test/junit/scala/reflect/internal/ScopeTest.scala
@@ -0,0 +1,54 @@
+package symtab
+
+import scala.tools.nsc.symtab
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.tools.testing.AssertUtil.assertThrows
+import scala.tools.nsc.symtab.SymbolTableForUnitTesting
+
+@RunWith(classOf[JUnit4])
+class ScopeTest {
+ object symbolTable extends SymbolTableForUnitTesting
+
+ import symbolTable._
+
+ @Test
+ def testNestedScopeSmall(): Unit = testNestedScope(0)
+ @Test
+ def testNestedScopeLarge(): Unit = testNestedScope(64) // exceeding MIN_HASH
+
+ private def testNestedScope(initSize: Int) {
+ def sym(termName: String): Symbol = NoSymbol.newValue(TermName(termName))
+ val foo = sym("foo")
+ val bar = sym("bar")
+
+ val outerElems = List.tabulate(initSize)(i => sym(i.toString))
+ val outer = newScopeWith(outerElems ++ List(foo, bar) : _*)
+ assertTrue(outer.containsName(foo.name))
+ assertTrue(outer.containsName(bar.name))
+
+ val baz = sym("baz")
+ val nested = newNestedScope(outer)
+
+ // Entries from the outer scope are entered in the nested.
+ assertTrue(outer.containsName(foo.name))
+ assertTrue(outer.containsName(bar.name))
+
+ // Nested scopes structurally share ScopeEntry-s with the outer.
+ assertSame(outer.lookupEntry(foo.name), nested.lookupEntry(foo.name))
+ nested.enter(baz)
+
+ // Symbols entered in the nested scope aren't visible in the outer.
+ assertTrue(nested.containsName(baz.name))
+ assertTrue(!outer.containsName(baz.name))
+
+ // Unlinking a symbol in the inner scope doesn't modify the outer
+ nested.unlink(bar)
+ assert(!nested.containsName(bar.name))
+ assert(outer.containsName(bar.name))
+ }
+}
diff --git a/test/junit/scala/reflect/internal/util/SourceFileTest.scala b/test/junit/scala/reflect/internal/util/SourceFileTest.scala
index 903e705ba2..cad23eba14 100644
--- a/test/junit/scala/reflect/internal/util/SourceFileTest.scala
+++ b/test/junit/scala/reflect/internal/util/SourceFileTest.scala
@@ -17,6 +17,11 @@ class SourceFileTest {
assertFalse(file.isEndOfLine(Int.MaxValue))
}
+ @Test def si8630_lineToString(): Unit = {
+ val code = "abc "
+ assertEquals(code, new BatchSourceFile("", code).lineToString(0))
+ }
+
@Test
def si8205_lineToString(): Unit = {
assertEquals("", lineContentOf("", 0))
diff --git a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
new file mode 100644
index 0000000000..b592d06501
--- /dev/null
+++ b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
@@ -0,0 +1,104 @@
+package scala.tools.nsc
+package backend.jvm
+
+import scala.tools.testing.AssertUtil._
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Test
+import scala.tools.asm.Opcodes
+import org.junit.Assert._
+
+@RunWith(classOf[JUnit4])
+class BTypesTest {
+ val g: Global = new Global(new Settings())
+
+ val btypes = new BTypes[g.type](g) {
+ def chrs = g.chrs
+ override type BTypeName = g.TypeName
+ override def createNewName(s: String) = g.newTypeName(s)
+ }
+
+ import btypes._
+
+ val jls = "java/lang/String"
+ val jlo = "java/lang/Object"
+
+ val o = ClassBType(jlo)
+ val s = ClassBType(jls)
+ val oArr = ArrayBType(o)
+ val method = MethodBType(List(oArr, INT, DOUBLE, s), UNIT)
+
+ @Test
+ def classBTypesEquality() {
+ val s1 = ClassBType(jls)
+ val s2 = ClassBType(jls)
+ val o = ClassBType(jlo)
+ assertEquals(s1, s2)
+ assertEquals(s1.hashCode, s2.hashCode)
+ assert(s1 != o)
+ assert(s2 != o)
+ }
+
+ @Test
+ def classBTypeRequiresInternalName() {
+ assertThrows[AssertionError](ClassBType(s"L$jls;"), _ contains "Descriptor instead of internal name")
+ }
+
+ @Test
+ def typedOpcodes() {
+ assert(UNIT.typedOpcode(Opcodes.IALOAD) == Opcodes.IALOAD)
+ assert(INT.typedOpcode(Opcodes.IALOAD) == Opcodes.IALOAD)
+ assert(BOOL.typedOpcode(Opcodes.IALOAD) == Opcodes.BALOAD)
+ assert(BYTE.typedOpcode(Opcodes.IALOAD) == Opcodes.BALOAD)
+ assert(CHAR.typedOpcode(Opcodes.IALOAD) == Opcodes.CALOAD)
+ assert(SHORT.typedOpcode(Opcodes.IALOAD) == Opcodes.SALOAD)
+ assert(FLOAT.typedOpcode(Opcodes.IALOAD) == Opcodes.FALOAD)
+ assert(LONG.typedOpcode(Opcodes.IALOAD) == Opcodes.LALOAD)
+ assert(DOUBLE.typedOpcode(Opcodes.IALOAD) == Opcodes.DALOAD)
+ assert(ClassBType(jls).typedOpcode(Opcodes.IALOAD) == Opcodes.AALOAD)
+
+ assert(UNIT.typedOpcode(Opcodes.IRETURN) == Opcodes.RETURN)
+ assert(BOOL.typedOpcode(Opcodes.IRETURN) == Opcodes.IRETURN)
+ assert(CHAR.typedOpcode(Opcodes.IRETURN) == Opcodes.IRETURN)
+ assert(BYTE.typedOpcode(Opcodes.IRETURN) == Opcodes.IRETURN)
+ assert(SHORT.typedOpcode(Opcodes.IRETURN) == Opcodes.IRETURN)
+ assert(INT.typedOpcode(Opcodes.IRETURN) == Opcodes.IRETURN)
+ assert(FLOAT.typedOpcode(Opcodes.IRETURN) == Opcodes.FRETURN)
+ assert(LONG.typedOpcode(Opcodes.IRETURN) == Opcodes.LRETURN)
+ assert(DOUBLE.typedOpcode(Opcodes.IRETURN) == Opcodes.DRETURN)
+ assert(ClassBType(jls).typedOpcode(Opcodes.IRETURN) == Opcodes.ARETURN)
+ }
+
+ @Test
+ def descriptors() {
+ assert(o.descriptor == "Ljava/lang/Object;")
+ assert(s.descriptor == "Ljava/lang/String;")
+ assert(oArr.descriptor == "[Ljava/lang/Object;")
+ assert(method.descriptor == "([Ljava/lang/Object;IDLjava/lang/String;)V")
+ }
+
+ @Test
+ def toAsmTypeTest() {
+ for (t <- List(o, s, oArr, method, INT, UNIT, DOUBLE)) {
+ assertEquals(o.descriptor, o.toASMType.getDescriptor)
+ }
+ }
+
+ @Test
+ def parseMethodDescriptorTest() {
+ val descriptors = List(
+ "()V",
+ "(ID)I",
+ "([[I[D)[D",
+ s"(L$jls;[L$jlo;)[[L$jls;",
+ s"(IL$jlo;)L$jls;"
+ )
+ for (d <- descriptors) {
+ assertEquals(d, MethodBType(d).descriptor)
+ }
+
+ // class types in method descriptor need surrounding 'L' and ';'
+ assertThrows[MatchError](MethodBType("(java/lang/String)V"), _ == "j (of class java.lang.Character)")
+ assertThrows[AssertionError](MethodBType("I"), _ contains "Not a valid method descriptor")
+ }
+}
diff --git a/test/junit/scala/tools/testing/AssertUtil.scala b/test/junit/scala/tools/testing/AssertUtil.scala
index 9efac64a97..9a97c5114f 100644
--- a/test/junit/scala/tools/testing/AssertUtil.scala
+++ b/test/junit/scala/tools/testing/AssertUtil.scala
@@ -5,15 +5,20 @@ package testing
* that are ultimately based on junit.Assert primitives.
*/
object AssertUtil {
- /** Check if exception T (or a subclass) was thrown during evaluation of f.
- * If any other exception or throwable is found instead it will be re-thrown.
+ /**
+ * Check if throwable T (or a subclass) was thrown during evaluation of f, and that its message
+ * satisfies the `checkMessage` predicate.
+ * If any other exception will be re-thrown.
*/
- def assertThrows[T <: Exception](f: => Any)(implicit manifest: Manifest[T]): Unit =
+ def assertThrows[T <: Throwable](f: => Any,
+ checkMessage: String => Boolean = s => true)
+ (implicit manifest: Manifest[T]): Unit = {
try f
catch {
- case e: Exception =>
- val clazz = manifest.erasure.asInstanceOf[Class[T]]
+ case e: Throwable if checkMessage(e.getMessage) =>
+ val clazz = manifest.runtimeClass
if (!clazz.isAssignableFrom(e.getClass))
throw e
}
-} \ No newline at end of file
+ }
+}
diff --git a/versions.properties b/versions.properties
index 2fbd4c466d..1212734d22 100644
--- a/versions.properties
+++ b/versions.properties
@@ -1,10 +1,10 @@
-#Wed, 16 Apr 2014 11:13:08 +0200
+#Tue, 20 May 2014 10:01:37 +0200
# NOTE: this file determines the content of the scala-distribution
# via scala-dist-pom.xml and scala-library-all-pom.xml
# when adding new properties that influence a release,
# also add them to the update.versions mechanism in build.xml,
# which is used by scala-release-2.11.x in scala/jenkins-scripts
-starr.version=2.11.0
+starr.version=2.11.1
starr.use.released=1
# These are the versions of the modules that go with this release.
@@ -14,13 +14,13 @@ starr.use.released=1
scala.binary.version=2.11
# e.g. 2.11.0-RC1, 2.11.0, 2.11.1-RC1, 2.11.1
# this defines the dependency on scala-continuations-plugin in scala-dist's pom
-scala.full.version=2.11.0
+scala.full.version=2.11.1
# external modules shipped with distribution, as specified by scala-library-all's pom
-scala-xml.version.number=1.0.1
+scala-xml.version.number=1.0.2
scala-parser-combinators.version.number=1.0.1
-scala-continuations-plugin.version.number=1.0.1
-scala-continuations-library.version.number=1.0.1
+scala-continuations-plugin.version.number=1.0.2
+scala-continuations-library.version.number=1.0.2
scala-swing.version.number=1.0.1
akka-actor.version.number=2.3.3
actors-migration.version.number=1.1.0