summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/files/jvm/innerClassAttribute/Test.scala29
-rw-r--r--test/files/jvm/t8582.check6
-rw-r--r--test/files/jvm/t8582.scala4
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala2
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala95
5 files changed, 115 insertions, 21 deletions
diff --git a/test/files/jvm/innerClassAttribute/Test.scala b/test/files/jvm/innerClassAttribute/Test.scala
index 1c1a0522e4..3820048cb4 100644
--- a/test/files/jvm/innerClassAttribute/Test.scala
+++ b/test/files/jvm/innerClassAttribute/Test.scala
@@ -84,17 +84,15 @@ object Test extends BytecodeTest {
}
def testA3() = {
- def t(c: String) = {
- val List(b1, b2) = innerClassNodes(c)
- // the outer class for classes nested inside top-level modules is not the module class, but the mirror class.
- // this is a hack for java interop, handled in the backend. see BTypes.scala, comment on "Java Compatibility".
- assertMember(b1, "A3", "B1", flags = publicStatic)
- assertMember(b2, "A3", "B2$", flags = publicStatic)
- }
- t("A3$")
- // the mirror class has the same inner class attributes as the module
- // class (added when the mirror is created in the backend)
- t("A3")
+ // the inner class entries for top-level object members are in the companion class, so nothing in the module class
+ val List() = innerClassNodes("A3$")
+
+ // inner class entries in the companion class (a backend-generated mirror class in this case)
+ val List(b1, b2) = innerClassNodes("A3")
+ // the outer class for classes nested inside top-level modules is not the module class, but the mirror class.
+ // this is a hack for java interop, handled in the backend. see BTypes.scala, comment on "Java Compatibility".
+ assertMember(b1, "A3", "B1", flags = publicStatic)
+ assertMember(b2, "A3", "B2$", flags = publicStatic)
}
def testA4() = {
@@ -164,7 +162,10 @@ object Test extends BytecodeTest {
}
def testA15() = {
- val List(b) = innerClassNodes("A15")
+ // no member classes, only anonymous / local. these are nested in the module class, not the companion.
+ val List() = innerClassNodes("A15")
+
+ val List(b) = innerClassNodes("A15$")
assertLocal(b, "A15$B$3", "B$3")
val List(_, c) = innerClassNodes("A15$B$3")
@@ -283,9 +284,7 @@ object Test extends BytecodeTest {
assertMember(i3c, "A21", "I3$", flags = publicStatic)
assertLocal(j1, "A21$J1$1", "J1$1")
- val List(i2m, i3m, j3, j4, j5) = innerClassNodes("A21$")
- assertMember(i2m, "A21", "I2", flags = publicStatic)
- assertMember(i3m, "A21", "I3$", flags = publicStatic)
+ val List(j3, j4, j5) = innerClassNodes("A21$")
assertLocal(j3, "A21$J3$1", "J3$1")
assertLocal(j4, "A21$J4$1", "J4$1")
assertLocal(j5, "A21$J5$1", "J5$1") // non-static!
diff --git a/test/files/jvm/t8582.check b/test/files/jvm/t8582.check
index 564f482ff8..e388366270 100644
--- a/test/files/jvm/t8582.check
+++ b/test/files/jvm/t8582.check
@@ -14,10 +14,10 @@ Reflection can find direct nested classes (A2-B2-C2)
A2$B2: List(class A2$B2$C2)
A2$B2$C2: List()
-Mirror classes have the same InnerClass attributes as the corresponding module class:
- className[p1/p2/Singleton$Singleton$] outerClassName[p1/p2/Singleton] innerName[Singleton$] access[9]
-Module class
+The InnerClass attribute of a mirror class contains the members of the module class:
className[p1/p2/Singleton$Singleton$] outerClassName[p1/p2/Singleton] innerName[Singleton$] access[9]
+The module members are not in the InnerClass table of the module class (unless referenced):
+
An outer class has a InnerClass attribute for direct nested classes
className[A1$B1] outerClassName[A1] innerName[B1] access[1]
diff --git a/test/files/jvm/t8582.scala b/test/files/jvm/t8582.scala
index 8a57ef7952..e9a01f9016 100644
--- a/test/files/jvm/t8582.scala
+++ b/test/files/jvm/t8582.scala
@@ -55,9 +55,9 @@ object Test extends BytecodeTest {
println(nested(classOf[A2#B2]))
println(nested(classOf[A2#B2#C2]))
- nprintln("Mirror classes have the same InnerClass attributes as the corresponding module class:")
+ nprintln("The InnerClass attribute of a mirror class contains the members of the module class:")
printInner("p1.p2.Singleton") // mirror class
- println("Module class")
+ println("The module members are not in the InnerClass table of the module class (unless referenced):")
printInner("p1.p2.Singleton$")
nprintln("An outer class has a InnerClass attribute for direct nested classes")
diff --git a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
index 221aad6536..2347e8288e 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
@@ -19,7 +19,7 @@ class BTypesTest {
val btypes = new BTypesFromSymbols[g.type](g)
import btypes._
- duringBackend(btypes.intializeCoreBTypes())
+ duringBackend(btypes.initializeCoreBTypes())
def classBTypeFromSymbol(sym: Symbol) = duringBackend(btypes.classBTypeFromSymbol(sym))
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala
new file mode 100644
index 0000000000..2975bd060d
--- /dev/null
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala
@@ -0,0 +1,95 @@
+package scala.tools.nsc
+package backend.jvm
+package opt
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Test
+import scala.tools.asm.Opcodes._
+import org.junit.Assert._
+
+import scala.tools.nsc.backend.jvm.BTypes.InternalName
+import scala.tools.testing.AssertUtil._
+
+import CodeGenTools._
+import scala.tools.partest.ASMConverters
+import ASMConverters._
+
+import scala.collection.convert.decorateAsScala._
+
+@RunWith(classOf[JUnit4])
+class BTypesFromClassfileTest {
+ val compiler = newCompiler(extraArgs = "-Ybackend:GenBCode")
+
+ import compiler._
+ import definitions._
+ import genBCode.bTypes
+ import bTypes._
+
+ def duringBackend[T](f: => T) = compiler.exitingDelambdafy(f)
+
+ val run = new compiler.Run() // initializes some of the compiler
+ duringBackend(bTypes.initializeCoreBTypes())
+
+ def clearCache() = bTypes.classBTypeFromInternalName.clear()
+
+ def sameBType(fromSym: ClassBType, fromClassfile: ClassBType, checked: Set[InternalName] = Set.empty): Set[InternalName] = {
+ if (checked(fromSym.internalName)) checked
+ else {
+ assert(fromSym == fromClassfile, s"$fromSym != $fromClassfile")
+ sameInfo(fromSym.info, fromClassfile.info, checked + fromSym.internalName)
+ }
+ }
+
+ def sameBTypes(fromSyms: Iterable[ClassBType], fromClassfiles: Iterable[ClassBType], checked: Set[InternalName]): Set[InternalName] = {
+ assert(fromSyms.size == fromClassfiles.size, s"\n$fromSyms\n$fromClassfiles")
+ (fromSyms, fromClassfiles).zipped.foldLeft(checked) {
+ case (chk, (fromSym, fromClassfile)) => sameBType(fromSym, fromClassfile, chk)
+ }
+ }
+
+ def sameInfo(fromSym: ClassInfo, fromClassfile: ClassInfo, checked: Set[InternalName]): Set[InternalName] = {
+ assert({
+ // Nested class symbols can undergo makeNotPrivate (ExplicitOuter). But this is only applied
+ // for symbols of class symbols that are being compiled, not those read from a pickle.
+ // So a class may be public in bytecode, but the symbol still says private.
+ if (fromSym.nestedInfo.isEmpty) fromSym.flags == fromClassfile.flags
+ else (fromSym.flags | ACC_PRIVATE | ACC_PUBLIC) == (fromClassfile.flags | ACC_PRIVATE | ACC_PUBLIC)
+ }, s"class flags differ\n$fromSym\n$fromClassfile")
+
+ val chk1 = sameBTypes(fromSym.superClass, fromClassfile.superClass, checked)
+
+ val chk2 = sameBTypes(fromSym.interfaces, fromClassfile.interfaces, chk1)
+
+ // The fromSym info has only member classes, no local or anonymous. The symbol is read from the
+ // Scala pickle data and only member classes are created / entered.
+ // (This is different for symbols that are being compiled, there flatten will enter all local
+ // and anonymous classes as members of the outer class. But not for unpickled symbols).
+ // The fromClassfile info has all nested classes, including anonymous and local. So we filter
+ // them out: member classes are identified by having the `outerName` defined.
+ val memberClassesFromClassfile = fromClassfile.nestedClasses.filter(_.info.nestedInfo.get.outerName.isDefined)
+ // Sorting is required: the backend sorts all InnerClass entries by internalName before writing
+ // them to the classfile (to make it deterministic: the entries are collected in a Set during
+ // code generation).
+ val chk3 = sameBTypes(fromSym.nestedClasses.sortBy(_.internalName), memberClassesFromClassfile.sortBy(_.internalName), chk2)
+ sameBTypes(fromSym.nestedInfo.map(_.enclosingClass), fromClassfile.nestedInfo.map(_.enclosingClass), chk3)
+ }
+
+ def check(classSym: Symbol): Unit = duringBackend {
+ clearCache()
+ val fromSymbol = classBTypeFromSymbol(classSym)
+ clearCache()
+ val fromClassfile = bTypes.classBTypeFromParsedClassfile(fromSymbol.internalName)
+ sameBType(fromSymbol, fromClassfile)
+ }
+
+ @Test
+ def compareClassBTypes(): Unit = {
+ // Note that not only these classes are tested, but also all their parents and all nested
+ // classes in their InnerClass attributes.
+ check(ObjectClass)
+ check(JavaNumberClass)
+ check(ConsClass)
+ check(ListModule.moduleClass)
+ }
+}