summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2015-02-03 11:29:08 +0100
committerLukas Rytz <lukas.rytz@gmail.com>2015-02-07 07:45:53 +0100
commitb2e22fa308b2f402d78dc3d3afc33256c1d3cbba (patch)
treee7bdb44726dd50866465af28618f643ab391867b
parentcd8f2f327106c7e2944afa7ac8b7675262626c1e (diff)
downloadscala-b2e22fa308b2f402d78dc3d3afc33256c1d3cbba.tar.gz
scala-b2e22fa308b2f402d78dc3d3afc33256c1d3cbba.tar.bz2
scala-b2e22fa308b2f402d78dc3d3afc33256c1d3cbba.zip
Fix InnerClass / EnclosingMethod for closures nested in value classes
Members of value classes are moved over to the companion object early. This change ensures that closure classes nested in value classes appear that way to Java reflection. This commit also changes the EnclosingMethod attribute for classes (and anonymous functions) nested in anonymous function bodies. Before, the enclosing method was in some cases the function's apply method. Not always though: () => { class C ... val a = { class D ...} } The class C used to be nested in the function's apply method, but not D, because the value definition for a was lifted out of the apply. After this commit, we uniformly set the enclosing method of classes nested in function bodies to `null`. This is consistent with the source-level view of the code. Note that under delambdafy:method, closures never appear as enclosing classes (this didn't change in this commit).
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala48
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala37
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala30
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala4
-rw-r--r--src/interactive/scala/tools/nsc/interactive/Global.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala7
-rw-r--r--test/files/jvm/innerClassAttribute.check10
-rw-r--r--test/files/jvm/innerClassAttribute/Classes_1.scala18
-rw-r--r--test/files/jvm/innerClassAttribute/Test.scala69
-rw-r--r--test/files/jvm/javaReflection.check2
10 files changed, 189 insertions, 38 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala
index fb9804be7f..27827015c3 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala
@@ -109,6 +109,15 @@ final class BCodeAsmCommon[G <: Global](val global: G) {
}
}
+ def nextEnclosingClass(sym: Symbol): Symbol = {
+ if (sym.isClass) sym
+ else nextEnclosingClass(nextEnclosing(sym))
+ }
+
+ def classOriginallyNestedInClass(nestedClass: Symbol, enclosingClass: Symbol) ={
+ nextEnclosingClass(nextEnclosing(nestedClass)) == enclosingClass
+ }
+
/**
* Returns the enclosing method for non-member classes. In the following example
*
@@ -134,12 +143,23 @@ 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) {
- // SI-9124, some trait methods don't exist in the generated interface. see comment in BTypes.
- if (sym.owner.isTrait && sym.isImplOnly) None
- else Some(sym)
+ if (doesNotExist(sym)) None else Some(sym)
}
else enclosingMethod(nextEnclosing(sym))
}
@@ -152,11 +172,7 @@ 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(nextEnclosing(sym))
- }
- val r = enclosingClass(nextEnclosing(classSym))
+ 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
@@ -175,10 +191,20 @@ final class BCodeAsmCommon[G <: Global](val global: G) {
def enclosingMethodAttribute(classSym: Symbol, classDesc: Symbol => String, methodDesc: Symbol => String): Option[EnclosingMethodEntry] = {
// trait impl classes are always top-level, see comment in BTypes
if (isAnonymousOrLocalClass(classSym) && !considerAsTopLevelImplementationArtifact(classSym)) {
- val methodOpt = enclosingMethodForEnclosingMethodAttribute(classSym)
- debuglog(s"enclosing method for $classSym is $methodOpt (in ${methodOpt.map(_.enclClass)})")
+ 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 {
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
index 52d5cafc9c..2af665d31c 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
@@ -125,11 +125,21 @@ 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)(memberClassesForInnerClassTable(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.
@@ -158,13 +168,28 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
// 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 linkedClass = exitingPickler(classSym.linkedClassOfClass) // linkedCoC does not work properly in late phases
- if (linkedClass != NoSymbol && isTopLevelModuleClass(linkedClass))
+ 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
+ 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
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index 0543929aef..707336e5de 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -700,30 +700,48 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self =>
else innerSym.rawname + innerSym.moduleSuffix
}
+ val linkedClass = exitingPickler(csym.linkedClassOfClass) // linkedCoC does not work properly in late phases
+
innerClassBuffer ++= {
val members = exitingPickler(memberClassesForInnerClassTable(csym))
// lambdalift makes all classes (also local, anonymous) members of their enclosing class
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.
+ // 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
+ 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.
+ // 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.
- val linkedClass = exitingPickler(csym.linkedClassOfClass) // linkedCoC does not work properly in late phases
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))
}
+
+ // 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/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/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/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/test/files/jvm/innerClassAttribute.check b/test/files/jvm/innerClassAttribute.check
index 8395ff0b09..bb532e4f36 100644
--- a/test/files/jvm/innerClassAttribute.check
+++ b/test/files/jvm/innerClassAttribute.check
@@ -30,11 +30,11 @@ fun4: () => 1: itself and the two outer closures
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 the apply method of the outer closure
+enclosing: nested closures have outer class defined, but no outer method
A20 / null / null
-A20$$anonfun$6 / apply / ()Lscala/Function0;
-A20$$anonfun$6 / apply / ()Lscala/Function0;
-A20$$anonfun$6$$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 e58fd6e26f..fb1f32aa3d 100644
--- a/test/files/jvm/innerClassAttribute/Classes_1.scala
+++ b/test/files/jvm/innerClassAttribute/Classes_1.scala
@@ -277,3 +277,21 @@ class SpecializedClassesAreTopLevel {
// 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 16e5d40052..bc9aa2376a 100644
--- a/test/files/jvm/innerClassAttribute/Test.scala
+++ b/test/files/jvm/innerClassAttribute/Test.scala
@@ -225,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(
@@ -236,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",
@@ -280,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)
@@ -336,7 +336,7 @@ object Test extends BytecodeTest {
def testSI_9105() {
val isDelambdafyMethod = classpath.findClass("SI_9105$lambda$1").isDefined
if (isDelambdafyMethod) {
- assertEnclosingMethod ("SI_9105$A$2" , "SI_9105", null , null)
+ 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;")
@@ -346,7 +346,7 @@ object Test extends BytecodeTest {
assertNoEnclosingMethod("SI_9105$lambda$1")
assertNoEnclosingMethod("SI_9105")
- assertLocal(innerClassNodes("SI_9105$A$2").head, "SI_9105$A$2", "A$2")
+ 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")
@@ -366,7 +366,7 @@ object Test extends BytecodeTest {
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$2" , "SI_9105$$anonfun$4" , null , null)
+ 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)
@@ -376,7 +376,7 @@ object Test extends BytecodeTest {
assertEnclosingMethod ("SI_9105$$anonfun$met$1" , "SI_9105" , "met" , "()Lscala/Function0;")
assertNoEnclosingMethod("SI_9105")
- assertLocal(ownInnerClassNode("SI_9105$$anonfun$4$A$2"), "SI_9105$$anonfun$4$A$2" , "A$2")
+ 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")
@@ -506,6 +506,60 @@ object Test extends BytecodeTest {
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 = {
testA1()
testA2()
@@ -533,5 +587,6 @@ object Test extends BytecodeTest {
testSI_9124()
testImplClassesTopLevel()
testSpecializedClassesTopLevel()
+ testNestedInValueClass()
}
}
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()