diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/files/jvm/innerClassAttribute/Test.scala | 29 | ||||
-rw-r--r-- | test/files/jvm/t8582.check | 6 | ||||
-rw-r--r-- | test/files/jvm/t8582.scala | 4 | ||||
-rw-r--r-- | test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala | 2 | ||||
-rw-r--r-- | test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala | 95 |
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) + } +} |