summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md36
-rw-r--r--bincompat-forward.whitelist.conf5
-rw-r--r--build-ant-macros.xml2
-rwxr-xr-xbuild.xml12
-rwxr-xr-xsrc/compiler/scala/tools/ant/templates/tool-unix.tmpl39
-rw-r--r--src/compiler/scala/tools/nsc/CompilationUnits.scala6
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala148
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala24
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala81
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala66
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala21
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala17
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala18
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala19
-rw-r--r--src/intellij-14/scaladoc.iml.SAMPLE1
-rw-r--r--src/interactive/scala/tools/nsc/interactive/Global.scala2
-rw-r--r--src/library/scala/collection/SetLike.scala30
-rw-r--r--src/library/scala/reflect/ClassTag.scala39
-rw-r--r--src/library/scala/util/Random.scala10
-rw-r--r--src/reflect/scala/reflect/internal/FreshNames.scala24
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala17
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala7
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala10
-rw-r--r--test/files/jvm/innerClassAttribute.check34
-rw-r--r--test/files/jvm/innerClassAttribute/Classes_1.scala110
-rw-r--r--test/files/jvm/innerClassAttribute/Test.scala259
-rw-r--r--test/files/jvm/innerClassEnclMethodJavaReflection.scala65
-rw-r--r--test/files/jvm/javaReflection.check2
-rw-r--r--test/files/jvm/t9105.check18
-rw-r--r--test/files/jvm/t9105.scala22
-rw-r--r--test/files/neg/names-defaults-neg.check12
-rw-r--r--test/files/neg/t5044.check4
-rw-r--r--test/files/neg/t5091.check4
-rw-r--r--test/files/neg/t8463.check19
-rw-r--r--test/files/neg/t8841.check9
-rw-r--r--test/files/neg/t8841.scala15
-rw-r--r--test/files/pos/t9116.scala7
-rw-r--r--test/files/pos/t9157.scala13
-rw-r--r--test/files/run/settings-parse.scala5
-rw-r--r--test/junit/scala/reflect/ClassTag.scala29
-rw-r--r--test/junit/scala/tools/nsc/symtab/FreshNameExtractorTest.scala12
-rw-r--r--test/junit/scala/tools/testing/AssertUtil.scala21
-rw-r--r--test/junit/scala/util/RandomTest.scala15
-rw-r--r--versions.properties4
47 files changed, 1096 insertions, 226 deletions
diff --git a/README.md b/README.md
index cb9701b3f2..d04197891c 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,23 @@ For more information on building and developing the core of Scala, read on! Plea
We're still using Jira for issue reporting, so please [report any issues](https://issues.scala-lang.org) over there.
(We would love to start using GitHub Issues, but we're too resource-constrained to take on this migration right now.)
+# Get in touch!
+If you need some help with your PR at any time, please feel free to @-mention anyone from the list below (or simply `@scala/team-core-scala`), and we will do our best to help you out:
+
+ | username | talk to me about... |
+--------------------------------------------------------------------------------------------------|----------------------------------------------------------------|---------------------------------------------------|
+ <img src="https://avatars.githubusercontent.com/adriaanm" height="50px" title="Adriaan Moors"/> | [`@adriaanm`](https://github.com/adriaanm) | anything (type checker, pattern matcher, CI,...) |
+ <img src="https://avatars.githubusercontent.com/gkossakowski" height="50px" title="Grzegorz Kossakowski"/> | [`@gkossakowski`](https://github.com/gkossakowski) | infrastructure, incremental compilation, back-end |
+ <img src="https://avatars.githubusercontent.com/retronym" height="50px" title="Jason Zaugg"/> | [`@retronym`](https://github.com/retronym) | Java 8 lambdas, tricky bug detective work |
+ <img src="https://avatars.githubusercontent.com/Ichoran" height="50px" title="Rex Kerr"/> | [`@Ichoran`](https://github.com/Ichoran) | the collections library, performance |
+ <img src="https://avatars.githubusercontent.com/lrytz" height="50px" title="Lukas Rytz"/> | [`@lrytz`](https://github.com/lrytz) | optimizer, named & default arguments |
+ <img src="https://avatars.githubusercontent.com/dickwall" height="50px" title="Dick Wall"/> | [`@dickwall`](https://github.com/dickwall) | process & documentation |
+ <img src="https://avatars.githubusercontent.com/VladUreche" height="50px" title="Vlad Ureche"/> | [`@VladUreche`](https://github.com/VladUreche) | specialization & the scaladoc tool |
+ <img src="https://avatars.githubusercontent.com/densh" height="50px" title="Denys Shabalin"/> | [`@densh`](https://github.com/densh) | quasiquotes, parser, string interpolators, macros in standard library |
+ <img src="https://avatars.githubusercontent.com/xeno-by" height="50px" title="Eugene Burmako"/> | [`@xeno-by`](https://github.com/xeno-by) | macros and reflection |
+
+
+PS: If you have some spare time to help out around here, we would be delighted to add your name to this list!
# Handy Links
- [A wealth of documentation](http://docs.scala-lang.org)
@@ -62,7 +79,7 @@ This facilitates reviewing: a commit that reformats code can be judged quickly n
Please do not @mention anyone in the commit message -- that's what the PR description and comments are for. Every time a commit is shuffled through github (in a merge in some fork, say), every @mention results in an email to that person (the core team treats them as personal email, straight to their inbox, so please don't flood us :-)).
-## Reviewing
+## Reviews
Please consider nominating a reviewer for your PR in the PR's description or a comment. If unsure, not to worry -- the core team will assign one for you.
@@ -70,7 +87,22 @@ Your reviewer is also your mentor, who will help you rework your PR so that it m
To help you plan your contributions, we communicate our plans on a regular basis on scala-internals, and deadlines are tracked as due dates for [GitHub milestones](https://github.com/scala/scala/milestones).
-Once you've established some history submitting PRs, we will invite you to become a reviewer for others's code. The main goal of this whole process, in the end, is to ensure the health of the Scala project by improving the quality of the code base, the documentation, as well as this process itself. Thank you for doing your part!
+## Reviewing
+
+Once you've gained some experience with the code base and the process, the logical next step is to offers reviews for others's contributions. The main goal of this whole process, in the end, is to ensure the health of the Scala project by improving the quality of the code base, the documentation, as well as this process itself. Thank you for doing your part!
+
+### Tips & Tricks
+Once the `publish-core` task has completed on a commit, you can try it out in sbt as follows:
+
+```
+$ sbt
+
+> set resolvers += "pr" at "http://private-repo.typesafe.com/typesafe/scala-pr-validation-snapshots/"
+> set scalaVersion := "<milestone>-<sha7>-SNAPSHOT"
+> console
+```
+
+Here, `<milestone>` is the milestone targeted by the PR (e.g., 2.11.6), and `<sha7>` is the 7-character sha (the format used by GitHub on the web).
## IDE Setup
### Eclipse
diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf
index 13e4f4ba85..3808083dd3 100644
--- a/bincompat-forward.whitelist.conf
+++ b/bincompat-forward.whitelist.conf
@@ -314,6 +314,11 @@ filter {
{
matchName="scala.reflect.runtime.Settings#IntSetting.valueSetByUser"
problemName=MissingMethodProblem
+ },
+ // SI-9059
+ {
+ matchName="scala.util.Random.scala$util$Random$$nextAlphaNum$1"
+ problemName=MissingMethodProblem
}
]
}
diff --git a/build-ant-macros.xml b/build-ant-macros.xml
index 609f106d09..259d6a6eb6 100644
--- a/build-ant-macros.xml
+++ b/build-ant-macros.xml
@@ -751,6 +751,7 @@
<attribute name="srcdir" default="files"/> <!-- TODO: make targets for `pending` and other subdirs -->
<attribute name="colors" default="${partest.colors}"/>
<attribute name="scalacOpts" default="${partest.scalac_opts} ${scalac.args.optimise}"/>
+ <attribute name="javaOpts" default="${env.ANT_OPTS}"/>
<attribute name="pcp" default="${toString:partest.compilation.path}"/>
<attribute name="kinds"/>
<sequential>
@@ -759,6 +760,7 @@
kinds="@{kinds}"
colors="@{colors}"
scalacOpts="@{scalacOpts}"
+ javaOpts="@{javaOpts}"
compilationpath="@{pcp}"/>
</sequential>
</macrodef>
diff --git a/build.xml b/build.xml
index f8e44c6f5c..5f6b04b8e4 100755
--- a/build.xml
+++ b/build.xml
@@ -1445,15 +1445,7 @@ TODO:
<stopwatch name="quick.sbt-interface.timer" action="total"/>
</target>
- <target name="test.junit.init" depends="quick.done">
- <uptodate property="test.junit.available" targetfile="${build-junit.dir}/test-compile.complete">
- <srcfiles dir="${test.junit.src}">
- <include name="**/*.scala"/>
- </srcfiles>
- </uptodate>
- </target>
-
- <target name="test.junit.comp" depends="test.junit.init, quick.done" unless="test.junit.available">
+ <target name="test.junit.comp" depends="pack.done">
<stopwatch name="test.junit.compiler.timer"/>
<mkdir dir="${test.junit.classes}"/>
<scalacfork
@@ -1469,7 +1461,7 @@ TODO:
<stopwatch name="test.junit.compiler.timer" action="total"/>
</target>
- <target name="test.junit" depends="test.junit.comp, test.junit.init">
+ <target name="test.junit" depends="test.junit.comp">
<stopwatch name="test.junit.timer"/>
<mkdir dir="${test.junit.classes}"/>
<echo message="Note: details of failed tests will be output to ${build-junit.dir}"/>
diff --git a/src/compiler/scala/tools/ant/templates/tool-unix.tmpl b/src/compiler/scala/tools/ant/templates/tool-unix.tmpl
index 7acb3632d2..9862ea7987 100755
--- a/src/compiler/scala/tools/ant/templates/tool-unix.tmpl
+++ b/src/compiler/scala/tools/ant/templates/tool-unix.tmpl
@@ -109,9 +109,6 @@ if [[ -n "$cygwin" ]]; then
JAVA_HOME="$(cygpath --$format "$JAVA_HOME")"
fi
TOOL_CLASSPATH="$(cygpath --path --$format "$TOOL_CLASSPATH")"
-elif [[ -n "$mingw" ]]; then
- SCALA_HOME="$(cmd //c echo "$SCALA_HOME")"
- TOOL_CLASSPATH="$(cmd //c echo "$TOOL_CLASSPATH")"
fi
if [[ -n "$cygwin$mingw" ]]; then
@@ -131,23 +128,6 @@ fi
declare -a java_args
declare -a scala_args
-# default to the boot classpath for speed, except on cygwin/mingw because
-# JLine on Windows requires a custom DLL to be loaded.
-unset usebootcp
-if [[ -z "$cygwin$mingw" ]]; then
- usebootcp="true"
-fi
-
-# If using the boot classpath, also pass an empty classpath
-# to java to suppress "." from materializing.
-classpathArgs () {
- if [[ -n $usebootcp ]]; then
- echo "-Xbootclasspath/a:$TOOL_CLASSPATH -classpath \"\""
- else
- echo "-classpath $TOOL_CLASSPATH"
- fi
-}
-
# SI-8358, SI-8368 -- the default should really be false,
# but I don't want to flip the default during 2.11's RC cycle
OVERRIDE_USEJAVACP="-Dscala.usejavacp=true"
@@ -200,6 +180,23 @@ if [[ -z "$JAVACMD" && -n "$JAVA_HOME" && -x "$JAVA_HOME/bin/java" ]]; then
JAVACMD="$JAVA_HOME/bin/java"
fi
+declare -a classpath_args
+
+# default to the boot classpath for speed, except on cygwin/mingw because
+# JLine on Windows requires a custom DLL to be loaded.
+unset usebootcp
+if [[ -z "$cygwin$mingw" ]]; then
+ usebootcp="true"
+fi
+
+# If using the boot classpath, also pass an empty classpath
+# to java to suppress "." from materializing.
+if [[ -n $usebootcp ]]; then
+ classpath_args=("-Xbootclasspath/a:$TOOL_CLASSPATH" -classpath "\"\"")
+else
+ classpath_args=(-classpath "$TOOL_CLASSPATH")
+fi
+
# note that variables which may intentionally be empty must not
# be quoted: otherwise an empty string will appear as a command line
# argument, and java will think that is the program to run.
@@ -207,7 +204,7 @@ execCommand \
"${JAVACMD:=java}" \
$JAVA_OPTS \
"${java_args[@@]}" \
- $(classpathArgs) \
+ "${classpath_args[@@]}" \
-Dscala.home="$SCALA_HOME" \
$OVERRIDE_USEJAVACP \
"$EMACS_OPT" \
diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala
index 1a6843a249..6be1fda1b5 100644
--- a/src/compiler/scala/tools/nsc/CompilationUnits.scala
+++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala
@@ -25,9 +25,9 @@ trait CompilationUnits { global: Global =>
class CompilationUnit(val source: SourceFile) extends CompilationUnitContextApi { self =>
/** the fresh name creator */
- implicit val fresh: FreshNameCreator = new FreshNameCreator
- def freshTermName(prefix: String = "x$") = global.freshTermName(prefix)
- def freshTypeName(prefix: String) = global.freshTypeName(prefix)
+ implicit val fresh: FreshNameCreator = new FreshNameCreator
+ def freshTermName(prefix: String = nme.FRESH_TERM_NAME_PREFIX) = global.freshTermName(prefix)
+ def freshTypeName(prefix: String) = global.freshTypeName(prefix)
/** the content of the compilation unit in tree form */
var body: Tree = EmptyTree
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala
index a5f33aa786..27827015c3 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala
@@ -22,6 +22,31 @@ final class BCodeAsmCommon[G <: Global](val global: G) {
}
/**
+ * True for classes generated by the Scala compiler that are considered top-level in terms of
+ * the InnerClass / EnclosingMethod classfile attributes. See comment in BTypes.
+ */
+ def considerAsTopLevelImplementationArtifact(classSym: Symbol) = {
+ classSym.isImplClass || classSym.isSpecialized
+ }
+
+ /**
+ * Cache the value of delambdafy == "inline" for each run. We need to query this value many
+ * times, so caching makes sense.
+ */
+ object delambdafyInline {
+ private var runId = -1
+ private var value = false
+
+ def apply(): Boolean = {
+ if (runId != global.currentRunId) {
+ runId = global.currentRunId
+ value = settings.Ydelambdafy.value == "inline"
+ }
+ value
+ }
+ }
+
+ /**
* True if `classSym` is an anonymous class or a local class. I.e., false if `classSym` is a
* member class. This method is used to decide if we should emit an EnclosingMethod attribute.
* It is also used to decide whether the "owner" field in the InnerClass attribute should be
@@ -29,10 +54,68 @@ final class BCodeAsmCommon[G <: Global](val global: G) {
*/
def isAnonymousOrLocalClass(classSym: Symbol): Boolean = {
assert(classSym.isClass, s"not a class: $classSym")
- // Here used to be an `assert(!classSym.isDelambdafyFunction)`: delambdafy lambda classes are
- // always top-level. However, SI-8900 shows an example where the weak name-based implementation
- // of isDelambdafyFunction failed (for a function declared in a package named "lambda").
- classSym.isAnonymousClass || !classSym.originalOwner.isClass
+ val r = exitingPickler(classSym.isAnonymousClass) || !classSym.originalOwner.isClass
+ if (r && settings.Ybackend.value == "GenBCode") {
+ // this assertion only holds in GenBCode. lambda lift renames symbols and may accidentally
+ // introduce `$lambda` into a class name, making `isDelambdafyFunction` true. under GenBCode
+ // we prevent this, see `nonAnon` in LambdaLift.
+ // phase travel necessary: after flatten, the name includes the name of outer classes.
+ // if some outer name contains $lambda, a non-lambda class is considered lambda.
+ assert(exitingPickler(!classSym.isDelambdafyFunction), classSym.name)
+ }
+ r
+ }
+
+ /**
+ * The next enclosing definition in the source structure. Includes anonymous function classes
+ * under delambdafy:inline, even though they are only generated during UnCurry.
+ */
+ def nextEnclosing(sym: Symbol): Symbol = {
+ val origOwner = sym.originalOwner
+ // phase travel necessary: after flatten, the name includes the name of outer classes.
+ // if some outer name contains $anon, a non-anon class is considered anon.
+ if (delambdafyInline() && sym.rawowner.isAnonymousFunction) {
+ // SI-9105: special handling for anonymous functions under delambdafy:inline.
+ //
+ // class C { def t = () => { def f { class Z } } }
+ //
+ // class C { def t = byNameMethod { def f { class Z } } }
+ //
+ // In both examples, the method f lambda-lifted into the anonfun class.
+ //
+ // In both examples, the enclosing method of Z is f, the enclosing class is the anonfun.
+ // So nextEnclosing needs to return the following chain: Z - f - anonFunClassSym - ...
+ //
+ // In the first example, the initial owner of f is a TermSymbol named "$anonfun" (note: not the anonFunClassSym!)
+ // In the second, the initial owner of f is t (no anon fun term symbol for by-name args!).
+ //
+ // In both cases, the rawowner of class Z is the anonFunClassSym. So the check in the `if`
+ // above makes sure we don't jump over the anonymous function in the by-name argument case.
+ //
+ // However, we cannot directly return the rawowner: if `sym` is Z, we need to include method f
+ // in the result. This is done by comparing the rawowners (read: lambdalift-targets) of `sym`
+ // and `sym.originalOwner`: if they are the same, then the originalOwner is "in between", and
+ // we need to return it.
+ // If the rawowners are different, the symbol was not in between. In the first example, the
+ // originalOwner of `f` is the anonfun-term-symbol, whose rawowner is C. So the nextEnclosing
+ // of `f` is its rawowner, the anonFunClassSym.
+ //
+ // In delambdafy:method we don't have that problem. The f method is lambda-lifted into C,
+ // not into the anonymous function class. The originalOwner chain is Z - f - C.
+ if (sym.originalOwner.rawowner == sym.rawowner) sym.originalOwner
+ else sym.rawowner
+ } else {
+ origOwner
+ }
+ }
+
+ def nextEnclosingClass(sym: Symbol): Symbol = {
+ if (sym.isClass) sym
+ else nextEnclosingClass(nextEnclosing(sym))
+ }
+
+ def classOriginallyNestedInClass(nestedClass: Symbol, enclosingClass: Symbol) ={
+ nextEnclosingClass(nextEnclosing(nestedClass)) == enclosingClass
}
/**
@@ -60,12 +143,27 @@ final class BCodeAsmCommon[G <: Global](val global: G) {
*/
private def enclosingMethodForEnclosingMethodAttribute(classSym: Symbol): Option[Symbol] = {
assert(classSym.isClass, classSym)
+
+ def doesNotExist(method: Symbol) = {
+ // (1) SI-9124, some trait methods don't exist in the generated interface. see comment in BTypes.
+ // (2) Value classes. Member methods of value classes exist in the generated box class. However,
+ // nested methods lifted into a value class are moved to the companion object and don't exist
+ // in the value class itself. We can identify such nested methods: the initial enclosing class
+ // is a value class, but the current owner is some other class (the module class).
+ method.owner.isTrait && method.isImplOnly || { // (1)
+ val enclCls = nextEnclosingClass(method)
+ exitingPickler(enclCls.isDerivedValueClass) && method.owner != enclCls // (2)
+ }
+ }
+
def enclosingMethod(sym: Symbol): Option[Symbol] = {
if (sym.isClass || sym == NoSymbol) None
- else if (sym.isMethod) Some(sym)
- else enclosingMethod(sym.originalOwner)
+ else if (sym.isMethod) {
+ if (doesNotExist(sym)) None else Some(sym)
+ }
+ else enclosingMethod(nextEnclosing(sym))
}
- enclosingMethod(classSym.originalOwner)
+ enclosingMethod(nextEnclosing(classSym))
}
/**
@@ -74,11 +172,10 @@ final class BCodeAsmCommon[G <: Global](val global: G) {
*/
private def enclosingClassForEnclosingMethodAttribute(classSym: Symbol): Symbol = {
assert(classSym.isClass, classSym)
- def enclosingClass(sym: Symbol): Symbol = {
- if (sym.isClass) sym
- else enclosingClass(sym.originalOwner)
- }
- enclosingClass(classSym.originalOwner)
+ val r = nextEnclosingClass(nextEnclosing(classSym))
+ // this should be an assertion, but we are more cautious for now as it was introduced before the 2.11.6 minor release
+ if (considerAsTopLevelImplementationArtifact(r)) devWarning(s"enclosing class of $classSym should not be an implementation artifact class: $r")
+ r
}
final case class EnclosingMethodEntry(owner: String, name: String, methodDescriptor: String)
@@ -92,11 +189,22 @@ final class BCodeAsmCommon[G <: Global](val global: G) {
* on the implementation of GenASM / GenBCode, so they need to be passed in.
*/
def enclosingMethodAttribute(classSym: Symbol, classDesc: Symbol => String, methodDesc: Symbol => String): Option[EnclosingMethodEntry] = {
- if (isAnonymousOrLocalClass(classSym)) {
- val methodOpt = enclosingMethodForEnclosingMethodAttribute(classSym)
- debuglog(s"enclosing method for $classSym is $methodOpt (in ${methodOpt.map(_.enclClass)})")
+ // trait impl classes are always top-level, see comment in BTypes
+ if (isAnonymousOrLocalClass(classSym) && !considerAsTopLevelImplementationArtifact(classSym)) {
+ val enclosingClass = enclosingClassForEnclosingMethodAttribute(classSym)
+ val methodOpt = enclosingMethodForEnclosingMethodAttribute(classSym) match {
+ case some @ Some(m) =>
+ if (m.owner != enclosingClass) {
+ // This should never happen. In case it does, it prevents emitting an invalid
+ // EnclosingMethod attribute: if the attribute specifies an enclosing method,
+ // it needs to exist in the specified enclosing class.
+ devWarning(s"the owner of the enclosing method ${m.locationString} should be the same as the enclosing class $enclosingClass")
+ None
+ } else some
+ case none => none
+ }
Some(EnclosingMethodEntry(
- classDesc(enclosingClassForEnclosingMethodAttribute(classSym)),
+ classDesc(enclosingClass),
methodOpt.map(_.javaSimpleName.toString).orNull,
methodOpt.map(methodDesc).orNull))
} else {
@@ -121,11 +229,13 @@ final class BCodeAsmCommon[G <: Global](val global: G) {
* The member classes of a class symbol. Note that the result of this method depends on the
* current phase, for example, after lambdalift, all local classes become member of the enclosing
* class.
+ *
+ * Impl classes are always considered top-level, see comment in BTypes.
*/
- def memberClassesOf(classSymbol: Symbol): List[Symbol] = classSymbol.info.decls.collect({
- case sym if sym.isClass =>
+ def memberClassesForInnerClassTable(classSymbol: Symbol): List[Symbol] = classSymbol.info.decls.collect({
+ case sym if sym.isClass && !considerAsTopLevelImplementationArtifact(sym) =>
sym
- case sym if sym.isModule =>
+ case sym if sym.isModule && !considerAsTopLevelImplementationArtifact(sym) => // impl classes get the lateMODULE flag in mixin
val r = exitingPickler(sym.moduleClass)
assert(r != NoSymbol, sym.fullLocationString)
r
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
index 8d1c37532e..ccee230191 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
@@ -362,8 +362,8 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
else if (sym == definitions.NullClass) RT_NULL
else {
val r = classBTypeFromSymbol(sym)
- if (r.isNestedClass) innerClassBufferASM += r
- r
+ if (r.isNestedClass) innerClassBufferASM += r
+ r
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
index a9bce82acd..a194fe8fe4 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
@@ -527,7 +527,7 @@ abstract class BTypes {
* local and anonymous classes, no matter if there is an enclosing method or not. Accordingly, the
* "class" field (see below) must be always defined, while the "method" field may be null.
*
- * NOTE: When a EnclosingMethod attribute is requried (local and anonymous classes), the "outer"
+ * NOTE: When an EnclosingMethod attribute is requried (local and anonymous classes), the "outer"
* field in the InnerClass table must be null.
*
* Fields:
@@ -634,6 +634,28 @@ abstract class BTypes {
* }
* }
*
+ *
+ * Traits Members
+ * --------------
+ *
+ * Some trait methods don't exist in the generated interface, but only in the implementation class
+ * (private methods in traits for example). Since EnclosingMethod expresses a source-level property,
+ * but the source-level enclosing method doesn't exist in the classfile, we the enclosing method
+ * is null (the enclosing class is still emitted).
+ * See BCodeAsmCommon.considerAsTopLevelImplementationArtifact
+ *
+ *
+ * Implementation Classes, Specialized Classes, Delambdafy:method closure classes
+ * ------------------------------------------------------------------------------
+ *
+ * Trait implementation classes and specialized classes are always considered top-level. Again,
+ * the InnerClass / EnclosingMethod attributes describe a source-level properties. The impl
+ * classes are compilation artifacts.
+ *
+ * The same is true for delambdafy:method closure classes. These classes are generated at
+ * top-level in the delambdafy phase, no special support is required in the backend.
+ *
+ *
* Mirror Classes
* --------------
*
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
index 94f9b585d9..2af665d31c 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
@@ -125,39 +125,71 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
* nested classes, but NOT nested in C, that are used within C.
*/
val nestedClassSymbols = {
+ val linkedClass = exitingPickler(classSym.linkedClassOfClass) // linkedCoC does not work properly in late phases
+
// The lambdalift phase lifts all nested classes to the enclosing class, so if we collect
// member classes right after lambdalift, we obtain all nested classes, including local and
// anonymous ones.
val nestedClasses = {
- val nested = exitingPhase(currentRun.lambdaliftPhase)(memberClassesOf(classSym))
+ val allNested = exitingPhase(currentRun.lambdaliftPhase)(memberClassesForInnerClassTable(classSym))
+ val nested = {
+ // Classes nested in value classes are nested in the companion at this point. For InnerClass /
+ // EnclosingMethod, we use the value class as the outer class. So we remove nested classes
+ // from the companion that were originally nested in the value class.
+ if (exitingPickler(linkedClass.isDerivedValueClass)) allNested.filterNot(classOriginallyNestedInClass(_, linkedClass))
+ else allNested
+ }
+
if (isTopLevelModuleClass(classSym)) {
// For Java compatibility, member classes of top-level objects are treated as members of
// the top-level companion class, see comment below.
- val members = exitingPickler(memberClassesOf(classSym))
+ val members = exitingPickler(memberClassesForInnerClassTable(classSym))
nested diff members
} else {
nested
}
}
- // If this is a top-level class, the member classes of the companion object are added as
- // members of the class. For example:
- // class C { }
- // object C {
- // class D
- // def f = { class E }
- // }
- // The class D is added as a member of class C. The reason is: for Java compatibility, the
- // InnerClass attribute for D has "C" (NOT the module class "C$") as the outer class of D
- // (done by buildNestedInfo). See comment in BTypes.
- // For consistency, the InnerClass entry for D needs to be present in C - to Java it looks
- // like D is a member of C, not C$.
- val linkedClass = exitingPickler(classSym.linkedClassOfClass) // linkedCoC does not work properly in late phases
- val companionModuleMembers = {
- // phase travel to exitingPickler: this makes sure that memberClassesOf only sees member classes,
- // not local classes of the companion module (E in the exmaple) that were lifted by lambdalift.
- if (isTopLevelModuleClass(linkedClass)) exitingPickler(memberClassesOf(linkedClass))
- else Nil
+ val companionModuleMembers = if (considerAsTopLevelImplementationArtifact(classSym)) Nil else {
+ // If this is a top-level non-impl (*) class, the member classes of the companion object are
+ // added as members of the class. For example:
+ // class C { }
+ // object C {
+ // class D
+ // def f = { class E }
+ // }
+ // The class D is added as a member of class C. The reason is: for Java compatibility, the
+ // InnerClass attribute for D has "C" (NOT the module class "C$") as the outer class of D
+ // (done by buildNestedInfo). See comment in BTypes.
+ // For consistency, the InnerClass entry for D needs to be present in C - to Java it looks
+ // like D is a member of C, not C$.
+ //
+ // (*) We exclude impl classes: if the classfile for the impl class exists on the classpath,
+ // a linkedClass symbol is found for which isTopLevelModule is true, so we end up searching
+ // members of that weird impl-class-module-class-symbol. that search probably cannot return
+ // any classes, but it's better to exclude it.
+ val javaCompatMembers = {
+ if (linkedClass != NoSymbol && isTopLevelModuleClass(linkedClass))
+ // phase travel to exitingPickler: this makes sure that memberClassesForInnerClassTable only sees member
+ // classes, not local classes of the companion module (E in the exmaple) that were lifted by lambdalift.
+ exitingPickler(memberClassesForInnerClassTable(linkedClass))
+ else
+ Nil
+ }
+
+ // Classes nested in value classes are nested in the companion at this point. For InnerClass /
+ // EnclosingMethod we use the value class as enclosing class. Here we search nested classes
+ // in the companion that were originally nested in the value class, and we add them as nested
+ // in the value class.
+ val valueClassCompanionMembers = {
+ if (linkedClass != NoSymbol && exitingPickler(classSym.isDerivedValueClass)) {
+ val moduleMemberClasses = exitingPhase(currentRun.lambdaliftPhase)(memberClassesForInnerClassTable(linkedClass))
+ moduleMemberClasses.filter(classOriginallyNestedInClass(_, classSym))
+ } else
+ Nil
+ }
+
+ javaCompatMembers ++ valueClassCompanionMembers
}
nestedClasses ++ companionModuleMembers
@@ -191,7 +223,8 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
assert(innerClassSym.isClass, s"Cannot build NestedInfo for non-class symbol $innerClassSym")
val isTopLevel = innerClassSym.rawowner.isPackageClass
- if (isTopLevel) None
+ // impl classes are considered top-level, see comment in BTypes
+ if (isTopLevel || considerAsTopLevelImplementationArtifact(innerClassSym)) None
else {
// See comment in BTypes, when is a class marked static in the InnerClass table.
val isStaticNestedClass = isOriginallyStaticOwner(innerClassSym.originalOwner)
@@ -227,7 +260,9 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
}
val innerName: Option[String] = {
- if (innerClassSym.isAnonymousClass || innerClassSym.isAnonymousFunction) None
+ // phase travel necessary: after flatten, the name includes the name of outer classes.
+ // if some outer name contains $anon, a non-anon class is considered anon.
+ if (exitingPickler(innerClassSym.isAnonymousClass || innerClassSym.isAnonymousFunction)) None
else Some(innerClassSym.rawname + innerClassSym.moduleSuffix) // moduleSuffix for module classes
}
@@ -246,7 +281,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
classBTypeFromInternalName.getOrElse(internalName, {
val c = ClassBType(internalName)
// class info consistent with BCodeHelpers.genMirrorClass
- val nested = exitingPickler(memberClassesOf(moduleClassSym)) map classBTypeFromSymbol
+ val nested = exitingPickler(memberClassesForInnerClassTable(moduleClassSym)) map classBTypeFromSymbol
c.info = ClassInfo(
superClass = Some(ObjectReference),
interfaces = Nil,
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index abe3bc512c..707336e5de 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -595,7 +595,8 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self =>
val x = innerClassSymbolFor(s)
if(x ne NoSymbol) {
assert(x.isClass, "not an inner-class symbol")
- val isInner = !x.rawowner.isPackageClass
+ // impl classes are considered top-level, see comment in BTypes
+ val isInner = !considerAsTopLevelImplementationArtifact(s) && !x.rawowner.isPackageClass
if (isInner) {
innerClassBuffer += x
collectInnerClass(x.rawowner)
@@ -692,30 +693,55 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self =>
}
}
- def innerName(innerSym: Symbol): String =
- if (innerSym.isAnonymousClass || innerSym.isAnonymousFunction)
- null
- else
- innerSym.rawname + innerSym.moduleSuffix
+ def innerName(innerSym: Symbol): String = {
+ // phase travel necessary: after flatten, the name includes the name of outer classes.
+ // if some outer name contains $anon, a non-anon class is considered anon.
+ if (exitingPickler(innerSym.isAnonymousClass || innerSym.isAnonymousFunction)) null
+ else innerSym.rawname + innerSym.moduleSuffix
+ }
+
+ val linkedClass = exitingPickler(csym.linkedClassOfClass) // linkedCoC does not work properly in late phases
innerClassBuffer ++= {
- val members = exitingPickler(memberClassesOf(csym))
+ val members = exitingPickler(memberClassesForInnerClassTable(csym))
// lambdalift makes all classes (also local, anonymous) members of their enclosing class
- val allNested = exitingPhase(currentRun.lambdaliftPhase)(memberClassesOf(csym))
+ val allNested = exitingPhase(currentRun.lambdaliftPhase)(memberClassesForInnerClassTable(csym))
+ val nested = {
+ // Classes nested in value classes are nested in the companion at this point. For InnerClass /
+ // EnclosingMethod, we use the value class as the outer class. So we remove nested classes
+ // from the companion that were originally nested in the value class.
+ if (exitingPickler(linkedClass.isDerivedValueClass)) allNested.filterNot(classOriginallyNestedInClass(_, linkedClass))
+ else allNested
+ }
- // for the mirror class, we take the members of the companion module class (Java compat,
- // see doc in BTypes.scala). for module classes, we filter out those members.
- if (isMirror) members
- else if (isTopLevelModule(csym)) allNested diff members
- else allNested
- }
+ // for the mirror class, we take the members of the companion module class (Java compat, see doc in BTypes.scala).
+ // for module classes, we filter out those members.
+ if (isMirror) members
+ else if (isTopLevelModule(csym)) nested diff members
+ else nested
+ }
+
+ if (!considerAsTopLevelImplementationArtifact(csym)) {
+ // If this is a top-level non-impl class, add members of the companion object. These are the
+ // classes for which we change the InnerClass entry to allow using them from Java.
+ // We exclude impl classes: if the classfile for the impl class exists on the classpath, a
+ // linkedClass symbol is found for which isTopLevelModule is true, so we end up searching
+ // members of that weird impl-class-module-class-symbol. that search probably cannot return
+ // any classes, but it's better to exclude it.
+ if (linkedClass != NoSymbol && isTopLevelModule(linkedClass)) {
+ // phase travel to exitingPickler: this makes sure that memberClassesForInnerClassTable only
+ // sees member classes, not local classes that were lifted by lambdalift.
+ innerClassBuffer ++= exitingPickler(memberClassesForInnerClassTable(linkedClass))
+ }
- // If this is a top-level class, add members of the companion object.
- val linkedClass = exitingPickler(csym.linkedClassOfClass) // linkedCoC does not work properly in late phases
- if (isTopLevelModule(linkedClass)) {
- // phase travel to exitingPickler: this makes sure that memberClassesOf only sees member classes,
- // not local classes that were lifted by lambdalift.
- innerClassBuffer ++= exitingPickler(memberClassesOf(linkedClass))
+ // Classes nested in value classes are nested in the companion at this point. For InnerClass /
+ // EnclosingMethod we use the value class as enclosing class. Here we search nested classes
+ // in the companion that were originally nested in the value class, and we add them as nested
+ // in the value class.
+ if (linkedClass != NoSymbol && exitingPickler(csym.isDerivedValueClass)) {
+ val moduleMemberClasses = exitingPhase(currentRun.lambdaliftPhase)(memberClassesForInnerClassTable(linkedClass))
+ innerClassBuffer ++= moduleMemberClasses.filter(classOriginallyNestedInClass(_, csym))
+ }
}
val allInners: List[Symbol] = innerClassBuffer.toList filterNot deadCode.elidedClosures
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index a703542587..5e2fe21eec 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -250,21 +250,30 @@ abstract class LambdaLift extends InfoTransform {
debuglog("renaming in %s: %s => %s".format(sym.owner.fullLocationString, originalName, sym.name))
}
+ // make sure that the name doesn't make the symbol accidentally `isAnonymousClass` (et.al) by
+ // introducing `$anon` in its name. to be cautious, we don't make this change in the default
+ // backend under 2.11.x, so only in GenBCode.
+ def nonAnon(s: String) = if (settings.Ybackend.value == "GenBCode") nme.ensureNonAnon(s) else s
+
def newName(sym: Symbol): Name = {
val originalName = sym.name
def freshen(prefix: String): Name =
if (originalName.isTypeName) unit.freshTypeName(prefix)
else unit.freshTermName(prefix)
+ val join = nme.NAME_JOIN_STRING
if (sym.isAnonymousFunction && sym.owner.isMethod) {
- freshen(sym.name + nme.NAME_JOIN_STRING + sym.owner.name + nme.NAME_JOIN_STRING)
+ freshen(sym.name + join + nonAnon(sym.owner.name.toString) + join)
} else {
+ val name = freshen(sym.name + join)
// SI-5652 If the lifted symbol is accessed from an inner class, it will be made public. (where?)
- // Generating a unique name, mangled with the enclosing class name, avoids a VerifyError
- // in the case that a sub-class happens to lifts out a method with the *same* name.
- val name = freshen("" + sym.name + nme.NAME_JOIN_STRING)
- if (originalName.isTermName && !sym.enclClass.isImplClass && calledFromInner(sym)) nme.expandedName(name.toTermName, sym.enclClass)
- else name
+ // Generating a unique name, mangled with the enclosing full class name (including
+ // package - subclass might have the same name), avoids a VerifyError in the case
+ // that a sub-class happens to lifts out a method with the *same* name.
+ if (originalName.isTermName && !sym.enclClass.isImplClass && calledFromInner(sym))
+ newTermNameCached(nonAnon(sym.enclClass.fullName('$')) + nme.EXPAND_SEPARATOR_STRING + name)
+ else
+ name
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 3544dc9966..e1cf53059a 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -225,6 +225,10 @@ abstract class UnCurry extends InfoTransform
if (inlineFunctionExpansion || !canUseDelamdafyMethod) {
val parents = addSerializable(abstractFunctionForFunctionType(fun.tpe))
val anonClass = fun.symbol.owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation SerialVersionUIDAnnotation
+ // The original owner is used in the backend for the EnclosingMethod attribute. If fun is
+ // nested in a value-class method, its owner was already changed to the extension method.
+ // Saving the original owner allows getting the source structure from the class symbol.
+ defineOriginalOwner(anonClass, fun.symbol.originalOwner)
anonClass setInfo ClassInfoType(parents, newScope, anonClass)
val applyMethodDef = mkMethod(anonClass, nme.apply)
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 5c36bd9d28..c80aaea160 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -45,6 +45,14 @@ trait ContextErrors {
case class NormalTypeError(underlyingTree: Tree, errMsg: String)
extends TreeTypeError
+ /**
+ * Marks a TypeError that was constructed from a CyclicReference (under silent).
+ * This is used for named arguments, where we need to know if an assignment expression
+ * failed with a cyclic reference or some other type error.
+ */
+ class NormalTypeErrorFromCyclicReference(underlyingTree: Tree, errMsg: String)
+ extends NormalTypeError(underlyingTree, errMsg)
+
case class AccessTypeError(underlyingTree: Tree, errMsg: String)
extends TreeTypeError
@@ -1087,8 +1095,9 @@ trait ContextErrors {
// hence we (together with reportTypeError in TypeDiagnostics) make sure that this CyclicReference
// evades all the handlers on its way and successfully reaches `isCyclicOrErroneous` in Implicits
throw ex
- case CyclicReference(sym, info: TypeCompleter) =>
- issueNormalTypeError(tree, typer.cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage())
+ case c @ CyclicReference(sym, info: TypeCompleter) =>
+ val error = new NormalTypeErrorFromCyclicReference(tree, typer.cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage)
+ issueTypeError(error)
case _ =>
contextNamerErrorGen.issue(TypeErrorWithUnderlyingTree(tree, ex))
}
@@ -1275,8 +1284,8 @@ trait ContextErrors {
}
def WarnAfterNonSilentRecursiveInference(param: Symbol, arg: Tree)(implicit context: Context) = {
- val note = "type-checking the invocation of "+ param.owner +" checks if the named argument expression '"+ param.name + " = ...' is a valid assignment\n"+
- "in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for "+ param.name +"."
+ val note = "failed to determine if '"+ param.name + " = ...' is a named argument or an assignment expression.\n"+
+ "an explicit type is required for the definition mentioned in the error message above."
context.warning(arg.pos, note)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index 50f658f68d..39cd610b1c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -521,8 +521,22 @@ trait NamesDefaults { self: Analyzer =>
WarnAfterNonSilentRecursiveInference(param, arg)(context)
res
} match {
- case SilentResultValue(t) => !t.isErroneous // #4041
- case _ => false
+ case SilentResultValue(t) =>
+ !t.isErroneous // #4041
+ case SilentTypeError(e: NormalTypeErrorFromCyclicReference) =>
+ // If we end up here, the CyclicReference was reported in a silent context. This can
+ // happen for local definitions, when the completer for a definition is created during
+ // type checking in silent mode. ContextErrors.TypeSigError catches that cyclic reference
+ // and transforms it into a NormalTypeErrorFromCyclicReference.
+ // The cycle needs to be reported, because the program cannot be typed: we don't know
+ // if we have an assignment or a named arg.
+ context.issue(e)
+ // 'err = true' is required because we're in a silent context
+ WarnAfterNonSilentRecursiveInference(param, arg)(context)
+ false
+ case _ =>
+ // We got a type error, so it cannot be an assignment (it doesn't type check as one).
+ false
}
catch {
// `silent` only catches and returns TypeErrors which are not
diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
index 743bbe53bd..02356580cc 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
@@ -266,7 +266,6 @@ abstract class TreeCheckers extends Analyzer {
if (tree ne typed)
treesDiffer(tree, typed)
-
tree
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index e4255e5333..3a85d16f55 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -76,7 +76,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case s : SilentTypeError => f(s.reportableErrors)
}
}
- class SilentTypeError private(val errors: List[AbsTypeError]) extends SilentResult[Nothing] {
+ class SilentTypeError private(val errors: List[AbsTypeError], val warnings: List[(Position, String)]) extends SilentResult[Nothing] {
override def isEmpty = true
def err: AbsTypeError = errors.head
def reportableErrors = errors match {
@@ -87,10 +87,14 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
}
object SilentTypeError {
- def apply(errors: AbsTypeError*): SilentTypeError = new SilentTypeError(errors.toList)
+ def apply(errors: AbsTypeError*): SilentTypeError = apply(errors.toList, Nil)
+ def apply(errors: List[AbsTypeError], warnings: List[(Position, String)]): SilentTypeError = new SilentTypeError(errors, warnings)
+ // todo: this extracts only one error, should be a separate extractor.
def unapply(error: SilentTypeError): Option[AbsTypeError] = error.errors.headOption
}
+ // todo: should include reporter warnings in SilentResultValue.
+ // e.g. tryTypedApply could print warnings on arguments when the typing succeeds.
case class SilentResultValue[+T](value: T) extends SilentResult[T] { override def isEmpty = false }
def newTyper(context: Context): Typer = new NormalTyper(context)
@@ -661,7 +665,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
@inline def wrapResult(reporter: ContextReporter, result: T) =
if (reporter.hasErrors) {
stopStats()
- SilentTypeError(reporter.errors: _*)
+ SilentTypeError(reporter.errors.toList, reporter.warnings.toList)
} else SilentResultValue(result)
try {
@@ -4435,7 +4439,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
def tryTypedApply(fun: Tree, args: List[Tree]): Tree = {
val start = if (Statistics.canEnable) Statistics.startTimer(failedApplyNanos) else null
- def onError(typeErrors: Seq[AbsTypeError]): Tree = {
+ def onError(typeErrors: Seq[AbsTypeError], warnings: Seq[(Position, String)]): Tree = {
if (Statistics.canEnable) Statistics.stopTimer(failedApplyNanos, start)
// If the problem is with raw types, copnvert to existentials and try again.
@@ -4483,10 +4487,14 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
}
typeErrors foreach context.issue
+ warnings foreach { case (p, m) => context.warning(p, m) }
setError(treeCopy.Apply(tree, fun, args))
}
- silent(_.doTypedApply(tree, fun, args, mode, pt)) orElse onError
+ silent(_.doTypedApply(tree, fun, args, mode, pt)) match {
+ case SilentResultValue(value) => value
+ case e: SilentTypeError => onError(e.errors, e.warnings)
+ }
}
def normalTypedApply(tree: Tree, fun: Tree, args: List[Tree]) = {
@@ -4537,6 +4545,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case err: SilentTypeError =>
onError({
err.reportableErrors foreach context.issue
+ err.warnings foreach { case (p, m) => context.warning(p, m) }
args foreach (arg => typed(arg, mode, ErrorType))
setError(tree)
})
diff --git a/src/intellij-14/scaladoc.iml.SAMPLE b/src/intellij-14/scaladoc.iml.SAMPLE
index 1e7621ffed..5c7015aa61 100644
--- a/src/intellij-14/scaladoc.iml.SAMPLE
+++ b/src/intellij-14/scaladoc.iml.SAMPLE
@@ -13,5 +13,6 @@
<orderEntry type="library" name="scaladoc-deps" level="project" />
<orderEntry type="library" name="partest" level="project" />
<orderEntry type="library" name="starr-no-deps" level="project" />
+ <orderEntry type="library" name="ant" level="project" />
</component>
</module> \ No newline at end of file
diff --git a/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala
index 9b34a39e02..a3d0346f81 100644
--- a/src/interactive/scala/tools/nsc/interactive/Global.scala
+++ b/src/interactive/scala/tools/nsc/interactive/Global.scala
@@ -152,7 +152,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
// don't keep the original owner in presentation compiler runs
// (the map will grow indefinitely, and the only use case is the backend)
- override protected def saveOriginalOwner(sym: Symbol) { }
+ override def defineOriginalOwner(sym: Symbol, owner: Symbol): Unit = { }
override def forInteractive = true
override protected def synchronizeNames = true
diff --git a/src/library/scala/collection/SetLike.scala b/src/library/scala/collection/SetLike.scala
index 3e549f72cd..f8ac1d754d 100644
--- a/src/library/scala/collection/SetLike.scala
+++ b/src/library/scala/collection/SetLike.scala
@@ -107,22 +107,36 @@ self =>
*/
def + (elem: A): This
- /** Creates a new $coll with additional elements.
+ /** Creates a new $coll with additional elements, omitting duplicates.
*
- * This method takes two or more elements to be added. Another overloaded
- * variant of this method handles the case where a single element is added.
+ * This method takes two or more elements to be added. Elements that already exist in the $coll will
+ * not be added. Another overloaded variant of this method handles the case where a single element is added.
+ *
+ * Example:
+ * {{{
+ * scala> val a = Set(1, 3) + 2 + 3
+ * a: scala.collection.immutable.Set[Int] = Set(1, 3, 2)
+ * }}}
*
* @param elem1 the first element to add.
* @param elem2 the second element to add.
* @param elems the remaining elements to add.
- * @return a new $coll with the given elements added.
+ * @return a new $coll with the given elements added, omitting duplicates.
*/
def + (elem1: A, elem2: A, elems: A*): This = this + elem1 + elem2 ++ elems
- /** Creates a new $coll by adding all elements contained in another collection to this $coll.
+ /** Creates a new $coll by adding all elements contained in another collection to this $coll, omitting duplicates.
+ *
+ * This method takes a collection of elements and adds all elements, omitting duplicates, into $coll.
+ *
+ * Example:
+ * {{{
+ * scala> val a = Set(1, 2) ++ Set(2, "a")
+ * a: scala.collection.immutable.Set[Any] = Set(1, 2, a)
+ * }}}
*
- * @param elems the collection containing the added elements.
- * @return a new $coll with the given elements added.
+ * @param elems the collection containing the elements to add.
+ * @return a new $coll with the given elements added, omitting duplicates.
*/
def ++ (elems: GenTraversableOnce[A]): This = (repr /: elems.seq)(_ + _)
@@ -171,7 +185,7 @@ self =>
*
* @return the iterator.
*/
- def subsets: Iterator[This] = new AbstractIterator[This] {
+ def subsets(): Iterator[This] = new AbstractIterator[This] {
private val elms = self.toIndexedSeq
private var len = 0
private var itr: Iterator[This] = Iterator.empty
diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala
index 2f4aa9cb84..9dd96183da 100644
--- a/src/library/scala/reflect/ClassTag.scala
+++ b/src/library/scala/reflect/ClassTag.scala
@@ -69,22 +69,22 @@ trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serial
* `SomeExtractor(...)` is turned into `ct(SomeExtractor(...))` if `T` in `SomeExtractor.unapply(x: T)`
* is uncheckable, but we have an instance of `ClassTag[T]`.
*/
- def unapply(x: Any): Option[T] = x match {
- case null => None
- case b: Byte => unapply(b)
- case s: Short => unapply(s)
- case c: Char => unapply(c)
- case i: Int => unapply(i)
- case l: Long => unapply(l)
- case f: Float => unapply(f)
- case d: Double => unapply(d)
- case b: Boolean => unapply(b)
- case u: Unit => unapply(u)
- case a: Any => unapplyImpl(a)
- }
+ def unapply(x: Any): Option[T] =
+ if (null != x && (
+ (runtimeClass.isInstance(x))
+ || (x.isInstanceOf[Byte] && runtimeClass.isAssignableFrom(classOf[Byte]))
+ || (x.isInstanceOf[Short] && runtimeClass.isAssignableFrom(classOf[Short]))
+ || (x.isInstanceOf[Char] && runtimeClass.isAssignableFrom(classOf[Char]))
+ || (x.isInstanceOf[Int] && runtimeClass.isAssignableFrom(classOf[Int]))
+ || (x.isInstanceOf[Long] && runtimeClass.isAssignableFrom(classOf[Long]))
+ || (x.isInstanceOf[Float] && runtimeClass.isAssignableFrom(classOf[Float]))
+ || (x.isInstanceOf[Double] && runtimeClass.isAssignableFrom(classOf[Double]))
+ || (x.isInstanceOf[Boolean] && runtimeClass.isAssignableFrom(classOf[Boolean]))
+ || (x.isInstanceOf[Unit] && runtimeClass.isAssignableFrom(classOf[Unit])))
+ ) Some(x.asInstanceOf[T])
+ else None
- // TODO: Inline the bodies of these into the Any-accepting unapply overload above and delete them.
- // This cannot be done until at least 2.12.0 for reasons of binary compatibility
+ // TODO: deprecate overloads in 2.12.0, remove in 2.13.0
def unapply(x: Byte) : Option[T] = unapplyImpl(x, classOf[Byte])
def unapply(x: Short) : Option[T] = unapplyImpl(x, classOf[Short])
def unapply(x: Char) : Option[T] = unapplyImpl(x, classOf[Char])
@@ -94,11 +94,10 @@ trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serial
def unapply(x: Double) : Option[T] = unapplyImpl(x, classOf[Double])
def unapply(x: Boolean) : Option[T] = unapplyImpl(x, classOf[Boolean])
def unapply(x: Unit) : Option[T] = unapplyImpl(x, classOf[Unit])
-
- private[this] def unapplyImpl(x: Any, alternative: jClass[_] = null): Option[T] = {
- val conforms = runtimeClass.isAssignableFrom(x.getClass) || (alternative != null && runtimeClass.isAssignableFrom(alternative))
- if (conforms) Some(x.asInstanceOf[T]) else None
- }
+
+ private[this] def unapplyImpl(x: Any, primitiveCls: java.lang.Class[_]): Option[T] =
+ if (runtimeClass.isInstance(x) || runtimeClass.isAssignableFrom(primitiveCls)) Some(x.asInstanceOf[T])
+ else None
// case class accessories
override def canEqual(x: Any) = x.isInstanceOf[ClassTag[_]]
diff --git a/src/library/scala/util/Random.scala b/src/library/scala/util/Random.scala
index 8d68c5be38..2d38c9d4a0 100644
--- a/src/library/scala/util/Random.scala
+++ b/src/library/scala/util/Random.scala
@@ -121,15 +121,21 @@ class Random(val self: java.util.Random) extends AnyRef with Serializable {
(bf(xs) ++= buf).result()
}
+ @deprecated("Preserved for backwards binary compatibility. To remove in 2.12.x.", "2.11.6")
+ final def `scala$util$Random$$isAlphaNum$1`(c: Char) = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')
+
/** Returns a Stream of pseudorandomly chosen alphanumeric characters,
* equally chosen from A-Z, a-z, and 0-9.
*
* @since 2.8
*/
def alphanumeric: Stream[Char] = {
- def isAlphaNum(c: Char) = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')
+ def nextAlphaNum: Char = {
+ val chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+ chars charAt (self nextInt chars.length)
+ }
- Stream continually nextPrintableChar filter isAlphaNum
+ Stream continually nextAlphaNum
}
}
diff --git a/src/reflect/scala/reflect/internal/FreshNames.scala b/src/reflect/scala/reflect/internal/FreshNames.scala
index 7e9a568266..17883d12ad 100644
--- a/src/reflect/scala/reflect/internal/FreshNames.scala
+++ b/src/reflect/scala/reflect/internal/FreshNames.scala
@@ -7,6 +7,7 @@ package reflect
package internal
import scala.reflect.internal.util.FreshNameCreator
+import scala.util.matching.Regex
trait FreshNames { self: Names with StdNames =>
// SI-6879 Keeps track of counters that are supposed to be globally unique
@@ -23,17 +24,20 @@ trait FreshNames { self: Names with StdNames =>
// Extractor that matches names which were generated by some
// FreshNameCreator with known prefix. Extracts user-specified
// prefix that was used as a parameter to newName by stripping
- // global creator prefix and unique number in the end of the name.
+ // global creator prefix and unique numerical suffix.
+ // The creator prefix and numerical suffix may both be empty.
class FreshNameExtractor(creatorPrefix: String = "") {
- // quote prefix so that it can be used with replaceFirst
- // which expects regExp rather than simple string
- val quotedCreatorPrefix = java.util.regex.Pattern.quote(creatorPrefix)
-
- def unapply(name: Name): Option[String] = {
- val sname = name.toString
- // name should start with creatorPrefix and end with number
- if (!sname.startsWith(creatorPrefix) || !sname.matches("^.*\\d*$")) None
- else Some(NameTransformer.decode(sname.replaceFirst(quotedCreatorPrefix, "").replaceAll("\\d*$", "")))
+
+ // name should start with creatorPrefix and end with number
+ val freshlyNamed = {
+ val pre = if (!creatorPrefix.isEmpty) Regex quote creatorPrefix else ""
+ s"""$pre(.*?)\\d*""".r
}
+
+ def unapply(name: Name): Option[String] =
+ name.toString match {
+ case freshlyNamed(prefix) => Some(prefix)
+ case _ => None
+ }
}
}
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index c94ee996e4..f32b7326fe 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -112,6 +112,23 @@ trait StdNames {
val ROOT: NameType = "<root>"
val SPECIALIZED_SUFFIX: NameType = "$sp"
+ val NESTED_IN: String = "$nestedIn"
+ val NESTED_IN_ANON_CLASS: String = NESTED_IN + ANON_CLASS_NAME.toString.replace("$", "")
+ val NESTED_IN_ANON_FUN: String = NESTED_IN + ANON_FUN_NAME.toString.replace("$", "")
+ val NESTED_IN_LAMBDA: String = NESTED_IN + DELAMBDAFY_LAMBDA_CLASS_NAME.toString.replace("$", "")
+
+ /**
+ * Ensures that name mangling does not accidentally make a class respond `true` to any of
+ * isAnonymousClass, isAnonymousFunction, isDelambdafyFunction, e.g. by introducing "$anon".
+ */
+ def ensureNonAnon(name: String) = {
+ name
+ .replace(nme.ANON_CLASS_NAME.toString, NESTED_IN_ANON_CLASS)
+ .replace(nme.ANON_FUN_NAME.toString, NESTED_IN_ANON_FUN)
+ .replace(nme.DELAMBDAFY_LAMBDA_CLASS_NAME.toString, NESTED_IN_LAMBDA)
+ }
+
+
// value types (and AnyRef) are all used as terms as well
// as (at least) arguments to the @specialize annotation.
final val Boolean: NameType = "Boolean"
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index d5fc52abbf..d23a102b28 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -66,14 +66,19 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// when under some flag. Define per-phase invariants for owner/owned relationships,
// e.g. after flatten all classes are owned by package classes, there are lots and
// lots of these to be declared (or more realistically, discovered.)
+ // could be private since 2.11.6, but left protected to avoid potential breakages (eg ensime)
protected def saveOriginalOwner(sym: Symbol): Unit = {
// some synthetic symbols have NoSymbol as owner initially
if (sym.owner != NoSymbol) {
if (originalOwnerMap contains sym) ()
- else originalOwnerMap(sym) = sym.rawowner
+ else defineOriginalOwner(sym, sym.rawowner)
}
}
+ def defineOriginalOwner(sym: Symbol, owner: Symbol): Unit = {
+ originalOwnerMap(sym) = owner
+ }
+
def symbolOf[T: WeakTypeTag]: TypeSymbol = weakTypeOf[T].typeSymbolDirect.asType
abstract class SymbolContextApiImpl extends SymbolApi {
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index ce36f7efa3..8f114caac0 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -1976,13 +1976,13 @@ trait Types
* usage scenario.
*/
private var relativeInfoCache: Type = _
- private var memberInfoCache: Type = _
+ private var relativeInfoPeriod: Period = NoPeriod
- private[Types] def relativeInfo = {
- val memberInfo = pre.memberInfo(sym)
- if (relativeInfoCache == null || (memberInfo ne memberInfoCache)) {
- memberInfoCache = memberInfo
+ private[Types] def relativeInfo = /*trace(s"relativeInfo(${safeToString}})")*/{
+ if (relativeInfoPeriod != currentPeriod) {
+ val memberInfo = pre.memberInfo(sym)
relativeInfoCache = transformInfo(memberInfo)
+ relativeInfoPeriod = currentPeriod
}
relativeInfoCache
}
diff --git a/test/files/jvm/innerClassAttribute.check b/test/files/jvm/innerClassAttribute.check
index 20518aa49e..bb532e4f36 100644
--- a/test/files/jvm/innerClassAttribute.check
+++ b/test/files/jvm/innerClassAttribute.check
@@ -14,27 +14,27 @@ A19 / null / null
A19 / null / null
A19 / null / null
-- A20 --
-A20$$anonfun$4 / null / null / 17
+A20$$anonfun$6 / null / null / 17
fun1: attribute for itself and the two child closures `() => ()` and `() => () => 1`
-A20$$anonfun$4 / null / null / 17
-A20$$anonfun$4$$anonfun$apply$1 / null / null / 17
-A20$$anonfun$4$$anonfun$apply$3 / null / null / 17
+A20$$anonfun$6 / null / null / 17
+A20$$anonfun$6$$anonfun$apply$1 / null / null / 17
+A20$$anonfun$6$$anonfun$apply$3 / null / null / 17
fun2 () => (): itself and the outer closure
-A20$$anonfun$4 / null / null / 17
-A20$$anonfun$4$$anonfun$apply$1 / null / null / 17
+A20$$anonfun$6 / null / null / 17
+A20$$anonfun$6$$anonfun$apply$1 / null / null / 17
fun3 () => () => (): itself, the outer closure and its child closure
-A20$$anonfun$4 / null / null / 17
-A20$$anonfun$4$$anonfun$apply$3 / null / null / 17
-A20$$anonfun$4$$anonfun$apply$3$$anonfun$apply$2 / null / null / 17
+A20$$anonfun$6 / null / null / 17
+A20$$anonfun$6$$anonfun$apply$3 / null / null / 17
+A20$$anonfun$6$$anonfun$apply$3$$anonfun$apply$2 / null / null / 17
fun4: () => 1: itself and the two outer closures
-A20$$anonfun$4 / null / null / 17
-A20$$anonfun$4$$anonfun$apply$3 / null / null / 17
-A20$$anonfun$4$$anonfun$apply$3$$anonfun$apply$2 / null / null / 17
-enclosing: nested closures have the apply method of the outer closure
+A20$$anonfun$6 / null / null / 17
+A20$$anonfun$6$$anonfun$apply$3 / null / null / 17
+A20$$anonfun$6$$anonfun$apply$3$$anonfun$apply$2 / null / null / 17
+enclosing: nested closures have outer class defined, but no outer method
A20 / null / null
-A20$$anonfun$4 / apply / ()Lscala/Function0;
-A20$$anonfun$4 / apply / ()Lscala/Function0;
-A20$$anonfun$4$$anonfun$apply$3 / apply / ()Lscala/Function0;
+A20$$anonfun$6 / null / null
+A20$$anonfun$6 / null / null
+A20$$anonfun$6$$anonfun$apply$3 / null / null
#partest -Ydelambdafy:method
-- A4 --
null / null / null
@@ -47,7 +47,7 @@ fun1: attribute for itself and the two child closures `() => ()` and `() => () =
fun2 () => (): itself and the outer closure
fun3 () => () => (): itself, the outer closure and its child closure
fun4: () => 1: itself and the two outer closures
-enclosing: nested closures have the apply method of the outer closure
+enclosing: nested closures have outer class defined, but no outer method
null / null / null
null / null / null
null / null / null
diff --git a/test/files/jvm/innerClassAttribute/Classes_1.scala b/test/files/jvm/innerClassAttribute/Classes_1.scala
index 9c3ea7f013..fb1f32aa3d 100644
--- a/test/files/jvm/innerClassAttribute/Classes_1.scala
+++ b/test/files/jvm/innerClassAttribute/Classes_1.scala
@@ -185,3 +185,113 @@ trait A24 extends A24Base {
override object Conc extends A24Sym
}
}
+
+class SI_9105 {
+ // the EnclosingMethod attributes depend on the delambdafy strategy (inline vs method)
+
+ // outerClass-inline enclMeth-inline outerClass-method enclMeth-method
+ val fun = () => {
+ class A // closure null (*) SI_9105 null
+ def m: Object = { class B; new B } // closure m$1 SI_9105 m$1
+ val f: Object = { class C; new C } // closure null (*) SI_9105 null
+ }
+ def met = () => {
+ class D // closure null (*) SI_9105 met
+ def m: Object = { class E; new E } // closure m$1 SI_9105 m$1
+ val f: Object = { class F; new F } // closure null (*) SI_9105 met
+ }
+
+ // (*) the originalOwner chain of A (similar for D) is: SI_9105.fun.$anonfun-value.A
+ // we can get to the anonfun-class (created by uncurry), but not to the apply method.
+ //
+ // for C and F, the originalOwner chain is fun.$anonfun-value.f.C. at later phases, the rawowner of f is
+ // an apply$sp method of the closure class. we could use that as enclosing method, but it would be unsystematic
+ // (A / D don't have an encl meth either), and also strange to use the $sp, which is a compilation artifact.
+ // So using `null` looks more like the situation in the source code: C / F are nested classes of the anon-fun, and
+ // there's no method in between.
+
+ def byName[T](op: => T) = 0
+
+ val bnV = byName {
+ class G // closure null (*) SI_9105 null
+ def m: Object = { class H; new H } // closure m$1 SI_9105 m$1
+ val f: Object = { class I; new I } // closure null (*) SI_9105 null
+ }
+ def bnM = byName {
+ class J // closure null (*) SI_9105 bnM
+ def m: Object = { class K; new K } // closure m$1 SI_9105 m$1
+ val f: Object = { class L; new L } // closure null (*) SI_9105 bnM
+ }
+}
+
+trait SI_9124 {
+ trait A // member class, no enclosing method attribute
+
+ new A { def f1 = 0 } // nested class, enclosing class SI_9124, no encl meth
+
+ def f = new A { def f2 = 0 } // enclosing method is f in the interface SI_9124
+
+ private def g = new A { def f3 = 0 } // only encl class (SI_9124), encl meth is null because the interface SI_9124 doesn't have a method g
+
+ object O { // member, no encl meth attribute
+ new A { def f4 = 0 } // enclosing class is O$, no enclosing method
+ }
+
+ val f1 = { new A { def f5 = 0 }; 1 } // encl class SI_9124, no encl meth
+ private val f2 = { new A { def f6 = 0 }; 1 } // like above
+}
+
+trait ImplClassesAreTopLevel {
+ // all impl classes are top-level, so they don't appear in any InnerClass entry, and none of them have an EnclosingMethod attr
+ trait B1 { def f = 1 }
+ { trait B2 { def f = 1 }; new B2 {} }
+ val m = {
+ trait B3 { def f = 1 }
+ new B3 {}
+ }
+ def n = {
+ trait B4 { def f = 1 }
+ new B4 {}
+ }
+}
+
+class SpecializedClassesAreTopLevel {
+ // all specialized classes are top-level
+ class A[@specialized(Int) T]; new A[Int]
+
+ object T {
+ class B[@specialized(Int) T]; new B[Int]
+ }
+
+ // these crash the compiler, SI-7625
+
+ // { class B[@specialized(Int) T]; new B[Int] }
+
+ // val m: Object = {
+ // class C[@specialized(Int) T]
+ // new C[Int]
+ // }
+
+ // def n: Object = {
+ // class D[@specialized(Int) T]
+ // new D[Int]
+ // }
+}
+
+object NestedInValueClass {
+ // note that we can only test anonymous functions, nested classes are not allowed inside value classes
+ class A(val arg: String) extends AnyVal {
+ // A has InnerClass entries for the two closures (and for A and A$). not for B / C
+ def f = {
+ def g = List().map(x => (() => x)) // outer class A, no outer method (g is moved to the companion, doesn't exist in A)
+ g.map(x => (() => x)) // outer class A, outer method f
+ }
+ // statements and field declarations are not allowed in value classes
+ }
+
+ object A {
+ // A$ has InnerClass entries for B, C, A, A$. Also for the closures above, because they are referenced in A$'s bytecode.
+ class B // member class of A$
+ def f = { class C; new C } // outer class A$, outer method f
+ }
+}
diff --git a/test/files/jvm/innerClassAttribute/Test.scala b/test/files/jvm/innerClassAttribute/Test.scala
index 3820048cb4..bc9aa2376a 100644
--- a/test/files/jvm/innerClassAttribute/Test.scala
+++ b/test/files/jvm/innerClassAttribute/Test.scala
@@ -16,6 +16,16 @@ object Test extends BytecodeTest {
loadClassNode(className).innerClasses.asScala.toList.sortBy(_.name)
}
+ def ownInnerClassNode(n: String) = innerClassNodes(n).filter(_.name == n).head
+
+ def testInner(cls: String, fs: (InnerClassNode => Unit)*) = {
+ val ns = innerClassNodes(cls)
+ assert(ns.length == fs.length, ns)
+ (ns zip fs.toList) foreach { case (n, f) => f(n) }
+ }
+
+
+
final case class EnclosingMethod(name: String, descriptor: String, outerClass: String)
def enclosingMethod(className: String) = {
val n = loadClassNode(className)
@@ -215,7 +225,7 @@ object Test extends BytecodeTest {
assertAnonymous(anon1, "A18$$anon$5")
assertAnonymous(anon2, "A18$$anon$6")
- assertLocal(a, "A18$A$1", "A$1")
+ assertLocal(a, "A18$A$2", "A$2")
assertLocal(b, "A18$B$4", "B$4")
assertEnclosingMethod(
@@ -226,7 +236,7 @@ object Test extends BytecodeTest {
"A18", "g$1", "()V")
assertEnclosingMethod(
- "A18$A$1",
+ "A18$A$2",
"A18", "g$1", "()V")
assertEnclosingMethod(
"A18$B$4",
@@ -256,10 +266,10 @@ object Test extends BytecodeTest {
printInnerClassNodes("A20")
- val fun1 = lambdaClass("A20$$anonfun$4", "A20$lambda$1")
- val fun2 = lambdaClass("A20$$anonfun$4$$anonfun$apply$1", "A20$lambda$$$nestedInAnonfun$5$1")
- val fun3 = lambdaClass("A20$$anonfun$4$$anonfun$apply$3", "A20$lambda$$$nestedInAnonfun$5$2")
- val fun4 = lambdaClass("A20$$anonfun$4$$anonfun$apply$3$$anonfun$apply$2", "A20$lambda$$$nestedInAnonfun$7$1")
+ val fun1 = lambdaClass("A20$$anonfun$6", "A20$lambda$1")
+ val fun2 = lambdaClass("A20$$anonfun$6$$anonfun$apply$1", "A20$lambda$$$nestedInAnonfun$5$1")
+ val fun3 = lambdaClass("A20$$anonfun$6$$anonfun$apply$3", "A20$lambda$$$nestedInAnonfun$5$2")
+ val fun4 = lambdaClass("A20$$anonfun$6$$anonfun$apply$3$$anonfun$apply$2", "A20$lambda$$$nestedInAnonfun$7$1")
println("fun1: attribute for itself and the two child closures `() => ()` and `() => () => 1`")
printInnerClassNodes(fun1)
@@ -270,7 +280,7 @@ object Test extends BytecodeTest {
println("fun4: () => 1: itself and the two outer closures")
printInnerClassNodes(fun4)
- println("enclosing: nested closures have the apply method of the outer closure")
+ println("enclosing: nested closures have outer class defined, but no outer method")
printEnclosingMethod(fun1)
printEnclosingMethod(fun2)
printEnclosingMethod(fun3)
@@ -316,12 +326,238 @@ object Test extends BytecodeTest {
}
def testA24() {
- val List(defsCls, abs, conc, defsApi, defsApiImpl) = innerClassNodes("A24$DefinitionsClass")
+ val List(defsCls, abs, conc, defsApi) = innerClassNodes("A24$DefinitionsClass")
assertMember(defsCls, "A24", "DefinitionsClass")
assertMember(abs, "A24$DefinitionsClass", "Abs$")
assertMember(conc, "A24$DefinitionsClass", "Conc$")
assertMember(defsApi, "A24Base", "DefinitionsApi", flags = publicAbstractInterface)
- assertMember(defsApiImpl, "A24Base", "DefinitionsApi$class", flags = Flags.ACC_PUBLIC | Flags.ACC_ABSTRACT)
+ }
+
+ def testSI_9105() {
+ val isDelambdafyMethod = classpath.findClass("SI_9105$lambda$1").isDefined
+ if (isDelambdafyMethod) {
+ assertEnclosingMethod ("SI_9105$A$3" , "SI_9105", null , null)
+ assertEnclosingMethod ("SI_9105$B$5" , "SI_9105", "m$1", "()Ljava/lang/Object;")
+ assertEnclosingMethod ("SI_9105$C$1" , "SI_9105", null , null)
+ assertEnclosingMethod ("SI_9105$D$1" , "SI_9105", "met", "()Lscala/Function0;")
+ assertEnclosingMethod ("SI_9105$E$1" , "SI_9105", "m$3", "()Ljava/lang/Object;")
+ assertEnclosingMethod ("SI_9105$F$1" , "SI_9105", "met", "()Lscala/Function0;")
+ assertNoEnclosingMethod("SI_9105$lambda$$met$1")
+ assertNoEnclosingMethod("SI_9105$lambda$1")
+ assertNoEnclosingMethod("SI_9105")
+
+ assertLocal(innerClassNodes("SI_9105$A$3").head, "SI_9105$A$3", "A$3")
+ assertLocal(innerClassNodes("SI_9105$B$5").head, "SI_9105$B$5", "B$5")
+ assertLocal(innerClassNodes("SI_9105$C$1").head, "SI_9105$C$1", "C$1")
+ assertLocal(innerClassNodes("SI_9105$D$1").head, "SI_9105$D$1", "D$1")
+ assertLocal(innerClassNodes("SI_9105$E$1").head, "SI_9105$E$1", "E$1")
+ assertLocal(innerClassNodes("SI_9105$F$1").head, "SI_9105$F$1", "F$1")
+
+ // by-name
+ assertEnclosingMethod("SI_9105$G$1", "SI_9105", null , null)
+ assertEnclosingMethod("SI_9105$H$1", "SI_9105", "m$2", "()Ljava/lang/Object;")
+ assertEnclosingMethod("SI_9105$I$1", "SI_9105", null , null)
+ assertEnclosingMethod("SI_9105$J$1", "SI_9105", "bnM", "()I")
+ assertEnclosingMethod("SI_9105$K$2", "SI_9105", "m$4", "()Ljava/lang/Object;")
+ assertEnclosingMethod("SI_9105$L$1", "SI_9105", "bnM", "()I")
+
+ assert(innerClassNodes("SI_9105$lambda$$met$1").isEmpty)
+ assert(innerClassNodes("SI_9105$lambda$1").isEmpty)
+ assert(innerClassNodes("SI_9105").length == 12) // the 12 local classes
+ } else {
+ // comment in innerClassAttribute/Classes_1.scala explains the difference between A / C and D / F.
+ assertEnclosingMethod ("SI_9105$$anonfun$4$A$3" , "SI_9105$$anonfun$4" , null , null)
+ assertEnclosingMethod ("SI_9105$$anonfun$4$B$5" , "SI_9105$$anonfun$4" , "m$1" , "()Ljava/lang/Object;")
+ assertEnclosingMethod ("SI_9105$$anonfun$4$C$1" , "SI_9105$$anonfun$4" , null , null)
+ assertEnclosingMethod ("SI_9105$$anonfun$met$1$D$1", "SI_9105$$anonfun$met$1", null , null)
+ assertEnclosingMethod ("SI_9105$$anonfun$met$1$E$1", "SI_9105$$anonfun$met$1", "m$3" , "()Ljava/lang/Object;")
+ assertEnclosingMethod ("SI_9105$$anonfun$met$1$F$1", "SI_9105$$anonfun$met$1", null , null)
+ assertEnclosingMethod ("SI_9105$$anonfun$4" , "SI_9105" , null , null)
+ assertEnclosingMethod ("SI_9105$$anonfun$met$1" , "SI_9105" , "met" , "()Lscala/Function0;")
+ assertNoEnclosingMethod("SI_9105")
+
+ assertLocal(ownInnerClassNode("SI_9105$$anonfun$4$A$3"), "SI_9105$$anonfun$4$A$3" , "A$3")
+ assertLocal(ownInnerClassNode("SI_9105$$anonfun$4$B$5"), "SI_9105$$anonfun$4$B$5" , "B$5")
+ assertLocal(ownInnerClassNode("SI_9105$$anonfun$4$C$1"), "SI_9105$$anonfun$4$C$1" , "C$1")
+ assertLocal(ownInnerClassNode("SI_9105$$anonfun$met$1$D$1"), "SI_9105$$anonfun$met$1$D$1", "D$1")
+ assertLocal(ownInnerClassNode("SI_9105$$anonfun$met$1$E$1"), "SI_9105$$anonfun$met$1$E$1", "E$1")
+ assertLocal(ownInnerClassNode("SI_9105$$anonfun$met$1$F$1"), "SI_9105$$anonfun$met$1$F$1", "F$1")
+
+ // by-name
+ assertEnclosingMethod("SI_9105$$anonfun$5$G$1", "SI_9105$$anonfun$5", null, null)
+ assertEnclosingMethod("SI_9105$$anonfun$5$H$1", "SI_9105$$anonfun$5", "m$2", "()Ljava/lang/Object;")
+ assertEnclosingMethod("SI_9105$$anonfun$5$I$1", "SI_9105$$anonfun$5", null, null)
+ assertEnclosingMethod("SI_9105$$anonfun$bnM$1$J$1", "SI_9105$$anonfun$bnM$1", null, null)
+ assertEnclosingMethod("SI_9105$$anonfun$bnM$1$K$2", "SI_9105$$anonfun$bnM$1", "m$4", "()Ljava/lang/Object;")
+ assertEnclosingMethod("SI_9105$$anonfun$bnM$1$L$1", "SI_9105$$anonfun$bnM$1", null, null)
+
+ assertAnonymous(ownInnerClassNode("SI_9105$$anonfun$4"), "SI_9105$$anonfun$4")
+ assertAnonymous(ownInnerClassNode("SI_9105$$anonfun$met$1"), "SI_9105$$anonfun$met$1")
+
+ assert(innerClassNodes("SI_9105$$anonfun$4").length == 4) // itself and three of the local classes
+ assert(innerClassNodes("SI_9105$$anonfun$met$1").length == 4) // itself and three of the local classes
+ assert(innerClassNodes("SI_9105").length == 4) // the four anon funs
+ }
+ }
+
+ def testSI_9124() {
+ val classes: Map[String, String] = {
+ List("SI_9124$$anon$10",
+ "SI_9124$$anon$11",
+ "SI_9124$$anon$12",
+ "SI_9124$$anon$8",
+ "SI_9124$$anon$9",
+ "SI_9124$O$$anon$13").map({ name =>
+ val node = loadClassNode(name)
+ val fMethod = node.methods.asScala.find(_.name.startsWith("f")).get.name
+ (fMethod, node.name)
+ }).toMap
+ }
+
+ // println(classes)
+
+ assertNoEnclosingMethod("SI_9124$A")
+ assertEnclosingMethod(classes("f1"), "SI_9124", null, null)
+ assertEnclosingMethod(classes("f2"), "SI_9124", "f", "()LSI_9124$A;")
+ assertEnclosingMethod(classes("f3"), "SI_9124", null, null)
+ assertEnclosingMethod(classes("f4"), "SI_9124$O$", null, null)
+ assertEnclosingMethod(classes("f5"), "SI_9124", null, null)
+ assertEnclosingMethod(classes("f6"), "SI_9124", null, null)
+ assertNoEnclosingMethod("SI_9124$O$")
+
+ assertMember(ownInnerClassNode("SI_9124$A"), "SI_9124", "A", flags = publicAbstractInterface)
+ classes.values.foreach(n => assertAnonymous(ownInnerClassNode(n), n))
+ assertMember(ownInnerClassNode("SI_9124$O$"), "SI_9124", "O$")
+ }
+
+ def testImplClassesTopLevel() {
+ val classes = List(
+ "ImplClassesAreTopLevel$$anon$14",
+ "ImplClassesAreTopLevel$$anon$15",
+ "ImplClassesAreTopLevel$$anon$16",
+ "ImplClassesAreTopLevel$B1$class",
+ "ImplClassesAreTopLevel$B1",
+ "ImplClassesAreTopLevel$B2$1$class",
+ "ImplClassesAreTopLevel$B2$1",
+ "ImplClassesAreTopLevel$B3$1$class",
+ "ImplClassesAreTopLevel$B3$1",
+ "ImplClassesAreTopLevel$B4$class",
+ "ImplClassesAreTopLevel$B4$1",
+ "ImplClassesAreTopLevel$class",
+ "ImplClassesAreTopLevel")
+
+ classes.filter(_.endsWith("$class")).foreach(assertNoEnclosingMethod)
+ classes.flatMap(innerClassNodes).foreach(icn => assert(!icn.name.endsWith("$class"), icn))
+
+ assertNoEnclosingMethod("ImplClassesAreTopLevel$B1") // member, no encl meth attr
+
+ // no encl meth, but encl class
+ List("ImplClassesAreTopLevel$B2$1", "ImplClassesAreTopLevel$B3$1",
+ "ImplClassesAreTopLevel$$anon$14", "ImplClassesAreTopLevel$$anon$15").foreach(assertEnclosingMethod(_, "ImplClassesAreTopLevel", null, null))
+
+ // encl meth n
+ List("ImplClassesAreTopLevel$B4$1", "ImplClassesAreTopLevel$$anon$16").foreach(assertEnclosingMethod(_, "ImplClassesAreTopLevel", "n", "()Ljava/lang/Object;"))
+
+ val an14 = assertAnonymous(_: InnerClassNode, "ImplClassesAreTopLevel$$anon$14")
+ val an15 = assertAnonymous(_: InnerClassNode, "ImplClassesAreTopLevel$$anon$15")
+ val an16 = assertAnonymous(_: InnerClassNode, "ImplClassesAreTopLevel$$anon$16")
+ val b1 = assertMember(_: InnerClassNode, "ImplClassesAreTopLevel", "B1", flags = publicAbstractInterface)
+ val b2 = assertLocal(_ : InnerClassNode, "ImplClassesAreTopLevel$B2$1", "B2$1", flags = publicAbstractInterface)
+ val b3 = assertLocal(_ : InnerClassNode, "ImplClassesAreTopLevel$B3$1", "B3$1", flags = publicAbstractInterface)
+ val b4 = assertLocal(_ : InnerClassNode, "ImplClassesAreTopLevel$B4$1", "B4$1", flags = publicAbstractInterface)
+
+ testInner("ImplClassesAreTopLevel$$anon$14", an14, b3)
+ testInner("ImplClassesAreTopLevel$$anon$15", an15, b2)
+ testInner("ImplClassesAreTopLevel$$anon$16", an16, b4)
+
+ testInner("ImplClassesAreTopLevel$B1$class", b1)
+ testInner("ImplClassesAreTopLevel$B2$1$class", b2)
+ testInner("ImplClassesAreTopLevel$B3$1$class", b3)
+ testInner("ImplClassesAreTopLevel$B4$class", b4)
+
+ testInner("ImplClassesAreTopLevel$B1", b1)
+ testInner("ImplClassesAreTopLevel$B2$1", b2)
+ testInner("ImplClassesAreTopLevel$B3$1", b3)
+ testInner("ImplClassesAreTopLevel$B4$1", b4)
+
+ testInner("ImplClassesAreTopLevel$class", an14, an15, an16)
+ testInner("ImplClassesAreTopLevel", an14, an15, an16, b1, b2, b3, b4)
+ }
+
+ def testSpecializedClassesTopLevel() {
+ val cls = List(
+ "SpecializedClassesAreTopLevel$A$mcI$sp",
+ "SpecializedClassesAreTopLevel$A",
+ "SpecializedClassesAreTopLevel$T$",
+ "SpecializedClassesAreTopLevel$T$B$mcI$sp",
+ "SpecializedClassesAreTopLevel$T$B",
+ "SpecializedClassesAreTopLevel")
+
+ // all classes are members, no local (can't test local, they crash in specialize)
+ cls.foreach(assertNoEnclosingMethod)
+ cls.flatMap(innerClassNodes).foreach(icn => assert(!icn.name.endsWith("$sp"), icn))
+
+ val a = assertMember(_: InnerClassNode, "SpecializedClassesAreTopLevel", "A")
+ val t = assertMember(_: InnerClassNode, "SpecializedClassesAreTopLevel", "T$")
+ val b = assertMember(_: InnerClassNode, "SpecializedClassesAreTopLevel$T$", "B", Some("SpecializedClassesAreTopLevel$T$B"))
+
+ List("SpecializedClassesAreTopLevel$A$mcI$sp", "SpecializedClassesAreTopLevel$A").foreach(testInner(_, a))
+ testInner("SpecializedClassesAreTopLevel", a, t)
+ List("SpecializedClassesAreTopLevel$T$", "SpecializedClassesAreTopLevel$T$B$mcI$sp", "SpecializedClassesAreTopLevel$T$B").foreach(testInner(_, t, b))
+ }
+
+ def testNestedInValueClass() {
+ List(
+ "NestedInValueClass",
+ "NestedInValueClass$",
+ "NestedInValueClass$A",
+ "NestedInValueClass$A$",
+ "NestedInValueClass$A$B").foreach(assertNoEnclosingMethod)
+
+ assertEnclosingMethod("NestedInValueClass$A$C$2", "NestedInValueClass$A$", "f", "()Ljava/lang/Object;")
+
+ type I = InnerClassNode
+ val a = assertMember(_: I, "NestedInValueClass", "A", flags = publicStatic | Flags.ACC_FINAL)
+ val am = assertMember(_: I, "NestedInValueClass", "A$", flags = publicStatic)
+ val b = assertMember(_: I, "NestedInValueClass$A$", "B", Some("NestedInValueClass$A$B"), flags = publicStatic)
+ val c = assertLocal(_: I, "NestedInValueClass$A$C$2", "C$2")
+
+ testInner("NestedInValueClass$")
+ testInner("NestedInValueClass", a, am)
+ testInner("NestedInValueClass$A$B", am, b)
+ testInner("NestedInValueClass$A$C$2", am, c)
+
+ val isDelambdafyMethod = classpath.findClass("NestedInValueClass$A$lambda$$f$extension$1").isDefined
+ if (isDelambdafyMethod) {
+ List(
+ "NestedInValueClass$A$lambda$$g$2$1",
+ "NestedInValueClass$A$lambda$$f$extension$1",
+ "NestedInValueClass$A$lambda$$$nestedInAnonfun$13$1",
+ "NestedInValueClass$A$lambda$$$nestedInAnonfun$15$1").foreach(assertNoEnclosingMethod)
+ testInner("NestedInValueClass$A", a, am)
+ testInner("NestedInValueClass$A$", a, am, b, c)
+ testInner("NestedInValueClass$A$lambda$$g$2$1", am)
+ testInner("NestedInValueClass$A$lambda$$f$extension$1", am)
+ testInner("NestedInValueClass$A$lambda$$$nestedInAnonfun$13$1", am)
+ testInner("NestedInValueClass$A$lambda$$$nestedInAnonfun$15$1", am)
+ } else {
+ assertEnclosingMethod("NestedInValueClass$A$$anonfun$g$2$1" , "NestedInValueClass$A" , null, null)
+ assertEnclosingMethod("NestedInValueClass$A$$anonfun$g$2$1$$anonfun$apply$4" , "NestedInValueClass$A$$anonfun$g$2$1" , null, null)
+ assertEnclosingMethod("NestedInValueClass$A$$anonfun$f$extension$1" , "NestedInValueClass$A" , "f", "()Lscala/collection/immutable/List;")
+ assertEnclosingMethod("NestedInValueClass$A$$anonfun$f$extension$1$$anonfun$apply$5", "NestedInValueClass$A$$anonfun$f$extension$1", null, null)
+
+ val gfun = assertAnonymous(_: I, "NestedInValueClass$A$$anonfun$g$2$1")
+ val ffun = assertAnonymous(_: I, "NestedInValueClass$A$$anonfun$f$extension$1")
+ val gfunfun = assertAnonymous(_: I, "NestedInValueClass$A$$anonfun$g$2$1$$anonfun$apply$4")
+ val ffunfun = assertAnonymous(_: I, "NestedInValueClass$A$$anonfun$f$extension$1$$anonfun$apply$5")
+
+ testInner("NestedInValueClass$A", a, am, ffun, gfun)
+ testInner("NestedInValueClass$A$", a, am, ffun, gfun, b, c)
+ testInner("NestedInValueClass$A$$anonfun$g$2$1", a, am, gfun, gfunfun)
+ testInner("NestedInValueClass$A$$anonfun$g$2$1$$anonfun$apply$4", am, gfun, gfunfun)
+ testInner("NestedInValueClass$A$$anonfun$f$extension$1", a, am, ffun, ffunfun)
+ testInner("NestedInValueClass$A$$anonfun$f$extension$1$$anonfun$apply$5", am, ffun, ffunfun)
+ }
}
def show(): Unit = {
@@ -347,5 +583,10 @@ object Test extends BytecodeTest {
testA22()
testA23()
testA24()
+ testSI_9105()
+ testSI_9124()
+ testImplClassesTopLevel()
+ testSpecializedClassesTopLevel()
+ testNestedInValueClass()
}
}
diff --git a/test/files/jvm/innerClassEnclMethodJavaReflection.scala b/test/files/jvm/innerClassEnclMethodJavaReflection.scala
new file mode 100644
index 0000000000..ee39cb43bf
--- /dev/null
+++ b/test/files/jvm/innerClassEnclMethodJavaReflection.scala
@@ -0,0 +1,65 @@
+import scala.reflect.io._
+import java.net.URLClassLoader
+
+object Test extends App {
+ val jarsOrDirectories = Set("partest.lib", "partest.reflect", "partest.comp") map sys.props
+
+ object AllowedMissingClass {
+ // Some classes in scala-compiler.jar have references to jline / ant classes, which seem to be
+ // not on the classpath. We just skip over those classes.
+ // PENDING: for now we also allow missing $anonfun classes: the optimizer may eliminate some closures
+ // that are refferred to in EnclosingClass attributes. SI-9136
+ val allowedMissingPackages = Set("jline", "org.apache.tools.ant", "$anonfun")
+
+ def ok(t: Throwable) = {
+ allowedMissingPackages.exists(p => t.getMessage.replace('/', '.').contains(p))
+ }
+
+ def unapply(t: Throwable): Option[Throwable] = t match {
+ case _: NoClassDefFoundError | _: ClassNotFoundException | _: TypeNotPresentException if ok(t) => Some(t)
+ case _ => None
+ }
+ }
+
+ jarsOrDirectories foreach testClasses
+
+ def testClasses(jarOrDirectory: String): Unit = {
+ val classPath = AbstractFile.getDirectory(new java.io.File(jarOrDirectory))
+
+ def flatten(f: AbstractFile): Iterator[AbstractFile] =
+ if (f.isClassContainer) f.iterator.flatMap(flatten)
+ else Iterator(f)
+
+ val classFullNames = flatten(classPath).filter(_.hasExtension("class")).map(_.path.replace("/", ".").replaceAll(".class$", ""))
+
+ // it seems that Class objects can only be GC'd together with their class loader
+ // (http://stackoverflow.com/questions/2433261/when-and-how-are-classes-garbage-collected-in-java)
+ // if we just use the same class loader for the entire test (Class.forName), we run out of PermGen
+ // even with that, we still neeed a PermGen of 90M or so, the default 64 is not enough. I tried
+ // using one class loader per 100 classes, but that didn't help, the classes didn't get GC'd.
+ val classLoader = new URLClassLoader(Array(classPath.toURL))
+
+ val faulty = new collection.mutable.ListBuffer[(String, Throwable)]
+
+ def tryGetClass(name: String) = try {
+ Some[Class[_]](classLoader.loadClass(name))
+ } catch {
+ case AllowedMissingClass(_) => None
+ }
+
+ for (name <- classFullNames; cls <- tryGetClass(name)) {
+ try {
+ cls.getEnclosingMethod
+ cls.getEnclosingClass
+ cls.getEnclosingConstructor
+ cls.getDeclaredClasses
+ } catch {
+ case AllowedMissingClass(_) =>
+ case t: Throwable => faulty += ((name, t))
+ }
+ }
+
+ if (faulty.nonEmpty)
+ println(faulty.toList mkString "\n")
+ }
+}
diff --git a/test/files/jvm/javaReflection.check b/test/files/jvm/javaReflection.check
index d40599507d..8180ecff8a 100644
--- a/test/files/jvm/javaReflection.check
+++ b/test/files/jvm/javaReflection.check
@@ -5,7 +5,7 @@ A$$anonfun$$lessinit$greater$1 / null (canon) / $anonfun$$lessinit$greater$1 (si
- properties : true (local) / false (member)
A$$anonfun$$lessinit$greater$1$$anonfun$apply$1 / null (canon) / $anonfun$apply$1 (simple)
- declared cls: List()
-- enclosing : null (declaring cls) / class A$$anonfun$$lessinit$greater$1 (cls) / null (constr) / public final scala.Function0 A$$anonfun$$lessinit$greater$1.apply() (meth)
+- enclosing : null (declaring cls) / class A$$anonfun$$lessinit$greater$1 (cls) / null (constr) / null (meth)
- properties : true (local) / false (member)
A$$anonfun$2 / null (canon) / $anonfun$2 (simple)
- declared cls: List()
diff --git a/test/files/jvm/t9105.check b/test/files/jvm/t9105.check
new file mode 100644
index 0000000000..34750833f1
--- /dev/null
+++ b/test/files/jvm/t9105.check
@@ -0,0 +1,18 @@
+#partest !-Ydelambdafy:method
+(class C$$anonfun$1$A$1,class C$$anonfun$1,null)
+(class C$$anonfun$1$B$1,class C$$anonfun$1,private final java.lang.Object C$$anonfun$1.m$1())
+(class C$$anonfun$1$C$1,class C$$anonfun$1,null)
+(class C$$anonfun$1$$anonfun$2$D$1,class C$$anonfun$1$$anonfun$2,null)
+(class C$$anonfun$met$1$E$1,class C$$anonfun$met$1,null)
+(class C$$anonfun$met$1$F$1,class C$$anonfun$met$1,private final java.lang.Object C$$anonfun$met$1.m$2())
+(class C$$anonfun$met$1$G$1,class C$$anonfun$met$1,null)
+(class C$$anonfun$met$1$$anonfun$3$H$1,class C$$anonfun$met$1$$anonfun$3,null)
+#partest -Ydelambdafy:method
+(class C$A$1,class C,null)
+(class C$B$1,class C,private final java.lang.Object C.m$1())
+(class C$C$1,class C,null)
+(class C$D$1,class C,null)
+(class C$E$1,class C,public scala.Function0 C.met())
+(class C$F$1,class C,private final java.lang.Object C.m$2())
+(class C$G$1,class C,public scala.Function0 C.met())
+(class C$H$1,class C,public scala.Function0 C.met())
diff --git a/test/files/jvm/t9105.scala b/test/files/jvm/t9105.scala
new file mode 100644
index 0000000000..636ee8a768
--- /dev/null
+++ b/test/files/jvm/t9105.scala
@@ -0,0 +1,22 @@
+class C {
+ val fun = () => {
+ class A
+ def m: Object = { class B; new B }
+ val f: Object = { class C; new C }
+ val g = () => { class D; new D }
+ List[Object](new A, m, f, g())
+ }
+ def met = () => {
+ class E
+ def m: Object = { class F; new F }
+ val f: Object = { class G; new G }
+ val g = () => { class H; new H }
+ List[Object](new E, m, f, g())
+ }
+}
+
+object Test extends App {
+ val x = new C().fun.apply() ::: new C().met.apply()
+ val results = x.map(_.getClass).map(cls => (cls, cls.getEnclosingClass, cls.getEnclosingMethod))
+ println(results.mkString("\n"))
+}
diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check
index 20ddd55f1f..2db24b6f32 100644
--- a/test/files/neg/names-defaults-neg.check
+++ b/test/files/neg/names-defaults-neg.check
@@ -151,15 +151,15 @@ names-defaults-neg.scala:144: error: variable definition needs type because 'x'
names-defaults-neg.scala:147: error: variable definition needs type because 'x' is used as a named argument in its body.
object t6 { var x = t.f(x = 1) }
^
-names-defaults-neg.scala:147: warning: type-checking the invocation of method f checks if the named argument expression 'x = ...' is a valid assignment
-in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for x.
+names-defaults-neg.scala:147: warning: failed to determine if 'x = ...' is a named argument or an assignment expression.
+an explicit type is required for the definition mentioned in the error message above.
object t6 { var x = t.f(x = 1) }
^
names-defaults-neg.scala:150: error: variable definition needs type because 'x' is used as a named argument in its body.
class t9 { var x = t.f(x = 1) }
^
-names-defaults-neg.scala:150: warning: type-checking the invocation of method f checks if the named argument expression 'x = ...' is a valid assignment
-in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for x.
+names-defaults-neg.scala:150: warning: failed to determine if 'x = ...' is a named argument or an assignment expression.
+an explicit type is required for the definition mentioned in the error message above.
class t9 { var x = t.f(x = 1) }
^
names-defaults-neg.scala:164: error: variable definition needs type because 'x' is used as a named argument in its body.
@@ -174,8 +174,8 @@ names-defaults-neg.scala:170: error: reference to x is ambiguous; it is both a m
names-defaults-neg.scala:177: error: variable definition needs type because 'x' is used as a named argument in its body.
class u15 { var x = u.f(x = 1) }
^
-names-defaults-neg.scala:177: warning: type-checking the invocation of method f checks if the named argument expression 'x = ...' is a valid assignment
-in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for x.
+names-defaults-neg.scala:177: warning: failed to determine if 'x = ...' is a named argument or an assignment expression.
+an explicit type is required for the definition mentioned in the error message above.
class u15 { var x = u.f(x = 1) }
^
names-defaults-neg.scala:180: error: reference to x is ambiguous; it is both a method parameter and a variable in scope.
diff --git a/test/files/neg/t5044.check b/test/files/neg/t5044.check
index 197da2a4e8..dc3708123f 100644
--- a/test/files/neg/t5044.check
+++ b/test/files/neg/t5044.check
@@ -1,8 +1,8 @@
t5044.scala:7: error: recursive value a needs type
val id = m(a)
^
-t5044.scala:6: warning: type-checking the invocation of method foo checks if the named argument expression 'id = ...' is a valid assignment
-in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for id.
+t5044.scala:6: warning: failed to determine if 'id = ...' is a named argument or an assignment expression.
+an explicit type is required for the definition mentioned in the error message above.
val a = foo(id = 1)
^
one warning found
diff --git a/test/files/neg/t5091.check b/test/files/neg/t5091.check
index abd24e3145..156f695f41 100644
--- a/test/files/neg/t5091.check
+++ b/test/files/neg/t5091.check
@@ -1,8 +1,8 @@
t5091.scala:8: error: recursive value xxx needs type
val param = bar(xxx)
^
-t5091.scala:7: warning: type-checking the invocation of method foo checks if the named argument expression 'param = ...' is a valid assignment
-in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for param.
+t5091.scala:7: warning: failed to determine if 'param = ...' is a named argument or an assignment expression.
+an explicit type is required for the definition mentioned in the error message above.
val xxx = foo(param = null)
^
one warning found
diff --git a/test/files/neg/t8463.check b/test/files/neg/t8463.check
index 1a3eea2870..9aaacf8391 100644
--- a/test/files/neg/t8463.check
+++ b/test/files/neg/t8463.check
@@ -7,4 +7,21 @@ Note that implicit conversions are not applicable because they are ambiguous:
are possible conversion functions from Long to ?T[Long]
insertCell(Foo(5))
^
-one error found
+t8463.scala:5: error: no type parameters for method apply: (activity: T[Long])Test.Foo[T] in object Foo exist so that it can be applied to arguments (Long)
+ --- because ---
+argument expression's type is not compatible with formal parameter type;
+ found : Long
+ required: ?T[Long]
+ insertCell(Foo(5))
+ ^
+t8463.scala:5: error: type mismatch;
+ found : Long(5L)
+ required: T[Long]
+ insertCell(Foo(5))
+ ^
+t8463.scala:5: error: type mismatch;
+ found : Test.Foo[T]
+ required: Test.Foo[Test.Cell]
+ insertCell(Foo(5))
+ ^
+four errors found
diff --git a/test/files/neg/t8841.check b/test/files/neg/t8841.check
new file mode 100644
index 0000000000..ad525dc3f8
--- /dev/null
+++ b/test/files/neg/t8841.check
@@ -0,0 +1,9 @@
+t8841.scala:13: error: recursive value c needs type
+ val ambiguousName = c.ambiguousName
+ ^
+t8841.scala:12: warning: failed to determine if 'ambiguousName = ...' is a named argument or an assignment expression.
+an explicit type is required for the definition mentioned in the error message above.
+ val c = new Cell(ambiguousName = Some("bla"))
+ ^
+one warning found
+one error found
diff --git a/test/files/neg/t8841.scala b/test/files/neg/t8841.scala
new file mode 100644
index 0000000000..80430d997e
--- /dev/null
+++ b/test/files/neg/t8841.scala
@@ -0,0 +1,15 @@
+class Cell(val ambiguousName: Option[String])
+
+class Test {
+ def wrap(f: Any): Nothing = ???
+
+ wrap {
+ // the namer for these two ValDefs is created when typing the argument expression
+ // of wrap. This happens to be in a silent context (tryTypedApply). Therefore, the
+ // cyclic reference will not be thrown, but transformed into a NormalTypeError by
+ // `silent`. This requires different handling in NamesDefaults.
+
+ val c = new Cell(ambiguousName = Some("bla"))
+ val ambiguousName = c.ambiguousName
+ }
+}
diff --git a/test/files/pos/t9116.scala b/test/files/pos/t9116.scala
new file mode 100644
index 0000000000..16b04c2e6b
--- /dev/null
+++ b/test/files/pos/t9116.scala
@@ -0,0 +1,7 @@
+
+trait X {
+ List(1, 2, 3).toSet.subsets.map(_.toList) // ok now
+
+ List(1, 2, 3).toSet.subsets().map(_.toList) // now also
+ List(1, 2, 3).toSet.subsets(2).map(_.toList) // still ok
+}
diff --git a/test/files/pos/t9157.scala b/test/files/pos/t9157.scala
new file mode 100644
index 0000000000..e178b5d84d
--- /dev/null
+++ b/test/files/pos/t9157.scala
@@ -0,0 +1,13 @@
+trait Flow[-In, +Out] {
+ type Repr[+O] <: Flow[In, O]
+ def map: Repr[String]
+}
+
+class Test {
+ // typechecking was exponentially slow wrt the number of projections here.
+ def slowFlow(
+ f: Flow[String,String]#Repr[String]#Repr[String]#Repr[String]#Repr[String]#Repr[String]#Repr[String]#Repr[String]#Repr[String]#Repr[String]#Repr[String]#Repr[String]
+ ) = {
+ f.map
+ }
+}
diff --git a/test/files/run/settings-parse.scala b/test/files/run/settings-parse.scala
index 2754feb972..8d83caf68f 100644
--- a/test/files/run/settings-parse.scala
+++ b/test/files/run/settings-parse.scala
@@ -3,9 +3,8 @@ import scala.language.postfixOps
import scala.tools.nsc._
object Test {
- val tokens = List("", "-deprecation", "foo.scala")
- val subsets = tokens.toSet.subsets.toList
- val permutations0 = subsets.flatMap(_.toList.permutations).distinct
+ val tokens = "" :: "-deprecation" :: "foo.scala" :: Nil
+ val permutations0 = tokens.toSet.subsets.flatMap(_.toList.permutations).toList.distinct
def runWithCp(cp: String) = {
val permutations = permutations0 flatMap ("-cp CPTOKEN" :: _ permutations)
diff --git a/test/junit/scala/reflect/ClassTag.scala b/test/junit/scala/reflect/ClassTag.scala
new file mode 100644
index 0000000000..90cc981fc1
--- /dev/null
+++ b/test/junit/scala/reflect/ClassTag.scala
@@ -0,0 +1,29 @@
+package scala.reflect
+
+import org.junit.Test
+import org.junit.Assert._
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.tools.testing.AssertUtil._
+
+class Misc
+
+@RunWith(classOf[JUnit4])
+class ClassTagTest {
+ def checkNotString[A: ClassTag](a: Any) = a match { case x: String => false case x: A => true case _ => false }
+ def checkNotInt[A: ClassTag](a: Any) = a match { case x: Int => false case x: A => true case _ => false }
+ def checkNotLong[A: ClassTag](a: Any) = a match { case x: Long => false case x: A => true case _ => false }
+
+ @Test def checkMisc = assertTrue(checkNotString[Misc](new Misc))
+ @Test def checkString = assertTrue(checkNotInt[String] ("woele"))
+ @Test def checkByte = assertTrue(checkNotInt[Byte] (0.toByte))
+ @Test def checkShort = assertTrue(checkNotInt[Short] (0.toShort))
+ @Test def checkChar = assertTrue(checkNotInt[Char] (0.toChar))
+ @Test def checkInt = assertTrue(checkNotLong[Int] (0.toInt))
+ @Test def checkLong = assertTrue(checkNotInt[Long] (0.toLong))
+ @Test def checkFloat = assertTrue(checkNotInt[Float] (0.toFloat))
+ @Test def checkDouble = assertTrue(checkNotInt[Double] (0.toDouble))
+ @Test def checkBoolean = assertTrue(checkNotInt[Boolean](false))
+ @Test def checkUnit = assertTrue(checkNotInt[Unit] ({}))
+} \ No newline at end of file
diff --git a/test/junit/scala/tools/nsc/symtab/FreshNameExtractorTest.scala b/test/junit/scala/tools/nsc/symtab/FreshNameExtractorTest.scala
index effbfb2f7c..7796345351 100644
--- a/test/junit/scala/tools/nsc/symtab/FreshNameExtractorTest.scala
+++ b/test/junit/scala/tools/nsc/symtab/FreshNameExtractorTest.scala
@@ -32,16 +32,16 @@ class FreshNameExtractorTest {
val Creator = new FreshNameCreator(prefixes.head)
val Extractor = new FreshNameExtractor(prefixes.tail.head)
assertThrows[MatchError] {
- val Extractor(_) = TermName(Creator.newName("foo"))
+ TermName(Creator.newName("foo")) match { case Extractor(_) => }
}
}
- @Test @org.junit.Ignore // SI-8818
- def extractionsFailsIfNameDoesntEndWithNumber = {
- val Creator = new FreshNameCreator(prefixes.head)
+ @Test
+ def `no numeric suffix? no problem!` = {
+ val Creator = new FreshNameCreator(prefixes.head)
val Extractor = new FreshNameExtractor(prefixes.head)
- assertThrows[MatchError] {
- val Extractor(_) = TermName(Creator.newName("foo") + "bar")
+ TermName(Creator.newName("foo") + "bar") match {
+ case Extractor(_) =>
}
}
}
diff --git a/test/junit/scala/tools/testing/AssertUtil.scala b/test/junit/scala/tools/testing/AssertUtil.scala
index d29f9a473f..d798f2e53e 100644
--- a/test/junit/scala/tools/testing/AssertUtil.scala
+++ b/test/junit/scala/tools/testing/AssertUtil.scala
@@ -36,21 +36,20 @@ object AssertUtil {
}
}
- /** 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.
+ /** Check that throwable T (or a subclass) was thrown during evaluation of `body`,
+ * and that its message satisfies the `checkMessage` predicate.
+ * Any other exception is propagated.
*/
- def assertThrows[T <: Throwable](f: => Any,
+ def assertThrows[T <: Throwable](body: => Any,
checkMessage: String => Boolean = s => true)
(implicit manifest: Manifest[T]): Unit = {
- try f
- catch {
- case e: Throwable if checkMessage(e.getMessage) =>
- val clazz = manifest.runtimeClass
- if (!clazz.isAssignableFrom(e.getClass))
- throw e
- else return
+ try {
+ body
+ fail("Expression did not throw!")
+ } catch {
+ case e: Throwable if (manifest.runtimeClass isAssignableFrom e.getClass) &&
+ checkMessage(e.getMessage) =>
}
- fail("Expression did not throw!")
}
/** JUnit-style assertion for `IterableLike.sameElements`.
diff --git a/test/junit/scala/util/RandomTest.scala b/test/junit/scala/util/RandomTest.scala
new file mode 100644
index 0000000000..32959675ee
--- /dev/null
+++ b/test/junit/scala/util/RandomTest.scala
@@ -0,0 +1,15 @@
+package scala.util
+
+import org.junit.{ Assert, Test }
+
+class RandomTest {
+ // Test for SI-9059
+ @Test def testAlphanumeric: Unit = {
+ def isAlphaNum(c: Char) = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')
+
+ val items = Random.alphanumeric.take(100000)
+ for (c <- items) {
+ Assert.assertTrue(s"$c should be alphanumeric", isAlphaNum(c))
+ }
+ }
+}
diff --git a/versions.properties b/versions.properties
index 88271da4eb..fa08e56346 100644
--- a/versions.properties
+++ b/versions.properties
@@ -24,10 +24,10 @@ scala-continuations-library.version.number=1.0.2
scala-swing.version.number=1.0.1
akka-actor.version.number=2.3.4
actors-migration.version.number=1.1.0
-jline.version=2.12
+jline.version=2.12.1
# external modules, used internally (not shipped)
-partest.version.number=1.0.3
+partest.version.number=1.0.5
scalacheck.version.number=1.11.4
# TODO: modularize the compiler