From ed9dfee181e56bb83afa0598523786bee5572068 Mon Sep 17 00:00:00 2001 From: Antoine Gourlay Date: Tue, 29 Jul 2014 18:12:42 +0200 Subject: SI-4563 friendlier behavior for Ctrl+D in the REPL Closing the REPL with Ctrl+D does not issue a newline, so the user's prompt displays on the same line as the `scala>` prompt. This is bad. We now force a newline before closing the interpreter, and display `:quit` while we're at it so that people know how to exit the REPL (since `exit` doesn't exist anymore). The tricky part was to only add a newline when the console is interrupted, and *not* when it is closed by a command (like `:quit`), since commands are processed after their text (including newline) has been sent to the console. --- test/files/jvm/interpreter.check | 2 +- test/files/jvm/throws-annot-from-java.check | 2 +- test/files/jvm/xml05.check | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'test/files/jvm') diff --git a/test/files/jvm/interpreter.check b/test/files/jvm/interpreter.check index d124794e72..d03edb638c 100644 --- a/test/files/jvm/interpreter.check +++ b/test/files/jvm/interpreter.check @@ -361,7 +361,7 @@ It would fail on the following inputs: Exp(), Term() ^ f: (e: Exp)Int -scala> +scala> :quit plusOne: (x: Int)Int res0: Int = 6 res0: String = after reset diff --git a/test/files/jvm/throws-annot-from-java.check b/test/files/jvm/throws-annot-from-java.check index be3ba412f8..c541b26fcc 100644 --- a/test/files/jvm/throws-annot-from-java.check +++ b/test/files/jvm/throws-annot-from-java.check @@ -44,4 +44,4 @@ bar tp.typeParams.isEmpty: true throws[test.PolymorphicException[_]](classOf[test.PolymorphicException]) -scala> +scala> :quit diff --git a/test/files/jvm/xml05.check b/test/files/jvm/xml05.check index 92ea995350..cad907525d 100644 --- a/test/files/jvm/xml05.check +++ b/test/files/jvm/xml05.check @@ -4,4 +4,4 @@ Type :help for more information. scala> res0: scala.xml.Elem = -scala> +scala> :quit -- cgit v1.2.3 From 0270972b9f70d107dff393081dc48c877be1f161 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Tue, 12 Aug 2014 10:57:42 +0200 Subject: test for InnerClass and EnclosingMethod attributes Some parts of the test assert (current) buggy behavior. This is marked in the test file with TODO. It will be fixed in later work on the backend. --- test/files/jvm/innerClassAttribute/Classes_1.scala | 99 ++++++++++ .../files/jvm/innerClassAttribute/JavaAnnot_1.java | 3 + test/files/jvm/innerClassAttribute/Test.scala | 208 +++++++++++++++++++++ 3 files changed, 310 insertions(+) create mode 100644 test/files/jvm/innerClassAttribute/Classes_1.scala create mode 100644 test/files/jvm/innerClassAttribute/JavaAnnot_1.java create mode 100644 test/files/jvm/innerClassAttribute/Test.scala (limited to 'test/files/jvm') diff --git a/test/files/jvm/innerClassAttribute/Classes_1.scala b/test/files/jvm/innerClassAttribute/Classes_1.scala new file mode 100644 index 0000000000..0875d9160c --- /dev/null +++ b/test/files/jvm/innerClassAttribute/Classes_1.scala @@ -0,0 +1,99 @@ +class A1 { + class B +} + +class A2 { + object B +} + +object A3 { + class B1 + object B2 +} + +class A4 { + def f(l: List[Int]): List[Int] = { + l map (_ + 1) + } +} + +class A5 { + def f(): Object = { + object B + B + } +} + +trait A6 { + def hui = -6 + trait TT +} + +class A7 extends A6 + +abstract class A8 extends A6 { + def fish: TT +} + +class A9 { + class brick extends annotation.StaticAnnotation +} + +class A10 { + val a9 = new A9() + // there's no reference to brick in the bytecode (only in the pickle), so there's no InnerClass attribute for it. + @a9.brick def f = -7 +} + +class A11 { + @JavaAnnot_1.Ann def f = -8 +} + +object A12 { + object B { + class C + } +} + +class A13 { + def oak: A12.B.C = new A12.B.C +} + +class A14 { + def f = { + val x: Object = { + class K + new K + } + x + } + def g = { + val x: Object = new A6 { } + } +} + +object A15 { + def f = { + class B { // static (does not have an outer pointer) + class C // non-static + } + } +} + +class A16 { + val x: A6 = { + class U extends A6 + new A6 { } + } + + { + class V extends A6 + new A6 { } + } +} + +class A17 { + object B { + class C // not static, has an outer pointer. + } +} diff --git a/test/files/jvm/innerClassAttribute/JavaAnnot_1.java b/test/files/jvm/innerClassAttribute/JavaAnnot_1.java new file mode 100644 index 0000000000..27c4d4e5d3 --- /dev/null +++ b/test/files/jvm/innerClassAttribute/JavaAnnot_1.java @@ -0,0 +1,3 @@ +public class JavaAnnot_1 { + public static @interface Ann {} +} diff --git a/test/files/jvm/innerClassAttribute/Test.scala b/test/files/jvm/innerClassAttribute/Test.scala new file mode 100644 index 0000000000..6cf60ab92d --- /dev/null +++ b/test/files/jvm/innerClassAttribute/Test.scala @@ -0,0 +1,208 @@ +import scala.tools.partest.BytecodeTest +import scala.tools.asm +import asm.tree.{ClassNode, InnerClassNode} +import asm.{Opcodes => Flags} +import scala.collection.JavaConverters._ + +object Test extends BytecodeTest { + def assertSame(a: Any, b: Any) = { + assert(a == b, s"\na: $a\nb: $b") + } + + val publicStatic = Flags.ACC_PUBLIC | Flags.ACC_STATIC + val publicAbstractInterface = Flags.ACC_PUBLIC | Flags.ACC_ABSTRACT | Flags.ACC_INTERFACE + + def innerClassNodes(className: String): List[InnerClassNode] = { + loadClassNode(className).innerClasses.asScala.toList.sortBy(_.name) + } + + final case class EnclosingMethod(name: String, descriptor: String, outerClass: String) + def enclosingMethod(className: String) = { + val n = loadClassNode(className) + EnclosingMethod(n.outerMethod, n.outerMethodDesc, n.outerClass) + } + + def assertMember(node: InnerClassNode, outer: String, inner: String, name: Option[String] = None, flags: Int = Flags.ACC_PUBLIC) = { + assertSame(node.name, name.getOrElse(s"$outer$$$inner")) + assertSame(node.outerName, outer) + assertSame(node.innerName, inner) + assertSame(node.access, flags) + } + + def assertAnonymous(node: InnerClassNode, name: String, flags: Int = Flags.ACC_PUBLIC | Flags.ACC_FINAL) = { + assertSame(node.name, name) + assertSame(node.outerName, null) + assertSame(node.innerName, null) + assertSame(node.access, flags) + } + + def assertLocal(node: InnerClassNode, name: String, inner: String, flags: Int = Flags.ACC_PUBLIC) = { + assertSame(node.name, name) + assertSame(node.outerName, null) + assertSame(node.innerName, inner) + assertSame(node.access, flags) + } + + def assertEnclosingMethod(enclosingMethod: EnclosingMethod, outerClass: String, name: String, descriptor: String) = { + assertSame(enclosingMethod.outerClass, outerClass) + assertSame(enclosingMethod.name, name) + assertSame(enclosingMethod.descriptor, descriptor) + } + + def testA1() = { + val List(b1) = innerClassNodes("A1") + assertMember(b1, "A1", "B") + val List(b2) = innerClassNodes("A1$B") + assertMember(b2, "A1", "B") + } + + def testA2() = { + val List(b1) = innerClassNodes("A2") + assertMember(b1, "A2", "B$") + val List(b2) = innerClassNodes("A2$B$") + assertMember(b2, "A2", "B$") + } + + 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") + } + + def testA4() = { + val List(an1) = innerClassNodes("A4") + assertAnonymous(an1, "A4$$anonfun$f$1") + val List(an2) = innerClassNodes("A4$$anonfun$f$1") + assertAnonymous(an2, "A4$$anonfun$f$1") + assertEnclosingMethod( + enclosingMethod("A4$$anonfun$f$1"), + "A4", "f", "(Lscala/collection/immutable/List;)Lscala/collection/immutable/List;") + } + + def testA5() = { + val List(b1) = innerClassNodes("A5") + assertLocal(b1, "A5$B$2$", "B$2$") + val List(b2) = innerClassNodes("A5$B$2$") + assertLocal(b2, "A5$B$2$", "B$2$") + assertEnclosingMethod( + enclosingMethod("A5$B$2$"), + "A5", "f", "()Ljava/lang/Object;") + } + + def testA6() = { + val List(tt1) = innerClassNodes("A6") + assertMember(tt1, "A6", "TT", flags = publicAbstractInterface) + val List() = innerClassNodes("A6$class") + val List(tt2) = innerClassNodes("A6$TT") + assertMember(tt2, "A6", "TT", flags = publicAbstractInterface) + } + + def testA7() = { + val List() = innerClassNodes("A7") + } + + def testA8() = { + val List(tt) = innerClassNodes("A8") + assertMember(tt, "A6", "TT", flags = publicAbstractInterface) + } + + def testA10() = { + val List() = innerClassNodes("A10") + } + + def testA11() = { + val List(ann) = innerClassNodes("A11") + // in the java class file, the INNERCLASS attribute has more flags (public | static | abstract | interface | annotation) + // the scala compiler has its own interpretation of java annotations ant their flags.. it only emits publicStatic. + assertMember(ann, "JavaAnnot_1", "Ann", flags = publicStatic) + } + + def testA13() = { + val List(b, c) = innerClassNodes("A13") + assertMember(b, "A12", "B$", flags = publicStatic) + assertMember(c, "A12$B$", "C", name = Some("A12$B$C"), flags = publicStatic) + } + + def testA14() = { + val List(anon, k) = innerClassNodes("A14") + + assertLocal(k, "A14$K$1", "K$1") + assertEnclosingMethod( + enclosingMethod("A14$K$1"), + "A14", "f", "()Ljava/lang/Object;") + + assertAnonymous(anon, "A14$$anon$1") + assertEnclosingMethod( + enclosingMethod("A14$$anon$1"), + "A14", "g", "()V") + } + + def testA15() = { + val List(b) = innerClassNodes("A15") + assertLocal(b, "A15$B$3", "B$3", flags = publicStatic) + + val List(_, c) = innerClassNodes("A15$B$3") + // TODO this is a bug in the backend, C should be a member. Instead, its outerClass is null + // assertMember(c, "A15$B$3", "C") + assertLocal(c, "A15$B$3$C", "C") + } + + def testA16() = { + val List(anon1, anon2, u, v) = innerClassNodes("A16") + // TODO there's a bug in the backend: anon$2 has outerClass A16, but anonymous classes should have outerClass null + // assertAnonymous(anon1, "A16$$anon$2") + assertMember(anon1, "A16", null, name = Some("A16$$anon$2"), flags = Flags.ACC_PUBLIC | Flags.ACC_FINAL) + assertAnonymous(anon2, "A16$$anon$3") + // TODO this is a bug in the backend, U should not be a member, its outerClass should be null + // assertLocal(u, "A16$U$1", "U$1") + assertMember(u, "A16", "U$1") + assertLocal(v, "A16$V$1", "V$1") + + assertEnclosingMethod( + enclosingMethod("A16$$anon$2"), + "A16", "", "()V") + assertEnclosingMethod( + enclosingMethod("A16$$anon$3"), + "A16", "", "()V") + // TODO this is a bug, there should be an enclosingMethod attribute in U + // assertEnclosingMethod( + // enclosingMethod("A16$U$1"), + // "A16", "", "()V") + assertEnclosingMethod( + enclosingMethod("A16$V$1"), + "A16", "", "()V") + } + + def testA17() = { + val List(b, c) = innerClassNodes("A17$B$") + assertMember(b, "A17", "B$") + // TODO this is a bug, should not be static. + assertMember(c, "A17$B$", "C", name = Some("A17$B$C"), flags = publicStatic) // (should be) not static, has an outer pointer. + } + + def show(): Unit = { + testA1() + testA2() + testA3() + testA4() + testA5() + testA6() + testA7() + testA8() + testA10() + testA11() + testA13() + testA14() + testA15() + testA16() + testA17() + } +} -- cgit v1.2.3