diff options
Diffstat (limited to 'test')
63 files changed, 2469 insertions, 2062 deletions
diff --git a/test/files/jvm/scala-concurrent-tck.check b/test/files/jvm/scala-concurrent-tck.check index 9aef07d1e5..8aec46e5d6 100644 --- a/test/files/jvm/scala-concurrent-tck.check +++ b/test/files/jvm/scala-concurrent-tck.check @@ -1 +1 @@ -warning: there were 73 deprecation warnings; re-run with -deprecation for details +warning: there were 75 deprecation warnings; re-run with -deprecation for details diff --git a/test/files/jvm/scala-concurrent-tck.scala b/test/files/jvm/scala-concurrent-tck.scala index 8069028cf5..7197c1d853 100644 --- a/test/files/jvm/scala-concurrent-tck.scala +++ b/test/files/jvm/scala-concurrent-tck.scala @@ -90,6 +90,25 @@ trait FutureCallbacks extends TestBase { promise.success(-1) } + def stressTestNumberofCallbacks(): Unit = once { + done => + val promise = Promise[Unit] + val otherPromise = Promise[Unit] + def attachMeaninglessCallbacksTo(f: Future[Any]): Unit = (1 to 1000).foreach(_ => f.onComplete(_ => ())) + attachMeaninglessCallbacksTo(promise.future) + val future = promise.future.flatMap { _ => + attachMeaninglessCallbacksTo(otherPromise.future) + otherPromise.future + } + val numbers = new java.util.concurrent.ConcurrentHashMap[Int, Unit]() + (0 to 10000) foreach { x => numbers.put(x, ()) } + Future.sequence((0 to 10000) map { x => future.andThen({ case _ => numbers.remove(x) }) }) onComplete { + _ => done(numbers.isEmpty) + } + promise.success(()) + otherPromise.success(()) + } + testOnSuccess() testOnSuccessWhenCompleted() testOnSuccessWhenFailed() @@ -100,6 +119,7 @@ trait FutureCallbacks extends TestBase { //testOnFailureWhenSpecialThrowable(7, new InterruptedException) testThatNestedCallbacksDoNotYieldStackOverflow() testOnFailureWhenTimeoutException() + stressTestNumberofCallbacks() } @@ -283,6 +303,16 @@ def testTransformFailure(): Unit = once { g onFailure { case t => done(t.getMessage() == "expected") } } + def testFlatMapDelayed(): Unit = once { + done => + val f = Future { 5 } + val p = Promise[Int] + val g = f flatMap { _ => p.future } + g onSuccess { case x => done(x == 10) } + g onFailure { case _ => done(false) } + p.success(10) + } + def testFilterSuccess(): Unit = once { done => val f = Future { 4 } @@ -458,6 +488,7 @@ def testTransformFailure(): Unit = once { testMapFailure() testFlatMapSuccess() testFlatMapFailure() + testFlatMapDelayed() testFilterSuccess() testFilterFailure() testCollectSuccess() diff --git a/test/files/neg/hkgadt.check b/test/files/neg/hkgadt.check new file mode 100644 index 0000000000..ef302a9abf --- /dev/null +++ b/test/files/neg/hkgadt.check @@ -0,0 +1,31 @@ +hkgadt.scala:7: error: type mismatch; + found : scala.collection.immutable.Set[Int] + required: F[Int] + case Bar() => Set(1) + ^ +hkgadt.scala:13: error: type mismatch; + found : Boolean(true) + required: A + case Bar1() => true + ^ +hkgadt.scala:24: error: type mismatch; + found : scala.collection.immutable.Set[Int] + required: F[Int] + case Bar() => Set(1) + ^ +hkgadt.scala:25: error: type mismatch; + found : List[Int] + required: F[Int] + case Baz() => List(1) + ^ +hkgadt.scala:32: error: type mismatch; + found : Boolean(true) + required: A + case Bar1() => true + ^ +hkgadt.scala:33: error: type mismatch; + found : Int(1) + required: A + case Baz1() => 1 + ^ +6 errors found diff --git a/test/files/neg/hkgadt.scala b/test/files/neg/hkgadt.scala new file mode 100644 index 0000000000..0107d2bdde --- /dev/null +++ b/test/files/neg/hkgadt.scala @@ -0,0 +1,35 @@ +object HKGADT { + sealed trait Foo[F[_]] + final case class Bar() extends Foo[List] + + def frob[F[_]](foo: Foo[F]): F[Int] = + foo match { + case Bar() => Set(1) + } + + sealed trait Foo1[F] + final case class Bar1() extends Foo1[Int] + def frob1[A](foo: Foo1[A]): A = foo match { + case Bar1() => true + } +} + +object HKGADT2 { + sealed trait Foo[F[_]] + final case class Bar() extends Foo[List] + final case class Baz() extends Foo[Set] + + def frob[F[_]](foo: Foo[F]): F[Int] = + foo match { + case Bar() => Set(1) + case Baz() => List(1) + } + + sealed trait Foo1[F] + final case class Bar1() extends Foo1[Int] + final case class Baz1() extends Foo1[Boolean] + def frob1[A](foo: Foo1[A]): A = foo match { + case Bar1() => true + case Baz1() => 1 + } +} diff --git a/test/files/neg/t9361.check b/test/files/neg/t9361.check new file mode 100644 index 0000000000..847d137f7d --- /dev/null +++ b/test/files/neg/t9361.check @@ -0,0 +1,11 @@ +t9361.scala:4: error: type mismatch; + found : Tc[_$2] where type _$2 + required: Nothing[] + new Foo { def tc = null.asInstanceOf[Tc[_]] } + ^ +t9361.scala:4: error: type mismatch; + found : Foo[Nothing] + required: Foo[Tc]{type T = Nothing} + new Foo { def tc = null.asInstanceOf[Tc[_]] } + ^ +two errors found diff --git a/test/files/neg/t9361.scala b/test/files/neg/t9361.scala new file mode 100644 index 0000000000..b689461e4d --- /dev/null +++ b/test/files/neg/t9361.scala @@ -0,0 +1,5 @@ +abstract class Foo[Tc[_]] { def tc: Tc[_] } +object Foo { + def foo[Tc[_]](): Foo[Tc] { type T = Nothing } = + new Foo { def tc = null.asInstanceOf[Tc[_]] } +} diff --git a/test/files/pos/hkgadt.scala b/test/files/pos/hkgadt.scala new file mode 100644 index 0000000000..5719c752cd --- /dev/null +++ b/test/files/pos/hkgadt.scala @@ -0,0 +1,35 @@ +object HKGADT { + sealed trait Foo[F[_]] + final case class Bar() extends Foo[List] + + def frob[F[_]](foo: Foo[F]): F[Int] = + foo match { + case Bar() => List(1) + } + + sealed trait Foo1[F] + final case class Bar1() extends Foo1[Int] + def frob1[A](foo: Foo1[A]): A = foo match { + case Bar1() => 1 + } +} + +object HKGADT2 { + sealed trait Foo[F[_]] + final case class Bar() extends Foo[List] + final case class Baz() extends Foo[Set] + + def frob[F[_]](foo: Foo[F]): F[Int] = + foo match { + case Bar() => List(1) + case Baz() => Set(1) + } + + sealed trait Foo1[F] + final case class Bar1() extends Foo1[Int] + final case class Baz1() extends Foo1[Boolean] + def frob1[A](foo: Foo1[A]): A = foo match { + case Bar1() => 1 + case Baz1() => true + } +} diff --git a/test/files/pos/t9665.scala b/test/files/pos/t9665.scala new file mode 100644 index 0000000000..1aa7a5d459 --- /dev/null +++ b/test/files/pos/t9665.scala @@ -0,0 +1,7 @@ + +object | { def unapply(x: (Any, Any)) = Some(x) } + +trait Test { + def f() = (1,2) match { case 1 `|` 2 => } + def g() = 2 match { case 1 | 2 => } +} diff --git a/test/files/run/repl-serialization.scala b/test/files/run/repl-serialization.scala index 55b7519631..8bc0dd3a8b 100644 --- a/test/files/run/repl-serialization.scala +++ b/test/files/run/repl-serialization.scala @@ -36,7 +36,7 @@ object Test { |extract(() => new AA(x + getX() + y + z + zz + O.apply + u.x)) """.stripMargin - imain = new IMain(settings) + imain = IMain(settings) println("== evaluating lines") imain.directBind("extract", "(AnyRef => Unit)", extract) code.lines.foreach(imain.interpret) diff --git a/test/files/run/t1500.scala b/test/files/run/t1500.scala index 30c026f70f..5a2735fbf1 100644 --- a/test/files/run/t1500.scala +++ b/test/files/run/t1500.scala @@ -20,7 +20,7 @@ object Test { val settings = new Settings() settings.classpath.value = System.getProperty("java.class.path") - val tool = new interpreter.IMain(settings) + val tool = interpreter.IMain(settings) val global = tool.global import global._ diff --git a/test/files/run/t5463.scala b/test/files/run/t5463.scala new file mode 100644 index 0000000000..30b8306156 --- /dev/null +++ b/test/files/run/t5463.scala @@ -0,0 +1,21 @@ +import scala.reflect.internal.FatalError +import scala.tools.partest.DirectTest + +object Test extends DirectTest { + + def code = "class A" + + override def show(): Unit = { + // Create a broken JAR file and put it on compiler classpath + val jarpath = testOutput.path + "/notajar.jar" + scala.reflect.io.File(jarpath).writeAll("This isn't really a JAR file") + + val classpath = List(sys.props("partest.lib"), jarpath, testOutput.path) mkString sys.props("path.separator") + try { + compileString(newCompiler("-cp", classpath, "-d", testOutput.path))(code) + throw new Error("Compilation should have failed"); + } catch { + case ex: FatalError => // this is expected + } + } +} diff --git a/test/files/run/t7843-jsr223-service.check b/test/files/run/t7843-jsr223-service.check deleted file mode 100644 index a668df3567..0000000000 --- a/test/files/run/t7843-jsr223-service.check +++ /dev/null @@ -1,2 +0,0 @@ -n: Object = 10 -12345678910 diff --git a/test/files/run/t7843-jsr223-service.scala b/test/files/run/t7843-jsr223-service.scala deleted file mode 100644 index 31112212ea..0000000000 --- a/test/files/run/t7843-jsr223-service.scala +++ /dev/null @@ -1,8 +0,0 @@ -import scala.tools.nsc.interpreter.IMain - -object Test extends App { - val engine = new IMain.Factory getScriptEngine() - engine.asInstanceOf[IMain].settings.usejavacp.value = true - engine put ("n", 10) - engine eval "1 to n.asInstanceOf[Int] foreach print" -} diff --git a/test/files/run/t7933.check b/test/files/run/t7933.check deleted file mode 100644 index 317e9677c3..0000000000 --- a/test/files/run/t7933.check +++ /dev/null @@ -1,2 +0,0 @@ -hello -hello diff --git a/test/files/run/t7933.scala b/test/files/run/t7933.scala deleted file mode 100644 index b06dffcd80..0000000000 --- a/test/files/run/t7933.scala +++ /dev/null @@ -1,11 +0,0 @@ -import scala.tools.nsc.interpreter.IMain - -object Test extends App { - val engine = new IMain.Factory getScriptEngine() - engine.asInstanceOf[IMain].settings.usejavacp.value = true - val res2 = engine.asInstanceOf[javax.script.Compilable] - res2 compile "8" eval() - val res5 = res2 compile """println("hello") ; 8""" - res5 eval() - res5 eval() -} diff --git a/test/files/scalacheck/MutablePriorityQueue.scala b/test/files/scalacheck/MutablePriorityQueue.scala new file mode 100644 index 0000000000..687e2e7c62 --- /dev/null +++ b/test/files/scalacheck/MutablePriorityQueue.scala @@ -0,0 +1,102 @@ +import scala.collection.mutable.PriorityQueue +import org.scalacheck._ +import Prop._ +import Arbitrary._ + +object Test extends Properties("PriorityQueue") { + type E = Int // the element type used for most/all of the tests + + def checkInvariant[A](pq: PriorityQueue[A])(implicit ord: Ordering[A]): Boolean = { + // The ordering invariant in the heap is that parent >= child. + // A child at index i has a parent at index i/2 in the priority + // queue's internal array. However, that array is padded with + // an extra slot in front so that the first real element is at + // index 1. The vector below is not padded, so subtract 1 from + // every index. + import ord._ + val vec = pq.toVector // elements in same order as pq's internal array + 2 until pq.size forall { i => vec(i/2-1) >= vec(i-1) } + } + + property("newBuilder (in companion)") = forAll { list: List[E] => + val builder = PriorityQueue.newBuilder[E] + for (x <- list) builder += x + val pq = builder.result() + checkInvariant(pq) && + pq.dequeueAll == list.sorted.reverse + } + + property("to[PriorityQueue]") = forAll { list: List[E] => + val pq = list.to[PriorityQueue] + checkInvariant(pq) && + pq.dequeueAll == list.sorted.reverse + } + + property("apply (in companion)") = forAll { list: List[E] => + val pq = PriorityQueue.apply(list : _*) + checkInvariant(pq) && + pq.dequeueAll == list.sorted.reverse + } + + property("size, isEmpty") = forAll { list: List[E] => + val pq = PriorityQueue(list : _*) + pq.size == list.size && pq.isEmpty == list.isEmpty + } + + property("+=") = forAll { (x: E, list: List[E]) => + val pq = PriorityQueue(list : _*) + pq += x + checkInvariant(pq) && + pq.dequeueAll == (x :: list).sorted.reverse + } + + property("++= on empty") = forAll { list: List[E] => + val pq = PriorityQueue.empty[E] + pq ++= list + checkInvariant(pq) && + pq.dequeueAll == list.sorted.reverse + } + + property("++=") = forAll { (list1: List[E], list2: List[E]) => + val pq = PriorityQueue(list1 : _*) + pq ++= list2 + checkInvariant(pq) && + pq.dequeueAll == (list1 ++ list2).sorted.reverse + } + + property("reverse") = forAll { list: List[E] => + val pq = PriorityQueue(list : _*).reverse + checkInvariant(pq)(implicitly[Ordering[E]].reverse) && + pq.dequeueAll == list.sorted + } + + property("reverse then ++=") = forAll { list: List[E] => + val pq = PriorityQueue.empty[E].reverse ++= list + checkInvariant(pq)(implicitly[Ordering[E]].reverse) && + pq.dequeueAll == list.sorted + } + + property("reverse then +=") = forAll { (x: E, list: List[E]) => + val pq = PriorityQueue(list : _*).reverse += x + checkInvariant(pq)(implicitly[Ordering[E]].reverse) && + pq.dequeueAll == (x +: list).sorted + } + + property("clone") = forAll { list: List[E] => + val pq = PriorityQueue(list : _*) + val c = pq.clone() + (pq ne c) && + checkInvariant(c) && + c.dequeueAll == pq.dequeueAll + } + + property("dequeue") = forAll { list: List[E] => + list.nonEmpty ==> { + val pq = PriorityQueue(list : _*) + val x = pq.dequeue() + checkInvariant(pq) && + x == list.max && pq.dequeueAll == list.sorted.reverse.tail + } + } + +} diff --git a/test/junit/scala/BoxUnboxTest.scala b/test/junit/scala/BoxUnboxTest.scala deleted file mode 100644 index 88b3037e69..0000000000 --- a/test/junit/scala/BoxUnboxTest.scala +++ /dev/null @@ -1,119 +0,0 @@ -package scala - -import org.junit.Test -import org.junit.Assert._ -import org.junit.runner.RunWith -import org.junit.runners.JUnit4 - -import scala.tools.testing.AssertUtil._ - -@RunWith(classOf[JUnit4]) -class BoxUnboxTest { - def genericNull[T] = null.asInstanceOf[T] // allowed, see SI-4437, point 2 - - @Test - def boxUnboxInt(): Unit = { - val b = new Integer(1) - val u = 1 - - assertEquals(1.toInt, u) - - assertEquals(Predef.int2Integer(1), b) - assertEquals(1: Integer, b) - assertEquals(Int.box(1), b) - assertEquals(1.asInstanceOf[Object], b) - - assertThrows[ClassCastException]("".asInstanceOf[Integer]) - - assertEquals(Predef.Integer2int(b), u) - assertEquals(b: Int, u) - assertEquals(Int.unbox(b), u) - assertEquals(b.asInstanceOf[Int], u) - assertEquals(b.intValue, u) - assertEquals(b.toInt, u) - intWrapper(b).toInt - - assertThrows[ClassCastException](Int.unbox("")) - assertThrows[ClassCastException]("".asInstanceOf[Int]) - - // null unboxing in various positions - - val n1 = Int.unbox(null) - assertEquals(n1, 0) - val n2 = Predef.Integer2int(null) - assertEquals(n2, 0) - val n3 = (null: Integer): Int - assertEquals(n3, 0) - val n4 = null.asInstanceOf[Int] - assertEquals(n4, 0) - val n5 = null.asInstanceOf[Int] == 0 - assertTrue(n5) - val n6 = null.asInstanceOf[Int] == null - assertFalse(n6) - val n7 = null.asInstanceOf[Int] != 0 - assertFalse(n7) - val n8 = null.asInstanceOf[Int] != null - assertTrue(n8) - - val mp = new java.util.HashMap[Int, Int] - val n9 = mp.get(0) - assertEquals(n9, 0) - val n10 = mp.get(0) == null // SI-602 - assertThrows[AssertionError](assertFalse(n10)) // should not throw - - def f(a: Any) = "" + a - val n11 = f(null.asInstanceOf[Int]) - assertEquals(n11, "0") - - def n12 = genericNull[Int] - assertEquals(n12, 0) - } - - @Test - def numericConversions(): Unit = { - val i1 = 1L.asInstanceOf[Int] - assertEquals(i1, 1) - assertThrows[ClassCastException] { - val i2 = (1L: Any).asInstanceOf[Int] // SI-1448, should not throw. see also SI-4437 point 1. - assertEquals(i2, 1) - } - } - - @Test - def boxUnboxBoolean(): Unit = { - val n1 = Option(null.asInstanceOf[Boolean]) - assertEquals(n1, Some(false)) - } - - @Test - def boxUnboxUnit(): Unit = { - // should not use assertEquals in this test: it takes two Object parameters. normally, Unit does - // not conform to Object, but for Java-defined methods scalac makes an exception and treats them - // as Any. passing a Unit as Any makes the compiler go through another layer of boxing, so it - // can hide some bugs (where we actually have a null, but the compiler makes it a ()). - - var v = 0 - def eff() = { v = 1 } - def chk() = { assert(v == 1); v = 0 } - - val b = runtime.BoxedUnit.UNIT - - assert(eff() == b); chk() - assert(Unit.box(eff()) == b); chk() - assert(().asInstanceOf[Object] == b) - - Unit.unbox({eff(); b}); chk() - Unit.unbox({eff(); null}); chk() - assertThrows[ClassCastException](Unit.unbox({eff(); ""})); chk() - - val n1 = null.asInstanceOf[Unit] - assert(n1 == b) - - val n2 = null.asInstanceOf[Unit] == b - assert(n2) - - def f(a: Any) = "" + a - val n3 = f(null.asInstanceOf[Unit]) - assertEquals(n3, "()") - } -} diff --git a/test/junit/scala/PartialFunctionSerializationTest.scala b/test/junit/scala/PartialFunctionSerializationTest.scala index d525b045cd..2019e3a425 100644 --- a/test/junit/scala/PartialFunctionSerializationTest.scala +++ b/test/junit/scala/PartialFunctionSerializationTest.scala @@ -7,24 +7,18 @@ import org.junit.runners.JUnit4 @RunWith(classOf[JUnit4]) class PartialFunctionSerializationTest { - val pf1: PartialFunction[Int, Int] = { - case n if n > 0 => 1 - } - - val pf2: PartialFunction[Int, Int] = { - case n if n <= 0 => 2 - } + val pf1: PartialFunction[Int, Int] = { case n if n > 0 => 1 } + val pf2: PartialFunction[Int, Int] = { case n if n <= 0 => 2 } - private def assertSerializable[A,B](fn: A => B) = { + private def assertSerializable[A,B](fn: A => B): Unit = { import java.io._ - new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(fn) } - @Test def canSerializeLiteral= assertSerializable(pf1) + @Test def canSerializeLiteral = assertSerializable(pf1) - @Test def canSerializeLifted= assertSerializable(pf1.lift) + @Test def canSerializeLifted = assertSerializable(pf1.lift) @Test def canSerializeOrElse = assertSerializable(pf1 orElse pf2) diff --git a/test/junit/scala/collection/convert/NullSafetyTest.scala b/test/junit/scala/collection/convert/NullSafetyTest.scala deleted file mode 100644 index 173568408c..0000000000 --- a/test/junit/scala/collection/convert/NullSafetyTest.scala +++ /dev/null @@ -1,279 +0,0 @@ -package scala.collection.convert - -import java.{util => ju, lang => jl} -import ju.{concurrent => juc} - -import org.junit.Test -import org.junit.experimental.runners.Enclosed -import org.junit.runner.RunWith - -import collection.convert.ImplicitConversions._ -import scala.collection.JavaConverters._ -import scala.collection.{mutable, concurrent} - -@RunWith(classOf[Enclosed]) -object NullSafetyTest { - - /* - * Pertinent: SI-9113 - * Tests to insure that wrappers return null instead of wrapping it as a collection - */ - - class ToScala { - - @Test def testIteratorWrapping(): Unit = { - val nullJIterator: ju.Iterator[AnyRef] = null - val iterator: Iterator[AnyRef] = nullJIterator - - assert(iterator == null) - } - - @Test def testEnumerationWrapping(): Unit = { - val nullJEnumeration: ju.Enumeration[AnyRef] = null - val enumeration: Iterator[AnyRef] = nullJEnumeration - - assert(enumeration == null) - } - - @Test def testIterableWrapping(): Unit = { - val nullJIterable: jl.Iterable[AnyRef] = null - val iterable: Iterable[AnyRef] = nullJIterable - - assert(iterable == null) - } - - @Test def testCollectionWrapping(): Unit = { - val nullJCollection: ju.Collection[AnyRef] = null - val collection: Iterable[AnyRef] = nullJCollection - - assert(collection == null) - } - - @Test def testBufferWrapping(): Unit = { - val nullJList: ju.List[AnyRef] = null - val buffer: mutable.Buffer[AnyRef] = nullJList - - assert(buffer == null) - } - - @Test def testSetWrapping(): Unit = { - val nullJSet: ju.Set[AnyRef] = null - val set: mutable.Set[AnyRef] = nullJSet - - assert(set == null) - } - - @Test def testMapWrapping(): Unit = { - val nullJMap: ju.Map[AnyRef, AnyRef] = null - val map: mutable.Map[AnyRef, AnyRef] = nullJMap - - assert(map == null) - } - - @Test def testConcurrentMapWrapping(): Unit = { - val nullJConMap: juc.ConcurrentMap[AnyRef, AnyRef] = null - val conMap: concurrent.Map[AnyRef, AnyRef] = nullJConMap - - assert(conMap == null) - } - - @Test def testDictionaryWrapping(): Unit = { - val nullJDict: ju.Dictionary[AnyRef, AnyRef] = null - val dict: mutable.Map[AnyRef, AnyRef] = nullJDict - - assert(dict == null) - } - - - @Test def testPropertyWrapping(): Unit = { - val nullJProps: ju.Properties = null - val props: mutable.Map[String, String] = nullJProps - - assert(props == null) - } - - @Test def testIteratorDecoration(): Unit = { - val nullJIterator: ju.Iterator[AnyRef] = null - - assert(nullJIterator.asScala == null) - } - - @Test def testEnumerationDecoration(): Unit = { - val nullJEnumeration: ju.Enumeration[AnyRef] = null - - assert(nullJEnumeration.asScala == null) - } - - @Test def testIterableDecoration(): Unit = { - val nullJIterable: jl.Iterable[AnyRef] = null - - assert(nullJIterable.asScala == null) - } - - @Test def testCollectionDecoration(): Unit = { - val nullJCollection: ju.Collection[AnyRef] = null - - assert(nullJCollection.asScala == null) - } - - @Test def testBufferDecoration(): Unit = { - val nullJBuffer: ju.List[AnyRef] = null - - assert(nullJBuffer.asScala == null) - } - - @Test def testSetDecoration(): Unit = { - val nullJSet: ju.Set[AnyRef] = null - - assert(nullJSet.asScala == null) - } - - @Test def testMapDecoration(): Unit = { - val nullJMap: ju.Map[AnyRef, AnyRef] = null - - assert(nullJMap.asScala == null) - } - - @Test def testConcurrentMapDecoration(): Unit = { - val nullJConMap: juc.ConcurrentMap[AnyRef, AnyRef] = null - - assert(nullJConMap.asScala == null) - } - - @Test def testDictionaryDecoration(): Unit = { - val nullJDict: ju.Dictionary[AnyRef, AnyRef] = null - - assert(nullJDict.asScala == null) - } - - @Test def testPropertiesDecoration(): Unit = { - val nullJProperties: ju.Properties = null - - assert(nullJProperties.asScala == null) - } - } - - class ToJava { - - @Test def testIteratorWrapping(): Unit = { - val nullIterator: Iterator[AnyRef] = null - val jIterator: ju.Iterator[AnyRef] = nullIterator - - assert(jIterator == null) - } - - @Test def testEnumerationWrapping(): Unit = { - val nullEnumeration: Iterator[AnyRef] = null - val enumeration: ju.Iterator[AnyRef] = nullEnumeration - - assert(enumeration == null) - } - - @Test def testIterableWrapping(): Unit = { - val nullIterable: Iterable[AnyRef] = null - val iterable: jl.Iterable[AnyRef] = asJavaIterable(nullIterable) - - assert(iterable == null) - } - - @Test def testCollectionWrapping(): Unit = { - val nullCollection: Iterable[AnyRef] = null - val collection: ju.Collection[AnyRef] = nullCollection - - assert(collection == null) - } - - @Test def testBufferWrapping(): Unit = { - val nullList: mutable.Buffer[AnyRef] = null - val buffer: ju.List[AnyRef] = nullList - - assert(buffer == null) - } - - @Test def testSetWrapping(): Unit = { - val nullSet: mutable.Set[AnyRef] = null - val set: ju.Set[AnyRef] = nullSet - - assert(set == null) - } - - @Test def testMapWrapping(): Unit = { - val nullMap: mutable.Map[AnyRef, AnyRef] = null - val map: ju.Map[AnyRef, AnyRef] = nullMap - - assert(map == null) - } - - @Test def testConcurrentMapWrapping(): Unit = { - val nullConMap: concurrent.Map[AnyRef, AnyRef] = null - val conMap: juc.ConcurrentMap[AnyRef, AnyRef] = nullConMap - - assert(conMap == null) - } - - @Test def testDictionaryWrapping(): Unit = { - val nullDict: mutable.Map[AnyRef, AnyRef] = null - val dict: ju.Dictionary[AnyRef, AnyRef] = nullDict - - assert(dict == null) - } - - // Implicit conversion to ju.Properties is not available - - @Test def testIteratorDecoration(): Unit = { - val nullIterator: Iterator[AnyRef] = null - - assert(nullIterator.asJava == null) - } - - @Test def testEnumerationDecoration(): Unit = { - val nullEnumeration: Iterator[AnyRef] = null - - assert(nullEnumeration.asJavaEnumeration == null) - } - - @Test def testIterableDecoration(): Unit = { - val nullIterable: Iterable[AnyRef] = null - - assert(nullIterable.asJava == null) - } - - @Test def testCollectionDecoration(): Unit = { - val nullCollection: Iterable[AnyRef] = null - - assert(nullCollection.asJavaCollection == null) - } - - @Test def testBufferDecoration(): Unit = { - val nullBuffer: mutable.Buffer[AnyRef] = null - - assert(nullBuffer.asJava == null) - } - - @Test def testSetDecoration(): Unit = { - val nullSet: Set[AnyRef] = null - - assert(nullSet.asJava == null) - } - - @Test def testMapDecoration(): Unit = { - val nullMap: mutable.Map[AnyRef, AnyRef] = null - - assert(nullMap.asJava == null) - } - - @Test def testConcurrentMapDecoration(): Unit = { - val nullConMap: concurrent.Map[AnyRef, AnyRef] = null - - assert(nullConMap.asJava == null) - } - - @Test def testDictionaryDecoration(): Unit = { - val nullDict: mutable.Map[AnyRef, AnyRef] = null - - assert(nullDict.asJavaDictionary == null) - } - - // Decorator conversion to ju.Properties is not available - } -} diff --git a/test/junit/scala/collection/convert/NullSafetyToJavaTest.scala b/test/junit/scala/collection/convert/NullSafetyToJavaTest.scala new file mode 100644 index 0000000000..da0513ed8a --- /dev/null +++ b/test/junit/scala/collection/convert/NullSafetyToJavaTest.scala @@ -0,0 +1,138 @@ +package scala.collection.convert + +import java.util.{concurrent => juc} +import java.{lang => jl, util => ju} + +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import scala.collection.JavaConverters._ +import scala.collection.convert.ImplicitConversions._ +import scala.collection.{concurrent, mutable} + +// SI-9113: tests to insure that wrappers return null instead of wrapping it as a collection + +@RunWith(classOf[JUnit4]) +class NullSafetyToJavaTest { + @Test def testIteratorWrapping(): Unit = { + val nullIterator: Iterator[AnyRef] = null + val jIterator: ju.Iterator[AnyRef] = nullIterator + + assert(jIterator == null) + } + + @Test def testEnumerationWrapping(): Unit = { + val nullEnumeration: Iterator[AnyRef] = null + val enumeration: ju.Iterator[AnyRef] = nullEnumeration + + assert(enumeration == null) + } + + @Test def testIterableWrapping(): Unit = { + val nullIterable: Iterable[AnyRef] = null + val iterable: jl.Iterable[AnyRef] = asJavaIterable(nullIterable) + + assert(iterable == null) + } + + @Test def testCollectionWrapping(): Unit = { + val nullCollection: Iterable[AnyRef] = null + val collection: ju.Collection[AnyRef] = nullCollection + + assert(collection == null) + } + + @Test def testBufferWrapping(): Unit = { + val nullList: mutable.Buffer[AnyRef] = null + val buffer: ju.List[AnyRef] = nullList + + assert(buffer == null) + } + + @Test def testSetWrapping(): Unit = { + val nullSet: mutable.Set[AnyRef] = null + val set: ju.Set[AnyRef] = nullSet + + assert(set == null) + } + + @Test def testMapWrapping(): Unit = { + val nullMap: mutable.Map[AnyRef, AnyRef] = null + val map: ju.Map[AnyRef, AnyRef] = nullMap + + assert(map == null) + } + + @Test def testConcurrentMapWrapping(): Unit = { + val nullConMap: concurrent.Map[AnyRef, AnyRef] = null + val conMap: juc.ConcurrentMap[AnyRef, AnyRef] = nullConMap + + assert(conMap == null) + } + + @Test def testDictionaryWrapping(): Unit = { + val nullDict: mutable.Map[AnyRef, AnyRef] = null + val dict: ju.Dictionary[AnyRef, AnyRef] = nullDict + + assert(dict == null) + } + + // Implicit conversion to ju.Properties is not available + + @Test def testIteratorDecoration(): Unit = { + val nullIterator: Iterator[AnyRef] = null + + assert(nullIterator.asJava == null) + } + + @Test def testEnumerationDecoration(): Unit = { + val nullEnumeration: Iterator[AnyRef] = null + + assert(nullEnumeration.asJavaEnumeration == null) + } + + @Test def testIterableDecoration(): Unit = { + val nullIterable: Iterable[AnyRef] = null + + assert(nullIterable.asJava == null) + } + + @Test def testCollectionDecoration(): Unit = { + val nullCollection: Iterable[AnyRef] = null + + assert(nullCollection.asJavaCollection == null) + } + + @Test def testBufferDecoration(): Unit = { + val nullBuffer: mutable.Buffer[AnyRef] = null + + assert(nullBuffer.asJava == null) + } + + @Test def testSetDecoration(): Unit = { + val nullSet: Set[AnyRef] = null + + assert(nullSet.asJava == null) + } + + @Test def testMapDecoration(): Unit = { + val nullMap: mutable.Map[AnyRef, AnyRef] = null + + assert(nullMap.asJava == null) + } + + @Test def testConcurrentMapDecoration(): Unit = { + val nullConMap: concurrent.Map[AnyRef, AnyRef] = null + + assert(nullConMap.asJava == null) + } + + @Test def testDictionaryDecoration(): Unit = { + val nullDict: mutable.Map[AnyRef, AnyRef] = null + + assert(nullDict.asJavaDictionary == null) + } + + // Decorator conversion to ju.Properties is not available +} diff --git a/test/junit/scala/collection/convert/NullSafetyToScalaTest.scala b/test/junit/scala/collection/convert/NullSafetyToScalaTest.scala new file mode 100644 index 0000000000..9b6d366faf --- /dev/null +++ b/test/junit/scala/collection/convert/NullSafetyToScalaTest.scala @@ -0,0 +1,148 @@ +package scala.collection.convert + +import java.util.{concurrent => juc} +import java.{lang => jl, util => ju} + +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import scala.collection.JavaConverters._ +import scala.collection.convert.ImplicitConversions._ +import scala.collection.{concurrent, mutable} + +// SI-9113: tests to insure that wrappers return null instead of wrapping it as a collection + +@RunWith(classOf[JUnit4]) +class NullSafetyToScalaTest { + @Test def testIteratorWrapping(): Unit = { + val nullJIterator: ju.Iterator[AnyRef] = null + val iterator: Iterator[AnyRef] = nullJIterator + + assert(iterator == null) + } + + @Test def testEnumerationWrapping(): Unit = { + val nullJEnumeration: ju.Enumeration[AnyRef] = null + val enumeration: Iterator[AnyRef] = nullJEnumeration + + assert(enumeration == null) + } + + @Test def testIterableWrapping(): Unit = { + val nullJIterable: jl.Iterable[AnyRef] = null + val iterable: Iterable[AnyRef] = nullJIterable + + assert(iterable == null) + } + + @Test def testCollectionWrapping(): Unit = { + val nullJCollection: ju.Collection[AnyRef] = null + val collection: Iterable[AnyRef] = nullJCollection + + assert(collection == null) + } + + @Test def testBufferWrapping(): Unit = { + val nullJList: ju.List[AnyRef] = null + val buffer: mutable.Buffer[AnyRef] = nullJList + + assert(buffer == null) + } + + @Test def testSetWrapping(): Unit = { + val nullJSet: ju.Set[AnyRef] = null + val set: mutable.Set[AnyRef] = nullJSet + + assert(set == null) + } + + @Test def testMapWrapping(): Unit = { + val nullJMap: ju.Map[AnyRef, AnyRef] = null + val map: mutable.Map[AnyRef, AnyRef] = nullJMap + + assert(map == null) + } + + @Test def testConcurrentMapWrapping(): Unit = { + val nullJConMap: juc.ConcurrentMap[AnyRef, AnyRef] = null + val conMap: concurrent.Map[AnyRef, AnyRef] = nullJConMap + + assert(conMap == null) + } + + @Test def testDictionaryWrapping(): Unit = { + val nullJDict: ju.Dictionary[AnyRef, AnyRef] = null + val dict: mutable.Map[AnyRef, AnyRef] = nullJDict + + assert(dict == null) + } + + + @Test def testPropertyWrapping(): Unit = { + val nullJProps: ju.Properties = null + val props: mutable.Map[String, String] = nullJProps + + assert(props == null) + } + + @Test def testIteratorDecoration(): Unit = { + val nullJIterator: ju.Iterator[AnyRef] = null + + assert(nullJIterator.asScala == null) + } + + @Test def testEnumerationDecoration(): Unit = { + val nullJEnumeration: ju.Enumeration[AnyRef] = null + + assert(nullJEnumeration.asScala == null) + } + + @Test def testIterableDecoration(): Unit = { + val nullJIterable: jl.Iterable[AnyRef] = null + + assert(nullJIterable.asScala == null) + } + + @Test def testCollectionDecoration(): Unit = { + val nullJCollection: ju.Collection[AnyRef] = null + + assert(nullJCollection.asScala == null) + } + + @Test def testBufferDecoration(): Unit = { + val nullJBuffer: ju.List[AnyRef] = null + + assert(nullJBuffer.asScala == null) + } + + @Test def testSetDecoration(): Unit = { + val nullJSet: ju.Set[AnyRef] = null + + assert(nullJSet.asScala == null) + } + + @Test def testMapDecoration(): Unit = { + val nullJMap: ju.Map[AnyRef, AnyRef] = null + + assert(nullJMap.asScala == null) + } + + @Test def testConcurrentMapDecoration(): Unit = { + val nullJConMap: juc.ConcurrentMap[AnyRef, AnyRef] = null + + assert(nullJConMap.asScala == null) + } + + @Test def testDictionaryDecoration(): Unit = { + val nullJDict: ju.Dictionary[AnyRef, AnyRef] = null + + assert(nullJDict.asScala == null) + } + + @Test def testPropertiesDecoration(): Unit = { + val nullJProperties: ju.Properties = null + + assert(nullJProperties.asScala == null) + } +} diff --git a/test/junit/scala/issues/BytecodeTest.scala b/test/junit/scala/issues/BytecodeTest.scala deleted file mode 100644 index 7b9474b52e..0000000000 --- a/test/junit/scala/issues/BytecodeTest.scala +++ /dev/null @@ -1,482 +0,0 @@ -package scala.issues - -import org.junit.runner.RunWith -import org.junit.runners.JUnit4 -import org.junit.Test - -import scala.tools.asm.Opcodes._ -import scala.tools.nsc.backend.jvm.AsmUtils -import scala.tools.nsc.backend.jvm.CodeGenTools._ -import org.junit.Assert._ - -import scala.collection.JavaConverters._ -import scala.tools.asm.Opcodes -import scala.tools.asm.tree.ClassNode -import scala.tools.partest.ASMConverters._ -import scala.tools.testing.ClearAfterClass - -@RunWith(classOf[JUnit4]) -class BytecodeTest extends ClearAfterClass { - val compiler = cached("compiler", () => newCompiler()) - - @Test - def t8731(): Unit = { - val code = - """class C { - | def f(x: Int) = (x: @annotation.switch) match { - | case 1 => 0 - | case 2 => 1 - | case 3 => 2 - | } - | final val K = 10 - | def g(x: Int) = (x: @annotation.switch) match { - | case K => 0 - | case 1 => 10 - | case 2 => 20 - | } - |} - """.stripMargin - - val List(c) = compileClasses(compiler)(code) - - assertTrue(getSingleMethod(c, "f").instructions.count(_.isInstanceOf[TableSwitch]) == 1) - assertTrue(getSingleMethod(c, "g").instructions.count(_.isInstanceOf[LookupSwitch]) == 1) - } - - @Test - def t8926(): Unit = { - import scala.reflect.internal.util.BatchSourceFile - - // this test cannot be implemented using partest because of its mixed-mode compilation strategy: - // partest first compiles all files with scalac, then the java files, and then again the scala - // using the output classpath. this shadows the bug SI-8926. - - val annotA = - """import java.lang.annotation.Retention; - |import java.lang.annotation.RetentionPolicy; - |@Retention(RetentionPolicy.RUNTIME) - |public @interface AnnotA { } - """.stripMargin - val annotB = "public @interface AnnotB { }" - - val scalaSrc = - """@AnnotA class A - |@AnnotB class B - """.stripMargin - - val run = new compiler.Run() - run.compileSources(List(new BatchSourceFile("AnnotA.java", annotA), new BatchSourceFile("AnnotB.java", annotB), new BatchSourceFile("Test.scala", scalaSrc))) - val outDir = compiler.settings.outputDirs.getSingleOutput.get - val outfiles = (for (f <- outDir.iterator if !f.isDirectory) yield (f.name, f.toByteArray)).toList - - def check(classfile: String, annotName: String) = { - val f = (outfiles collect { case (`classfile`, bytes) => AsmUtils.readClass(bytes) }).head - val descs = f.visibleAnnotations.asScala.map(_.desc).toList - assertTrue(descs.toString, descs exists (_ contains annotName)) - } - - check("A.class", "AnnotA") - - // known issue SI-8928: the visibility of AnnotB should be CLASS, but annotation classes without - // a @Retention annotation are currently emitted as RUNTIME. - check("B.class", "AnnotB") - } - - @Test - def t6288bJumpPosition(): Unit = { - val code = - """object Case3 { // 01 - | def unapply(z: Any): Option[Int] = Some(-1) // 02 - | def main(args: Array[String]) { // 03 - | ("": Any) match { // 04 - | case x : String => // 05 - | println("case 0") // 06 println and jump at 6 - | case _ => // 07 - | println("default") // 08 println and jump at 8 - | } // 09 - | println("done") // 10 - | } - |} - """.stripMargin - val List(mirror, module) = compileClasses(compiler)(code) - - val unapplyLineNumbers = getSingleMethod(module, "unapply").instructions.filter(_.isInstanceOf[LineNumber]) - assert(unapplyLineNumbers == List(LineNumber(2, Label(0))), unapplyLineNumbers) - - val expected = List( - LineNumber(4, Label(0)), - LineNumber(5, Label(5)), - Jump(IFEQ, Label(20)), - - LineNumber(6, Label(11)), - Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false), - Jump(GOTO, Label(33)), - - LineNumber(5, Label(20)), - Jump(GOTO, Label(24)), - - LineNumber(8, Label(24)), - Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false), - Jump(GOTO, Label(33)), - - LineNumber(10, Label(33)), - Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false) - ) - - val mainIns = getSingleMethod(module, "main").instructions filter { - case _: LineNumber | _: Invoke | _: Jump => true - case _ => false - } - assertSameCode(mainIns, expected) - } - - @Test - def bytecodeForBranches(): Unit = { - val code = - """class C { - | def t1(b: Boolean) = if (b) 1 else 2 - | def t2(x: Int) = if (x == 393) 1 else 2 - | def t3(a: Array[String], b: AnyRef) = a != b && b == a - | def t4(a: AnyRef) = a == null || null != a - | def t5(a: AnyRef) = (a eq null) || (null ne a) - | def t6(a: Int, b: Boolean) = if ((a == 10) && b || a != 1) 1 else 2 - | def t7(a: AnyRef, b: AnyRef) = a == b - | def t8(a: AnyRef) = Nil == a || "" != a - |} - """.stripMargin - - val List(c) = compileClasses(compiler)(code) - - // t1: no unnecessary GOTOs - assertSameCode(getSingleMethod(c, "t1"), List( - VarOp(ILOAD, 1), Jump(IFEQ, Label(6)), - Op(ICONST_1), Jump(GOTO, Label(9)), - Label(6), Op(ICONST_2), - Label(9), Op(IRETURN))) - - // t2: no unnecessary GOTOs - assertSameCode(getSingleMethod(c, "t2"), List( - VarOp(ILOAD, 1), IntOp(SIPUSH, 393), Jump(IF_ICMPNE, Label(7)), - Op(ICONST_1), Jump(GOTO, Label(10)), - Label(7), Op(ICONST_2), - Label(10), Op(IRETURN))) - - // t3: Array == is translated to reference equality, AnyRef == to null checks and equals - assertSameCode(getSingleMethod(c, "t3"), List( - // Array == - VarOp(ALOAD, 1), VarOp(ALOAD, 2), Jump(IF_ACMPEQ, Label(23)), - // AnyRef == - VarOp(ALOAD, 2), VarOp(ALOAD, 1), VarOp(ASTORE, 3), Op(DUP), Jump(IFNONNULL, Label(14)), - Op(POP), VarOp(ALOAD, 3), Jump(IFNULL, Label(19)), Jump(GOTO, Label(23)), - Label(14), VarOp(ALOAD, 3), Invoke(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false), Jump(IFEQ, Label(23)), - Label(19), Op(ICONST_1), Jump(GOTO, Label(26)), - Label(23), Op(ICONST_0), - Label(26), Op(IRETURN))) - - val t4t5 = List( - VarOp(ALOAD, 1), Jump(IFNULL, Label(6)), - VarOp(ALOAD, 1), Jump(IFNULL, Label(10)), - Label(6), Op(ICONST_1), Jump(GOTO, Label(13)), - Label(10), Op(ICONST_0), - Label(13), Op(IRETURN)) - - // t4: one side is known null, so just a null check on the other - assertSameCode(getSingleMethod(c, "t4"), t4t5) - - // t5: one side known null, so just a null check on the other - assertSameCode(getSingleMethod(c, "t5"), t4t5) - - // t6: no unnecessary GOTOs - assertSameCode(getSingleMethod(c, "t6"), List( - VarOp(ILOAD, 1), IntOp(BIPUSH, 10), Jump(IF_ICMPNE, Label(7)), - VarOp(ILOAD, 2), Jump(IFNE, Label(12)), - Label(7), VarOp(ILOAD, 1), Op(ICONST_1), Jump(IF_ICMPEQ, Label(16)), - Label(12), Op(ICONST_1), Jump(GOTO, Label(19)), - Label(16), Op(ICONST_2), - Label(19), Op(IRETURN))) - - // t7: universal equality - assertInvoke(getSingleMethod(c, "t7"), "scala/runtime/BoxesRunTime", "equals") - - // t8: no null checks invoking equals on modules and constants - assertSameCode(getSingleMethod(c, "t8"), List( - Field(GETSTATIC, "scala/collection/immutable/Nil$", "MODULE$", "Lscala/collection/immutable/Nil$;"), VarOp(ALOAD, 1), Invoke(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false), Jump(IFNE, Label(10)), - Ldc(LDC, ""), VarOp(ALOAD, 1), Invoke(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false), Jump(IFNE, Label(14)), - Label(10), Op(ICONST_1), Jump(GOTO, Label(17)), - Label(14), Op(ICONST_0), - Label(17), Op(IRETURN))) - } - - object forwarderTestUtils { - def findMethods(cls: ClassNode, name: String): List[Method] = cls.methods.iterator.asScala.find(_.name == name).map(convertMethod).toList - - import language.implicitConversions - implicit def s2c(s: Symbol)(implicit classes: Map[String, ClassNode]): ClassNode = classes(s.name) - - def checkForwarder(c: ClassNode, target: String) = { - val List(f) = findMethods(c, "f") - assertSameCode(f, List(VarOp(ALOAD, 0), Invoke(INVOKESPECIAL, target, "f", "()I", false), Op(IRETURN))) - } - } - - @Test - def traitMethodForwarders(): Unit = { - import forwarderTestUtils._ - val code = - """trait T1 { def f = 1 } - |trait T2 extends T1 { override def f = 2 } - |trait T3 { self: T1 => override def f = 3 } - | - |abstract class A1 { def f: Int } - |class A2 { def f: Int = 4 } - | - |trait T4 extends A1 { def f = 5 } - |trait T5 extends A2 { override def f = 6 } - | - |trait T6 { def f: Int } - |trait T7 extends T6 { abstract override def f = super.f + 1 } - | - |trait T8 { override def clone() = super.clone() } - | - |class A3 extends T1 { override def f = 7 } - | - |class C1 extends T1 - |class C2 extends T2 - |class C3 extends T1 with T2 - |class C4 extends T2 with T1 - |class C5 extends T1 with T3 - | - |// traits extending a class that defines f - |class C6 extends T4 - |class C7 extends T5 - |class C8 extends A1 with T4 - |class C9 extends A2 with T5 - | - |// T6: abstract f in trait - |class C10 extends T6 with T1 - |class C11 extends T6 with T2 - |abstract class C12 extends A1 with T6 - |class C13 extends A2 with T6 - |class C14 extends T4 with T6 - |class C15 extends T5 with T6 - | - |// superclass overrides a trait method - |class C16 extends A3 - |class C17 extends A3 with T1 - | - |// abstract override - |class C18 extends T6 { def f = 22 } - |class C19 extends C18 with T7 - | - |class C20 extends T8 - """.stripMargin - - implicit val classes = compileClasses(compiler)(code).map(c => (c.name, c)).toMap - - val noForwarder = List('C1, 'C2, 'C3, 'C4, 'C10, 'C11, 'C12, 'C13, 'C16, 'C17) - for (c <- noForwarder) assertEquals(findMethods(c, "f"), Nil) - - checkForwarder('C5, "T3") - checkForwarder('C6, "T4") - checkForwarder('C7, "T5") - checkForwarder('C8, "T4") - checkForwarder('C9, "T5") - checkForwarder('C14, "T4") - checkForwarder('C15, "T5") - assertSameSummary(getSingleMethod('C18, "f"), List(BIPUSH, IRETURN)) - checkForwarder('C19, "T7") - assertSameCode(getSingleMethod('C19, "T7$$super$f"), List(VarOp(ALOAD, 0), Invoke(INVOKESPECIAL, "C18", "f", "()I", false), Op(IRETURN))) - assertInvoke(getSingleMethod('C20, "clone"), "T8", "clone") // mixin forwarder - } - - @Test - def noTraitMethodForwardersForOverloads(): Unit = { - import forwarderTestUtils._ - val code = - """trait T1 { def f(x: Int) = 0 } - |trait T2 { def f(x: String) = 1 } - |class C extends T1 with T2 - """.stripMargin - val List(c, t1, t2) = compileClasses(compiler)(code) - assertEquals(findMethods(c, "f"), Nil) - } - - @Test - def traitMethodForwardersForJavaDefaultMethods(): Unit = { - import forwarderTestUtils._ - val j1 = ("interface J1 { int f(); }", "J1.java") - val j2 = ("interface J2 { default int f() { return 1; } }", "J2.java") - val j3 = ("interface J3 extends J1 { default int f() { return 2; } }", "J3.java") - val j4 = ("interface J4 extends J2 { default int f() { return 3; } }", "J4.java") - val code = - """trait T1 extends J2 { override def f = 4 } - |trait T2 { self: J2 => override def f = 5 } - | - |class K1 extends J2 - |class K2 extends J1 with J2 - |class K3 extends J2 with J1 - | - |class K4 extends J3 - |class K5 extends J3 with J1 - |class K6 extends J1 with J3 - | - |class K7 extends J4 - |class K8 extends J4 with J2 - |class K9 extends J2 with J4 - | - |class K10 extends T1 with J2 - |class K11 extends J2 with T1 - | - |class K12 extends J2 with T2 - """.stripMargin - implicit val classes = compileClasses(compiler)(code, List(j1, j2, j3, j4)).map(c => (c.name, c)).toMap - - val noForwarder = List('K1, 'K2, 'K3, 'K4, 'K5, 'K6, 'K7, 'K8, 'K9, 'K10, 'K11) - for (c <- noForwarder) assertEquals(findMethods(c, "f"), Nil) - - checkForwarder('K12, "T2") - } - - @Test - def invocationReceivers(): Unit = { - val List(c1, c2, t, u) = compileClasses(compiler)(invocationReceiversTestCode.definitions("Object")) - // mixin forwarder in C1 - assertSameCode(getSingleMethod(c1, "clone"), List(VarOp(ALOAD, 0), Invoke(INVOKESPECIAL, "T", "clone", "()Ljava/lang/Object;", false), Op(ARETURN))) - assertInvoke(getSingleMethod(c1, "f1"), "T", "clone") - assertInvoke(getSingleMethod(c1, "f2"), "T", "clone") - assertInvoke(getSingleMethod(c1, "f3"), "C1", "clone") - assertInvoke(getSingleMethod(c2, "f1"), "T", "clone") - assertInvoke(getSingleMethod(c2, "f2"), "T", "clone") - assertInvoke(getSingleMethod(c2, "f3"), "C1", "clone") - - val List(c1b, c2b, tb, ub) = compileClasses(compiler)(invocationReceiversTestCode.definitions("String")) - def ms(c: ClassNode, n: String) = c.methods.asScala.toList.filter(_.name == n) - assert(ms(tb, "clone").length == 1) - assert(ms(ub, "clone").isEmpty) - val List(c1Clone) = ms(c1b, "clone") - assertEquals(c1Clone.desc, "()Ljava/lang/Object;") - assert((c1Clone.access | Opcodes.ACC_BRIDGE) != 0) - assertSameCode(convertMethod(c1Clone), List(VarOp(ALOAD, 0), Invoke(INVOKEVIRTUAL, "C1", "clone", "()Ljava/lang/String;", false), Op(ARETURN))) - - def iv(m: Method) = getSingleMethod(c1b, "f1").instructions.collect({case i: Invoke => i}) - assertSameCode(iv(getSingleMethod(c1b, "f1")), List(Invoke(INVOKEINTERFACE, "T", "clone", "()Ljava/lang/String;", true))) - assertSameCode(iv(getSingleMethod(c1b, "f2")), List(Invoke(INVOKEINTERFACE, "T", "clone", "()Ljava/lang/String;", true))) - // invokeinterface T.clone in C1 is OK here because it is not an override of Object.clone (different siganture) - assertSameCode(iv(getSingleMethod(c1b, "f3")), List(Invoke(INVOKEINTERFACE, "T", "clone", "()Ljava/lang/String;", true))) - } - - @Test - def invocationReceiversProtected(): Unit = { - // http://lrytz.github.io/scala-aladdin-bugtracker/displayItem.do%3Fid=455.html / 9954eaf - // also https://issues.scala-lang.org/browse/SI-1430 / 0bea2ab (same but with interfaces) - val aC = - """package a; - |/*package private*/ abstract class A { - | public int f() { return 1; } - | public int t; - |} - """.stripMargin - val bC = - """package a; - |public class B extends A { } - """.stripMargin - val iC = - """package a; - |/*package private*/ interface I { int f(); } - """.stripMargin - val jC = - """package a; - |public interface J extends I { } - """.stripMargin - val cC = - """package b - |class C { - | def f1(b: a.B) = b.f - | def f2(b: a.B) = { b.t = b.t + 1 } - | def f3(j: a.J) = j.f - |} - """.stripMargin - val List(c) = compileClasses(compiler)(cC, javaCode = List((aC, "A.java"), (bC, "B.java"), (iC, "I.java"), (jC, "J.java"))) - assertInvoke(getSingleMethod(c, "f1"), "a/B", "f") // receiver needs to be B (A is not accessible in class C, package b) - println(getSingleMethod(c, "f2").instructions.stringLines) - assertInvoke(getSingleMethod(c, "f3"), "a/J", "f") // receiver needs to be J - } - - @Test - def specialInvocationReceivers(): Unit = { - val code = - """class C { - | def f1(a: Array[String]) = a.clone() - | def f2(a: Array[Int]) = a.hashCode() - | def f3(n: Nothing) = n.hashCode() - | def f4(n: Null) = n.toString() - | - |} - """.stripMargin - val List(c) = compileClasses(compiler)(code) - assertInvoke(getSingleMethod(c, "f1"), "[Ljava/lang/String;", "clone") // array descriptor as receiver - assertInvoke(getSingleMethod(c, "f2"), "java/lang/Object", "hashCode") // object receiver - assertInvoke(getSingleMethod(c, "f3"), "java/lang/Object", "hashCode") - assertInvoke(getSingleMethod(c, "f4"), "java/lang/Object", "toString") - } - - @Test - def superConstructorArgumentInSpecializedClass(): Unit = { - // see comment in SpecializeTypes.forwardCtorCall - val code = "case class C[@specialized(Int) T](_1: T)" - val List(c, cMod, cSpec) = compileClasses(compiler)(code) - assertSameSummary(getSingleMethod(cSpec, "<init>"), - // pass `null` to super constructor, no box-unbox, no Integer created - List(ALOAD, ILOAD, PUTFIELD, ALOAD, ACONST_NULL, "<init>", RETURN)) - } -} - -object invocationReceiversTestCode { - // if cloneType is more specific than Object (e.g., String), a bridge method is generated. - def definitions(cloneType: String) = - s"""trait T { override def clone(): $cloneType = "hi" } - |trait U extends T - |class C1 extends U with Cloneable { - | // The comments below are true when $cloneType is Object. - | // C1 gets a forwarder for clone that invokes T.clone. this is needed because JVM method - | // resolution always prefers class members, so it would resolve to Object.clone, even if - | // C1 is a subtype of the interface T which has an overriding default method for clone. - | - | // invokeinterface T.clone - | def f1 = (this: T).clone() - | - | // cannot invokeinterface U.clone (NoSuchMethodError). Object.clone would work here, but - | // not in the example in C2 (illegal access to protected). T.clone works in all cases and - | // resolves correctly. - | def f2 = (this: U).clone() - | - | // invokevirtual C1.clone() - | def f3 = (this: C1).clone() - |} - | - |class C2 { - | def f1(t: T) = t.clone() // invokeinterface T.clone - | def f2(t: U) = t.clone() // invokeinterface T.clone -- Object.clone would be illegal (protected, explained in C1) - | def f3(t: C1) = t.clone() // invokevirtual C1.clone -- Object.clone would be illegal - |} - """.stripMargin - - val runCode = - """ - |val r = new StringBuffer() - |val c1 = new C1 - |r.append(c1.f1) - |r.append(c1.f2) - |r.append(c1.f3) - |val t = new T { } - |val u = new U { } - |val c2 = new C2 - |r.append(c2.f1(t)) - |r.append(c2.f1(u)) - |r.append(c2.f1(c1)) - |r.append(c2.f2(u)) - |r.append(c2.f2(c1)) - |r.append(c2.f3(c1)) - |r.toString - """.stripMargin -} diff --git a/test/junit/scala/issues/RunTest.scala b/test/junit/scala/issues/RunTest.scala deleted file mode 100644 index 3ebdc8a72f..0000000000 --- a/test/junit/scala/issues/RunTest.scala +++ /dev/null @@ -1,253 +0,0 @@ -package scala.issues - -import org.junit.runner.RunWith -import org.junit.runners.JUnit4 -import org.junit.{AfterClass, BeforeClass, Test} -import org.junit.Assert._ - -import scala.reflect.runtime._ -import scala.tools.reflect.ToolBox -import scala.tools.testing.ClearAfterClass - -object RunTest { - class VC(val x: Any) extends AnyVal - class VCI(val x: Int) extends AnyVal { override def toString = "" + x } -} - -@RunWith(classOf[JUnit4]) -class RunTest extends ClearAfterClass { - val toolBox = cached("toolbox", () => universe.runtimeMirror(getClass.getClassLoader).mkToolBox()) - - def run[T](code: String): T = { - toolBox.eval(toolBox.parse(code)).asInstanceOf[T] - } - - @Test - def classOfValueClassAlias(): Unit = { - val code = - """import scala.issues.RunTest.VC - |type aVC = VC - |type aInt = Int - |type aInteger = Integer - |classOf[VC] == classOf[aVC] && - | classOf[aInt] == classOf[Int] && - | classOf[aInteger] == classOf[Integer] && - | classOf[aInt] != classOf[aInteger] - """.stripMargin - assertTrue(run[Boolean](code)) - } - - @Test - def classOfFinalVal(): Unit = { - val code = - """class C { - | final val a1 = classOf[Int] - | final val b1 = classOf[List[_]] - | final val c1 = classOf[List[String]] - | final val d1 = classOf[Array[Int]] - | final val e1 = classOf[Array[List[_]]] - | final val f1 = classOf[Array[_]] - | - | val a2 = classOf[Int] - | val b2 = classOf[List[_]] - | val c2 = classOf[List[String]] - | val d2 = classOf[Array[Int]] - | val e2 = classOf[Array[List[_]]] - | val f2 = classOf[Array[_]] - | - | val listC = Class.forName("scala.collection.immutable.List") - | - | val compare = List( - | (a1, a2, Integer.TYPE), - | (b1, b2, listC), - | (c1, c2, listC), - | (d1, d2, Array(1).getClass), - | (e1, e2, Array(List()).getClass), - | (f1, f2, new Object().getClass)) - |} - |(new C).compare - """.stripMargin - type K = Class[_] - val cs = run[List[(K, K, K)]](code) - for ((x, y, z) <- cs) { - assertEquals(x, y) - assertEquals(x, z) - } - } - - @Test - def t9702(): Unit = { - val code = - """import javax.annotation.Resource - |import scala.issues.RunTest.VC - |class C { - | type aList[K] = List[K] - | type aVC = VC - | type aInt = Int - | type aInteger = Integer - | @Resource(`type` = classOf[List[Int]]) def a = 0 - | @Resource(`type` = classOf[List[_]]) def b = 0 - | @Resource(`type` = classOf[aList[_]]) def c = 0 - | @Resource(`type` = classOf[Int]) def d = 0 - | @Resource(`type` = classOf[aInt]) def e = 0 - | @Resource(`type` = classOf[Integer]) def f = 0 - | @Resource(`type` = classOf[aInteger]) def g = 0 - | @Resource(`type` = classOf[VC]) def h = 0 - | @Resource(`type` = classOf[aVC]) def i = 0 - | @Resource(`type` = classOf[Array[Int]]) def j = 0 - | @Resource(`type` = classOf[Array[List[_]]]) def k = 0 - |} - |val c = classOf[C] - |def typeArg(meth: String) = c.getDeclaredMethod(meth).getDeclaredAnnotation(classOf[Resource]).`type` - |('a' to 'k').toList.map(_.toString).map(typeArg) - """.stripMargin - - val l = Class.forName("scala.collection.immutable.List") - val i = Integer.TYPE - val ig = new Integer(1).getClass - val v = new RunTest.VC(1).getClass - val ai = Array(1).getClass - val al = Array(List()).getClass - - // sanity checks - assertEquals(i, classOf[Int]) - assertNotEquals(i, ig) - - assertEquals(run[List[Class[_]]](code), - List(l, l, l, i, i, ig, ig, v, v, ai, al)) - } - - @Test - def annotationInfoNotErased(): Unit = { - val code = - """import javax.annotation.Resource - |import scala.annotation.meta.getter - |class C { - | type Rg = Resource @getter - | @(Resource @getter)(`type` = classOf[Int]) def a = 0 - | @Rg(`type` = classOf[Int]) def b = 0 - |} - |val c = classOf[C] - |def typeArg(meth: String) = c.getDeclaredMethod(meth).getDeclaredAnnotation(classOf[Resource]).`type` - |List("a", "b") map typeArg - |""".stripMargin - - val i = Integer.TYPE - assertEquals(run[List[Class[_]]](code), List(i, i)) - } - - @Test - def invocationReceivers(): Unit = { - import invocationReceiversTestCode._ - assertEquals(run[String](definitions("Object") + runCode), "hi" * 9) - assertEquals(run[String](definitions("String") + runCode), "hi" * 9) // bridge method for clone generated - } - - @Test - def classOfUnitConstant(): Unit = { - val code = - """abstract class A { def f: Class[_] } - |class C extends A { final val f = classOf[Unit] } - |val c = new C - |(c.f, (c: A).f) - """.stripMargin - val u = Void.TYPE - assertEquals(run[(Class[_], Class[_])](code), (u, u)) - } - - @Test - def t9671(): Unit = { - val code = - """import scala.issues.RunTest.VCI - | - |def f1(a: Any) = "" + a - |def f2(a: AnyVal) = "" + a - |def f3[T](a: T) = "" + a - |def f4(a: Int) = "" + a - |def f5(a: VCI) = "" + a - |def f6(u: Unit) = "" + u - | - |def n1: AnyRef = null - |def n2: Null = null - |def n3: Any = null - |def n4[T]: T = null.asInstanceOf[T] - | - |def npe(s: => String) = try { s; throw new Error() } catch { case _: NullPointerException => "npe" } - | - | f1(null.asInstanceOf[Int]) + - | f1( n1.asInstanceOf[Int]) + - | f1( n2.asInstanceOf[Int]) + - | f1( n3.asInstanceOf[Int]) + - | f1( n4[Int]) + // "null" - |"-" + - | f1(null.asInstanceOf[VCI]) + - |npe(f1( n1.asInstanceOf[VCI])) + // SI-8097 - | f1( n2.asInstanceOf[VCI]) + - |npe(f1( n3.asInstanceOf[VCI])) + // SI-8097 - | f1( n4[VCI]) + // "null" - |"-" + - | f1(null.asInstanceOf[Unit]) + - | f1( n1.asInstanceOf[Unit]) + - | f1( n2.asInstanceOf[Unit]) + - | f1( n3.asInstanceOf[Unit]) + - | f1( n4[Unit]) + // "null" - |"-" + - | f2(null.asInstanceOf[Int]) + - | f2( n1.asInstanceOf[Int]) + - | f2( n2.asInstanceOf[Int]) + - | f2( n3.asInstanceOf[Int]) + - | f2( n4[Int]) + // "null" - |"-" + - | f2(null.asInstanceOf[VCI]) + - |npe(f2( n1.asInstanceOf[VCI])) + // SI-8097 - | f2( n2.asInstanceOf[VCI]) + - |npe(f2( n3.asInstanceOf[VCI])) + // SI-8097 - | f2( n4[VCI]) + // "null" - |"-" + - | f2(null.asInstanceOf[Unit]) + - | f2( n1.asInstanceOf[Unit]) + - | f2( n2.asInstanceOf[Unit]) + - | f2( n3.asInstanceOf[Unit]) + - | f2( n4[Unit]) + // "null" - |"-" + - | f3(null.asInstanceOf[Int]) + - | f3( n1.asInstanceOf[Int]) + - | f3( n2.asInstanceOf[Int]) + - | f3( n3.asInstanceOf[Int]) + - | f3( n4[Int]) + // "null" - |"-" + - | f3(null.asInstanceOf[VCI]) + - |npe(f3( n1.asInstanceOf[VCI])) + // SI-8097 - | f3( n2.asInstanceOf[VCI]) + - |npe(f3( n3.asInstanceOf[VCI])) + // SI-8097 - | f3( n4[VCI]) + // "null" - |"-" + - | f3(null.asInstanceOf[Unit]) + - | f3( n1.asInstanceOf[Unit]) + - | f3( n2.asInstanceOf[Unit]) + - | f3( n3.asInstanceOf[Unit]) + - | f3( n4[Unit]) + // "null" - |"-" + - | f4(null.asInstanceOf[Int]) + - | f4( n1.asInstanceOf[Int]) + - | f4( n2.asInstanceOf[Int]) + - | f4( n3.asInstanceOf[Int]) + - | f4( n4[Int]) + - |"-" + - | f5(null.asInstanceOf[VCI]) + - |npe(f5( n1.asInstanceOf[VCI])) + // SI-8097 - | f5( n2.asInstanceOf[VCI]) + - |npe(f5( n3.asInstanceOf[VCI])) + // SI-8097 - |npe(f5( n4[VCI])) + // SI-8097 - |"-" + - | f6(null.asInstanceOf[Unit]) + - | f6( n1.asInstanceOf[Unit]) + - | f6( n2.asInstanceOf[Unit]) + - | f6( n3.asInstanceOf[Unit]) + - | f6( n4[Unit]) // "null" - """.stripMargin - - assertEquals(run[String](code), - "0000null-0npe0npenull-()()()()null-0000null-0npe0npenull-()()()()null-0000null-0npe0npenull-()()()()null-00000-0npe0npenpe-()()()()null") - } -} diff --git a/test/junit/scala/lang/annotations/BytecodeTest.scala b/test/junit/scala/lang/annotations/BytecodeTest.scala new file mode 100644 index 0000000000..09fc1d3572 --- /dev/null +++ b/test/junit/scala/lang/annotations/BytecodeTest.scala @@ -0,0 +1,80 @@ +package scala.lang.annotations + +import org.junit.Assert._ +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import scala.collection.JavaConverters._ +import scala.tools.nsc.backend.jvm.AsmUtils +import scala.tools.partest.ASMConverters._ +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ + +@RunWith(classOf[JUnit4]) +class BytecodeTest extends BytecodeTesting { + import compiler._ + + @Test + def t8731(): Unit = { + val code = + """class C { + | def f(x: Int) = (x: @annotation.switch) match { + | case 1 => 0 + | case 2 => 1 + | case 3 => 2 + | } + | final val K = 10 + | def g(x: Int) = (x: @annotation.switch) match { + | case K => 0 + | case 1 => 10 + | case 2 => 20 + | } + |} + """.stripMargin + + val c = compileClass(code) + + assertTrue(getInstructions(c, "f").count(_.isInstanceOf[TableSwitch]) == 1) + assertTrue(getInstructions(c, "g").count(_.isInstanceOf[LookupSwitch]) == 1) + } + + @Test + def t8926(): Unit = { + import scala.reflect.internal.util.BatchSourceFile + + // this test cannot be implemented using partest because of its mixed-mode compilation strategy: + // partest first compiles all files with scalac, then the java files, and then again the scala + // using the output classpath. this shadows the bug SI-8926. + + val annotA = + """import java.lang.annotation.Retention; + |import java.lang.annotation.RetentionPolicy; + |@Retention(RetentionPolicy.RUNTIME) + |public @interface AnnotA { } + """.stripMargin + val annotB = "public @interface AnnotB { }" + + val scalaSrc = + """@AnnotA class A + |@AnnotB class B + """.stripMargin + + val run = new global.Run() + run.compileSources(List(new BatchSourceFile("AnnotA.java", annotA), new BatchSourceFile("AnnotB.java", annotB), new BatchSourceFile("Test.scala", scalaSrc))) + val outDir = global.settings.outputDirs.getSingleOutput.get + val outfiles = (for (f <- outDir.iterator if !f.isDirectory) yield (f.name, f.toByteArray)).toList + + def check(classfile: String, annotName: String) = { + val f = (outfiles collect { case (`classfile`, bytes) => AsmUtils.readClass(bytes) }).head + val descs = f.visibleAnnotations.asScala.map(_.desc).toList + assertTrue(descs.toString, descs exists (_ contains annotName)) + } + + check("A.class", "AnnotA") + + // known issue SI-8928: the visibility of AnnotB should be CLASS, but annotation classes without + // a @Retention annotation are currently emitted as RUNTIME. + check("B.class", "AnnotB") + } +}
\ No newline at end of file diff --git a/test/junit/scala/lang/annotations/RunTest.scala b/test/junit/scala/lang/annotations/RunTest.scala new file mode 100644 index 0000000000..0d9c0c4713 --- /dev/null +++ b/test/junit/scala/lang/annotations/RunTest.scala @@ -0,0 +1,32 @@ +package scala.lang.annotations + +import org.junit.Assert._ +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import scala.tools.testing.RunTesting + +@RunWith(classOf[JUnit4]) +class RunTest extends RunTesting { + import runner._ + + @Test + def annotationInfoNotErased(): Unit = { + val code = + """import javax.annotation.Resource + |import scala.annotation.meta.getter + |class C { + | type Rg = Resource @getter + | @(Resource @getter)(`type` = classOf[Int]) def a = 0 + | @Rg(`type` = classOf[Int]) def b = 0 + |} + |val c = classOf[C] + |def typeArg(meth: String) = c.getDeclaredMethod(meth).getDeclaredAnnotation(classOf[Resource]).`type` + |List("a", "b") map typeArg + |""".stripMargin + + val i = Integer.TYPE + assertEquals(run[List[Class[_]]](code), List(i, i)) + } +} diff --git a/test/junit/scala/lang/primitives/BoxUnboxTest.scala b/test/junit/scala/lang/primitives/BoxUnboxTest.scala new file mode 100644 index 0000000000..e4911f1af5 --- /dev/null +++ b/test/junit/scala/lang/primitives/BoxUnboxTest.scala @@ -0,0 +1,249 @@ +package scala.lang.primitives + +import org.junit.Assert._ +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import scala.tools.testing.RunTesting + +object BoxUnboxTest { + class VCI(val x: Int) extends AnyVal { override def toString = "" + x } +} + +@RunWith(classOf[JUnit4]) +class BoxUnboxTest extends RunTesting { + import runner._ + + @Test + def boxUnboxInt(): Unit = { + // Once we use 2.12.0-M5 as starr, this code can be run directly in the JUnit test. + // Some fixes not yet available in M4 make the test fail when compiled with M4. + val code = + """import scala.tools.testing.AssertUtil._ + |import org.junit.Assert._ + | + |def genericNull[T] = null.asInstanceOf[T] // allowed, see SI-4437, point 2 + | + |val b = new Integer(1) + |val u = 1 + | + |assertEquals(1.toInt, u) + | + |assertEquals(Predef.int2Integer(1), b) + |assertEquals(1: Integer, b) + |assertEquals(Int.box(1), b) + |assertEquals(1.asInstanceOf[Object], b) + | + |assertThrows[ClassCastException]("".asInstanceOf[Integer]) + | + |assertEquals(Predef.Integer2int(b), u) + |assertEquals(b: Int, u) + |assertEquals(Int.unbox(b), u) + |assertEquals(b.asInstanceOf[Int], u) + |assertEquals(b.intValue, u) + |assertEquals(b.toInt, u) + |intWrapper(b).toInt + | + |assertThrows[ClassCastException](Int.unbox("")) + |assertThrows[ClassCastException]("".asInstanceOf[Int]) + | + |// null unboxing in various positions + | + |val n1 = Int.unbox(null) + |assertEquals(n1, 0) + |val n2 = Predef.Integer2int(null) + |assertEquals(n2, 0) + |val n3 = (null: Integer): Int + |assertEquals(n3, 0) + |val n4 = null.asInstanceOf[Int] + |assertEquals(n4, 0) + |val n5 = null.asInstanceOf[Int] == 0 + |assertTrue(n5) + |val n6 = null.asInstanceOf[Int] == null + |assertFalse(n6) + |val n7 = null.asInstanceOf[Int] != 0 + |assertFalse(n7) + |val n8 = null.asInstanceOf[Int] != null + |assertTrue(n8) + | + |val mp = new java.util.HashMap[Int, Int] + |val n9 = mp.get(0) + |assertEquals(n9, 0) + |val n10 = mp.get(0) == null // SI-602 + |assertThrows[AssertionError](assertFalse(n10)) // should not throw + | + |def f(a: Any) = "" + a + |val n11 = f(null.asInstanceOf[Int]) + |assertEquals(n11, "0") + | + |def n12 = genericNull[Int] + |assertEquals(n12, 0) + """.stripMargin + + run[Unit](code) + } + + @Test + def numericConversions(): Unit = { + // Once we use 2.12.0-M5 as starr, this code can be run directly in the JUnit test. + val code = + """import scala.tools.testing.AssertUtil._ + |import org.junit.Assert._ + | + |val i1 = 1L.asInstanceOf[Int] + |assertEquals(i1, 1) + |assertThrows[ClassCastException] { + | val i2 = (1L: Any).asInstanceOf[Int] // SI-1448, should not throw. see also SI-4437 point 1. + | assertEquals(i2, 1) + |} + """.stripMargin + run[Unit](code) + } + + @Test + def boxUnboxBoolean(): Unit = { + // Once we use 2.12.0-M5 as starr, this code can be run directly in the JUnit test. + val code = + """val n1 = Option(null.asInstanceOf[Boolean]) + |n1 + """.stripMargin + assertEquals(run[Option[Boolean]](code), Some(false)) + } + + @Test + def boxUnboxUnit(): Unit = { + // should not use assertEquals in this test: it takes two Object parameters. normally, Unit does + // not conform to Object, but for Java-defined methods scalac makes an exception and treats them + // as Any. passing a Unit as Any makes the compiler go through another layer of boxing, so it + // can hide some bugs (where we actually have a null, but the compiler makes it a ()). + + // Once we use 2.12.0-M5 as starr, this code can be run directly in the JUnit test. + val code = + """import scala.tools.testing.AssertUtil._ + |import org.junit.Assert._ + | + |var v = 0 + |def eff() = { v = 1 } + |def chk() = { assert(v == 1); v = 0 } + | + |val b = runtime.BoxedUnit.UNIT + | + |assert(eff() == b); chk() + |assert(Unit.box(eff()) == b); chk() + |assert(().asInstanceOf[Object] == b) + | + |Unit.unbox({eff(); b}); chk() + |Unit.unbox({eff(); null}); chk() + |assertThrows[ClassCastException](Unit.unbox({eff(); ""})); chk() + | + |val n1 = null.asInstanceOf[Unit] + |assert(n1 == b) + | + |val n2 = null.asInstanceOf[Unit] == b + |assert(n2) + | + |def f(a: Any) = "" + a + |val n3 = f(null.asInstanceOf[Unit]) + |assertEquals(n3, "()") + """.stripMargin + run[Unit](code) + } + + @Test + def t9671(): Unit = { + // Once we use 2.12.0-M5 as starr, this code can be run directly in the JUnit test. + val code = + """import scala.lang.primitives.BoxUnboxTest.VCI + | + |def f1(a: Any) = "" + a + |def f2(a: AnyVal) = "" + a + |def f3[T](a: T) = "" + a + |def f4(a: Int) = "" + a + |def f5(a: VCI) = "" + a + |def f6(u: Unit) = "" + u + | + |def n1: AnyRef = null + |def n2: Null = null + |def n3: Any = null + |def n4[T]: T = null.asInstanceOf[T] + | + |def npe(s: => String) = try { s; throw new Error() } catch { case _: NullPointerException => "npe" } + | + | f1(null.asInstanceOf[Int]) + + | f1( n1.asInstanceOf[Int]) + + | f1( n2.asInstanceOf[Int]) + + | f1( n3.asInstanceOf[Int]) + + | f1( n4[Int]) + // "null" + |"-" + + | f1(null.asInstanceOf[VCI]) + + |npe(f1( n1.asInstanceOf[VCI])) + // SI-8097 + | f1( n2.asInstanceOf[VCI]) + + |npe(f1( n3.asInstanceOf[VCI])) + // SI-8097 + | f1( n4[VCI]) + // "null" + |"-" + + | f1(null.asInstanceOf[Unit]) + + | f1( n1.asInstanceOf[Unit]) + + | f1( n2.asInstanceOf[Unit]) + + | f1( n3.asInstanceOf[Unit]) + + | f1( n4[Unit]) + // "null" + |"-" + + | f2(null.asInstanceOf[Int]) + + | f2( n1.asInstanceOf[Int]) + + | f2( n2.asInstanceOf[Int]) + + | f2( n3.asInstanceOf[Int]) + + | f2( n4[Int]) + // "null" + |"-" + + | f2(null.asInstanceOf[VCI]) + + |npe(f2( n1.asInstanceOf[VCI])) + // SI-8097 + | f2( n2.asInstanceOf[VCI]) + + |npe(f2( n3.asInstanceOf[VCI])) + // SI-8097 + | f2( n4[VCI]) + // "null" + |"-" + + | f2(null.asInstanceOf[Unit]) + + | f2( n1.asInstanceOf[Unit]) + + | f2( n2.asInstanceOf[Unit]) + + | f2( n3.asInstanceOf[Unit]) + + | f2( n4[Unit]) + // "null" + |"-" + + | f3(null.asInstanceOf[Int]) + + | f3( n1.asInstanceOf[Int]) + + | f3( n2.asInstanceOf[Int]) + + | f3( n3.asInstanceOf[Int]) + + | f3( n4[Int]) + // "null" + |"-" + + | f3(null.asInstanceOf[VCI]) + + |npe(f3( n1.asInstanceOf[VCI])) + // SI-8097 + | f3( n2.asInstanceOf[VCI]) + + |npe(f3( n3.asInstanceOf[VCI])) + // SI-8097 + | f3( n4[VCI]) + // "null" + |"-" + + | f3(null.asInstanceOf[Unit]) + + | f3( n1.asInstanceOf[Unit]) + + | f3( n2.asInstanceOf[Unit]) + + | f3( n3.asInstanceOf[Unit]) + + | f3( n4[Unit]) + // "null" + |"-" + + | f4(null.asInstanceOf[Int]) + + | f4( n1.asInstanceOf[Int]) + + | f4( n2.asInstanceOf[Int]) + + | f4( n3.asInstanceOf[Int]) + + | f4( n4[Int]) + + |"-" + + | f5(null.asInstanceOf[VCI]) + + |npe(f5( n1.asInstanceOf[VCI])) + // SI-8097 + | f5( n2.asInstanceOf[VCI]) + + |npe(f5( n3.asInstanceOf[VCI])) + // SI-8097 + |npe(f5( n4[VCI])) + // SI-8097 + |"-" + + | f6(null.asInstanceOf[Unit]) + + | f6( n1.asInstanceOf[Unit]) + + | f6( n2.asInstanceOf[Unit]) + + | f6( n3.asInstanceOf[Unit]) + + | f6( n4[Unit]) // "null" + """.stripMargin + + assertEquals(run[String](code), + "0000null-0npe0npenull-()()()()null-0000null-0npe0npenull-()()()()null-0000null-0npe0npenull-()()()()null-00000-0npe0npenpe-()()()()null") + } +} diff --git a/test/junit/scala/PredefAutoboxingTest.scala b/test/junit/scala/lang/primitives/PredefAutoboxingTest.scala index e5d8ded5d4..ab31a9e8f1 100644 --- a/test/junit/scala/PredefAutoboxingTest.scala +++ b/test/junit/scala/lang/primitives/PredefAutoboxingTest.scala @@ -1,12 +1,10 @@ -package scala +package scala.lang.primitives -import org.junit.Test import org.junit.Assert._ +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import scala.tools.testing.AssertUtil._ - @RunWith(classOf[JUnit4]) class PredefAutoboxingTest { @Test def unboxNullByte() = diff --git a/test/junit/scala/StringContextTest.scala b/test/junit/scala/lang/stringinterpol/StringContextTest.scala index b5af6de7eb..d2cb8149d7 100644 --- a/test/junit/scala/StringContextTest.scala +++ b/test/junit/scala/lang/stringinterpol/StringContextTest.scala @@ -1,15 +1,14 @@ -package scala +package scala.lang.stringinterpol import java.text.DecimalFormat -import language.implicitConversions - -import org.junit.Test import org.junit.Assert._ +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +import scala.language.implicitConversions import scala.tools.testing.AssertUtil._ object StringContextTestUtils { @@ -128,7 +127,7 @@ class StringContextTest { val fff = new java.util.Formattable { def formatTo(f: java.util.Formatter, g: Int, w: Int, p: Int) = f.format("4") } - import java.util.{ Calendar, Locale } + import java.util.{Calendar, Locale} val c = Calendar.getInstance(Locale.US) c.set(2012, Calendar.MAY, 26) implicit def strToDate(x: String): Calendar = c diff --git a/test/junit/scala/lang/traits/BytecodeTest.scala b/test/junit/scala/lang/traits/BytecodeTest.scala new file mode 100644 index 0000000000..f47fc9c127 --- /dev/null +++ b/test/junit/scala/lang/traits/BytecodeTest.scala @@ -0,0 +1,282 @@ +package scala.lang.traits + +import org.junit.Assert._ +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import scala.collection.JavaConverters._ +import scala.tools.asm.Opcodes +import scala.tools.asm.Opcodes._ +import scala.tools.asm.tree.ClassNode +import scala.tools.partest.ASMConverters._ +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ + +@RunWith(classOf[JUnit4]) +class BytecodeTest extends BytecodeTesting { + import compiler._ + + def checkForwarder(classes: Map[String, ClassNode], clsName: Symbol, target: String) = { + val List(f) = getMethods(classes(clsName.name), "f") + assertSameCode(f, List(VarOp(ALOAD, 0), Invoke(INVOKESPECIAL, target, "f", "()I", false), Op(IRETURN))) + } + + @Test + def traitMethodForwarders(): Unit = { + val code = + """trait T1 { def f = 1 } + |trait T2 extends T1 { override def f = 2 } + |trait T3 { self: T1 => override def f = 3 } + | + |abstract class A1 { def f: Int } + |class A2 { def f: Int = 4 } + | + |trait T4 extends A1 { def f = 5 } + |trait T5 extends A2 { override def f = 6 } + | + |trait T6 { def f: Int } + |trait T7 extends T6 { abstract override def f = super.f + 1 } + | + |trait T8 { override def clone() = super.clone() } + | + |class A3 extends T1 { override def f = 7 } + | + |class C1 extends T1 + |class C2 extends T2 + |class C3 extends T1 with T2 + |class C4 extends T2 with T1 + |class C5 extends T1 with T3 + | + |// traits extending a class that defines f + |class C6 extends T4 + |class C7 extends T5 + |class C8 extends A1 with T4 + |class C9 extends A2 with T5 + | + |// T6: abstract f in trait + |class C10 extends T6 with T1 + |class C11 extends T6 with T2 + |abstract class C12 extends A1 with T6 + |class C13 extends A2 with T6 + |class C14 extends T4 with T6 + |class C15 extends T5 with T6 + | + |// superclass overrides a trait method + |class C16 extends A3 + |class C17 extends A3 with T1 + | + |// abstract override + |class C18 extends T6 { def f = 22 } + |class C19 extends C18 with T7 + | + |class C20 extends T8 + """.stripMargin + + val c = compileClasses(code).map(c => (c.name, c)).toMap + + val noForwarder = List('C1, 'C2, 'C3, 'C4, 'C10, 'C11, 'C12, 'C13, 'C16, 'C17) + for (cn <- noForwarder) assertEquals(getMethods(c(cn.name), "f"), Nil) + + checkForwarder(c, 'C5, "T3") + checkForwarder(c, 'C6, "T4") + checkForwarder(c, 'C7, "T5") + checkForwarder(c, 'C8, "T4") + checkForwarder(c, 'C9, "T5") + checkForwarder(c, 'C14, "T4") + checkForwarder(c, 'C15, "T5") + assertSameSummary(getMethod(c("C18"), "f"), List(BIPUSH, IRETURN)) + checkForwarder(c, 'C19, "T7") + assertSameCode(getMethod(c("C19"), "T7$$super$f"), List(VarOp(ALOAD, 0), Invoke(INVOKESPECIAL, "C18", "f", "()I", false), Op(IRETURN))) + assertInvoke(getMethod(c("C20"), "clone"), "T8", "clone") // mixin forwarder + } + + @Test + def noTraitMethodForwardersForOverloads(): Unit = { + val code = + """trait T1 { def f(x: Int) = 0 } + |trait T2 { def f(x: String) = 1 } + |class C extends T1 with T2 + """.stripMargin + val List(c, t1, t2) = compileClasses(code) + assertEquals(getMethods(c, "f"), Nil) + } + + @Test + def traitMethodForwardersForJavaDefaultMethods(): Unit = { + val j1 = ("interface J1 { int f(); }", "J1.java") + val j2 = ("interface J2 { default int f() { return 1; } }", "J2.java") + val j3 = ("interface J3 extends J1 { default int f() { return 2; } }", "J3.java") + val j4 = ("interface J4 extends J2 { default int f() { return 3; } }", "J4.java") + val code = + """trait T1 extends J2 { override def f = 4 } + |trait T2 { self: J2 => override def f = 5 } + | + |class K1 extends J2 + |class K2 extends J1 with J2 + |class K3 extends J2 with J1 + | + |class K4 extends J3 + |class K5 extends J3 with J1 + |class K6 extends J1 with J3 + | + |class K7 extends J4 + |class K8 extends J4 with J2 + |class K9 extends J2 with J4 + | + |class K10 extends T1 with J2 + |class K11 extends J2 with T1 + | + |class K12 extends J2 with T2 + """.stripMargin + val c = compileClasses(code, List(j1, j2, j3, j4)).map(c => (c.name, c)).toMap + + val noForwarder = List('K1, 'K2, 'K3, 'K4, 'K5, 'K6, 'K7, 'K8, 'K9, 'K10, 'K11) + for (cn <- noForwarder) assertEquals(getMethods(c(cn.name), "f"), Nil) + + checkForwarder(c, 'K12, "T2") + } + + @Test + def invocationReceivers(): Unit = { + val List(c1, c2, t, u) = compileClasses(invocationReceiversTestCode.definitions("Object")) + // mixin forwarder in C1 + assertSameCode(getMethod(c1, "clone"), List(VarOp(ALOAD, 0), Invoke(INVOKESPECIAL, "T", "clone", "()Ljava/lang/Object;", false), Op(ARETURN))) + assertInvoke(getMethod(c1, "f1"), "T", "clone") + assertInvoke(getMethod(c1, "f2"), "T", "clone") + assertInvoke(getMethod(c1, "f3"), "C1", "clone") + assertInvoke(getMethod(c2, "f1"), "T", "clone") + assertInvoke(getMethod(c2, "f2"), "T", "clone") + assertInvoke(getMethod(c2, "f3"), "C1", "clone") + + val List(c1b, c2b, tb, ub) = compileClasses(invocationReceiversTestCode.definitions("String")) + def ms(c: ClassNode, n: String) = c.methods.asScala.toList.filter(_.name == n) + assert(ms(tb, "clone").length == 1) + assert(ms(ub, "clone").isEmpty) + val List(c1Clone) = ms(c1b, "clone") + assertEquals(c1Clone.desc, "()Ljava/lang/Object;") + assert((c1Clone.access | Opcodes.ACC_BRIDGE) != 0) + assertSameCode(convertMethod(c1Clone), List(VarOp(ALOAD, 0), Invoke(INVOKEVIRTUAL, "C1", "clone", "()Ljava/lang/String;", false), Op(ARETURN))) + + def iv(m: Method) = getInstructions(c1b, "f1").collect({case i: Invoke => i}) + assertSameCode(iv(getMethod(c1b, "f1")), List(Invoke(INVOKEINTERFACE, "T", "clone", "()Ljava/lang/String;", true))) + assertSameCode(iv(getMethod(c1b, "f2")), List(Invoke(INVOKEINTERFACE, "T", "clone", "()Ljava/lang/String;", true))) + // invokeinterface T.clone in C1 is OK here because it is not an override of Object.clone (different siganture) + assertSameCode(iv(getMethod(c1b, "f3")), List(Invoke(INVOKEINTERFACE, "T", "clone", "()Ljava/lang/String;", true))) + } + + @Test + def invocationReceiversProtected(): Unit = { + // http://lrytz.github.io/scala-aladdin-bugtracker/displayItem.do%3Fid=455.html / 9954eaf + // also https://issues.scala-lang.org/browse/SI-1430 / 0bea2ab (same but with interfaces) + val aC = + """package a; + |/*package private*/ abstract class A { + | public int f() { return 1; } + | public int t; + |} + """.stripMargin + val bC = + """package a; + |public class B extends A { } + """.stripMargin + val iC = + """package a; + |/*package private*/ interface I { int f(); } + """.stripMargin + val jC = + """package a; + |public interface J extends I { } + """.stripMargin + val cC = + """package b + |class C { + | def f1(b: a.B) = b.f + | def f2(b: a.B) = { b.t = b.t + 1 } + | def f3(j: a.J) = j.f + |} + """.stripMargin + val c = compileClass(cC, javaCode = List((aC, "A.java"), (bC, "B.java"), (iC, "I.java"), (jC, "J.java"))) + assertInvoke(getMethod(c, "f1"), "a/B", "f") // receiver needs to be B (A is not accessible in class C, package b) + assertInvoke(getMethod(c, "f3"), "a/J", "f") // receiver needs to be J + } + + @Test + def specialInvocationReceivers(): Unit = { + val code = + """class C { + | def f1(a: Array[String]) = a.clone() + | def f2(a: Array[Int]) = a.hashCode() + | def f3(n: Nothing) = n.hashCode() + | def f4(n: Null) = n.toString() + | + |} + """.stripMargin + val c = compileClass(code) + assertInvoke(getMethod(c, "f1"), "[Ljava/lang/String;", "clone") // array descriptor as receiver + assertInvoke(getMethod(c, "f2"), "java/lang/Object", "hashCode") // object receiver + assertInvoke(getMethod(c, "f3"), "java/lang/Object", "hashCode") + assertInvoke(getMethod(c, "f4"), "java/lang/Object", "toString") + } + + @Test + def superConstructorArgumentInSpecializedClass(): Unit = { + // see comment in SpecializeTypes.forwardCtorCall + val code = "case class C[@specialized(Int) T](_1: T)" + val List(c, cMod, cSpec) = compileClasses(code) + assertSameSummary(getMethod(cSpec, "<init>"), + // pass `null` to super constructor, no box-unbox, no Integer created + List(ALOAD, ILOAD, PUTFIELD, ALOAD, ACONST_NULL, "<init>", RETURN)) + } + +} + +object invocationReceiversTestCode { + // if cloneType is more specific than Object (e.g., String), a bridge method is generated. + def definitions(cloneType: String) = + s"""trait T { override def clone(): $cloneType = "hi" } + |trait U extends T + |class C1 extends U with Cloneable { + | // The comments below are true when $cloneType is Object. + | // C1 gets a forwarder for clone that invokes T.clone. this is needed because JVM method + | // resolution always prefers class members, so it would resolve to Object.clone, even if + | // C1 is a subtype of the interface T which has an overriding default method for clone. + | + | // invokeinterface T.clone + | def f1 = (this: T).clone() + | + | // cannot invokeinterface U.clone (NoSuchMethodError). Object.clone would work here, but + | // not in the example in C2 (illegal access to protected). T.clone works in all cases and + | // resolves correctly. + | def f2 = (this: U).clone() + | + | // invokevirtual C1.clone() + | def f3 = (this: C1).clone() + |} + | + |class C2 { + | def f1(t: T) = t.clone() // invokeinterface T.clone + | def f2(t: U) = t.clone() // invokeinterface T.clone -- Object.clone would be illegal (protected, explained in C1) + | def f3(t: C1) = t.clone() // invokevirtual C1.clone -- Object.clone would be illegal + |} + """.stripMargin + + val runCode = + """ + |val r = new StringBuffer() + |val c1 = new C1 + |r.append(c1.f1) + |r.append(c1.f2) + |r.append(c1.f3) + |val t = new T { } + |val u = new U { } + |val c2 = new C2 + |r.append(c2.f1(t)) + |r.append(c2.f1(u)) + |r.append(c2.f1(c1)) + |r.append(c2.f2(u)) + |r.append(c2.f2(c1)) + |r.append(c2.f3(c1)) + |r.toString + """.stripMargin +} diff --git a/test/junit/scala/lang/traits/RunTest.scala b/test/junit/scala/lang/traits/RunTest.scala new file mode 100644 index 0000000000..d27dc15e20 --- /dev/null +++ b/test/junit/scala/lang/traits/RunTest.scala @@ -0,0 +1,20 @@ +package scala.lang.traits + +import org.junit.Assert._ +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import scala.tools.testing.RunTesting + +@RunWith(classOf[JUnit4]) +class RunTest extends RunTesting { + import runner._ + + @Test + def invocationReceivers(): Unit = { + import invocationReceiversTestCode._ + assertEquals(run[String](definitions("Object") + runCode), "hi" * 9) + assertEquals(run[String](definitions("String") + runCode), "hi" * 9) // bridge method for clone generated + } +} diff --git a/test/junit/scala/reflect/ClassOfTest.scala b/test/junit/scala/reflect/ClassOfTest.scala new file mode 100644 index 0000000000..520b14ccd4 --- /dev/null +++ b/test/junit/scala/reflect/ClassOfTest.scala @@ -0,0 +1,124 @@ +package scala.reflect + +import org.junit.Assert._ +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import scala.tools.testing.RunTesting + +object ClassOfTest { + class VC(val x: Any) extends AnyVal +} + +@RunWith(classOf[JUnit4]) +class ClassOfTest extends RunTesting { + import runner._ + + @Test + def classOfValueClassAlias(): Unit = { + val code = + """import scala.reflect.ClassOfTest.VC + |type aVC = VC + |type aInt = Int + |type aInteger = Integer + |classOf[VC] == classOf[aVC] && + | classOf[aInt] == classOf[Int] && + | classOf[aInteger] == classOf[Integer] && + | classOf[aInt] != classOf[aInteger] + """.stripMargin + assertTrue(run[Boolean](code)) + } + + @Test + def classOfFinalVal(): Unit = { + val code = + """class C { + | final val a1 = classOf[Int] + | final val b1 = classOf[List[_]] + | final val c1 = classOf[List[String]] + | final val d1 = classOf[Array[Int]] + | final val e1 = classOf[Array[List[_]]] + | final val f1 = classOf[Array[_]] + | + | val a2 = classOf[Int] + | val b2 = classOf[List[_]] + | val c2 = classOf[List[String]] + | val d2 = classOf[Array[Int]] + | val e2 = classOf[Array[List[_]]] + | val f2 = classOf[Array[_]] + | + | val listC = Class.forName("scala.collection.immutable.List") + | + | val compare = List( + | (a1, a2, Integer.TYPE), + | (b1, b2, listC), + | (c1, c2, listC), + | (d1, d2, Array(1).getClass), + | (e1, e2, Array(List()).getClass), + | (f1, f2, new Object().getClass)) + |} + |(new C).compare + """.stripMargin + type K = Class[_] + val cs = run[List[(K, K, K)]](code) + for ((x, y, z) <- cs) { + assertEquals(x, y) + assertEquals(x, z) + } + } + + @Test + def t9702(): Unit = { + val code = + """import javax.annotation.Resource + |import scala.reflect.ClassOfTest.VC + |class C { + | type aList[K] = List[K] + | type aVC = VC + | type aInt = Int + | type aInteger = Integer + | @Resource(`type` = classOf[List[Int]]) def a = 0 + | @Resource(`type` = classOf[List[_]]) def b = 0 + | @Resource(`type` = classOf[aList[_]]) def c = 0 + | @Resource(`type` = classOf[Int]) def d = 0 + | @Resource(`type` = classOf[aInt]) def e = 0 + | @Resource(`type` = classOf[Integer]) def f = 0 + | @Resource(`type` = classOf[aInteger]) def g = 0 + | @Resource(`type` = classOf[VC]) def h = 0 + | @Resource(`type` = classOf[aVC]) def i = 0 + | @Resource(`type` = classOf[Array[Int]]) def j = 0 + | @Resource(`type` = classOf[Array[List[_]]]) def k = 0 + |} + |val c = classOf[C] + |def typeArg(meth: String) = c.getDeclaredMethod(meth).getDeclaredAnnotation(classOf[Resource]).`type` + |('a' to 'k').toList.map(_.toString).map(typeArg) + """.stripMargin + + val l = Class.forName("scala.collection.immutable.List") + val i = Integer.TYPE + val ig = new Integer(1).getClass + val v = new ClassOfTest.VC(1).getClass + val ai = Array(1).getClass + val al = Array(List()).getClass + + // sanity checks + assertEquals(i, classOf[Int]) + assertNotEquals(i, ig) + + assertEquals(run[List[Class[_]]](code), + List(l, l, l, i, i, ig, ig, v, v, ai, al)) + } + + @Test + def classOfUnitConstant(): Unit = { + val code = + """abstract class A { def f: Class[_] } + |class C extends A { final val f = classOf[Unit] } + |val c = new C + |(c.f, (c: A).f) + """.stripMargin + val u = Void.TYPE + assertEquals(run[(Class[_], Class[_])](code), (u, u)) + } +} diff --git a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala index e7bbbb9a4f..0144fa7366 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala @@ -1,30 +1,29 @@ package scala.tools.nsc package backend.jvm +import org.junit.Assert._ +import org.junit.Test 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.CodeGenTools._ -import scala.tools.testing.ClearAfterClass +import scala.tools.asm.Opcodes +import scala.tools.testing.BytecodeTesting @RunWith(classOf[JUnit4]) -class BTypesTest extends ClearAfterClass { - val compiler = cached("compiler", () => { - val comp = newCompiler(extraArgs = "-Yopt:l:none") - new comp.Run() // initializes some of the compiler - comp.exitingDelambdafy(comp.scalaPrimitives.init()) // needed: it's only done when running the backend, and we don't actually run the compiler - comp.exitingDelambdafy(comp.genBCode.bTypes.initializeCoreBTypes()) - comp - }) - import compiler.genBCode.bTypes._ +class BTypesTest extends BytecodeTesting { + override def compilerArgs = "-Yopt:l:none" + import compiler.global + locally { + new global.Run() // initializes some of the compiler + global.exitingDelambdafy(global.scalaPrimitives.init()) // needed: it's only done when running the backend, and we don't actually run the compiler + global.exitingDelambdafy(global.genBCode.bTypes.initializeCoreBTypes()) + } + import global.genBCode.bTypes._ - def classBTFS(sym: compiler.Symbol) = compiler.exitingDelambdafy(classBTypeFromSymbol(sym)) + def classBTFS(sym: global.Symbol) = global.exitingDelambdafy(classBTypeFromSymbol(sym)) - def jlo = compiler.definitions.ObjectClass - def jls = compiler.definitions.StringClass + def jlo = global.definitions.ObjectClass + def jls = global.definitions.StringClass def o = classBTFS(jlo) def s = classBTFS(jls) def oArr = ArrayBType(o) diff --git a/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala b/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala new file mode 100644 index 0000000000..b2ee8b3a45 --- /dev/null +++ b/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala @@ -0,0 +1,171 @@ +package scala.tools.nsc.backend.jvm + +import org.junit.Assert._ +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import scala.tools.asm.Opcodes._ +import scala.tools.partest.ASMConverters._ +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ + +@RunWith(classOf[JUnit4]) +class BytecodeTest extends BytecodeTesting { + import compiler._ + + @Test + def t6288bJumpPosition(): Unit = { + val code = + """object Case3 { // 01 + | def unapply(z: Any): Option[Int] = Some(-1) // 02 + | def main(args: Array[String]) { // 03 + | ("": Any) match { // 04 + | case x : String => // 05 + | println("case 0") // 06 println and jump at 6 + | case _ => // 07 + | println("default") // 08 println and jump at 8 + | } // 09 + | println("done") // 10 + | } + |} + """.stripMargin + val List(mirror, module) = compileClasses(code) + + val unapplyLineNumbers = getInstructions(module, "unapply").filter(_.isInstanceOf[LineNumber]) + assert(unapplyLineNumbers == List(LineNumber(2, Label(0))), unapplyLineNumbers) + + val expected = List( + LineNumber(4, Label(0)), + LineNumber(5, Label(5)), + Jump(IFEQ, Label(20)), + + LineNumber(6, Label(11)), + Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false), + Jump(GOTO, Label(33)), + + LineNumber(5, Label(20)), + Jump(GOTO, Label(24)), + + LineNumber(8, Label(24)), + Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false), + Jump(GOTO, Label(33)), + + LineNumber(10, Label(33)), + Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false) + ) + + val mainIns = getInstructions(module, "main") filter { + case _: LineNumber | _: Invoke | _: Jump => true + case _ => false + } + assertSameCode(mainIns, expected) + } + + @Test + def bytecodeForBranches(): Unit = { + val code = + """class C { + | def t1(b: Boolean) = if (b) 1 else 2 + | def t2(x: Int) = if (x == 393) 1 else 2 + | def t3(a: Array[String], b: AnyRef) = a != b && b == a + | def t4(a: AnyRef) = a == null || null != a + | def t5(a: AnyRef) = (a eq null) || (null ne a) + | def t6(a: Int, b: Boolean) = if ((a == 10) && b || a != 1) 1 else 2 + | def t7(a: AnyRef, b: AnyRef) = a == b + | def t8(a: AnyRef) = Nil == a || "" != a + |} + """.stripMargin + + val c = compileClass(code) + + // t1: no unnecessary GOTOs + assertSameCode(getMethod(c, "t1"), List( + VarOp(ILOAD, 1), Jump(IFEQ, Label(6)), + Op(ICONST_1), Jump(GOTO, Label(9)), + Label(6), Op(ICONST_2), + Label(9), Op(IRETURN))) + + // t2: no unnecessary GOTOs + assertSameCode(getMethod(c, "t2"), List( + VarOp(ILOAD, 1), IntOp(SIPUSH, 393), Jump(IF_ICMPNE, Label(7)), + Op(ICONST_1), Jump(GOTO, Label(10)), + Label(7), Op(ICONST_2), + Label(10), Op(IRETURN))) + + // t3: Array == is translated to reference equality, AnyRef == to null checks and equals + assertSameCode(getMethod(c, "t3"), List( + // Array == + VarOp(ALOAD, 1), VarOp(ALOAD, 2), Jump(IF_ACMPEQ, Label(23)), + // AnyRef == + VarOp(ALOAD, 2), VarOp(ALOAD, 1), VarOp(ASTORE, 3), Op(DUP), Jump(IFNONNULL, Label(14)), + Op(POP), VarOp(ALOAD, 3), Jump(IFNULL, Label(19)), Jump(GOTO, Label(23)), + Label(14), VarOp(ALOAD, 3), Invoke(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false), Jump(IFEQ, Label(23)), + Label(19), Op(ICONST_1), Jump(GOTO, Label(26)), + Label(23), Op(ICONST_0), + Label(26), Op(IRETURN))) + + val t4t5 = List( + VarOp(ALOAD, 1), Jump(IFNULL, Label(6)), + VarOp(ALOAD, 1), Jump(IFNULL, Label(10)), + Label(6), Op(ICONST_1), Jump(GOTO, Label(13)), + Label(10), Op(ICONST_0), + Label(13), Op(IRETURN)) + + // t4: one side is known null, so just a null check on the other + assertSameCode(getMethod(c, "t4"), t4t5) + + // t5: one side known null, so just a null check on the other + assertSameCode(getMethod(c, "t5"), t4t5) + + // t6: no unnecessary GOTOs + assertSameCode(getMethod(c, "t6"), List( + VarOp(ILOAD, 1), IntOp(BIPUSH, 10), Jump(IF_ICMPNE, Label(7)), + VarOp(ILOAD, 2), Jump(IFNE, Label(12)), + Label(7), VarOp(ILOAD, 1), Op(ICONST_1), Jump(IF_ICMPEQ, Label(16)), + Label(12), Op(ICONST_1), Jump(GOTO, Label(19)), + Label(16), Op(ICONST_2), + Label(19), Op(IRETURN))) + + // t7: universal equality + assertInvoke(getMethod(c, "t7"), "scala/runtime/BoxesRunTime", "equals") + + // t8: no null checks invoking equals on modules and constants + assertSameCode(getMethod(c, "t8"), List( + Field(GETSTATIC, "scala/collection/immutable/Nil$", "MODULE$", "Lscala/collection/immutable/Nil$;"), VarOp(ALOAD, 1), Invoke(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false), Jump(IFNE, Label(10)), + Ldc(LDC, ""), VarOp(ALOAD, 1), Invoke(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false), Jump(IFNE, Label(14)), + Label(10), Op(ICONST_1), Jump(GOTO, Label(17)), + Label(14), Op(ICONST_0), + Label(17), Op(IRETURN))) + } + + @Test // wrong local variable table for methods containing while loops + def t9179(): Unit = { + val code = + """class C { + | def t(): Unit = { + | var x = "" + | while (x != null) { + | foo() + | x = null + | } + | bar() + | } + | def foo(): Unit = () + | def bar(): Unit = () + |} + """.stripMargin + val c = compileClass(code) + val t = getMethod(c, "t") + val isFrameLine = (x: Instruction) => x.isInstanceOf[FrameEntry] || x.isInstanceOf[LineNumber] + assertSameCode(t.instructions.filterNot(isFrameLine), List( + Label(0), Ldc(LDC, ""), Label(3), VarOp(ASTORE, 1), + Label(5), VarOp(ALOAD, 1), Jump(IFNULL, Label(21)), + Label(10), VarOp(ALOAD, 0), Invoke(INVOKEVIRTUAL, "C", "foo", "()V", false), Label(14), Op(ACONST_NULL), VarOp(ASTORE, 1), Label(18), Jump(GOTO, Label(5)), + Label(21), VarOp(ALOAD, 0), Invoke(INVOKEVIRTUAL, "C", "bar", "()V", false), Label(26), Op(RETURN), Label(28))) + val labels = t.instructions collect { case l: Label => l } + val x = t.localVars.find(_.name == "x").get + assertEquals(x.start, labels(1)) + assertEquals(x.end, labels(7)) + } +} diff --git a/test/junit/scala/tools/nsc/backend/jvm/DefaultMethodTest.scala b/test/junit/scala/tools/nsc/backend/jvm/DefaultMethodTest.scala index 7d4ae866fc..c9a958ee4f 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/DefaultMethodTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/DefaultMethodTest.scala @@ -4,30 +4,29 @@ import org.junit.Assert._ import org.junit.Test import scala.collection.JavaConverters +import scala.collection.JavaConverters._ import scala.tools.asm.Opcodes import scala.tools.asm.tree.ClassNode -import scala.tools.nsc.backend.jvm.CodeGenTools._ -import JavaConverters._ -import scala.tools.testing.ClearAfterClass - -class DefaultMethodTest extends ClearAfterClass { - val compiler = cached("compiler", () => newCompiler()) +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ +class DefaultMethodTest extends BytecodeTesting { + import compiler._ @Test def defaultMethodsViaGenBCode(): Unit = { - import compiler._ + import global._ val code = "package pack { trait T { def foo: Int }}" object makeFooDefaultMethod extends Transformer { val Foo = TermName("foo") /** Transforms a single tree. */ - override def transform(tree: compiler.Tree): compiler.Tree = tree match { + override def transform(tree: global.Tree): global.Tree = tree match { case dd @ DefDef(_, Foo, _, _, _, _) => dd.symbol.setFlag(reflect.internal.Flags.JAVA_DEFAULTMETHOD) copyDefDef(dd)(rhs = Literal(Constant(1)).setType(definitions.IntTpe)) case _ => super.transform(tree) } } - val asmClasses: List[ClassNode] = readAsmClasses(compileTransformed(compiler)(code, Nil, makeFooDefaultMethod.transform(_))) + val asmClasses: List[ClassNode] = compiler.compileClassesTransformed(code, Nil, makeFooDefaultMethod.transform(_)) val foo = asmClasses.head.methods.iterator.asScala.toList.last assertTrue("default method should not be abstract", (foo.access & Opcodes.ACC_ABSTRACT) == 0) assertTrue("default method body emitted", foo.instructions.size() > 0) diff --git a/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala b/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala index e984b75518..7fdfb31577 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala @@ -1,21 +1,23 @@ package scala.tools.nsc.backend.jvm +import org.junit.Assert._ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.junit.Assert._ -import CodeGenTools._ + import scala.tools.asm.Opcodes._ import scala.tools.partest.ASMConverters._ -import scala.tools.testing.ClearAfterClass +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ @RunWith(classOf[JUnit4]) -class DirectCompileTest extends ClearAfterClass { - val compiler = cached("compiler", () => newCompiler(extraArgs = "-Yopt:l:method")) +class DirectCompileTest extends BytecodeTesting { + override def compilerArgs = "-Yopt:l:method" + import compiler._ @Test def testCompile(): Unit = { - val List(("C.class", bytes)) = compile(compiler)( + val List(("C.class", bytes)) = compileToBytes( """class C { | def f = 1 |} @@ -26,12 +28,12 @@ class DirectCompileTest extends ClearAfterClass { @Test def testCompileClasses(): Unit = { - val List(cClass, cModuleClass) = compileClasses(compiler)("class C; object C") + val List(cClass, cModuleClass) = compileClasses("class C; object C") assertTrue(cClass.name == "C") assertTrue(cModuleClass.name == "C$") - val List(dMirror, dModuleClass) = compileClasses(compiler)("object D") + val List(dMirror, dModuleClass) = compileClasses("object D") assertTrue(dMirror.name == "D") assertTrue(dModuleClass.name == "D$") @@ -39,25 +41,23 @@ class DirectCompileTest extends ClearAfterClass { @Test def testCompileMethods(): Unit = { - val List(f, g) = compileMethods(compiler)( + val List(f, g) = compileMethods( """def f = 10 |def g = f """.stripMargin) - assertTrue(f.name == "f") - assertTrue(g.name == "g") - assertSameCode(instructionsFromMethod(f).dropNonOp, + assertSameCode(f.instructions.dropNonOp, List(IntOp(BIPUSH, 10), Op(IRETURN))) - assertSameCode(instructionsFromMethod(g).dropNonOp, + assertSameCode(g.instructions.dropNonOp, List(VarOp(ALOAD, 0), Invoke(INVOKEVIRTUAL, "C", "f", "()I", itf = false), Op(IRETURN))) } @Test def testDropNonOpAliveLabels(): Unit = { // makes sure that dropNoOp doesn't drop labels that are being used - val List(f) = compileMethods(compiler)("""def f(x: Int) = if (x == 0) "a" else "b"""") - assertSameCode(instructionsFromMethod(f).dropLinesFrames, List( + val is = compileInstructions("""def f(x: Int) = if (x == 0) "a" else "b"""") + assertSameCode(is.dropLinesFrames, List( Label(0), VarOp(ILOAD, 1), Op(ICONST_0), @@ -77,7 +77,7 @@ class DirectCompileTest extends ClearAfterClass { val codeA = "class A { def f = 1 }" val codeB = "class B extends A { def g = f }" val List(a, b) = compileClassesSeparately(List(codeA, codeB)) - val ins = getSingleMethod(b, "g").instructions + val ins = getInstructions(b, "g") assert(ins exists { case Invoke(_, "B", "f", _, _) => true case _ => false @@ -86,6 +86,6 @@ class DirectCompileTest extends ClearAfterClass { @Test def compileErroneous(): Unit = { - compileClasses(compiler)("class C { def f: String = 1 }", allowMessage = _.msg contains "type mismatch") + compileToBytes("class C { def f: String = 1 }", allowMessage = _.msg contains "type mismatch") } } diff --git a/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala b/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala index b906942ffa..ac2aab01dc 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala @@ -1,21 +1,19 @@ package scala.tools.nsc.backend.jvm import org.junit.Assert._ -import org.junit.{Assert, Test} +import org.junit.Test -import scala.tools.asm.{Handle, Opcodes} -import scala.tools.asm.tree.InvokeDynamicInsnNode -import scala.tools.nsc.backend.jvm.AsmUtils._ -import scala.tools.nsc.backend.jvm.CodeGenTools._ -import scala.tools.testing.ClearAfterClass import scala.collection.JavaConverters._ +import scala.tools.asm.Handle +import scala.tools.asm.tree.InvokeDynamicInsnNode +import scala.tools.testing.BytecodeTesting -class IndyLambdaTest extends ClearAfterClass { - val compiler = cached("compiler", () => newCompiler()) +class IndyLambdaTest extends BytecodeTesting { + import compiler._ @Test def boxingBridgeMethodUsedSelectively(): Unit = { def implMethodDescriptorFor(code: String): String = { - val method = compileMethods(compiler)(s"""def f = $code """).find(_.name == "f").get + val method = compileAsmMethods(s"""def f = $code """).find(_.name == "f").get val x = method.instructions.iterator.asScala.toList x.flatMap { case insn : InvokeDynamicInsnNode => insn.bsmArgs.collect { case h : Handle => h.getDesc } @@ -48,17 +46,17 @@ class IndyLambdaTest extends ClearAfterClass { assertEquals("(I)I", implMethodDescriptorFor("(x: Int) => x")) // non-builtin sams are like specialized functions - compileClasses(compiler)("class VC(private val i: Int) extends AnyVal; trait FunVC { def apply(a: VC): VC }") + compileToBytes("class VC(private val i: Int) extends AnyVal; trait FunVC { def apply(a: VC): VC }") assertEquals("(I)I", implMethodDescriptorFor("((x: VC) => x): FunVC")) - compileClasses(compiler)("trait Fun1[T, U] { def apply(a: T): U }") + compileToBytes("trait Fun1[T, U] { def apply(a: T): U }") assertEquals(s"($obj)$str", implMethodDescriptorFor("(x => x.toString): Fun1[Int, String]")) assertEquals(s"($obj)$obj", implMethodDescriptorFor("(x => println(x)): Fun1[Int, Unit]")) assertEquals(s"($obj)$str", implMethodDescriptorFor("((x: VC) => \"\") : Fun1[VC, String]")) assertEquals(s"($str)$obj", implMethodDescriptorFor("((x: String) => new VC(0)) : Fun1[String, VC]")) - compileClasses(compiler)("trait Coll[A, Repr] extends Any") - compileClasses(compiler)("final class ofInt(val repr: Array[Int]) extends AnyVal with Coll[Int, Array[Int]]") + compileToBytes("trait Coll[A, Repr] extends Any") + compileToBytes("final class ofInt(val repr: Array[Int]) extends AnyVal with Coll[Int, Array[Int]]") assertEquals(s"([I)$obj", implMethodDescriptorFor("((xs: Array[Int]) => new ofInt(xs)): Array[Int] => Coll[Int, Array[Int]]")) } diff --git a/test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala b/test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala index 5c2ab6a2c7..2bcbcc870c 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala @@ -2,26 +2,20 @@ package scala.tools.nsc package backend.jvm import org.junit.Assert.assertEquals +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.junit.Test import scala.tools.asm.Opcodes._ -import scala.tools.asm.tree._ import scala.tools.nsc.reporters.StoreReporter -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ - -import scala.tools.testing.ClearAfterClass +import scala.tools.partest.ASMConverters._ +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ @RunWith(classOf[JUnit4]) -class IndySammyTest extends ClearAfterClass { - - val compiler = cached("compiler", () => newCompiler()) - def compile(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] = - compileClasses(compiler)(scalaCode, javaCode, allowMessage) +class IndySammyTest extends BytecodeTesting { + import compiler._ def funClassName(from: String, to: String) = s"Fun$from$to" def classPrologue(from: String, to: String) = @@ -45,13 +39,13 @@ class IndySammyTest extends ClearAfterClass { def test(from: String, to: String, arg: String, body: String => String = x => x) (expectedSig: String, lamBody: List[Instruction], appArgs: List[Instruction], ret: Instruction) (allowMessage: StoreReporter#Info => Boolean = _ => false) = { - val cls = compile(s"${classPrologue(from, to)}") - val methodNodes = compileMethods(compiler)(lamDef(from, to, body) +";"+ appDef(arg), allowMessage) + val List(funClass, vcClass, vcCompanion) = compileClasses(s"${classPrologue(from, to)}") + val c = compileClass(s"class C { ${lamDef(from, to, body)}; ${appDef(arg)} }", allowMessage = allowMessage) - val applySig = cls.head.methods.get(0).desc - val anonfun = methodNodes.find(_.name contains "$anonfun$").map(convertMethod).get - val lamInsn = methodNodes.find(_.name == "lam").map(instructionsFromMethod).get.dropNonOp - val applyInvoke = methodNodes.find(_.name == "app").map(convertMethod).get + val applySig = getAsmMethod(funClass, "apply").desc + val anonfun = getMethod(c, "C$$$anonfun$1") + val lamInsn = getInstructions(c, "lam").dropNonOp + val applyInvoke = getMethod(c, "app") assertEquals(expectedSig, applySig) assert(lamInsn.length == 2 && lamInsn.head.isInstanceOf[InvokeDynamic], lamInsn) @@ -64,7 +58,7 @@ class IndySammyTest extends ClearAfterClass { } // def testSpecial(lam: String, lamTp: String, arg: String)(allowMessage: StoreReporter#Info => Boolean = _ => false) = { -// val cls = compile("trait Special[@specialized A] { def apply(a: A): A}" ) +// val cls = compileClasses("trait Special[@specialized A] { def apply(a: A): A}" ) // val methodNodes = compileMethods(compiler)(s"def lam : $lamTp = $lam" +";"+ appDef(arg), allowMessage) // // val anonfun = methodNodes.filter(_.name contains "$anonfun$").map(convertMethod) @@ -146,7 +140,7 @@ class IndySammyTest extends ClearAfterClass { // Tests ThisReferringMethodsTraverser @Test def testStaticIfNoThisReference: Unit = { - val methodNodes = compileMethods(compiler)("def foo = () => () => () => 42") + val methodNodes = compileAsmMethods("def foo = () => () => () => 42") methodNodes.forall(m => !m.name.contains("anonfun") || (m.access & ACC_STATIC) == ACC_STATIC) } } diff --git a/test/junit/scala/issues/OptimizedBytecodeTest.scala b/test/junit/scala/tools/nsc/backend/jvm/OptimizedBytecodeTest.scala index c69229ae22..003162c1ad 100644 --- a/test/junit/scala/issues/OptimizedBytecodeTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/OptimizedBytecodeTest.scala @@ -1,24 +1,18 @@ -package scala.issues +package scala.tools.nsc.backend.jvm +import org.junit.Test 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.{AsmUtils, CodeGenTools} - -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ -import AsmUtils._ - -import scala.tools.testing.ClearAfterClass +import scala.tools.asm.Opcodes._ +import scala.tools.partest.ASMConverters._ +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ @RunWith(classOf[JUnit4]) -class OptimizedBytecodeTest extends ClearAfterClass { - val args = "-Yopt:l:classpath -Yopt-warnings" - val compiler = cached("compiler", () => newCompiler(extraArgs = args)) +class OptimizedBytecodeTest extends BytecodeTesting { + override def compilerArgs = "-Yopt:l:classpath -Yopt-warnings" + import compiler._ @Test def t2171(): Unit = { @@ -28,8 +22,8 @@ class OptimizedBytecodeTest extends ClearAfterClass { | def t(): Unit = while (true) m("...") |} """.stripMargin - val List(c) = compileClasses(compiler)(code) - assertSameCode(getSingleMethod(c, "t"), List(Label(0), Jump(GOTO, Label(0)))) + val c = compileClass(code) + assertSameCode(getMethod(c, "t"), List(Label(0), Jump(GOTO, Label(0)))) } @Test @@ -46,12 +40,12 @@ class OptimizedBytecodeTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(compiler)(code) + val c = compileClass(code) - assertSameSummary(getSingleMethod(c, "t"), List( + assertSameSummary(getMethod(c, "t"), List( LDC, ASTORE, ALOAD /*0*/, ALOAD /*1*/, "C$$$anonfun$1", IRETURN)) - assertSameSummary(getSingleMethod(c, "C$$$anonfun$1"), List(LDC, "C$$$anonfun$2", IRETURN)) - assertSameSummary(getSingleMethod(c, "C$$$anonfun$2"), List(-1 /*A*/, GOTO /*A*/)) + assertSameSummary(getMethod(c, "C$$$anonfun$1"), List(LDC, "C$$$anonfun$2", IRETURN)) + assertSameSummary(getMethod(c, "C$$$anonfun$2"), List(-1 /*A*/, GOTO /*A*/)) } @Test @@ -72,8 +66,8 @@ class OptimizedBytecodeTest extends ClearAfterClass { | def h(block: => Unit): Nothing = ??? |} """.stripMargin - val List(c, t, tMod) = compileClasses(compiler)(code, allowMessage = _.msg.contains("not be exhaustive")) - assertSameSummary(getSingleMethod(c, "t"), List(GETSTATIC, "$qmark$qmark$qmark", ATHROW)) + val List(c, t, tMod) = compileClasses(code, allowMessage = _.msg.contains("not be exhaustive")) + assertSameSummary(getMethod(c, "t"), List(GETSTATIC, "$qmark$qmark$qmark", ATHROW)) } @Test @@ -97,7 +91,7 @@ class OptimizedBytecodeTest extends ClearAfterClass { |arguments expected by the callee ErrorHandler$::defaultIfIOException(Lscala/Function0;Lscala/Function0;)Ljava/lang/Object;. These values would be discarded |when entering an exception handler declared in the inlined method.""".stripMargin - compileClasses(compiler)(code, allowMessage = _.msg == msg) + compileClasses(code, allowMessage = _.msg == msg) } @Test @@ -110,7 +104,7 @@ class OptimizedBytecodeTest extends ClearAfterClass { | } |} """.stripMargin - compileClasses(compiler)(code) + compileToBytes(code) } @Test @@ -120,8 +114,8 @@ class OptimizedBytecodeTest extends ClearAfterClass { |object Warmup { def filter[A](p: Any => Boolean): Any = filter[Any](p) } """.stripMargin val c2 = "class C { def t = warmup.Warmup.filter[Any](x => false) }" - val List(c, _, _) = compileClassesSeparately(List(c1, c2), extraArgs = args) - assertInvoke(getSingleMethod(c, "t"), "warmup/Warmup$", "filter") + val List(c, _, _) = compileClassesSeparately(List(c1, c2), extraArgs = compilerArgs) + assertInvoke(getMethod(c, "t"), "warmup/Warmup$", "filter") } @Test @@ -135,7 +129,7 @@ class OptimizedBytecodeTest extends ClearAfterClass { | } |} """.stripMargin - compileClasses(compiler)(code) + compileToBytes(code) } @Test @@ -163,7 +157,7 @@ class OptimizedBytecodeTest extends ClearAfterClass { | } |} """.stripMargin - compileClasses(compiler)(code) + compileToBytes(code) } @Test @@ -179,7 +173,7 @@ class OptimizedBytecodeTest extends ClearAfterClass { | } |} """.stripMargin - compileClasses(compiler)(code) + compileToBytes(code) } @Test @@ -201,7 +195,7 @@ class OptimizedBytecodeTest extends ClearAfterClass { | val NoContext = self.analyzer.NoContext |} """.stripMargin - compileClasses(compiler)(code) + compileClasses(code) } @Test @@ -218,8 +212,8 @@ class OptimizedBytecodeTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(compiler)(code) - assertSameSummary(getSingleMethod(c, "t"), List( + val c = compileClass(code) + assertSameSummary(getMethod(c, "t"), List( ALOAD /*1*/, INSTANCEOF /*Some*/, IFNE /*A*/, ALOAD /*0*/, "getInt", POP, -1 /*A*/, BIPUSH, IRETURN)) @@ -237,8 +231,8 @@ class OptimizedBytecodeTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(compiler)(code) - assertSameSummary(getSingleMethod(c, "t"), List( + val c = compileClass(code) + assertSameSummary(getMethod(c, "t"), List( -1 /*A*/, ILOAD /*1*/, TABLESWITCH, -1, ALOAD, "pr", RETURN, -1, ALOAD, "pr", RETURN, @@ -261,9 +255,9 @@ class OptimizedBytecodeTest extends ClearAfterClass { |} """.stripMargin - val cls = compileClassesSeparately(List(c1, c2), extraArgs = args) - val c = cls.find(_.name == "C").get - assertSameSummary(getSingleMethod(c, "t"), List( + val cls = compileClassesSeparately(List(c1, c2), extraArgs = compilerArgs) + val c = findClass(cls, "C") + assertSameSummary(getMethod(c, "t"), List( GETSTATIC, IFNONNULL, ACONST_NULL, ATHROW, // module load and null checks not yet eliminated -1, ICONST_1, GETSTATIC, IFNONNULL, ACONST_NULL, ATHROW, -1, ICONST_2, IADD, IRETURN)) @@ -300,11 +294,11 @@ class OptimizedBytecodeTest extends ClearAfterClass { | def f2b() = identity(wrapper2(5)) // not inlined |} """.stripMargin - val List(c) = compileClasses(compiler)(code, allowMessage = _.msg.contains("exception handler declared in the inlined method")) - assertInvoke(getSingleMethod(c, "f1a"), "C", "C$$$anonfun$1") - assertInvoke(getSingleMethod(c, "f1b"), "C", "wrapper1") - assertInvoke(getSingleMethod(c, "f2a"), "C", "C$$$anonfun$3") - assertInvoke(getSingleMethod(c, "f2b"), "C", "wrapper2") + val c = compileClass(code, allowMessage = _.msg.contains("exception handler declared in the inlined method")) + assertInvoke(getMethod(c, "f1a"), "C", "C$$$anonfun$1") + assertInvoke(getMethod(c, "f1b"), "C", "wrapper1") + assertInvoke(getMethod(c, "f2a"), "C", "C$$$anonfun$3") + assertInvoke(getMethod(c, "f2b"), "C", "wrapper2") } @Test @@ -318,8 +312,8 @@ class OptimizedBytecodeTest extends ClearAfterClass { | def t = mbarray_apply_minibox(null, 0) |} """.stripMargin - val List(c) = compileClasses(compiler)(code) - assertNoInvoke(getSingleMethod(c, "t")) + val c = compileClass(code) + assertNoInvoke(getMethod(c, "t")) } @Test @@ -336,8 +330,8 @@ class OptimizedBytecodeTest extends ClearAfterClass { |object Nill extends Listt |class Listt """.stripMargin - val List(c, nil, nilMod, listt) = compileClasses(compiler)(code) - assertInvoke(getSingleMethod(c, "t"), "C", "C$$$anonfun$1") + val List(c, nil, nilMod, listt) = compileClasses(code) + assertInvoke(getMethod(c, "t"), "C", "C$$$anonfun$1") } @Test @@ -355,14 +349,14 @@ class OptimizedBytecodeTest extends ClearAfterClass { | final def apply(a: Any): Any = throw new RuntimeException(key) |} """.stripMargin - val List(c, f) = compileClasses(compiler)(code) - assertInvoke(getSingleMethod(c, "crash"), "C", "map") + val List(c, f) = compileClasses(code) + assertInvoke(getMethod(c, "crash"), "C", "map") } @Test def optimiseEnablesNewOpt(): Unit = { val code = """class C { def t = (1 to 10) foreach println }""" - val List(c) = readAsmClasses(compile(newCompiler(extraArgs = "-optimise -deprecation"))(code, allowMessage = _.msg.contains("is deprecated"))) - assertInvoke(getSingleMethod(c, "t"), "C", "C$$$anonfun$1") // range-foreach inlined from classpath + val List(c) = readAsmClasses(newCompiler(extraArgs = "-optimise -deprecation").compileToBytes(code, allowMessage = _.msg.contains("is deprecated"))) + assertInvoke(getMethod(c, "t"), "C", "C$$$anonfun$1") // range-foreach inlined from classpath } } diff --git a/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala b/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala index fc0c96e71a..af2c8f9ce0 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala @@ -1,22 +1,18 @@ package scala.tools.nsc package backend.jvm +import org.junit.Assert._ +import org.junit.Test 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.testing.AssertUtil._ -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ -import scala.tools.testing.ClearAfterClass +import scala.tools.partest.ASMConverters._ +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ @RunWith(classOf[JUnit4]) -class StringConcatTest extends ClearAfterClass { - val compiler = cached("compiler", () => newCompiler()) +class StringConcatTest extends BytecodeTesting { + import compiler._ @Test def appendOverloadNoBoxing(): Unit = { @@ -54,9 +50,9 @@ class StringConcatTest extends ClearAfterClass { | chrs: Array[Char]) = this + str + v + z + c + b + s + i + f + l + d + sbuf + chsq + chrs |} """.stripMargin - val List(c) = compileClasses(compiler)(code) + val c = compileClass(code) - def invokeNameDesc(m: String): List[String] = getSingleMethod(c, m).instructions collect { + def invokeNameDesc(m: String): List[String] = getInstructions(c, m) collect { case Invoke(_, _, name, desc, _) => name + desc } assertEquals(invokeNameDesc("t1"), List( diff --git a/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala index 075f42d18f..b0a86dfd28 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala @@ -2,32 +2,29 @@ package scala.tools.nsc package backend.jvm package analysis +import org.junit.Assert._ +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.junit.Test -import scala.tools.asm.Opcodes._ -import org.junit.Assert._ -import CodeGenTools._ -import scala.tools.asm.tree.{AbstractInsnNode, MethodNode} +import scala.collection.JavaConverters._ +import scala.tools.asm.tree.MethodNode +import scala.tools.nsc.backend.jvm.AsmUtils._ import scala.tools.nsc.backend.jvm.BTypes._ -import scala.tools.partest.ASMConverters -import ASMConverters._ -import scala.tools.testing.ClearAfterClass import scala.tools.nsc.backend.jvm.opt.BytecodeUtils._ -import AsmUtils._ - -import scala.collection.JavaConverters._ +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ @RunWith(classOf[JUnit4]) -class NullnessAnalyzerTest extends ClearAfterClass { - val noOptCompiler = cached("noOptCompiler", () => newCompiler(extraArgs = "-Yopt:l:none")) - import noOptCompiler.genBCode.bTypes.backendUtils._ +class NullnessAnalyzerTest extends BytecodeTesting { + override def compilerArgs = "-Yopt:l:none" + import compiler._ + import global.genBCode.bTypes.backendUtils._ - def newNullnessAnalyzer(methodNode: MethodNode, classInternalName: InternalName = "C") = new AsmAnalyzer(methodNode, classInternalName, new NullnessAnalyzer(noOptCompiler.genBCode.bTypes)) + def newNullnessAnalyzer(methodNode: MethodNode, classInternalName: InternalName = "C") = new AsmAnalyzer(methodNode, classInternalName, new NullnessAnalyzer(global.genBCode.bTypes)) def testNullness(analyzer: AsmAnalyzer[NullnessValue], method: MethodNode, query: String, index: Int, nullness: NullnessValue): Unit = { - for (i <- findInstr(method, query)) { + for (i <- findInstrs(method, query)) { val r = analyzer.frameAt(i).getValue(index) assertTrue(s"Expected: $nullness, found: $r. At instr ${textify(i)}", nullness == r) } @@ -53,7 +50,7 @@ class NullnessAnalyzerTest extends ClearAfterClass { @Test def showNullnessFramesTest(): Unit = { - val List(m) = compileMethods(noOptCompiler)("def f = this.toString") + val m = compileAsmMethod("def f = this.toString") // NOTE: the frame for an instruction represents the state *before* executing that instr. // So in the frame for `ALOAD 0`, the stack is still empty. @@ -71,14 +68,14 @@ class NullnessAnalyzerTest extends ClearAfterClass { @Test def thisNonNull(): Unit = { - val List(m) = compileMethods(noOptCompiler)("def f = this.toString") + val m = compileAsmMethod("def f = this.toString") val a = newNullnessAnalyzer(m) testNullness(a, m, "ALOAD 0", 0, NotNullValue) } @Test def instanceMethodCall(): Unit = { - val List(m) = compileMethods(noOptCompiler)("def f(a: String) = a.trim") + val m = compileAsmMethod("def f(a: String) = a.trim") val a = newNullnessAnalyzer(m) testNullness(a, m, "INVOKEVIRTUAL java/lang/String.trim", 1, UnknownValue1) testNullness(a, m, "ARETURN", 1, NotNullValue) @@ -86,7 +83,7 @@ class NullnessAnalyzerTest extends ClearAfterClass { @Test def constructorCall(): Unit = { - val List(m) = compileMethods(noOptCompiler)("def f = { val a = new Object; a.toString }") + val m = compileAsmMethod("def f = { val a = new Object; a.toString }") val a = newNullnessAnalyzer(m) // for reference, the output of showAllNullnessFrames(a, m) - note that the frame represents the state *before* executing the instr. @@ -111,7 +108,7 @@ class NullnessAnalyzerTest extends ClearAfterClass { @Test def explicitNull(): Unit = { - val List(m) = compileMethods(noOptCompiler)("def f = { var a: Object = null; a }") + val m = compileAsmMethod("def f = { var a: Object = null; a }") val a = newNullnessAnalyzer(m) for ((insn, index, nullness) <- List( ("+ACONST_NULL", 2, NullValue), @@ -122,14 +119,14 @@ class NullnessAnalyzerTest extends ClearAfterClass { @Test def stringLiteralsNotNull(): Unit = { - val List(m) = compileMethods(noOptCompiler)("""def f = { val a = "hi"; a.trim }""") + val m = compileAsmMethod("""def f = { val a = "hi"; a.trim }""") val a = newNullnessAnalyzer(m) testNullness(a, m, "+ASTORE 1", 1, NotNullValue) } @Test def newArraynotNull() { - val List(m) = compileMethods(noOptCompiler)("def f = { val a = new Array[Int](2); a(0) }") + val m = compileAsmMethod("def f = { val a = new Array[Int](2); a(0) }") val a = newNullnessAnalyzer(m) testNullness(a, m, "+NEWARRAY T_INT", 2, NotNullValue) // new array on stack testNullness(a, m, "+ASTORE 1", 1, NotNullValue) // local var (a) @@ -147,7 +144,7 @@ class NullnessAnalyzerTest extends ClearAfterClass { | a.toString |} """.stripMargin - val List(m) = compileMethods(noOptCompiler)(code) + val m = compileAsmMethod(code) val a = newNullnessAnalyzer(m) val toSt = "+INVOKEVIRTUAL java/lang/Object.toString" testNullness(a, m, toSt, 3, UnknownValue1) @@ -173,7 +170,7 @@ class NullnessAnalyzerTest extends ClearAfterClass { | // d is null here, assinged in both branches. |} """.stripMargin - val List(m) = compileMethods(noOptCompiler)(code) + val m = compileAsmMethod(code) val a = newNullnessAnalyzer(m) val trim = "INVOKEVIRTUAL java/lang/String.trim" @@ -209,7 +206,7 @@ class NullnessAnalyzerTest extends ClearAfterClass { | a.asInstanceOf[String].trim // the stack value (LOAD of local a) is still not-null after the CHECKCAST |} """.stripMargin - val List(m) = compileMethods(noOptCompiler)(code) + val m = compileAsmMethod(code) val a = newNullnessAnalyzer(m) val instof = "+INSTANCEOF" diff --git a/test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala index 8d4bc19ec3..fc26785237 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala @@ -2,22 +2,23 @@ package scala.tools.nsc package backend.jvm package analysis +import org.junit.Assert._ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.junit.Assert._ import scala.tools.asm.Opcodes import scala.tools.asm.tree.AbstractInsnNode +import scala.tools.nsc.backend.jvm.AsmUtils._ import scala.tools.partest.ASMConverters._ -import scala.tools.testing.ClearAfterClass -import CodeGenTools._ -import AsmUtils._ +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ @RunWith(classOf[JUnit4]) -class ProdConsAnalyzerTest extends ClearAfterClass { - val noOptCompiler =cached("compiler", () => newCompiler(extraArgs = "-Yopt:l:none")) - import noOptCompiler.genBCode.bTypes.backendUtils._ +class ProdConsAnalyzerTest extends BytecodeTesting { + override def compilerArgs = "-Yopt:l:none" + import compiler._ + import global.genBCode.bTypes.backendUtils._ def prodToString(producer: AbstractInsnNode) = producer match { case p: InitialProducer => p.toString @@ -48,9 +49,9 @@ class ProdConsAnalyzerTest extends ClearAfterClass { @Test def parameters(): Unit = { - val List(m) = compileMethods(noOptCompiler)("def f = this.toString") + val m = compileAsmMethod("def f = this.toString") val a = new ProdConsAnalyzer(m, "C") - val call = findInstr(m, "INVOKEVIRTUAL").head + val call = findInstr(m, "INVOKEVIRTUAL") testSingleInsn(a.producersForValueAt(call, 1), "ALOAD 0") // producer of stack value testSingleInsn(a.producersForInputsOf(call), "ALOAD 0") @@ -83,55 +84,55 @@ class ProdConsAnalyzerTest extends ClearAfterClass { m.maxStack = 1 val a = new ProdConsAnalyzer(m, "C") - val ifne = findInstr(m, "IFNE").head + val ifne = findInstr(m, "IFNE") testSingleInsn(a.producersForValueAt(ifne, 1), "ParameterProducer") - val ret = findInstr(m, "IRETURN").head + val ret = findInstr(m, "IRETURN") testMultiInsns(a.producersForValueAt(ret, 1), List("ParameterProducer", "ISTORE 1")) } @Test def branching(): Unit = { - val List(m) = compileMethods(noOptCompiler)("def f(x: Int) = { var a = x; if (a == 0) a = 12; a }") + val m = compileAsmMethod("def f(x: Int) = { var a = x; if (a == 0) a = 12; a }") val a = new ProdConsAnalyzer(m, "C") - val List(ret) = findInstr(m, "IRETURN") + val ret = findInstr(m, "IRETURN") testMultiInsns(a.producersForValueAt(ret, 2), List("ISTORE 2", "ISTORE 2")) testMultiInsns(a.initialProducersForValueAt(ret, 2), List("BIPUSH 12", "ParameterProducer")) - val List(bipush) = findInstr(m, "BIPUSH 12") + val bipush = findInstr(m, "BIPUSH 12") testSingleInsn(a.consumersOfOutputsFrom(bipush), "ISTORE 2") testSingleInsn(a.ultimateConsumersOfValueAt(bipush.getNext, 3), "IRETURN") } @Test def checkCast(): Unit = { - val List(m) = compileMethods(noOptCompiler)("def f(o: Object) = o.asInstanceOf[String]") + val m = compileAsmMethod("def f(o: Object) = o.asInstanceOf[String]") val a = new ProdConsAnalyzer(m, "C") - assert(findInstr(m, "CHECKCAST java/lang/String").length == 1) + assert(findInstrs(m, "CHECKCAST java/lang/String").length == 1) - val List(ret) = findInstr(m, "ARETURN") + val ret = findInstr(m, "ARETURN") testSingleInsn(a.initialProducersForInputsOf(ret), "ParameterProducer(1)") } @Test def instanceOf(): Unit = { - val List(m) = compileMethods(noOptCompiler)("def f(o: Object) = o.isInstanceOf[String]") + val m = compileAsmMethod("def f(o: Object) = o.isInstanceOf[String]") val a = new ProdConsAnalyzer(m, "C") - assert(findInstr(m, "INSTANCEOF java/lang/String").length == 1) + assert(findInstrs(m, "INSTANCEOF java/lang/String").length == 1) - val List(ret) = findInstr(m, "IRETURN") + val ret = findInstr(m, "IRETURN") testSingleInsn(a.initialProducersForInputsOf(ret), "INSTANCEOF") } @Test def unInitLocal(): Unit = { - val List(m) = compileMethods(noOptCompiler)("def f(b: Boolean) = { if (b) { var a = 0; println(a) }; 1 }") + val m = compileAsmMethod("def f(b: Boolean) = { if (b) { var a = 0; println(a) }; 1 }") val a = new ProdConsAnalyzer(m, "C") - val List(store) = findInstr(m, "ISTORE") - val List(call) = findInstr(m, "INVOKEVIRTUAL") - val List(ret) = findInstr(m, "IRETURN") + val store = findInstr(m, "ISTORE") + val call = findInstr(m, "INVOKEVIRTUAL") + val ret = findInstr(m, "IRETURN") testSingleInsn(a.producersForValueAt(store, 2), "UninitializedLocalProducer(2)") testSingleInsn(a.producersForValueAt(call, 2), "ISTORE") @@ -140,11 +141,11 @@ class ProdConsAnalyzerTest extends ClearAfterClass { @Test def dupCopying(): Unit = { - val List(m) = compileMethods(noOptCompiler)("def f = new Object") + val m = compileAsmMethod("def f = new Object") val a = new ProdConsAnalyzer(m, "C") - val List(newO) = findInstr(m, "NEW") - val List(constr) = findInstr(m, "INVOKESPECIAL") + val newO = findInstr(m, "NEW") + val constr = findInstr(m, "INVOKESPECIAL") testSingleInsn(a.producersForInputsOf(constr), "DUP") testSingleInsn(a.initialProducersForInputsOf(constr), "NEW") @@ -169,11 +170,11 @@ class ProdConsAnalyzerTest extends ClearAfterClass { m.maxStack = 4 val a = new ProdConsAnalyzer(m, "C") - val List(dup2) = findInstr(m, "DUP2") - val List(add) = findInstr(m, "IADD") - val List(swap) = findInstr(m, "SWAP") - val List(store) = findInstr(m, "ISTORE") - val List(ret) = findInstr(m, "IRETURN") + val dup2 = findInstr(m, "DUP2") + val add = findInstr(m, "IADD") + val swap = findInstr(m, "SWAP") + val store = findInstr(m, "ISTORE") + val ret = findInstr(m, "IRETURN") testMultiInsns(a.producersForInputsOf(dup2), List("ILOAD", "ILOAD")) testSingleInsn(a.consumersOfValueAt(dup2.getNext, 4), "IADD") @@ -204,9 +205,9 @@ class ProdConsAnalyzerTest extends ClearAfterClass { m.maxStack = 1 val a = new ProdConsAnalyzer(m, "C") - val List(inc) = findInstr(m, "IINC") - val List(load) = findInstr(m, "ILOAD") - val List(ret) = findInstr(m, "IRETURN") + val inc = findInstr(m, "IINC") + val load = findInstr(m, "ILOAD") + val ret = findInstr(m, "IRETURN") testSingleInsn(a.producersForInputsOf(inc), "ParameterProducer(1)") testSingleInsn(a.consumersOfOutputsFrom(inc), "ILOAD") @@ -222,12 +223,12 @@ class ProdConsAnalyzerTest extends ClearAfterClass { @Test def copyingInsns(): Unit = { - val List(m) = compileMethods(noOptCompiler)("def f = 0l.asInstanceOf[Int]") + val m = compileAsmMethod("def f = 0l.asInstanceOf[Int]") val a = new ProdConsAnalyzer(m, "C") - val List(cnst) = findInstr(m, "LCONST_0") - val List(l2i) = findInstr(m, "L2I") // l2i is not a copying instruction - val List(ret) = findInstr(m, "IRETURN") + val cnst = findInstr(m, "LCONST_0") + val l2i = findInstr(m, "L2I") // l2i is not a copying instruction + val ret = findInstr(m, "IRETURN") testSingleInsn(a.consumersOfOutputsFrom(cnst), "L2I") testSingleInsn(a.ultimateConsumersOfOutputsFrom(cnst), "L2I") @@ -263,10 +264,10 @@ class ProdConsAnalyzerTest extends ClearAfterClass { m.maxStack = 2 val a = new ProdConsAnalyzer(m, "C") - val List(iadd) = findInstr(m, "IADD") + val iadd = findInstr(m, "IADD") val firstLoad = iadd.getPrevious.getPrevious assert(firstLoad.getOpcode == ILOAD) - val secondLoad = findInstr(m, "ISTORE").head.getPrevious + val secondLoad = findInstr(m, "ISTORE").getPrevious assert(secondLoad.getOpcode == ILOAD) testSingleInsn(a.producersForValueAt(iadd, 2), "ILOAD") diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/AnalyzerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/AnalyzerTest.scala index 09675870f0..025248ac28 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/AnalyzerTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/AnalyzerTest.scala @@ -2,28 +2,21 @@ package scala.tools.nsc package backend.jvm package opt +import org.junit.Assert._ +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.junit.Test -import org.junit.Assert._ -import scala.tools.asm.tree._ import scala.tools.asm.tree.analysis._ -import scala.tools.nsc.backend.jvm.analysis.{AliasingFrame, AliasingAnalyzer} - -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ -import AsmUtils._ -import BackendReporting._ -import BytecodeUtils._ - -import scala.collection.JavaConverters._ -import scala.tools.testing.ClearAfterClass +import scala.tools.nsc.backend.jvm.analysis.{AliasingAnalyzer, AliasingFrame} +import scala.tools.nsc.backend.jvm.opt.BytecodeUtils._ +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ @RunWith(classOf[JUnit4]) -class AnalyzerTest extends ClearAfterClass { - val noOptCompiler = cached("compiler", () => newCompiler(extraArgs = "-Yopt:l:none")) +class AnalyzerTest extends BytecodeTesting { + override def compilerArgs = "-Yopt:l:none" + import compiler._ @Test def aliasingOfPrimitives(): Unit = { @@ -39,17 +32,17 @@ class AnalyzerTest extends ClearAfterClass { |} """.stripMargin - val List(c) = compileClasses(noOptCompiler)(code) + val c = compileClass(code) val a = new AliasingAnalyzer(new BasicInterpreter) - val f = findAsmMethod(c, "f") + val f = getAsmMethod(c, "f") a.analyze("C", f) - val List(_, i2l) = findInstr(f, "I2L") + val List(_, i2l) = findInstrs(f, "I2L") val aliasesAtI2l = a.frameAt(i2l, f).asInstanceOf[AliasingFrame[_]].aliases assertEquals(aliasesAtI2l(1).iterator.toList, List(1, 8, 9)) // a, e and stack top assertEquals(aliasesAtI2l(4).iterator.toList, List(4, 6)) - val List(add) = findInstr(f, "LADD") + val add = findInstr(f, "LADD") val aliasesAtAdd = a.frameAt(add, f).asInstanceOf[AliasingFrame[_]].aliases assertEquals(aliasesAtAdd(1).iterator.toList, List(1, 8)) // after i2l the value on the stack is no longer an alias assertEquals(aliasesAtAdd(4).iterator.toList, List(4, 6, 10)) // c, d and stack top diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala index aba0aab038..e7aea71e72 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala @@ -2,37 +2,29 @@ package scala.tools.nsc package backend.jvm package opt +import org.junit.{Ignore, Test} 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.asm.Opcodes._ import scala.tools.nsc.backend.jvm.BTypes.InternalName -import scala.tools.testing.AssertUtil._ - -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ - -import BackendReporting._ - -import scala.collection.JavaConverters._ +import scala.tools.nsc.backend.jvm.BackendReporting._ +import scala.tools.testing.BytecodeTesting @RunWith(classOf[JUnit4]) -class BTypesFromClassfileTest { +class BTypesFromClassfileTest extends BytecodeTesting { // inliner enabled -> inlineInfos are collected (and compared) in ClassBTypes - val compiler = newCompiler(extraArgs = "-Yopt:inline-global") + override def compilerArgs = "-Yopt:inline-global" - import compiler._ + import compiler.global._ import definitions._ import genBCode.bTypes import bTypes._ - def duringBackend[T](f: => T) = compiler.exitingDelambdafy(f) + def duringBackend[T](f: => T) = global.exitingDelambdafy(f) - val run = new compiler.Run() // initializes some of the compiler - duringBackend(compiler.scalaPrimitives.init()) // needed: it's only done when running the backend, and we don't actually run the compiler + val run = new global.Run() // initializes some of the compiler + duringBackend(global.scalaPrimitives.init()) // needed: it's only done when running the backend, and we don't actually run the compiler duringBackend(bTypes.initializeCoreBTypes()) def clearCache() = bTypes.classBTypeFromInternalName.clear() @@ -91,7 +83,9 @@ class BTypesFromClassfileTest { sameBType(fromSymbol, fromClassfile) } - @Test + // Can be enabled when using 2.12.0-M5 as starr. This test works under a full boostrap, but not + // when compiled with M4. + @Test @Ignore def compareClassBTypes(): Unit = { // Note that not only these classes are tested, but also all their parents and all nested // classes in their InnerClass attributes. diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala index 9a27c42cac..630416a925 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala @@ -2,46 +2,38 @@ package scala.tools.nsc package backend.jvm package opt +import org.junit.Assert._ +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.junit.Test + +import scala.collection.JavaConverters._ import scala.collection.generic.Clearable import scala.collection.immutable.IntMap -import scala.tools.asm.Opcodes._ -import org.junit.Assert._ - import scala.tools.asm.tree._ -import scala.tools.asm.tree.analysis._ +import scala.tools.nsc.backend.jvm.BackendReporting._ import scala.tools.nsc.reporters.StoreReporter -import scala.tools.testing.AssertUtil._ - -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ -import AsmUtils._ -import BackendReporting._ - -import scala.collection.JavaConverters._ -import scala.tools.testing.ClearAfterClass +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ @RunWith(classOf[JUnit4]) -class CallGraphTest extends ClearAfterClass { - val compiler = cached("compiler", () => newCompiler(extraArgs = "-Yopt:inline-global -Yopt-warnings") - ) - import compiler.genBCode.bTypes +class CallGraphTest extends BytecodeTesting { + override def compilerArgs = "-Yopt:inline-global -Yopt-warnings" + import compiler._ + import global.genBCode.bTypes val notPerRun: List[Clearable] = List( bTypes.classBTypeFromInternalName, bTypes.byteCodeRepository.compilingClasses, bTypes.byteCodeRepository.parsedClasses, bTypes.callGraph.callsites) - notPerRun foreach compiler.perRunCaches.unrecordCache + notPerRun foreach global.perRunCaches.unrecordCache - import compiler.genBCode.bTypes._ + import global.genBCode.bTypes._ import callGraph._ def compile(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] = { notPerRun.foreach(_.clear()) - compileClasses(compiler)(code, allowMessage = allowMessage).map(c => byteCodeRepository.classNode(c.name).get) + compileClasses(code, allowMessage = allowMessage).map(c => byteCodeRepository.classNode(c.name).get) } def callsInMethod(methodNode: MethodNode): List[MethodInsnNode] = methodNode.instructions.iterator.asScala.collect({ @@ -112,10 +104,10 @@ class CallGraphTest extends ClearAfterClass { val List(cCls, cMod, dCls, testCls) = compile(code, checkMsg) assert(msgCount == 6, msgCount) - val List(cf1, cf2, cf3, cf4, cf5, cf6, cf7) = findAsmMethods(cCls, _.startsWith("f")) - val List(df1, df3) = findAsmMethods(dCls, _.startsWith("f")) - val g1 = findAsmMethod(cMod, "g1") - val List(t1, t2) = findAsmMethods(testCls, _.startsWith("t")) + val List(cf1, cf2, cf3, cf4, cf5, cf6, cf7) = getAsmMethods(cCls, _.startsWith("f")) + val List(df1, df3) = getAsmMethods(dCls, _.startsWith("f")) + val g1 = getAsmMethod(cMod, "g1") + val List(t1, t2) = getAsmMethods(testCls, _.startsWith("t")) val List(cf1Call, cf2Call, cf3Call, cf4Call, cf5Call, cf6Call, cf7Call, cg1Call) = callsInMethod(t1) val List(df1Call, df2Call, df3Call, df4Call, df5Call, df6Call, df7Call, dg1Call) = callsInMethod(t2) @@ -151,7 +143,7 @@ class CallGraphTest extends ClearAfterClass { |} """.stripMargin val List(c) = compile(code) - val m = findAsmMethod(c, "m") + val m = getAsmMethod(c, "m") val List(fn) = callsInMethod(m) val forNameMeth = byteCodeRepository.methodNode("java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;").get._1 val classTp = classBTypeFromInternalName("java/lang/Class") diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala index e8530af4e0..218b02f822 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala @@ -2,34 +2,19 @@ package scala.tools.nsc package backend.jvm package opt +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.junit.Test -import scala.collection.generic.Clearable -import scala.collection.mutable.ListBuffer -import scala.reflect.internal.util.BatchSourceFile -import scala.tools.asm.Opcodes._ -import org.junit.Assert._ - -import scala.tools.asm.tree._ -import scala.tools.asm.tree.analysis._ -import scala.tools.nsc.io._ -import scala.tools.nsc.reporters.StoreReporter -import scala.tools.testing.AssertUtil._ -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ -import AsmUtils._ - -import BackendReporting._ - -import scala.collection.JavaConverters._ -import scala.tools.testing.ClearAfterClass +import scala.tools.asm.Opcodes._ +import scala.tools.partest.ASMConverters._ +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ @RunWith(classOf[JUnit4]) -class ClosureOptimizerTest extends ClearAfterClass { - val compiler = cached("compiler", () => newCompiler(extraArgs = "-Yopt:l:classpath -Yopt-warnings:_")) +class ClosureOptimizerTest extends BytecodeTesting { + override def compilerArgs = "-Yopt:l:classpath -Yopt-warnings:_" + import compiler._ @Test def nothingTypedClosureBody(): Unit = { @@ -41,9 +26,9 @@ class ClosureOptimizerTest extends ClearAfterClass { |} """.stripMargin - val List(c) = compileClasses(compiler)(code) - val t = findAsmMethod(c, "t") - val List(bodyCall) = findInstr(t, "INVOKESTATIC C.C$$$anonfun$1 ()Lscala/runtime/Nothing$") + val c = compileClass(code) + val t = getAsmMethod(c, "t") + val bodyCall = findInstr(t, "INVOKESTATIC C.C$$$anonfun$1 ()Lscala/runtime/Nothing$") assert(bodyCall.getNext.getOpcode == ATHROW) } @@ -57,9 +42,9 @@ class ClosureOptimizerTest extends ClearAfterClass { |} """.stripMargin - val List(c) = compileClasses(compiler)(code) - val t = findAsmMethod(c, "t") - val List(bodyCall) = findInstr(t, "INVOKESTATIC C.C$$$anonfun$1 ()Lscala/runtime/Null$") + val c = compileClass(code) + val t = getAsmMethod(c, "t") + val bodyCall = findInstr(t, "INVOKESTATIC C.C$$$anonfun$1 ()Lscala/runtime/Null$") assert(bodyCall.getNext.getOpcode == POP) assert(bodyCall.getNext.getNext.getOpcode == ACONST_NULL) } @@ -74,8 +59,8 @@ class ClosureOptimizerTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(compiler)(code) - assertSameCode(getSingleMethod(c, "t"), + val c = compileClass(code) + assertSameCode(getMethod(c, "t"), List(VarOp(ALOAD, 1), Invoke(INVOKEVIRTUAL, "scala/collection/immutable/List", "head", "()Ljava/lang/Object;", false), TypeOp(CHECKCAST, "java/lang/String"), Invoke(INVOKESTATIC, "C", "C$$$anonfun$1", "(Ljava/lang/String;)Ljava/lang/String;", false), Op(ARETURN))) @@ -95,7 +80,7 @@ class ClosureOptimizerTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(compiler)(code) - assertSameSummary(getSingleMethod(c, "t"), List(NEW, DUP, LDC, "<init>", ATHROW)) + val c = compileClass(code) + assertSameSummary(getMethod(c, "t"), List(NEW, DUP, LDC, "<init>", ATHROW)) } } diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala index ac1b759fe2..c3748a05bd 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala @@ -2,23 +2,21 @@ package scala.tools.nsc package backend.jvm package opt +import org.junit.Assert._ +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.junit.Test -import scala.tools.asm.Opcodes._ -import org.junit.Assert._ -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ +import scala.tools.partest.ASMConverters._ +import scala.tools.testing.BytecodeTesting._ +import scala.tools.testing.ClearAfterClass @RunWith(classOf[JUnit4]) -class CompactLocalVariablesTest { - +class CompactLocalVariablesTest extends ClearAfterClass { // recurse-unreachable-jumps is required for eliminating catch blocks, in the first dce round they // are still live.only after eliminating the empty handler the catch blocks become unreachable. - val methodOptCompiler = newCompiler(extraArgs = "-Yopt:unreachable-code,compact-locals") - val noCompactVarsCompiler = newCompiler(extraArgs = "-Yopt:unreachable-code") + val methodOptCompiler = cached("methodOptCompiler", () => newCompiler(extraArgs = "-Yopt:unreachable-code,compact-locals")) + val noCompactVarsCompiler = cached("noCompactVarsCompiler", () => newCompiler(extraArgs = "-Yopt:unreachable-code")) @Test def compactUnused(): Unit = { @@ -58,8 +56,8 @@ class CompactLocalVariablesTest { |} |""".stripMargin - val List(noCompact) = compileMethods(noCompactVarsCompiler)(code) - val List(withCompact) = compileMethods(methodOptCompiler)(code) + val noCompact = noCompactVarsCompiler.compileAsmMethod(code) + val withCompact = methodOptCompiler.compileAsmMethod(code) // code is the same, except for local var indices assertTrue(noCompact.instructions.size == withCompact.instructions.size) diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala index 6d566c722f..3324058cb7 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala @@ -2,22 +2,23 @@ package scala.tools.nsc package backend.jvm package opt +import org.junit.Assert._ +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.junit.Test -import scala.tools.asm.Opcodes._ -import org.junit.Assert._ -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ -import scala.tools.testing.ClearAfterClass +import scala.tools.asm.Opcodes._ +import scala.tools.partest.ASMConverters._ +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ @RunWith(classOf[JUnit4]) -class EmptyExceptionHandlersTest extends ClearAfterClass { +class EmptyExceptionHandlersTest extends BytecodeTesting { + override def compilerArgs = "-Yopt:unreachable-code" + def dceCompiler = compiler + val noOptCompiler = cached("noOptCompiler", () => newCompiler(extraArgs = "-Yopt:l:none")) - val dceCompiler = cached("dceCompiler", () => newCompiler(extraArgs = "-Yopt:unreachable-code")) val exceptionDescriptor = "java/lang/Exception" @@ -59,8 +60,8 @@ class EmptyExceptionHandlersTest extends ClearAfterClass { def eliminateUnreachableHandler(): Unit = { val code = "def f: Unit = try { } catch { case _: Exception => println(0) }; println(1)" - assertTrue(singleMethod(noOptCompiler)(code).handlers.length == 1) - val optMethod = singleMethod(dceCompiler)(code) + assertTrue(noOptCompiler.compileMethod(code).handlers.length == 1) + val optMethod = dceCompiler.compileMethod(code) assertTrue(optMethod.handlers.isEmpty) val code2 = @@ -72,7 +73,7 @@ class EmptyExceptionHandlersTest extends ClearAfterClass { | println(2) |}""".stripMargin - assertTrue(singleMethod(dceCompiler)(code2).handlers.isEmpty) + assertTrue(dceCompiler.compileMethod(code2).handlers.isEmpty) } @Test @@ -84,6 +85,6 @@ class EmptyExceptionHandlersTest extends ClearAfterClass { | catch { case _: Exception => 2 } |}""".stripMargin - assertTrue(singleMethod(dceCompiler)(code).handlers.length == 1) + assertTrue(dceCompiler.compileMethod(code).handlers.length == 1) } } diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala index 7283e20745..d57d44f2a3 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala @@ -2,16 +2,16 @@ package scala.tools.nsc package backend.jvm package opt +import org.junit.Assert._ +import org.junit.Test 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.testing.AssertUtil._ -import CodeGenTools._ +import scala.tools.asm.Opcodes._ import scala.tools.partest.ASMConverters -import ASMConverters._ +import scala.tools.partest.ASMConverters._ +import scala.tools.testing.AssertUtil._ +import scala.tools.testing.BytecodeTesting._ @RunWith(classOf[JUnit4]) class EmptyLabelsAndLineNumbersTest { diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala index 5cb1aab4a9..e45d7139a3 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala @@ -2,36 +2,31 @@ package scala.tools.nsc package backend.jvm package opt +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.junit.Test -import scala.collection.generic.Clearable -import org.junit.Assert._ - -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ -import AsmUtils._ -import scala.tools.testing.ClearAfterClass - -import BackendReporting._ import scala.collection.JavaConverters._ +import scala.collection.generic.Clearable +import scala.tools.nsc.backend.jvm.BackendReporting._ +import scala.tools.testing.BytecodeTesting @RunWith(classOf[JUnit4]) -class InlineInfoTest extends ClearAfterClass { - val compiler = cached("compiler", () => newCompiler(extraArgs = "-Yopt:l:classpath")) +class InlineInfoTest extends BytecodeTesting { + import compiler.global + import global.genBCode.bTypes + + override def compilerArgs = "-Yopt:l:classpath" - import compiler.genBCode.bTypes def notPerRun: List[Clearable] = List( bTypes.classBTypeFromInternalName, bTypes.byteCodeRepository.compilingClasses, bTypes.byteCodeRepository.parsedClasses) - notPerRun foreach compiler.perRunCaches.unrecordCache + notPerRun foreach global.perRunCaches.unrecordCache def compile(code: String) = { notPerRun.foreach(_.clear()) - compileClasses(compiler)(code) + compiler.compileClasses(code) } @Test @@ -55,11 +50,11 @@ class InlineInfoTest extends ClearAfterClass { """.stripMargin val classes = compile(code) - val fromSyms = classes.map(c => compiler.genBCode.bTypes.classBTypeFromInternalName(c.name).info.get.inlineInfo) + val fromSyms = classes.map(c => global.genBCode.bTypes.classBTypeFromInternalName(c.name).info.get.inlineInfo) val fromAttrs = classes.map(c => { assert(c.attrs.asScala.exists(_.isInstanceOf[InlineInfoAttribute]), c.attrs) - compiler.genBCode.bTypes.inlineInfoFromClassfile(c) + global.genBCode.bTypes.inlineInfoFromClassfile(c) }) assert(fromSyms == fromAttrs) diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala index 6dd0a33289..f0913f3631 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala @@ -2,41 +2,21 @@ package scala.tools.nsc package backend.jvm package opt +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.junit.Test -import scala.collection.generic.Clearable -import scala.collection.mutable.ListBuffer -import scala.reflect.internal.util.BatchSourceFile -import scala.tools.asm.Opcodes._ -import org.junit.Assert._ - -import scala.tools.asm.tree._ -import scala.tools.asm.tree.analysis._ -import scala.tools.nsc.io._ -import scala.tools.nsc.reporters.StoreReporter -import scala.tools.testing.AssertUtil._ -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ -import AsmUtils._ +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ -import BackendReporting._ +@RunWith(classOf[JUnit4]) +class InlineWarningTest extends BytecodeTesting { + def optCp = "-Yopt:l:classpath" + override def compilerArgs = s"$optCp -Yopt-warnings" -import scala.collection.JavaConverters._ -import scala.tools.testing.ClearAfterClass + import compiler._ -@RunWith(classOf[JUnit4]) -class InlineWarningTest extends ClearAfterClass { - val argsNoWarn = "-Yopt:l:classpath" - val args = argsNoWarn + " -Yopt-warnings" - val compiler = cached("compiler", () => newCompiler(extraArgs = args)) - val compilerWarnAll = cached("compilerWarnAll", () => newCompiler(extraArgs = argsNoWarn + " -Yopt-warnings:_")) - - def compile(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false, compiler: Global = compiler): List[ClassNode] = { - compileClasses(compiler)(scalaCode, javaCode, allowMessage) - } + val compilerWarnAll = cached("compilerWarnAll", () => newCompiler(extraArgs = s"$optCp -Yopt-warnings:_")) @Test def nonFinal(): Unit = { @@ -58,7 +38,7 @@ class InlineWarningTest extends ClearAfterClass { "C::m1()I is annotated @inline but cannot be inlined: the method is not final and may be overridden", "T::m2()I is annotated @inline but cannot be inlined: the method is not final and may be overridden", "D::m2()I is annotated @inline but cannot be inlined: the method is not final and may be overridden") - compile(code, allowMessage = i => {count += 1; warns.exists(i.msg contains _)}) + compileToBytes(code, allowMessage = i => {count += 1; warns.exists(i.msg contains _)}) assert(count == 4, count) } @@ -73,7 +53,7 @@ class InlineWarningTest extends ClearAfterClass { """.stripMargin var c = 0 - compile(code, allowMessage = i => {c += 1; i.msg contains "operand stack at the callsite in C::t1()V contains more values"}) + compileToBytes(code, allowMessage = i => {c += 1; i.msg contains "operand stack at the callsite in C::t1()V contains more values"}) assert(c == 1, c) } @@ -103,14 +83,14 @@ class InlineWarningTest extends ClearAfterClass { |Note that the parent class A is defined in a Java source (mixed compilation), no bytecode is available.""".stripMargin) var c = 0 - val List(b) = compile(scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; warns.tail.exists(i.msg contains _)}) + val List(b) = compileToBytes(scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; warns.tail.exists(i.msg contains _)}) assert(c == 1, c) // no warnings here - compileClasses(newCompiler(extraArgs = argsNoWarn + " -Yopt-warnings:none"))(scalaCode, List((javaCode, "A.java"))) + newCompiler(extraArgs = s"$optCp -Yopt-warnings:none").compileToBytes(scalaCode, List((javaCode, "A.java"))) c = 0 - compileClasses(newCompiler(extraArgs = argsNoWarn + " -Yopt-warnings:no-inline-mixed"))(scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; warns.exists(i.msg contains _)}) + newCompiler(extraArgs = s"$optCp -Yopt-warnings:no-inline-mixed").compileToBytes(scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; warns.exists(i.msg contains _)}) assert(c == 2, c) } @@ -137,7 +117,7 @@ class InlineWarningTest extends ClearAfterClass { |that would cause an IllegalAccessError when inlined into class N""".stripMargin var c = 0 - compile(code, allowMessage = i => { c += 1; i.msg contains warn }) + compileToBytes(code, allowMessage = i => { c += 1; i.msg contains warn }) assert(c == 1, c) } @@ -156,7 +136,7 @@ class InlineWarningTest extends ClearAfterClass { | def t(a: M) = a.f(x => x + 1) |} """.stripMargin - compile(code, allowMessage = _ => false) // no warnings allowed + compileToBytes(code, allowMessage = _ => false) // no warnings allowed val warn = """M::f(Lscala/Function1;)I could not be inlined: @@ -164,7 +144,7 @@ class InlineWarningTest extends ClearAfterClass { |that would cause an IllegalAccessError when inlined into class N""".stripMargin var c = 0 - compile(code, compiler = compilerWarnAll, allowMessage = i => { c += 1; i.msg contains warn }) + compilerWarnAll.compileToBytes(code, allowMessage = i => { c += 1; i.msg contains warn }) assert(c == 1, c) } @@ -185,7 +165,7 @@ class InlineWarningTest extends ClearAfterClass { |does not have the same strictfp mode as the callee C::f()I.""".stripMargin var c = 0 - compile(code, allowMessage = i => { c += 1; i.msg contains warn }) + compileToBytes(code, allowMessage = i => { c += 1; i.msg contains warn }) assert(c == 1, c) } } diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala index ab1aef47cd..c2ada8afec 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala @@ -2,27 +2,22 @@ package scala.tools.nsc package backend.jvm package opt +import org.junit.Test 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.asm.tree._ -import scala.tools.testing.AssertUtil._ - -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ -import AsmUtils._ import scala.collection.JavaConverters._ -import scala.tools.testing.ClearAfterClass +import scala.tools.asm.Opcodes._ +import scala.tools.asm.tree._ +import scala.tools.nsc.backend.jvm.AsmUtils._ +import scala.tools.testing.BytecodeTesting @RunWith(classOf[JUnit4]) -class InlinerIllegalAccessTest extends ClearAfterClass { - val compiler = cached("compiler", () => newCompiler(extraArgs = "-Yopt:l:none")) - import compiler.genBCode.bTypes._ +class InlinerIllegalAccessTest extends BytecodeTesting { + override def compilerArgs = "-Yopt:l:none" + + import compiler._ + import global.genBCode.bTypes._ def addToRepo(cls: List[ClassNode]): Unit = for (c <- cls) byteCodeRepository.add(c, ByteCodeRepository.Classfile) def assertEmpty(ins: Option[AbstractInsnNode]) = for (i <- ins) @@ -44,7 +39,7 @@ class InlinerIllegalAccessTest extends ClearAfterClass { |} """.stripMargin - val allClasses = compileClasses(compiler)(code) + val allClasses = compileClasses(code) val List(cClass, dClass, eClass) = allClasses assert(cClass.name == "a/C" && dClass.name == "a/D" && eClass.name == "b/E", s"${cClass.name}, ${dClass.name}, ${eClass.name}") addToRepo(allClasses) // they are not on the compiler's classpath, so we add them manually to the code repo @@ -120,7 +115,7 @@ class InlinerIllegalAccessTest extends ClearAfterClass { |} """.stripMargin - val allClasses = compileClasses(compiler)(code) + val allClasses = compileClasses(code) val List(cCl, dCl, eCl, fCl, gCl, hCl, iCl) = allClasses addToRepo(allClasses) diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerSeparateCompilationTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerSeparateCompilationTest.scala index 075513a2b7..b196f1a9ba 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerSeparateCompilationTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerSeparateCompilationTest.scala @@ -2,26 +2,15 @@ package scala.tools.nsc package backend.jvm package opt +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.junit.Test -import scala.tools.asm.Opcodes._ -import org.junit.Assert._ -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ -import AsmUtils._ - -import scala.collection.JavaConverters._ - -object InlinerSeparateCompilationTest { - val args = "-Yopt:l:classpath" -} +import scala.tools.testing.BytecodeTesting._ @RunWith(classOf[JUnit4]) class InlinerSeparateCompilationTest { - import InlinerSeparateCompilationTest._ + val args = "-Yopt:l:classpath" @Test def inlnieMixedinMember(): Unit = { @@ -44,9 +33,9 @@ class InlinerSeparateCompilationTest { val warn = "T::f()I is annotated @inline but cannot be inlined: the method is not final and may be overridden" val List(c, o, oMod, t) = compileClassesSeparately(List(codeA, codeB), args + " -Yopt-warnings", _.msg contains warn) - assertInvoke(getSingleMethod(c, "t1"), "T", "f") - assertNoInvoke(getSingleMethod(c, "t2")) - assertNoInvoke(getSingleMethod(c, "t3")) + assertInvoke(getMethod(c, "t1"), "T", "f") + assertNoInvoke(getMethod(c, "t2")) + assertNoInvoke(getMethod(c, "t3")) } @Test @@ -64,7 +53,7 @@ class InlinerSeparateCompilationTest { """.stripMargin val List(c, t) = compileClassesSeparately(List(codeA, codeB), args) - assertNoInvoke(getSingleMethod(c, "t1")) + assertNoInvoke(getMethod(c, "t1")) } @Test @@ -87,7 +76,7 @@ class InlinerSeparateCompilationTest { """.stripMargin val List(c, t, u) = compileClassesSeparately(List(codeA, codeB), args) - for (m <- List("t1", "t2", "t3")) assertNoInvoke(getSingleMethod(c, m)) + for (m <- List("t1", "t2", "t3")) assertNoInvoke(getMethod(c, m)) } @Test @@ -108,7 +97,7 @@ class InlinerSeparateCompilationTest { """.stripMargin val List(a, t) = compileClassesSeparately(List(codeA, assembly), args) - assertNoInvoke(getSingleMethod(t, "f")) - assertNoInvoke(getSingleMethod(a, "n")) + assertNoInvoke(getMethod(t, "f")) + assertNoInvoke(getMethod(a, "n")) } } diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala index b7641b5ec7..fd020c7d93 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala @@ -2,48 +2,44 @@ package scala.tools.nsc package backend.jvm package opt +import org.junit.Assert._ +import org.junit.{Ignore, Test} import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.junit.Test + +import scala.collection.JavaConverters._ import scala.collection.generic.Clearable import scala.tools.asm.Opcodes._ -import org.junit.Assert._ - import scala.tools.asm.tree._ +import scala.tools.nsc.backend.jvm.BackendReporting._ import scala.tools.nsc.reporters.StoreReporter - -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ -import AsmUtils._ - -import BackendReporting._ - -import scala.collection.JavaConverters._ -import scala.tools.testing.ClearAfterClass +import scala.tools.partest.ASMConverters._ +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ @RunWith(classOf[JUnit4]) -class InlinerTest extends ClearAfterClass { - val args = "-Yopt:l:classpath -Yopt-warnings" - val compiler = cached("compiler", () => newCompiler(extraArgs = args)) +class InlinerTest extends BytecodeTesting { + override def compilerArgs = "-Yopt:l:classpath -Yopt-warnings" + val inlineOnlyCompiler = cached("inlineOnlyCompiler", () => newCompiler(extraArgs = "-Yopt:inline-project")) - import compiler.genBCode.bTypes + + import compiler._ + import global.genBCode.bTypes // allows inspecting the caches after a compilation run def notPerRun: List[Clearable] = List( bTypes.classBTypeFromInternalName, bTypes.byteCodeRepository.compilingClasses, bTypes.byteCodeRepository.parsedClasses, bTypes.callGraph.callsites) - notPerRun foreach compiler.perRunCaches.unrecordCache + notPerRun foreach global.perRunCaches.unrecordCache - import compiler.genBCode.bTypes._ - import compiler.genBCode.bTypes.backendUtils._ + import global.genBCode.bTypes.{byteCodeRepository, callGraph, inliner, inlinerHeuristics} import inlinerHeuristics._ def compile(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] = { notPerRun.foreach(_.clear()) - compileClasses(compiler)(scalaCode, javaCode, allowMessage) + compileToBytes(scalaCode, javaCode, allowMessage) // Use the class nodes stored in the byteCodeRepository. The ones returned by compileClasses are not the same, // these are created new from the classfile byte array. They are completely separate instances which cannot // be used to look up methods / callsites in the callGraph hash maps for example. @@ -64,7 +60,7 @@ class InlinerTest extends ClearAfterClass { def gMethAndFCallsite(code: String, mod: ClassNode => Unit = _ => ()) = { val List(c) = compile(code) mod(c) - val gMethod = findAsmMethod(c, "g") + val gMethod = getAsmMethod(c, "g") val fCall = getCallsite(gMethod, "f") (gMethod, fCall) } @@ -138,7 +134,7 @@ class InlinerTest extends ClearAfterClass { assertSameCode(convertMethod(g), gBeforeLocalOpt) - compiler.genBCode.bTypes.localOpt.methodOptimizations(g, "C") + global.genBCode.bTypes.localOpt.methodOptimizations(g, "C") assertSameCode(convertMethod(g), invokeQQQ :+ Op(ATHROW)) } @@ -152,7 +148,7 @@ class InlinerTest extends ClearAfterClass { """.stripMargin val can = canInlineTest(code, cls => { - val f = cls.methods.asScala.find(_.name == "f").get + val f = getAsmMethod(cls, "f") f.access |= ACC_SYNCHRONIZED }) assert(can.nonEmpty && can.get.isInstanceOf[SynchronizedMethod], can) @@ -201,7 +197,7 @@ class InlinerTest extends ClearAfterClass { """.stripMargin val List(c, d) = compile(code) - val hMeth = findAsmMethod(d, "h") + val hMeth = getAsmMethod(d, "h") val gCall = getCallsite(hMeth, "g") val r = inliner.canInlineBody(gCall) assert(r.nonEmpty && r.get.isInstanceOf[IllegalAccessInstruction], r) @@ -218,7 +214,7 @@ class InlinerTest extends ClearAfterClass { |} """.stripMargin val List(cCls) = compile(code) - val instructions = getSingleMethod(cCls, "test").instructions + val instructions = getInstructions(cCls, "test") assert(instructions.contains(Op(ICONST_0)), instructions.stringLines) assert(!instructions.contains(Op(ICONST_1)), instructions) } @@ -284,7 +280,7 @@ class InlinerTest extends ClearAfterClass { |} """.stripMargin val List(c, _, _) = compile(code) - val ins = getSingleMethod(c, "f").instructions + val ins = getInstructions(c, "f") val invokeSysArraycopy = Invoke(INVOKESTATIC, "java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V", false) assert(ins contains invokeSysArraycopy, ins.stringLines) } @@ -316,7 +312,7 @@ class InlinerTest extends ClearAfterClass { |} """.stripMargin val List(c, t) = compile(code) - assertNoInvoke(getSingleMethod(c, "g")) + assertNoInvoke(getMethod(c, "g")) } @Test @@ -329,7 +325,7 @@ class InlinerTest extends ClearAfterClass { """.stripMargin val List(c) = compile(code) // no more invoke, f is inlined - assertNoInvoke(getSingleMethod(c, "g")) + assertNoInvoke(getMethod(c, "g")) } @Test @@ -341,7 +337,7 @@ class InlinerTest extends ClearAfterClass { """.stripMargin val List(c) = compile(code) - val fMeth = findAsmMethod(c, "f") + val fMeth = getAsmMethod(c, "f") val call = getCallsite(fMeth, "lowestOneBit") val warning = inliner.canInlineBody(call) @@ -380,7 +376,7 @@ class InlinerTest extends ClearAfterClass { """.stripMargin // use a compiler without local optimizations (cleanups) - val List(c) = compileClasses(inlineOnlyCompiler)(code) + val c = inlineOnlyCompiler.compileClass(code) val ms @ List(f1, f2, g1, g2) = c.methods.asScala.filter(_.name.length == 2).toList // stack height at callsite of f1 is 1, so max of g1 after inlining is max of f1 + 1 @@ -425,7 +421,7 @@ class InlinerTest extends ClearAfterClass { var c = 0 val List(b) = compile(scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; i.msg contains warn}) assert(c == 1, c) - val ins = getSingleMethod(b, "g").instructions + val ins = getInstructions(b, "g") val invokeFlop = Invoke(INVOKEVIRTUAL, "B", "flop", "()I", false) assert(ins contains invokeFlop, ins.stringLines) } @@ -445,8 +441,8 @@ class InlinerTest extends ClearAfterClass { """.stripMargin val List(c, t) = compile(code) // both are just `return 1`, no more calls - assertNoInvoke(getSingleMethod(c, "t1")) - assertNoInvoke(getSingleMethod(c, "t2")) + assertNoInvoke(getMethod(c, "t1")) + assertNoInvoke(getMethod(c, "t2")) } @Test @@ -464,8 +460,8 @@ class InlinerTest extends ClearAfterClass { |} """.stripMargin val List(c, t, u) = compile(code) - assertNoInvoke(getSingleMethod(c, "t1")) - assertNoInvoke(getSingleMethod(c, "t2")) + assertNoInvoke(getMethod(c, "t1")) + assertNoInvoke(getMethod(c, "t2")) } @Test @@ -485,8 +481,8 @@ class InlinerTest extends ClearAfterClass { var count = 0 val List(c, t) = compile(code, allowMessage = i => {count += 1; warns.exists(i.msg contains _)}) assert(count == 2, count) - assertInvoke(getSingleMethod(c, "t1"), "T", "f") - assertInvoke(getSingleMethod(c, "t2"), "C", "f") + assertInvoke(getMethod(c, "t1"), "T", "f") + assertInvoke(getMethod(c, "t2"), "C", "f") } @Test @@ -500,7 +496,7 @@ class InlinerTest extends ClearAfterClass { |} """.stripMargin val List(c, t) = compile(code) - assertNoInvoke(getSingleMethod(c, "t1")) + assertNoInvoke(getMethod(c, "t1")) } @Test @@ -524,11 +520,11 @@ class InlinerTest extends ClearAfterClass { val List(c, oMirror, oModule, t) = compile(code, allowMessage = i => {count += 1; i.msg contains warn}) assert(count == 1, count) - assertNoInvoke(getSingleMethod(t, "f")) + assertNoInvoke(getMethod(t, "f")) - assertNoInvoke(getSingleMethod(c, "t1")) - assertNoInvoke(getSingleMethod(c, "t2")) - assertInvoke(getSingleMethod(c, "t3"), "T", "f") + assertNoInvoke(getMethod(c, "t1")) + assertNoInvoke(getMethod(c, "t2")) + assertInvoke(getMethod(c, "t3"), "T", "f") } @Test @@ -550,12 +546,12 @@ class InlinerTest extends ClearAfterClass { val List(assembly, c, t) = compile(code) - assertNoInvoke(getSingleMethod(t, "f")) + assertNoInvoke(getMethod(t, "f")) - assertNoInvoke(getSingleMethod(assembly, "n")) + assertNoInvoke(getMethod(assembly, "n")) - assertNoInvoke(getSingleMethod(c, "t1")) - assertNoInvoke(getSingleMethod(c, "t2")) + assertNoInvoke(getMethod(c, "t1")) + assertNoInvoke(getMethod(c, "t2")) } @Test @@ -628,20 +624,20 @@ class InlinerTest extends ClearAfterClass { val List(ca, cb, t1, t2a, t2b) = compile(code, allowMessage = i => {count += 1; i.msg contains warning}) assert(count == 4, count) // see comments, f is not inlined 4 times - assertNoInvoke(getSingleMethod(t2a, "g2a")) - assertInvoke(getSingleMethod(t2b, "g2b"), "T1", "f") + assertNoInvoke(getMethod(t2a, "g2a")) + assertInvoke(getMethod(t2b, "g2b"), "T1", "f") - assertInvoke(getSingleMethod(ca, "m1a"), "T1", "f") - assertNoInvoke(getSingleMethod(ca, "m2a")) // no invoke, see comment on def g2a - assertNoInvoke(getSingleMethod(ca, "m3a")) - assertInvoke(getSingleMethod(ca, "m4a"), "T1", "f") - assertNoInvoke(getSingleMethod(ca, "m5a")) + assertInvoke(getMethod(ca, "m1a"), "T1", "f") + assertNoInvoke(getMethod(ca, "m2a")) // no invoke, see comment on def g2a + assertNoInvoke(getMethod(ca, "m3a")) + assertInvoke(getMethod(ca, "m4a"), "T1", "f") + assertNoInvoke(getMethod(ca, "m5a")) - assertInvoke(getSingleMethod(cb, "m1b"), "T1", "f") - assertInvoke(getSingleMethod(cb, "m2b"), "T1", "f") // invoke, see comment on def g2b - assertNoInvoke(getSingleMethod(cb, "m3b")) - assertInvoke(getSingleMethod(cb, "m4b"), "T1", "f") - assertNoInvoke(getSingleMethod(cb, "m5b")) + assertInvoke(getMethod(cb, "m1b"), "T1", "f") + assertInvoke(getMethod(cb, "m2b"), "T1", "f") // invoke, see comment on def g2b + assertNoInvoke(getMethod(cb, "m3b")) + assertInvoke(getMethod(cb, "m4b"), "T1", "f") + assertNoInvoke(getMethod(cb, "m5b")) } @Test @@ -658,7 +654,7 @@ class InlinerTest extends ClearAfterClass { |} // so d.f can be resolved statically. same for E.f """.stripMargin val List(c, d, e, eModule, t) = compile(code) - assertNoInvoke(getSingleMethod(t, "t1")) + assertNoInvoke(getMethod(t, "t1")) } @Test @@ -673,8 +669,8 @@ class InlinerTest extends ClearAfterClass { |} """.stripMargin val List(c, d, t) = compile(code) - assertNoInvoke(getSingleMethod(d, "m")) - assertNoInvoke(getSingleMethod(c, "m")) + assertNoInvoke(getMethod(d, "m")) + assertNoInvoke(getMethod(c, "m")) } @Test @@ -688,8 +684,8 @@ class InlinerTest extends ClearAfterClass { |} """.stripMargin val List(c, t) = compile(code) - val t1 = getSingleMethod(t, "t1") - val t2 = getSingleMethod(t, "t2") + val t1 = getMethod(t, "t1") + val t2 = getMethod(t, "t2") val cast = TypeOp(CHECKCAST, "C") Set(t1, t2).foreach(m => assert(m.instructions.contains(cast), m.instructions)) } @@ -769,27 +765,27 @@ class InlinerTest extends ClearAfterClass { """.stripMargin val List(c, t, u) = compile(code, allowMessage = _.msg contains "i()I is annotated @inline but cannot be inlined") - val m1 = getSingleMethod(c, "m1") + val m1 = getMethod(c, "m1") assertInvoke(m1, "T", "a") assertInvoke(m1, "T", "b") assertInvoke(m1, "T", "c") - assertNoInvoke(getSingleMethod(c, "m2")) + assertNoInvoke(getMethod(c, "m2")) - val m3 = getSingleMethod(c, "m3") + val m3 = getMethod(c, "m3") assertInvoke(m3, "T", "f") assertInvoke(m3, "T", "g") assertInvoke(m3, "T", "h") assertInvoke(m3, "T", "i") - val m4 = getSingleMethod(c, "m4") + val m4 = getMethod(c, "m4") assertInvoke(m4, "U", "a") assertInvoke(m4, "U", "b") assertInvoke(m4, "U", "c") - assertNoInvoke(getSingleMethod(c, "m5")) + assertNoInvoke(getMethod(c, "m5")) - val m6 = getSingleMethod(c, "m6") + val m6 = getMethod(c, "m6") assertInvoke(m6, "U", "f") assertInvoke(m6, "U", "g") assertInvoke(m6, "U", "h") @@ -829,7 +825,7 @@ class InlinerTest extends ClearAfterClass { var c = 0 - compileClasses(newCompiler(extraArgs = args + " -Yopt-warnings:_"))( + newCompiler(extraArgs = compilerArgs + " -Yopt-warnings:_").compileClasses( scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; i.msg contains warn}) @@ -873,15 +869,15 @@ class InlinerTest extends ClearAfterClass { val List(a, b, t) = compile(code, allowMessage = i => {c += 1; i.msg contains warn}) assert(c == 1, c) - assertInvoke(getSingleMethod(b, "t1"), "Aa", "f1") - assertInvoke(getSingleMethod(b, "t2"), "B", "B$$f2m") - assertInvoke(getSingleMethod(b, "t3"), "B", "<init>") - assertInvoke(getSingleMethod(b, "t4"), "B", "<init>") + assertInvoke(getMethod(b, "t1"), "Aa", "f1") + assertInvoke(getMethod(b, "t2"), "B", "B$$f2m") + assertInvoke(getMethod(b, "t3"), "B", "<init>") + assertInvoke(getMethod(b, "t4"), "B", "<init>") - assertInvoke(getSingleMethod(t, "t1"), "B", "f1") - assertInvoke(getSingleMethod(t, "t2"), "B", "B$$f2m") - assertInvoke(getSingleMethod(t, "t3"), "B", "<init>") - assertInvoke(getSingleMethod(t, "t4"), "B", "<init>") + assertInvoke(getMethod(t, "t1"), "B", "f1") + assertInvoke(getMethod(t, "t2"), "B", "B$$f2m") + assertInvoke(getMethod(t, "t3"), "B", "<init>") + assertInvoke(getMethod(t, "t4"), "B", "<init>") } @Test @@ -891,8 +887,8 @@ class InlinerTest extends ClearAfterClass { | def t = System.arraycopy(null, 0, null, 0, 0) |} """.stripMargin - val List(c) = compileClasses(newCompiler(extraArgs = args + " -Yopt-inline-heuristics:everything"))(code) - assertInvoke(getSingleMethod(c, "t"), "java/lang/System", "arraycopy") + val c = newCompiler(extraArgs = compilerArgs + " -Yopt-inline-heuristics:everything").compileClass(code) + assertInvoke(getMethod(c, "t"), "java/lang/System", "arraycopy") } @Test @@ -906,7 +902,7 @@ class InlinerTest extends ClearAfterClass { """.stripMargin val List(c) = compile(code) - assertInvoke(getSingleMethod(c, "t"), "java/lang/Error", "<init>") + assertInvoke(getMethod(c, "t"), "java/lang/Error", "<init>") } @Test @@ -919,7 +915,7 @@ class InlinerTest extends ClearAfterClass { """.stripMargin val List(c) = compile(code) - val t = getSingleMethod(c, "t").instructions + val t = getInstructions(c, "t") assertNoInvoke(t) assert(1 == t.collect({case Ldc(_, "hai!") => }).size) // push-pop eliminates the first LDC("hai!") assert(1 == t.collect({case Jump(IFNONNULL, _) => }).size) // one single null check @@ -946,12 +942,12 @@ class InlinerTest extends ClearAfterClass { val List(c, _, _) = compile(code) - val t1 = getSingleMethod(c, "t1") + val t1 = getMethod(c, "t1") assertNoIndy(t1) // the indy call is inlined into t, and the closure elimination rewrites the closure invocation to the body method assertInvoke(t1, "C", "C$$$anonfun$2") - val t2 = getSingleMethod(c, "t2") + val t2 = getMethod(c, "t2") assertNoIndy(t2) assertInvoke(t2, "M$", "M$$$anonfun$1") } @@ -968,9 +964,9 @@ class InlinerTest extends ClearAfterClass { """.stripMargin val List(c) = compile(code) - val hMeth = findAsmMethod(c, "h") - val gMeth = findAsmMethod(c, "g") - val iMeth = findAsmMethod(c, "i") + val hMeth = getAsmMethod(c, "h") + val gMeth = getAsmMethod(c, "g") + val iMeth = getAsmMethod(c, "i") val fCall = getCallsite(gMeth, "f") val gCall = getCallsite(hMeth, "g") val hCall = getCallsite(iMeth, "h") @@ -997,7 +993,7 @@ class InlinerTest extends ClearAfterClass { """.stripMargin val List(cl) = compile(code) - val List(b, c, d) = List("b", "c", "d").map(findAsmMethod(cl, _)) + val List(b, c, d) = List("b", "c", "d").map(getAsmMethod(cl, _)) val aCall = getCallsite(b, "a") val bCall = getCallsite(c, "b") val cCall = getCallsite(d, "c") @@ -1037,15 +1033,15 @@ class InlinerTest extends ClearAfterClass { """.stripMargin val List(c) = compile(code) - assertInvoke(getSingleMethod(c, "t1"), "C", "C$$$anonfun$1") - assertInvoke(getSingleMethod(c, "t2"), "C", "a") - assertInvoke(getSingleMethod(c, "t3"), "C", "b") - assertNoInvoke(getSingleMethod(c, "t4")) - assertNoInvoke(getSingleMethod(c, "t5")) - assertNoInvoke(getSingleMethod(c, "t6")) - assertInvoke(getSingleMethod(c, "t7"), "C", "c") - assertInvoke(getSingleMethod(c, "t8"), "scala/Predef$", "println") - assertNoInvoke(getSingleMethod(c, "t9")) + assertInvoke(getMethod(c, "t1"), "C", "C$$$anonfun$1") + assertInvoke(getMethod(c, "t2"), "C", "a") + assertInvoke(getMethod(c, "t3"), "C", "b") + assertNoInvoke(getMethod(c, "t4")) + assertNoInvoke(getMethod(c, "t5")) + assertNoInvoke(getMethod(c, "t6")) + assertInvoke(getMethod(c, "t7"), "C", "c") + assertInvoke(getMethod(c, "t8"), "scala/Predef$", "println") + assertNoInvoke(getMethod(c, "t9")) } @Test @@ -1070,15 +1066,15 @@ class InlinerTest extends ClearAfterClass { """.stripMargin val List(c) = compile(code) - assertNoInvoke(getSingleMethod(c, "t1")) - assertInvoke(getSingleMethod(c, "t2"), "C", "f2") - assertInvoke(getSingleMethod(c, "t3"), "C", "f1") - assertInvoke(getSingleMethod(c, "t4"), "C", "f2") - assertNoInvoke(getSingleMethod(c, "t5")) - assertInvoke(getSingleMethod(c, "t6"), "C", "f3") - assertNoInvoke(getSingleMethod(c, "t7")) - assertInvoke(getSingleMethod(c, "t8"), "C", "f1") - assertNoInvoke(getSingleMethod(c, "t9")) + assertNoInvoke(getMethod(c, "t1")) + assertInvoke(getMethod(c, "t2"), "C", "f2") + assertInvoke(getMethod(c, "t3"), "C", "f1") + assertInvoke(getMethod(c, "t4"), "C", "f2") + assertNoInvoke(getMethod(c, "t5")) + assertInvoke(getMethod(c, "t6"), "C", "f3") + assertNoInvoke(getMethod(c, "t7")) + assertInvoke(getMethod(c, "t8"), "C", "f1") + assertNoInvoke(getMethod(c, "t9")) } @Test @@ -1101,11 +1097,11 @@ class InlinerTest extends ClearAfterClass { """.stripMargin val List(c) = compile(code) - assertInvoke(getSingleMethod(c, "t1"), "C", "C$$$anonfun$1") - assertInvoke(getSingleMethod(c, "t2"), "C", "C$$$anonfun$2") - assertInvoke(getSingleMethod(c, "t3"), "scala/Function1", "apply$mcII$sp") - assertInvoke(getSingleMethod(c, "t4"), "scala/Function1", "apply$mcII$sp") - assertInvoke(getSingleMethod(c, "t5"), "C", "h") + assertInvoke(getMethod(c, "t1"), "C", "C$$$anonfun$1") + assertInvoke(getMethod(c, "t2"), "C", "C$$$anonfun$2") + assertInvoke(getMethod(c, "t3"), "scala/Function1", "apply$mcII$sp") + assertInvoke(getMethod(c, "t4"), "scala/Function1", "apply$mcII$sp") + assertInvoke(getMethod(c, "t5"), "C", "h") } @Test @@ -1125,7 +1121,7 @@ class InlinerTest extends ClearAfterClass { |when entering an exception handler declared in the inlined method.""".stripMargin val List(c) = compile(code, allowMessage = _.msg contains warn) - assertInvoke(getSingleMethod(c, "t"), "C", "g") + assertInvoke(getMethod(c, "t"), "C", "g") } @Test @@ -1149,8 +1145,8 @@ class InlinerTest extends ClearAfterClass { |that would cause an IllegalAccessError when inlined into class D.""".stripMargin val List(c, d) = compile(code, allowMessage = _.msg contains warn) - assertInvoke(getSingleMethod(c, "h"), "C", "f$1") - assertInvoke(getSingleMethod(d, "t"), "C", "h") + assertInvoke(getMethod(c, "h"), "C", "f$1") + assertInvoke(getMethod(d, "t"), "C", "h") } @Test @@ -1168,8 +1164,8 @@ class InlinerTest extends ClearAfterClass { """.stripMargin val List(c, d) = compile(code) - assertNoInvoke(getSingleMethod(c, "g")) - assertNoInvoke(getSingleMethod(d, "t")) + assertNoInvoke(getMethod(c, "g")) + assertNoInvoke(getMethod(d, "t")) } @Test @@ -1277,40 +1273,40 @@ class InlinerTest extends ClearAfterClass { """.stripMargin val List(c, _, _) = compile(code) - assertSameSummary(getSingleMethod(c, "t1"), List(BIPUSH, "C$$$anonfun$1", IRETURN)) - assertSameSummary(getSingleMethod(c, "t1a"), List(LCONST_1, "C$$$anonfun$2", IRETURN)) - assertSameSummary(getSingleMethod(c, "t2"), List(ICONST_1, ICONST_2, "C$$$anonfun$3",IRETURN)) + assertSameSummary(getMethod(c, "t1"), List(BIPUSH, "C$$$anonfun$1", IRETURN)) + assertSameSummary(getMethod(c, "t1a"), List(LCONST_1, "C$$$anonfun$2", IRETURN)) + assertSameSummary(getMethod(c, "t2"), List(ICONST_1, ICONST_2, "C$$$anonfun$3",IRETURN)) // val a = new ValKl(n); new ValKl(anonfun(a.x)).x // value class instantiation-extraction should be optimized by boxing elim - assertSameSummary(getSingleMethod(c, "t3"), List( + assertSameSummary(getMethod(c, "t3"), List( NEW, DUP, ICONST_1, "<init>", ASTORE, NEW, DUP, ALOAD, "x", "C$$$anonfun$4", "<init>", "x", IRETURN)) - assertSameSummary(getSingleMethod(c, "t4"), List(BIPUSH, "C$$$anonfun$5", "boxToInteger", ARETURN)) - assertSameSummary(getSingleMethod(c, "t4a"), List(ICONST_1, LDC, "C$$$anonfun$6", LRETURN)) - assertSameSummary(getSingleMethod(c, "t5"), List(BIPUSH, ICONST_3, "C$$$anonfun$7", "boxToInteger", ARETURN)) - assertSameSummary(getSingleMethod(c, "t5a"), List(BIPUSH, BIPUSH, I2B, "C$$$anonfun$8", IRETURN)) - assertSameSummary(getSingleMethod(c, "t6"), List(BIPUSH, "C$$$anonfun$9", RETURN)) - assertSameSummary(getSingleMethod(c, "t7"), List(ICONST_1, "C$$$anonfun$10", RETURN)) - assertSameSummary(getSingleMethod(c, "t8"), List(ICONST_1, LDC, "C$$$anonfun$11", LRETURN)) - assertSameSummary(getSingleMethod(c, "t9"), List(ICONST_1, "boxToInteger", "C$$$anonfun$12", RETURN)) + assertSameSummary(getMethod(c, "t4"), List(BIPUSH, "C$$$anonfun$5", "boxToInteger", ARETURN)) + assertSameSummary(getMethod(c, "t4a"), List(ICONST_1, LDC, "C$$$anonfun$6", LRETURN)) + assertSameSummary(getMethod(c, "t5"), List(BIPUSH, ICONST_3, "C$$$anonfun$7", "boxToInteger", ARETURN)) + assertSameSummary(getMethod(c, "t5a"), List(BIPUSH, BIPUSH, I2B, "C$$$anonfun$8", IRETURN)) + assertSameSummary(getMethod(c, "t6"), List(BIPUSH, "C$$$anonfun$9", RETURN)) + assertSameSummary(getMethod(c, "t7"), List(ICONST_1, "C$$$anonfun$10", RETURN)) + assertSameSummary(getMethod(c, "t8"), List(ICONST_1, LDC, "C$$$anonfun$11", LRETURN)) + assertSameSummary(getMethod(c, "t9"), List(ICONST_1, "boxToInteger", "C$$$anonfun$12", RETURN)) // t9a inlines Range.foreach, which is quite a bit of code, so just testing the core - assertInvoke(getSingleMethod(c, "t9a"), "C", "C$$$anonfun$13") - assertInvoke(getSingleMethod(c, "t9a"), "scala/runtime/BoxesRunTime", "boxToInteger") + assertInvoke(getMethod(c, "t9a"), "C", "C$$$anonfun$13") + assertInvoke(getMethod(c, "t9a"), "scala/runtime/BoxesRunTime", "boxToInteger") - assertSameSummary(getSingleMethod(c, "t10"), List( + assertSameSummary(getMethod(c, "t10"), List( ICONST_1, ISTORE, ALOAD, ILOAD, "C$$$anonfun$14", RETURN)) // t10a inlines Range.foreach - assertInvoke(getSingleMethod(c, "t10a"), "C", "C$$$anonfun$15") - assertDoesNotInvoke(getSingleMethod(c, "t10a"), "boxToInteger") + assertInvoke(getMethod(c, "t10a"), "C", "C$$$anonfun$15") + assertDoesNotInvoke(getMethod(c, "t10a"), "boxToInteger") } @Test @@ -1333,8 +1329,8 @@ class InlinerTest extends ClearAfterClass { |} """.stripMargin val List(c) = compile(code) - assertSameCode(getSingleMethod(c, "t1"), List(Op(ICONST_0), Op(ICONST_1), Op(IADD), Op(IRETURN))) - assertEquals(getSingleMethod(c, "t2").instructions collect { case i: Invoke => i.owner +"."+ i.name }, List( + assertSameCode(getMethod(c, "t1"), List(Op(ICONST_0), Op(ICONST_1), Op(IADD), Op(IRETURN))) + assertEquals(getInstructions(c, "t2") collect { case i: Invoke => i.owner +"."+ i.name }, List( "scala/runtime/IntRef.create", "C.C$$$anonfun$1")) } @@ -1374,11 +1370,11 @@ class InlinerTest extends ClearAfterClass { |} """.stripMargin val List(c) = compile(code) - assertSameCode(getSingleMethod(c, "t1"), List(Op(ICONST_3), Op(ICONST_4), Op(IADD), Op(IRETURN))) - assertSameCode(getSingleMethod(c, "t2"), List(Op(ICONST_1), Op(ICONST_2), Op(IADD), Op(IRETURN))) - assertSameCode(getSingleMethod(c, "t3"), List(Op(ICONST_1), Op(ICONST_3), Op(ISUB), Op(IRETURN))) - assertNoInvoke(getSingleMethod(c, "t4")) - assertNoInvoke(getSingleMethod(c, "t5")) + assertSameCode(getMethod(c, "t1"), List(Op(ICONST_3), Op(ICONST_4), Op(IADD), Op(IRETURN))) + assertSameCode(getMethod(c, "t2"), List(Op(ICONST_1), Op(ICONST_2), Op(IADD), Op(IRETURN))) + assertSameCode(getMethod(c, "t3"), List(Op(ICONST_1), Op(ICONST_3), Op(ISUB), Op(IRETURN))) + assertNoInvoke(getMethod(c, "t4")) + assertNoInvoke(getMethod(c, "t5")) } @Test @@ -1404,10 +1400,10 @@ class InlinerTest extends ClearAfterClass { |class D extends C """.stripMargin val List(c, _) = compile(code) - def casts(m: String) = getSingleMethod(c, m).instructions collect { case TypeOp(CHECKCAST, tp) => tp } - assertSameCode(getSingleMethod(c, "t1"), List(VarOp(ALOAD, 1), Op(ARETURN))) - assertSameCode(getSingleMethod(c, "t2"), List(VarOp(ALOAD, 1), Op(ARETURN))) - assertSameCode(getSingleMethod(c, "t3"), List(VarOp(ALOAD, 1), TypeOp(CHECKCAST, "C"), Op(ARETURN))) + def casts(m: String) = getInstructions(c, m) collect { case TypeOp(CHECKCAST, tp) => tp } + assertSameCode(getMethod(c, "t1"), List(VarOp(ALOAD, 1), Op(ARETURN))) + assertSameCode(getMethod(c, "t2"), List(VarOp(ALOAD, 1), Op(ARETURN))) + assertSameCode(getMethod(c, "t3"), List(VarOp(ALOAD, 1), TypeOp(CHECKCAST, "C"), Op(ARETURN))) assertEquals(casts("t4"), List("C")) assertEquals(casts("t5"), Nil) assertEquals(casts("t6"), Nil) @@ -1432,8 +1428,8 @@ class InlinerTest extends ClearAfterClass { """.stripMargin val cls = compile(code) - val test = cls.find(_.name == "Test$").get - assertSameSummary(getSingleMethod(test, "f"), List( + val test = findClass(cls, "Test$") + assertSameSummary(getMethod(test, "f"), List( GETSTATIC, "mkFoo", BIPUSH, ISTORE, IFNONNULL, ACONST_NULL, ATHROW, -1 /*label*/, @@ -1452,7 +1448,7 @@ class InlinerTest extends ClearAfterClass { val List(c) = compile(code) // box-unbox will clean it up - assertSameSummary(getSingleMethod(c, "t"), List( + assertSameSummary(getMethod(c, "t"), List( ALOAD, "C$$$anonfun$1", IFEQ /*A*/, "C$$$anonfun$2", IRETURN, -1 /*A*/, "C$$$anonfun$3", IRETURN)) @@ -1464,7 +1460,7 @@ class InlinerTest extends ClearAfterClass { val codeB = "class B { def t(a: A) = a.f }" // tests that no warning is emitted val List(a, b) = compileClassesSeparately(List(codeA, codeB), extraArgs = "-Yopt:l:project -Yopt-warnings") - assertInvoke(getSingleMethod(b, "t"), "A", "f") + assertInvoke(getMethod(b, "t"), "A", "f") } @Test @@ -1476,7 +1472,7 @@ class InlinerTest extends ClearAfterClass { """.stripMargin val List(c, t1, t2) = compile(code, allowMessage = _ => true) // the forwarder C.f is inlined, so there's no invocation - assertSameSummary(getSingleMethod(c, "f"), List(ICONST_1, IRETURN)) + assertSameSummary(getMethod(c, "f"), List(ICONST_1, IRETURN)) } @Test @@ -1489,10 +1485,12 @@ class InlinerTest extends ClearAfterClass { |class C { def t = (new K).f } """.stripMargin val c :: _ = compile(code) - assertSameSummary(getSingleMethod(c, "t"), List(NEW, "<init>", ICONST_1, IRETURN)) // ICONST_1, U.f is inlined (not T.f) + assertSameSummary(getMethod(c, "t"), List(NEW, "<init>", ICONST_1, IRETURN)) // ICONST_1, U.f is inlined (not T.f) } - @Test + // Can be enabled when using 2.12.0-M5 as starr. This test works under a full boostrap, but not + // when compiled with M4. + @Test @Ignore def inlineArrayForeach(): Unit = { val code = """class C { @@ -1501,8 +1499,31 @@ class InlinerTest extends ClearAfterClass { |} """.stripMargin val List(c) = compile(code) - val t = getSingleMethod(c, "t") + val t = getMethod(c, "t") assertNoIndy(t) assertInvoke(t, "C", "C$$$anonfun$1") } + + @Test + def t9121(): Unit = { + val codes = List( + """package p1 + |object Implicits { + | class ScalaObservable(val underlying: Any) extends AnyVal { + | @inline def scMap[R](f: String): Any = f.toRx + | } + | implicit class RichFunction1[T1, R](val f: String) extends AnyVal { + | def toRx: Any = "" + | } + |} + """.stripMargin, + """ + |import p1.Implicits._ + |class C { + | def t(): Unit = new ScalaObservable("").scMap("") + |} + """.stripMargin) + val c :: _ = compileClassesSeparately(codes, extraArgs = compilerArgs) + assertInvoke(getMethod(c, "t"), "p1/Implicits$RichFunction1$", "toRx$extension") + } } diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala index 003b2d4880..fa76c0d930 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala @@ -2,42 +2,40 @@ package scala.tools.nsc package backend.jvm package opt +import org.junit.Assert._ +import org.junit.Test 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.collection.JavaConverters._ +import scala.tools.asm.Opcodes._ import scala.tools.asm.tree.ClassNode import scala.tools.nsc.backend.jvm.AsmUtils._ -import scala.tools.testing.AssertUtil._ - -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ -import scala.tools.testing.ClearAfterClass -import scala.collection.JavaConverters._ +import scala.tools.partest.ASMConverters._ +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ @RunWith(classOf[JUnit4]) -class MethodLevelOptsTest extends ClearAfterClass { - val methodOptCompiler = cached("methodOptCompiler", () => newCompiler(extraArgs = "-Yopt:l:method")) +class MethodLevelOptsTest extends BytecodeTesting { + override def compilerArgs = "-Yopt:l:method" + import compiler._ def wrapInDefault(code: Instruction*) = List(Label(0), LineNumber(1, Label(0))) ::: code.toList ::: List(Label(1)) - def locals(c: ClassNode, m: String) = findAsmMethod(c, m).localVariables.asScala.toList.map(l => (l.name, l.index)).sortBy(_._2) + def locals(c: ClassNode, m: String) = getAsmMethod(c, m).localVariables.asScala.toList.map(l => (l.name, l.index)).sortBy(_._2) @Test def eliminateEmptyTry(): Unit = { val code = "def f = { try {} catch { case _: Throwable => 0; () }; 1 }" val warn = "a pure expression does nothing in statement position" - assertSameCode(singleMethodInstructions(methodOptCompiler)(code, allowMessage = _.msg contains warn), wrapInDefault(Op(ICONST_1), Op(IRETURN))) + assertSameCode(compileInstructions(code, allowMessage = _.msg contains warn), wrapInDefault(Op(ICONST_1), Op(IRETURN))) } @Test def eliminateLoadBoxedUnit(): Unit = { // the compiler inserts a boxed into the try block. it's therefore non-empty (and live) and not eliminated. val code = "def f = { try {} catch { case _: Throwable => 0 }; 1 }" - val m = singleMethod(methodOptCompiler)(code) + val m = compileMethod(code) assertTrue(m.handlers.length == 0) assertSameCode(m, List(Op(ICONST_1), Op(IRETURN))) } @@ -46,7 +44,7 @@ class MethodLevelOptsTest extends ClearAfterClass { def inlineThrowInCatchNotTry(): Unit = { // the try block does not contain the `ATHROW` instruction, but in the catch block, `ATHROW` is inlined val code = "def f(e: Exception) = throw { try e catch { case _: Throwable => e } }" - val m = singleMethod(methodOptCompiler)(code) + val m = compileMethod(code) assertHandlerLabelPostions(m.handlers.head, m.instructions, 0, 3, 5) assertSameCode(m.instructions, wrapInDefault(VarOp(ALOAD, 1), Label(3), Op(ATHROW), Label(5), FrameEntry(4, List(), List("java/lang/Throwable")), Op(POP), VarOp(ALOAD, 1), Op(ATHROW)) @@ -57,7 +55,7 @@ class MethodLevelOptsTest extends ClearAfterClass { def inlineReturnInCatchNotTry(): Unit = { val code = "def f: Int = return { try 1 catch { case _: Throwable => 2 } }" // cannot inline the IRETURN into the try block (because RETURN may throw IllegalMonitorState) - val m = singleMethod(methodOptCompiler)(code) + val m = compileMethod(code) assertHandlerLabelPostions(m.handlers.head, m.instructions, 0, 3, 5) assertSameCode(m.instructions, wrapInDefault(Op(ICONST_1), Label(3), Op(IRETURN), Label(5), FrameEntry(4, List(), List("java/lang/Throwable")), Op(POP), Op(ICONST_2), Op(IRETURN))) @@ -79,7 +77,7 @@ class MethodLevelOptsTest extends ClearAfterClass { | println(x) | } """.stripMargin - val m = singleMethod(methodOptCompiler)(code) + val m = compileMethod(code) assertTrue(m.handlers.isEmpty) assertSameCode(m, List(Op(ICONST_3), Op(IRETURN))) } @@ -99,8 +97,8 @@ class MethodLevelOptsTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) - assertSameCode(getSingleMethod(c, "t"), List( + val c = compileClass(code) + assertSameCode(getMethod(c, "t"), List( Op(ACONST_NULL), Invoke(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;", false), Op(ARETURN))) } @@ -116,9 +114,9 @@ class MethodLevelOptsTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) + val c = compileClass(code) assertSameCode( - getSingleMethod(c, "t"), List(Ldc(LDC, "c"), Op(ARETURN))) + getMethod(c, "t"), List(Ldc(LDC, "c"), Op(ARETURN))) } @Test @@ -136,9 +134,9 @@ class MethodLevelOptsTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) + val c = compileClass(code) - assertSameCode(getSingleMethod(c, "t"), List( + assertSameCode(getMethod(c, "t"), List( Ldc(LDC, "el"), VarOp(ASTORE, 1), Field(GETSTATIC, "scala/Predef$", "MODULE$", "Lscala/Predef$;"), VarOp(ALOAD, 1), Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false), Op(ACONST_NULL), VarOp(ASTORE, 1), @@ -160,8 +158,8 @@ class MethodLevelOptsTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) - assertSameCode(getSingleMethod(c, "t"), List( + val c = compileClass(code) + assertSameCode(getMethod(c, "t"), List( IntOp(BIPUSH, 23), IntOp(NEWARRAY, 5), Op(POP), VarOp(ILOAD, 1), VarOp(ILOAD, 2), Op(IADD), Op(IRETURN))) } @@ -175,8 +173,8 @@ class MethodLevelOptsTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) - assertSameCode(getSingleMethod(c, "t"), List( + val c = compileClass(code) + assertSameCode(getMethod(c, "t"), List( TypeOp(NEW, "java/lang/Integer"), Ldc(LDC, "nono"), Invoke(INVOKESPECIAL, "java/lang/Integer", "<init>", "(Ljava/lang/String;)V", false), VarOp(ILOAD, 1), VarOp(ILOAD, 2), Op(IADD), Op(IRETURN))) } @@ -201,8 +199,8 @@ class MethodLevelOptsTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) - assertSameCode(getSingleMethod(c, "t"), List(Op(ICONST_0), Op(IRETURN))) + val c = compileClass(code) + assertSameCode(getMethod(c, "t"), List(Op(ICONST_0), Op(IRETURN))) } @Test @@ -217,8 +215,8 @@ class MethodLevelOptsTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) - assertSameCode(getSingleMethod(c, "t"), List( + val c = compileClass(code) + assertSameCode(getMethod(c, "t"), List( IntOp(BIPUSH, 30), VarOp(ISTORE, 3), // no constant propagation, so we keep the store (and load below) of a const VarOp(ILOAD, 1), VarOp(ILOAD, 2), @@ -238,8 +236,8 @@ class MethodLevelOptsTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) - val t = getSingleMethod(c, "t") + val c = compileClass(code) + val t = getMethod(c, "t") assert(!t.instructions.exists(_.opcode == INVOKEDYNAMIC), t) } @@ -319,23 +317,23 @@ class MethodLevelOptsTest extends ClearAfterClass { |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) - - assertNoInvoke(getSingleMethod(c, "t1")) - assertNoInvoke(getSingleMethod(c, "t2")) - assertInvoke(getSingleMethod(c, "t3"), "scala/runtime/BoxesRunTime", "unboxToInt") - assertInvoke(getSingleMethod(c, "t4"), "scala/runtime/BoxesRunTime", "boxToLong") - assertNoInvoke(getSingleMethod(c, "t5")) - assertNoInvoke(getSingleMethod(c, "t6")) - assertNoInvoke(getSingleMethod(c, "t7")) - assertSameSummary(getSingleMethod(c, "t8"), List(ICONST_0, IRETURN)) - assertNoInvoke(getSingleMethod(c, "t9")) + val c = compileClass(code) + + assertNoInvoke(getMethod(c, "t1")) + assertNoInvoke(getMethod(c, "t2")) + assertInvoke(getMethod(c, "t3"), "scala/runtime/BoxesRunTime", "unboxToInt") + assertInvoke(getMethod(c, "t4"), "scala/runtime/BoxesRunTime", "boxToLong") + assertNoInvoke(getMethod(c, "t5")) + assertNoInvoke(getMethod(c, "t6")) + assertNoInvoke(getMethod(c, "t7")) + assertSameSummary(getMethod(c, "t8"), List(ICONST_0, IRETURN)) + assertNoInvoke(getMethod(c, "t9")) // t10: no invocation of unbox - assertEquals(getSingleMethod(c, "t10").instructions collect { case Invoke(_, owner, name, _, _) => (owner, name) }, List( + assertEquals(getInstructions(c, "t10") collect { case Invoke(_, owner, name, _, _) => (owner, name) }, List( ("java/lang/Integer", "valueOf"), ("C", "escape"))) - assertSameSummary(getSingleMethod(c, "t11"), List( + assertSameSummary(getMethod(c, "t11"), List( BIPUSH, "valueOf", ASTORE /*2*/, BIPUSH, "valueOf", ASTORE /*3*/, ALOAD /*0*/, ALOAD /*2*/, "escape", @@ -343,7 +341,7 @@ class MethodLevelOptsTest extends ClearAfterClass { ASTORE /*4*/, GETSTATIC /*Predef*/, ALOAD /*4*/, "Integer2int", IRETURN)) // no unbox invocations - assertEquals(getSingleMethod(c, "t12").instructions collect { case Invoke(_, owner, name, _, _) => (owner, name) }, List( + assertEquals(getInstructions(c, "t12") collect { case Invoke(_, owner, name, _, _) => (owner, name) }, List( ("java/lang/Integer", "valueOf"), ("java/lang/Integer", "valueOf"), ("C", "escape"))) @@ -395,14 +393,14 @@ class MethodLevelOptsTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) - assertSameSummary(getSingleMethod(c, "t1"), List(ICONST_0, IRETURN)) - assertNoInvoke(getSingleMethod(c, "t2")) - assertSameSummary(getSingleMethod(c, "t3"), List(LDC, LDC, LADD, LRETURN)) - assertNoInvoke(getSingleMethod(c, "t4")) - assertEquals(getSingleMethod(c, "t5").instructions collect { case Field(_, owner, name, _) => s"$owner.$name" }, + val c = compileClass(code) + assertSameSummary(getMethod(c, "t1"), List(ICONST_0, IRETURN)) + assertNoInvoke(getMethod(c, "t2")) + assertSameSummary(getMethod(c, "t3"), List(LDC, LDC, LADD, LRETURN)) + assertNoInvoke(getMethod(c, "t4")) + assertEquals(getInstructions(c, "t5") collect { case Field(_, owner, name, _) => s"$owner.$name" }, List("scala/runtime/IntRef.elem")) - assertEquals(getSingleMethod(c, "t6").instructions collect { case Field(op, owner, name, _) => s"$op $owner.$name" }, + assertEquals(getInstructions(c, "t6") collect { case Field(op, owner, name, _) => s"$op $owner.$name" }, List(s"$PUTFIELD scala/runtime/IntRef.elem", s"$GETFIELD scala/runtime/IntRef.elem")) } @@ -459,23 +457,23 @@ class MethodLevelOptsTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) - assertNoInvoke(getSingleMethod(c, "t1")) - assertSameSummary(getSingleMethod(c, "t2"), List(ICONST_1, ICONST_3, IADD, IRETURN)) - assertSameSummary(getSingleMethod(c, "t3"), List(ICONST_3, ICONST_4, IADD, IRETURN)) - assertSameSummary(getSingleMethod(c, "t4"), List(ICONST_3, "boxToInteger", ARETURN)) - assertEquals(getSingleMethod(c, "t5").instructions collect { case Invoke(_, owner, name, _, _) => (owner, name) }, List( + val c = compileClass(code) + assertNoInvoke(getMethod(c, "t1")) + assertSameSummary(getMethod(c, "t2"), List(ICONST_1, ICONST_3, IADD, IRETURN)) + assertSameSummary(getMethod(c, "t3"), List(ICONST_3, ICONST_4, IADD, IRETURN)) + assertSameSummary(getMethod(c, "t4"), List(ICONST_3, "boxToInteger", ARETURN)) + assertEquals(getInstructions(c, "t5") collect { case Invoke(_, owner, name, _, _) => (owner, name) }, List( ("scala/runtime/BoxesRunTime", "boxToInteger"), ("scala/runtime/BoxesRunTime", "boxToInteger"), ("C", "tpl"), ("scala/Tuple2", "_1$mcI$sp"))) - assertSameSummary(getSingleMethod(c, "t6"), List(ICONST_1, ICONST_2, ISUB, IRETURN)) - assertSameSummary(getSingleMethod(c, "t7"), List( + assertSameSummary(getMethod(c, "t6"), List(ICONST_1, ICONST_2, ISUB, IRETURN)) + assertSameSummary(getMethod(c, "t7"), List( ICONST_1, ICONST_2, ISTORE, ISTORE, ICONST_3, ISTORE, ILOAD, ILOAD, IADD, ILOAD, IADD, IRETURN)) - assertNoInvoke(getSingleMethod(c, "t8")) - assertNoInvoke(getSingleMethod(c, "t9")) + assertNoInvoke(getMethod(c, "t8")) + assertNoInvoke(getMethod(c, "t9")) } @Test @@ -524,14 +522,14 @@ class MethodLevelOptsTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) - assertSameSummary(getSingleMethod(c, "t1"), List(NEW, DUP, "<init>", ARETURN)) - assertSameCode(getSingleMethod(c, "t2"), List(Op(LCONST_0), Op(LRETURN))) - assertSameCode(getSingleMethod(c, "t3"), List(Op(ICONST_1), Op(IRETURN))) - assertSameCode(getSingleMethod(c, "t4"), List(Op(ICONST_1), Op(IRETURN))) - assertSameCode(getSingleMethod(c, "t5"), List(Op(DCONST_0), Op(DRETURN))) - assertSameCode(getSingleMethod(c, "t6"), List(Op(ACONST_NULL), Op(ARETURN))) - assertSameCode(getSingleMethod(c, "t7"), List(Op(ICONST_0), Op(IRETURN))) + val c = compileClass(code) + assertSameSummary(getMethod(c, "t1"), List(NEW, DUP, "<init>", ARETURN)) + assertSameCode(getMethod(c, "t2"), List(Op(LCONST_0), Op(LRETURN))) + assertSameCode(getMethod(c, "t3"), List(Op(ICONST_1), Op(IRETURN))) + assertSameCode(getMethod(c, "t4"), List(Op(ICONST_1), Op(IRETURN))) + assertSameCode(getMethod(c, "t5"), List(Op(DCONST_0), Op(DRETURN))) + assertSameCode(getMethod(c, "t6"), List(Op(ACONST_NULL), Op(ARETURN))) + assertSameCode(getMethod(c, "t7"), List(Op(ICONST_0), Op(IRETURN))) } @Test @@ -544,9 +542,9 @@ class MethodLevelOptsTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) + val c = compileClass(code) assertSameCode( - getSingleMethod(c, "t"), List( + getMethod(c, "t"), List( VarOp(ALOAD, 1), Jump(IFNULL, Label(6)), Op(ICONST_1), Op(IRETURN), Label(6), Op(ICONST_0), Op(IRETURN))) } @@ -615,28 +613,28 @@ class MethodLevelOptsTest extends ClearAfterClass { |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) - def stores(m: String) = getSingleMethod(c, m).instructions.filter(_.opcode == ASTORE) + val c = compileClass(code) + def stores(m: String) = getInstructions(c, m).filter(_.opcode == ASTORE) assertEquals(locals(c, "t1"), List(("this",0), ("kept1",1), ("result",2))) assert(stores("t1") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 2), VarOp(ASTORE, 1), VarOp(ASTORE, 1)), - textify(findAsmMethod(c, "t1"))) + textify(getAsmMethod(c, "t1"))) assertEquals(locals(c, "t2"), List(("this",0), ("kept2",1), ("kept3",2))) assert(stores("t2") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 2), VarOp(ASTORE, 1)), - textify(findAsmMethod(c, "t2"))) + textify(getAsmMethod(c, "t2"))) assertEquals(locals(c, "t3"), List(("this",0), ("kept4",1))) assert(stores("t3") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 1)), - textify(findAsmMethod(c, "t3"))) + textify(getAsmMethod(c, "t3"))) assertEquals(locals(c, "t4"), List(("this",0), ("kept5",1))) assert(stores("t4") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 1)), - textify(findAsmMethod(c, "t4"))) + textify(getAsmMethod(c, "t4"))) assertEquals(locals(c, "t5"), List(("this",0), ("kept6",1))) assert(stores("t5") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 1)), - textify(findAsmMethod(c, "t5"))) + textify(getAsmMethod(c, "t5"))) } @Test @@ -683,13 +681,13 @@ class MethodLevelOptsTest extends ClearAfterClass { |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) + val c = compileClass(code) assertEquals(locals(c, "t1"), List(("this", 0), ("x", 1))) assertEquals(locals(c, "t2"), List(("this", 0), ("x", 1))) // we don't have constant propagation (yet). // the local var can't be optimized as a store;laod sequence, there's a GETSTATIC between the two - assertSameSummary(getSingleMethod(c, "t2"), List( + assertSameSummary(getMethod(c, "t2"), List( ICONST_2, ISTORE, GETSTATIC, ILOAD, "boxToInteger", "println", RETURN)) assertEquals(locals(c, "t3"), List(("this", 0))) @@ -711,8 +709,8 @@ class MethodLevelOptsTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) - val t = getSingleMethod(c, "t") + val c = compileClass(code) + val t = getMethod(c, "t") assertEquals(t.handlers, Nil) assertEquals(locals(c, "t"), List(("this", 0))) assertSameSummary(t, List(GETSTATIC, LDC, "print", -1, GOTO)) @@ -729,8 +727,8 @@ class MethodLevelOptsTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) - assertNoInvoke(getSingleMethod(c, "compare")) + val c = compileClass(code) + assertNoInvoke(getMethod(c, "compare")) } @Test @@ -743,9 +741,9 @@ class MethodLevelOptsTest extends ClearAfterClass { | } |} """.stripMargin - val List(c) = compileClasses(methodOptCompiler)(code) + val c = compileClass(code) - assertSameSummary(getSingleMethod(c, "t"), List( + assertSameSummary(getMethod(c, "t"), List( BIPUSH, ILOAD, IF_ICMPNE, BIPUSH, ILOAD, IF_ICMPNE, LDC, ASTORE, GOTO, diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala index 6cb3fd3bba..5bd285f97f 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala @@ -2,23 +2,20 @@ package scala.tools.nsc package backend.jvm package opt +import org.junit.Assert._ +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.junit.Test -import scala.tools.asm.Opcodes._ -import org.junit.Assert._ -import CodeGenTools._ -import scala.tools.asm.tree.ClassNode -import scala.tools.nsc.backend.jvm.BTypes.{MethodInlineInfo, InlineInfo} -import scala.tools.partest.ASMConverters -import ASMConverters._ import scala.collection.JavaConverters._ -import scala.tools.testing.ClearAfterClass +import scala.tools.asm.tree.ClassNode +import scala.tools.nsc.backend.jvm.BTypes.{InlineInfo, MethodInlineInfo} +import scala.tools.testing.BytecodeTesting @RunWith(classOf[JUnit4]) -class ScalaInlineInfoTest extends ClearAfterClass { - val compiler = cached("compiler", () => newCompiler(extraArgs = "-Yopt:l:none")) +class ScalaInlineInfoTest extends BytecodeTesting { + override def compilerArgs = "-Yopt:l:none" + import compiler._ def inlineInfo(c: ClassNode): InlineInfo = c.attrs.asScala.collect({ case a: InlineInfoAttribute => a.inlineInfo }).head @@ -72,7 +69,7 @@ class ScalaInlineInfoTest extends ClearAfterClass { |} """.stripMargin - val cs @ List(c, t, tl, to) = compileClasses(compiler)(code) + val cs @ List(c, t, tl, to) = compileClasses(code) val infoT = inlineInfo(t) val expectT = InlineInfo ( false, // final class @@ -149,7 +146,7 @@ class ScalaInlineInfoTest extends ClearAfterClass { | def nullary: Int |} """.stripMargin - val cs = compileClasses(compiler)(code) + val cs = compileClasses(code) val sams = cs.map(c => (c.name, inlineInfo(c).sam)) assertEquals(sams, List( @@ -165,7 +162,7 @@ class ScalaInlineInfoTest extends ClearAfterClass { @Test def lzyComputeInlineInfo(): Unit = { val code = "class C { object O }" - val List(c, om) = compileClasses(compiler)(code) + val List(c, om) = compileClasses(code) val infoC = inlineInfo(c) val expected = Map( "<init>()V" -> MethodInlineInfo(false,false,false), diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala index 99acb318de..992a0e541b 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala @@ -2,15 +2,15 @@ package scala.tools.nsc package backend.jvm package opt +import org.junit.Assert._ +import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.junit.Test -import scala.tools.asm.Opcodes._ -import org.junit.Assert._ -import CodeGenTools._ +import scala.tools.asm.Opcodes._ import scala.tools.partest.ASMConverters -import ASMConverters._ +import scala.tools.partest.ASMConverters._ +import scala.tools.testing.BytecodeTesting._ @RunWith(classOf[JUnit4]) class SimplifyJumpsTest { diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala index 46f06d1d39..63bbcc396b 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala @@ -2,17 +2,15 @@ package scala.tools.nsc package backend.jvm package opt +import org.junit.Assert._ +import org.junit.Test 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.asm.Opcodes._ +import scala.tools.partest.ASMConverters._ import scala.tools.testing.AssertUtil._ - -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ +import scala.tools.testing.BytecodeTesting._ import scala.tools.testing.ClearAfterClass @RunWith(classOf[JUnit4]) @@ -20,12 +18,12 @@ class UnreachableCodeTest extends ClearAfterClass { // jvm-1.6 enables emitting stack map frames, which impacts the code generation wrt dead basic blocks, // see comment in BCodeBodyBuilder val methodOptCompiler = cached("methodOptCompiler", () => newCompiler(extraArgs = "-Yopt:l:method")) - val dceCompiler = cached("dceCompiler", () => newCompiler(extraArgs = "-Yopt:unreachable-code")) - val noOptCompiler = cached("noOptCompiler", () => newCompiler(extraArgs = "-Yopt:l:none")) + val dceCompiler = cached("dceCompiler", () => newCompiler(extraArgs = "-Yopt:unreachable-code")) + val noOptCompiler = cached("noOptCompiler", () => newCompiler(extraArgs = "-Yopt:l:none")) def assertEliminateDead(code: (Instruction, Boolean)*): Unit = { val method = genMethod()(code.map(_._1): _*) - dceCompiler.genBCode.bTypes.localOpt.removeUnreachableCodeImpl(method, "C") + dceCompiler.global.genBCode.bTypes.localOpt.removeUnreachableCodeImpl(method, "C") val nonEliminated = instructionsFromMethod(method) val expectedLive = code.filter(_._2).map(_._1).toList assertSameCode(nonEliminated, expectedLive) @@ -112,10 +110,10 @@ class UnreachableCodeTest extends ClearAfterClass { @Test def basicEliminationCompiler(): Unit = { val code = "def f: Int = { return 1; 2 }" - val withDce = singleMethodInstructions(dceCompiler)(code) + val withDce = dceCompiler.compileInstructions(code) assertSameCode(withDce.dropNonOp, List(Op(ICONST_1), Op(IRETURN))) - val noDce = singleMethodInstructions(noOptCompiler)(code) + val noDce = noOptCompiler.compileInstructions(code) // The emitted code is ICONST_1, IRETURN, ICONST_2, IRETURN. The latter two are dead. // @@ -141,23 +139,23 @@ class UnreachableCodeTest extends ClearAfterClass { def wrapInDefault(code: Instruction*) = List(Label(0), LineNumber(1, Label(0))) ::: code.toList ::: List(Label(1)) val code = "def f: Int = { return 0; try { 1 } catch { case _: Exception => 2 } }" - val m = singleMethod(dceCompiler)(code) + val m = dceCompiler.compileMethod(code) assertTrue(m.handlers.isEmpty) // redundant (if code is gone, handler is gone), but done once here for extra safety assertSameCode(m.instructions, wrapInDefault(Op(ICONST_0), Op(IRETURN))) val code2 = "def f: Unit = { try { } catch { case _: Exception => () }; () }" // requires fixpoint optimization of methodOptCompiler (dce alone is not enough): first the handler is eliminated, then it's dead catch block. - assertSameCode(singleMethodInstructions(methodOptCompiler)(code2), wrapInDefault(Op(RETURN))) + assertSameCode(methodOptCompiler.compileInstructions(code2), wrapInDefault(Op(RETURN))) val code3 = "def f: Unit = { try { } catch { case _: Exception => try { } catch { case _: Exception => () } }; () }" - assertSameCode(singleMethodInstructions(methodOptCompiler)(code3), wrapInDefault(Op(RETURN))) + assertSameCode(methodOptCompiler.compileInstructions(code3), wrapInDefault(Op(RETURN))) // this example requires two iterations to get rid of the outer handler. // the first iteration of DCE cannot remove the inner handler. then the inner (empty) handler is removed. // then the second iteration of DCE removes the inner catch block, and then the outer handler is removed. val code4 = "def f: Unit = { try { try { } catch { case _: Exception => () } } catch { case _: Exception => () }; () }" - assertSameCode(singleMethodInstructions(methodOptCompiler)(code4), wrapInDefault(Op(RETURN))) + assertSameCode(methodOptCompiler.compileInstructions(code4), wrapInDefault(Op(RETURN))) } @Test // test the dce-testing tools @@ -174,7 +172,7 @@ class UnreachableCodeTest extends ClearAfterClass { } @Test - def bytecodeEquivalence: Unit = { + def bytecodeEquivalence(): Unit = { assertTrue(List(VarOp(ILOAD, 1)) === List(VarOp(ILOAD, 2))) assertTrue(List(VarOp(ILOAD, 1), VarOp(ISTORE, 1)) === @@ -216,35 +214,35 @@ class UnreachableCodeTest extends ClearAfterClass { | def t4 = cons(nt) |} """.stripMargin - val List(c) = compileClasses(noOptCompiler)(code) + val c = noOptCompiler.compileClass(code) - assertSameSummary(getSingleMethod(c, "nl"), List(ACONST_NULL, ARETURN)) + assertSameSummary(getMethod(c, "nl"), List(ACONST_NULL, ARETURN)) - assertSameSummary(getSingleMethod(c, "nt"), List( + assertSameSummary(getMethod(c, "nt"), List( NEW, DUP, LDC, "<init>", ATHROW)) - assertSameSummary(getSingleMethod(c, "t1"), List( + assertSameSummary(getMethod(c, "t1"), List( ALOAD, ACONST_NULL, "cons", RETURN)) // GenBCode introduces POP; ACONST_NULL after loading an expression of type scala.runtime.Null$, // see comment in BCodeBodyBuilder.adapt - assertSameSummary(getSingleMethod(c, "t2"), List( + assertSameSummary(getMethod(c, "t2"), List( ALOAD, ALOAD, "nl", POP, ACONST_NULL, "cons", RETURN)) // the bytecode generated by GenBCode is ... ATHROW; INVOKEVIRTUAL C.cons; RETURN // the ASM classfile writer creates a new basic block (creates a label) right after the ATHROW // and replaces all instructions by NOP*; ATHROW, see comment in BCodeBodyBuilder.adapt // NOTE: DCE is enabled by default and gets rid of the redundant code (tested below) - assertSameSummary(getSingleMethod(c, "t3"), List( + assertSameSummary(getMethod(c, "t3"), List( ALOAD, NEW, DUP, LDC, "<init>", ATHROW, NOP, NOP, NOP, ATHROW)) // GenBCode introduces an ATHROW after the invocation of C.nt, see BCodeBodyBuilder.adapt // NOTE: DCE is enabled by default and gets rid of the redundant code (tested below) - assertSameSummary(getSingleMethod(c, "t4"), List( + assertSameSummary(getMethod(c, "t4"), List( ALOAD, ALOAD, "nt", ATHROW, NOP, NOP, NOP, ATHROW)) - val List(cDCE) = compileClasses(dceCompiler)(code) - assertSameSummary(getSingleMethod(cDCE, "t3"), List(ALOAD, NEW, DUP, LDC, "<init>", ATHROW)) - assertSameSummary(getSingleMethod(cDCE, "t4"), List(ALOAD, ALOAD, "nt", ATHROW)) + val cDCE = dceCompiler.compileClass(code) + assertSameSummary(getMethod(cDCE, "t3"), List(ALOAD, NEW, DUP, LDC, "<init>", ATHROW)) + assertSameSummary(getMethod(cDCE, "t4"), List(ALOAD, ALOAD, "nt", ATHROW)) } } diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala index 77e73e64b9..c9c98b403b 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala @@ -2,21 +2,20 @@ package scala.tools.nsc package backend.jvm package opt +import org.junit.Assert._ +import org.junit.Test 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.collection.JavaConverters._ -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ -import scala.tools.testing.ClearAfterClass +import scala.collection.JavaConverters._ +import scala.tools.partest.ASMConverters._ +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ @RunWith(classOf[JUnit4]) -class UnusedLocalVariablesTest extends ClearAfterClass { - val dceCompiler = cached("dceCompiler", () => newCompiler(extraArgs = "-Yopt:unreachable-code")) +class UnusedLocalVariablesTest extends BytecodeTesting { + override def compilerArgs = "-Yopt:unreachable-code" + import compiler._ @Test def removeUnusedVar(): Unit = { @@ -49,7 +48,7 @@ class UnusedLocalVariablesTest extends ClearAfterClass { | } |} |""".stripMargin - val cls = compileClasses(dceCompiler)(code).head + val cls = compileClass(code) val m = convertMethod(cls.methods.asScala.toList.find(_.desc == "(I)V").get) assertTrue(m.localVars.length == 2) // this, a, but not y @@ -70,19 +69,14 @@ class UnusedLocalVariablesTest extends ClearAfterClass { |} """.stripMargin - val clss2 = compileClasses(dceCompiler)(code2) - val cls2 = clss2.find(_.name == "C").get - val companion2 = clss2.find(_.name == "C$").get - - val clsConstr = convertMethod(cls2.methods.asScala.toList.find(_.name == "<init>").get) - val companionConstr = convertMethod(companion2.methods.asScala.toList.find(_.name == "<init>").get) + val List(cls2, companion2) = compileClasses(code2) - assertTrue(clsConstr.localVars.length == 1) // this - assertTrue(companionConstr.localVars.length == 1) // this + assertTrue(getMethod(cls2, "<init>").localVars.length == 1) // this + assertTrue(getMethod(companion2, "<init>").localVars.length == 1) // this } def assertLocalVarCount(code: String, numVars: Int): Unit = { - assertTrue(singleMethod(dceCompiler)(code).localVars.length == numVars) + assertTrue(compileMethod(code).localVars.length == numVars) } } diff --git a/test/junit/scala/tools/nsc/interpreter/ScriptedTest.scala b/test/junit/scala/tools/nsc/interpreter/ScriptedTest.scala new file mode 100644 index 0000000000..a8dc8eb3e0 --- /dev/null +++ b/test/junit/scala/tools/nsc/interpreter/ScriptedTest.scala @@ -0,0 +1,83 @@ +package scala.tools.nsc +package interpreter + +import org.junit._, Assert._, runner.RunWith, runners.JUnit4 +import scala.tools.testing.AssertUtil.assertThrows + +@RunWith(classOf[JUnit4]) +class ScriptedTest { + import javax.script._ + import scala.tools.nsc.interpreter.Scripted + + def scripted: ScriptEngine with Compilable = Scripted() + // same as by service discovery + //new ScriptEngineManager().getEngineByName("scala").asInstanceOf[ScriptEngine with Compilable] + + @Test def eval() = { + val engine = scripted + engine.put("foo","bar") + assert("bar" == engine.eval("foo")) + val bindings = engine.createBindings() + bindings.put("foo","baz") + assert("baz" == engine.eval("foo", bindings)) + val c = engine.compile("def f = foo.asInstanceOf[String] ; f * 2") + assert("barbar" == c.eval()) + assert("bazbaz" == c.eval(bindings)) + } + @Test def `SI-7933 multiple eval compiled script`() = { + val engine = scripted + val init = """val i = new java.util.concurrent.atomic.AtomicInteger""" + val code = """i.getAndIncrement()""" + engine eval init + val c = engine compile code + assert(0 == c.eval()) + assert(1 == c.eval()) + } + @Test def `SI-8422 captured i/o`() = { + import java.io.StringWriter + val engine = scripted + val ctx = new SimpleScriptContext + val w = new StringWriter + val code = """print("hello, world")""" + + ctx.setWriter(w) + engine.eval(code, ctx) + assertEquals("hello, world", w.toString) + } + @Test def `SI-8422 captured multi i/o`() = { + import java.io.{ StringWriter, StringReader } + import scala.compat.Platform.EOL + val engine = scripted + val ctx = new SimpleScriptContext + val out = new StringWriter + val err = new StringWriter + val text = + """Now is the time + |for all good + |dogs to come for supper.""".stripMargin + val in = new StringReader(text) + + val code = + """var s: String = _ + |var i: Int = 0 + |do { + | s = scala.io.StdIn.readLine() + | val out = if ((i & 1) == 0) Console.out else Console.err + | i += 1 + | Option(s) foreach out.println + |} while (s != null)""".stripMargin + + ctx.setWriter(out) + ctx.setErrorWriter(err) + ctx.setReader(in) + engine.eval(code, ctx) + val lines = text.lines.toList + assertEquals(lines.head + EOL + lines.last + EOL, out.toString) + assertEquals(lines(1) + EOL, err.toString) + } + @Test def `on compile error`(): Unit = { + val engine = scripted + val err = "not found: value foo in def f = foo at line number 11 at column number 16" + assertThrows[ScriptException](engine.compile("def f = foo"), _ == err) + } +} diff --git a/test/junit/scala/tools/nsc/transform/delambdafy/DelambdafyTest.scala b/test/junit/scala/tools/nsc/transform/delambdafy/DelambdafyTest.scala index e4bf038f32..609f481721 100644 --- a/test/junit/scala/tools/nsc/transform/delambdafy/DelambdafyTest.scala +++ b/test/junit/scala/tools/nsc/transform/delambdafy/DelambdafyTest.scala @@ -1,17 +1,15 @@ package scala.tools.nsc.transform.delambdafy -import scala.reflect.io.Path.jfile2path -import scala.tools.nsc.backend.jvm.CodeGenTools.getGeneratedClassfiles -import scala.tools.nsc.backend.jvm.CodeGenTools.makeSourceFile -import scala.tools.nsc.backend.jvm.CodeGenTools.newCompilerWithoutVirtualOutdir -import scala.tools.nsc.io.AbstractFile -import scala.tools.testing.TempDir - import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +import scala.reflect.io.Path.jfile2path +import scala.tools.nsc.io.AbstractFile +import scala.tools.testing.BytecodeTesting._ +import scala.tools.testing.TempDir + @RunWith(classOf[JUnit4]) class DelambdafyTest { def compileToMultipleOutputWithDelamdbafyMethod(): List[(String, Array[Byte])] = { @@ -55,9 +53,9 @@ object Delambdafy { val extraArgs = "-Ydelambdafy:method" val argsWithOutDir = extraArgs + s" -d $outDirPath -cp $outDirPath" val compiler = newCompilerWithoutVirtualOutdir(extraArgs = argsWithOutDir) - compiler.settings.outputDirs.add(srcFile.file, outDir) + compiler.global.settings.outputDirs.add(srcFile.file, outDir) - new compiler.Run().compileSources(List(srcFile)) + new compiler.global.Run().compileSources(List(srcFile)) val classfiles = getGeneratedClassfiles(outDir) outDir.delete() diff --git a/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala b/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala index aa83520efb..b6e8d4fbf2 100644 --- a/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala +++ b/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala @@ -1,26 +1,21 @@ package scala.tools.nsc package transform.patmat +import org.junit.Test 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.asm.Opcodes._ import scala.tools.nsc.backend.jvm.AsmUtils._ -import scala.tools.nsc.backend.jvm.CodeGenTools -import scala.tools.testing.AssertUtil._ - -import CodeGenTools._ -import scala.tools.partest.ASMConverters -import ASMConverters._ -import scala.tools.testing.ClearAfterClass +import scala.tools.testing.BytecodeTesting +import scala.tools.testing.BytecodeTesting._ @RunWith(classOf[JUnit4]) -class PatmatBytecodeTest extends ClearAfterClass { - val compiler = cached("compiler", () => newCompiler()) +class PatmatBytecodeTest extends BytecodeTesting { val optCompiler = cached("optCompiler", () => newCompiler(extraArgs = "-Yopt:l:project")) + import compiler._ + @Test def t6956(): Unit = { val code = @@ -43,9 +38,9 @@ class PatmatBytecodeTest extends ClearAfterClass { |} """.stripMargin - val List(c) = compileClasses(compiler)(code) - assert(getSingleMethod(c, "s1").instructions.count(_.opcode == TABLESWITCH) == 1, textify(c)) - assert(getSingleMethod(c, "s2").instructions.count(_.opcode == TABLESWITCH) == 1, textify(c)) + val c = compileClass(code) + assert(getInstructions(c, "s1").count(_.opcode == TABLESWITCH) == 1, textify(c)) + assert(getInstructions(c, "s2").count(_.opcode == TABLESWITCH) == 1, textify(c)) } @Test @@ -71,9 +66,9 @@ class PatmatBytecodeTest extends ClearAfterClass { |} """.stripMargin - val List(c) = compileClasses(compiler)(code) - assert(getSingleMethod(c, "s1").instructions.count(_.opcode == TABLESWITCH) == 1, textify(c)) - assert(getSingleMethod(c, "s2").instructions.count(_.opcode == TABLESWITCH) == 1, textify(c)) + val c = compileClass(code) + assert(getInstructions(c, "s1").count(_.opcode == TABLESWITCH) == 1, textify(c)) + assert(getInstructions(c, "s2").count(_.opcode == TABLESWITCH) == 1, textify(c)) } @Test @@ -86,9 +81,9 @@ class PatmatBytecodeTest extends ClearAfterClass { | } |} """.stripMargin - val c = compileClasses(optCompiler)(code).head + val c :: _ = optCompiler.compileClasses(code) - assertSameSummary(getSingleMethod(c, "a"), List( + assertSameSummary(getMethod(c, "a"), List( NEW, DUP, ICONST_1, LDC, "<init>", "y", ARETURN)) } @@ -103,8 +98,8 @@ class PatmatBytecodeTest extends ClearAfterClass { | } |} """.stripMargin - val c = compileClasses(optCompiler)(code).head - assert(!getSingleMethod(c, "a").instructions.exists(i => i.opcode == IFNULL || i.opcode == IFNONNULL), textify(findAsmMethod(c, "a"))) + val c :: _ = optCompiler.compileClasses(code) + assert(!getInstructions(c, "a").exists(i => i.opcode == IFNULL || i.opcode == IFNONNULL), textify(getAsmMethod(c, "a"))) } @Test @@ -117,8 +112,8 @@ class PatmatBytecodeTest extends ClearAfterClass { | } |} """.stripMargin - val c = compileClasses(optCompiler)(code).head - assertSameSummary(getSingleMethod(c, "a"), List( + val c :: _ = optCompiler.compileClasses(code) + assertSameSummary(getMethod(c, "a"), List( NEW, DUP, ICONST_1, "boxToInteger", LDC, "<init>", ASTORE /*1*/, ALOAD /*1*/, "y", ASTORE /*2*/, ALOAD /*1*/, "x", INSTANCEOF, IFNE /*R*/, @@ -138,7 +133,7 @@ class PatmatBytecodeTest extends ClearAfterClass { | } |} """.stripMargin - val c = compileClasses(optCompiler)(code, allowMessage = _.msg.contains("may not be exhaustive")).head + val c = optCompiler.compileClass(code, allowMessage = _.msg.contains("may not be exhaustive")) val expected = List( ALOAD /*1*/ , INSTANCEOF /*::*/ , IFEQ /*A*/ , @@ -147,8 +142,8 @@ class PatmatBytecodeTest extends ClearAfterClass { -1 /*A*/ , NEW /*MatchError*/ , DUP, ALOAD /*1*/ , "<init>", ATHROW, -1 /*B*/ , ILOAD, IRETURN) - assertSameSummary(getSingleMethod(c, "a"), expected) - assertSameSummary(getSingleMethod(c, "b"), expected) + assertSameSummary(getMethod(c, "a"), expected) + assertSameSummary(getMethod(c, "b"), expected) } @Test @@ -170,18 +165,18 @@ class PatmatBytecodeTest extends ClearAfterClass { | def t9 = { val C(a, _) = C("hi", 23); a.toString } |} """.stripMargin - val List(c, cMod) = compileClasses(optCompiler)(code) - assertSameSummary(getSingleMethod(c, "t1"), List(ICONST_1, ICONST_2, IADD, IRETURN)) - assertSameSummary(getSingleMethod(c, "t2"), List(ICONST_1, IRETURN)) - assertInvokedMethods(getSingleMethod(c, "t3"), List("C.tplCall", "scala/Tuple2._1", "scala/Tuple2._2$mcI$sp", "scala/MatchError.<init>", "java/lang/String.length")) - assertInvokedMethods(getSingleMethod(c, "t4"), List("C.tplCall", "scala/Tuple2._2$mcI$sp", "scala/MatchError.<init>")) - assertNoInvoke(getSingleMethod(c, "t5")) - assertSameSummary(getSingleMethod(c, "t6"), List(BIPUSH, IRETURN)) + val List(c, cMod) = optCompiler.compileClasses(code) + assertSameSummary(getMethod(c, "t1"), List(ICONST_1, ICONST_2, IADD, IRETURN)) + assertSameSummary(getMethod(c, "t2"), List(ICONST_1, IRETURN)) + assertInvokedMethods(getMethod(c, "t3"), List("C.tplCall", "scala/Tuple2._1", "scala/Tuple2._2$mcI$sp", "scala/MatchError.<init>", "java/lang/String.length")) + assertInvokedMethods(getMethod(c, "t4"), List("C.tplCall", "scala/Tuple2._2$mcI$sp", "scala/MatchError.<init>")) + assertNoInvoke(getMethod(c, "t5")) + assertSameSummary(getMethod(c, "t6"), List(BIPUSH, IRETURN)) // MatchError reachable because of the type pattern `s: String` - assertInvokedMethods(getSingleMethod(c, "t7"), List("C.a", "C.b", "scala/MatchError.<init>", "java/lang/String.length")) - assertSameSummary(getSingleMethod(c, "t8"), List(ALOAD, "b", IRETURN)) + assertInvokedMethods(getMethod(c, "t7"), List("C.a", "C.b", "scala/MatchError.<init>", "java/lang/String.length")) + assertSameSummary(getMethod(c, "t8"), List(ALOAD, "b", IRETURN)) // C allocation not eliminated - constructor may have side-effects. - assertSameSummary(getSingleMethod(c, "t9"), List(NEW, DUP, LDC, BIPUSH, "<init>", "a", "toString", ARETURN)) + assertSameSummary(getMethod(c, "t9"), List(NEW, DUP, LDC, BIPUSH, "<init>", "a", "toString", ARETURN)) } } diff --git a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala b/test/junit/scala/tools/testing/BytecodeTesting.scala index 389e5b2ead..b11ad27148 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala +++ b/test/junit/scala/tools/testing/BytecodeTesting.scala @@ -1,32 +1,117 @@ -package scala.tools.nsc.backend.jvm +package scala.tools.testing import org.junit.Assert._ +import scala.collection.JavaConverters._ import scala.collection.mutable.ListBuffer import scala.reflect.internal.util.BatchSourceFile import scala.reflect.io.VirtualDirectory import scala.tools.asm.Opcodes import scala.tools.asm.tree.{AbstractInsnNode, ClassNode, MethodNode} import scala.tools.cmd.CommandLineParser +import scala.tools.nsc.backend.jvm.AsmUtils +import scala.tools.nsc.backend.jvm.AsmUtils._ import scala.tools.nsc.io.AbstractFile import scala.tools.nsc.reporters.StoreReporter -import scala.tools.nsc.settings.MutableSettings -import scala.tools.nsc.{Settings, Global} -import scala.tools.partest.ASMConverters -import scala.collection.JavaConverters._ -import scala.tools.testing.TempDir -import AsmUtils._ - -object CodeGenTools { - import ASMConverters._ - - def genMethod( flags: Int = Opcodes.ACC_PUBLIC, - name: String = "m", - descriptor: String = "()V", - genericSignature: String = null, - throwsExceptions: Array[String] = null, - handlers: List[ExceptionHandler] = Nil, - localVars: List[LocalVariable] = Nil)(body: Instruction*): MethodNode = { +import scala.tools.nsc.{Global, Settings} +import scala.tools.partest.ASMConverters._ + +trait BytecodeTesting extends ClearAfterClass { + def compilerArgs = "" // to be overridden + val compiler = cached("compiler", () => BytecodeTesting.newCompiler(extraArgs = compilerArgs)) +} + +class Compiler(val global: Global) { + import BytecodeTesting._ + + def resetOutput(): Unit = { + global.settings.outputDirs.setSingleOutput(new VirtualDirectory("(memory)", None)) + } + + private def newRun: global.Run = { + global.reporter.reset() + resetOutput() + new global.Run() + } + + private def reporter = global.reporter.asInstanceOf[StoreReporter] + + def checkReport(allowMessage: StoreReporter#Info => Boolean = _ => false): Unit = { + val disallowed = reporter.infos.toList.filter(!allowMessage(_)) // toList prevents an infer-non-wildcard-existential warning. + if (disallowed.nonEmpty) { + val msg = disallowed.mkString("\n") + assert(false, "The compiler issued non-allowed warnings or errors:\n" + msg) + } + } + + def compileToBytes(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[(String, Array[Byte])] = { + val run = newRun + run.compileSources(makeSourceFile(scalaCode, "unitTestSource.scala") :: javaCode.map(p => makeSourceFile(p._1, p._2))) + checkReport(allowMessage) + getGeneratedClassfiles(global.settings.outputDirs.getSingleOutput.get) + } + + def compileClasses(code: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] = { + readAsmClasses(compileToBytes(code, javaCode, allowMessage)) + } + + def compileClass(code: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): ClassNode = { + val List(c) = compileClasses(code, javaCode, allowMessage) + c + } + + def compileToBytesTransformed(scalaCode: String, javaCode: List[(String, String)] = Nil, beforeBackend: global.Tree => global.Tree): List[(String, Array[Byte])] = { + import global._ + settings.stopBefore.value = "jvm" :: Nil + val run = newRun + val scalaUnit = newCompilationUnit(scalaCode, "unitTestSource.scala") + val javaUnits = javaCode.map(p => newCompilationUnit(p._1, p._2)) + val units = scalaUnit :: javaUnits + run.compileUnits(units, run.parserPhase) + settings.stopBefore.value = Nil + scalaUnit.body = beforeBackend(scalaUnit.body) + checkReport(_ => false) + val run1 = newRun + run1.compileUnits(units, run1.phaseNamed("jvm")) + checkReport(_ => false) + getGeneratedClassfiles(settings.outputDirs.getSingleOutput.get) + } + + def compileClassesTransformed(scalaCode: String, javaCode: List[(String, String)] = Nil, beforeBackend: global.Tree => global.Tree): List[ClassNode] = + readAsmClasses(compileToBytesTransformed(scalaCode, javaCode, beforeBackend)) + + def compileAsmMethods(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[MethodNode] = { + val c = compileClass(s"class C { $code }", allowMessage = allowMessage) + getAsmMethods(c, _ != "<init>") + } + + def compileAsmMethod(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): MethodNode = { + val List(m) = compileAsmMethods(code, allowMessage) + m + } + + def compileMethods(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[Method] = + compileAsmMethods(code, allowMessage).map(convertMethod) + + def compileMethod(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): Method = { + val List(m) = compileMethods(code, allowMessage = allowMessage) + m + } + + def compileInstructions(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[Instruction] = { + val List(m) = compileMethods(code, allowMessage = allowMessage) + m.instructions + } +} + +object BytecodeTesting { + def genMethod(flags: Int = Opcodes.ACC_PUBLIC, + name: String = "m", + descriptor: String = "()V", + genericSignature: String = null, + throwsExceptions: Array[String] = null, + handlers: List[ExceptionHandler] = Nil, + localVars: List[LocalVariable] = Nil)(body: Instruction*): MethodNode = { val node = new MethodNode(flags, name, descriptor, genericSignature, throwsExceptions) applyToMethod(node, Method(body.toList, handlers, localVars)) node @@ -39,33 +124,21 @@ object CodeGenTools { cls } - private def resetOutput(compiler: Global): Unit = { - compiler.settings.outputDirs.setSingleOutput(new VirtualDirectory("(memory)", None)) - } - - def newCompiler(defaultArgs: String = "-usejavacp", extraArgs: String = ""): Global = { + def newCompiler(defaultArgs: String = "-usejavacp", extraArgs: String = ""): Compiler = { val compiler = newCompilerWithoutVirtualOutdir(defaultArgs, extraArgs) - resetOutput(compiler) + compiler.resetOutput() compiler } - def newCompilerWithoutVirtualOutdir(defaultArgs: String = "-usejavacp", extraArgs: String = ""): Global = { + def newCompilerWithoutVirtualOutdir(defaultArgs: String = "-usejavacp", extraArgs: String = ""): Compiler = { def showError(s: String) = throw new Exception(s) val settings = new Settings(showError) val args = (CommandLineParser tokenize defaultArgs) ++ (CommandLineParser tokenize extraArgs) val (_, nonSettingsArgs) = settings.processArguments(args, processAll = true) if (nonSettingsArgs.nonEmpty) showError("invalid compiler flags: " + nonSettingsArgs.mkString(" ")) - new Global(settings, new StoreReporter) - } - - def newRun(compiler: Global): compiler.Run = { - compiler.reporter.reset() - resetOutput(compiler) - new compiler.Run() + new Compiler(new Global(settings, new StoreReporter)) } - def reporter(compiler: Global) = compiler.reporter.asInstanceOf[StoreReporter] - def makeSourceFile(code: String, filename: String): BatchSourceFile = new BatchSourceFile(filename, code) def getGeneratedClassfiles(outDir: AbstractFile): List[(String, Array[Byte])] = { @@ -80,38 +153,6 @@ object CodeGenTools { files(outDir) } - def checkReport(compiler: Global, allowMessage: StoreReporter#Info => Boolean = _ => false): Unit = { - val disallowed = reporter(compiler).infos.toList.filter(!allowMessage(_)) // toList prevents an infer-non-wildcard-existential warning. - if (disallowed.nonEmpty) { - val msg = disallowed.mkString("\n") - assert(false, "The compiler issued non-allowed warnings or errors:\n" + msg) - } - } - - def compile(compiler: Global)(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[(String, Array[Byte])] = { - val run = newRun(compiler) - run.compileSources(makeSourceFile(scalaCode, "unitTestSource.scala") :: javaCode.map(p => makeSourceFile(p._1, p._2))) - checkReport(compiler, allowMessage) - getGeneratedClassfiles(compiler.settings.outputDirs.getSingleOutput.get) - } - - def compileTransformed(compiler: Global)(scalaCode: String, javaCode: List[(String, String)] = Nil, beforeBackend: compiler.Tree => compiler.Tree): List[(String, Array[Byte])] = { - compiler.settings.stopBefore.value = "jvm" :: Nil - val run = newRun(compiler) - import compiler._ - val scalaUnit = newCompilationUnit(scalaCode, "unitTestSource.scala") - val javaUnits = javaCode.map(p => newCompilationUnit(p._1, p._2)) - val units = scalaUnit :: javaUnits - run.compileUnits(units, run.parserPhase) - compiler.settings.stopBefore.value = Nil - scalaUnit.body = beforeBackend(scalaUnit.body) - checkReport(compiler, _ => false) - val run1 = newRun(compiler) - run1.compileUnits(units, run1.phaseNamed("jvm")) - checkReport(compiler, _ => false) - getGeneratedClassfiles(compiler.settings.outputDirs.getSingleOutput.get) - } - /** * Compile multiple Scala files separately into a single output directory. * @@ -121,15 +162,15 @@ object CodeGenTools { * The output directory is a physical directory, I have not figured out if / how it's possible to * add a VirtualDirectory to the classpath of a compiler. */ - def compileSeparately(codes: List[String], extraArgs: String = "", allowMessage: StoreReporter#Info => Boolean = _ => false, afterEach: AbstractFile => Unit = _ => ()): List[(String, Array[Byte])] = { + def compileToBytesSeparately(codes: List[String], extraArgs: String = "", allowMessage: StoreReporter#Info => Boolean = _ => false, afterEach: AbstractFile => Unit = _ => ()): List[(String, Array[Byte])] = { val outDir = AbstractFile.getDirectory(TempDir.createTempDir()) val outDirPath = outDir.canonicalPath val argsWithOutDir = extraArgs + s" -d $outDirPath -cp $outDirPath" for (code <- codes) { val compiler = newCompilerWithoutVirtualOutdir(extraArgs = argsWithOutDir) - new compiler.Run().compileSources(List(makeSourceFile(code, "unitTestSource.scala"))) - checkReport(compiler, allowMessage) + new compiler.global.Run().compileSources(List(makeSourceFile(code, "unitTestSource.scala"))) + compiler.checkReport(allowMessage) afterEach(outDir) } @@ -138,31 +179,11 @@ object CodeGenTools { classfiles } - def compileClassesSeparately(codes: List[String], extraArgs: String = "", allowMessage: StoreReporter#Info => Boolean = _ => false, afterEach: AbstractFile => Unit = _ => ()) = { - readAsmClasses(compileSeparately(codes, extraArgs, allowMessage, afterEach)) + def compileClassesSeparately(codes: List[String], extraArgs: String = "", allowMessage: StoreReporter#Info => Boolean = _ => false, afterEach: AbstractFile => Unit = _ => ()): List[ClassNode] = { + readAsmClasses(compileToBytesSeparately(codes, extraArgs, allowMessage, afterEach)) } - def readAsmClasses(classfiles: List[(String, Array[Byte])]) = { - classfiles.map(p => AsmUtils.readClass(p._2)).sortBy(_.name) - } - - def compileClasses(compiler: Global)(code: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] = { - readAsmClasses(compile(compiler)(code, javaCode, allowMessage)) - } - - def compileMethods(compiler: Global)(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[MethodNode] = { - compileClasses(compiler)(s"class C { $code }", allowMessage = allowMessage).head.methods.asScala.toList.filterNot(_.name == "<init>") - } - - def singleMethodInstructions(compiler: Global)(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[Instruction] = { - val List(m) = compileMethods(compiler)(code, allowMessage = allowMessage) - instructionsFromMethod(m) - } - - def singleMethod(compiler: Global)(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): Method = { - val List(m) = compileMethods(compiler)(code, allowMessage = allowMessage) - convertMethod(m) - } + def readAsmClasses(classfiles: List[(String, Array[Byte])]) = classfiles.map(p => AsmUtils.readClass(p._2)).sortBy(_.name) def assertSameCode(method: Method, expected: List[Instruction]): Unit = assertSameCode(method.instructions.dropNonOp, expected) def assertSameCode(actual: List[Instruction], expected: List[Instruction]): Unit = { @@ -212,23 +233,51 @@ object CodeGenTools { assert(indy.isEmpty, indy) } - def getSingleMethod(classNode: ClassNode, name: String): Method = - convertMethod(classNode.methods.asScala.toList.find(_.name == name).get) + def findClass(cs: List[ClassNode], name: String): ClassNode = { + val List(c) = cs.filter(_.name == name) + c + } + + def getAsmMethods(c: ClassNode, p: String => Boolean): List[MethodNode] = + c.methods.iterator.asScala.filter(m => p(m.name)).toList.sortBy(_.name) - def findAsmMethods(c: ClassNode, p: String => Boolean) = c.methods.iterator.asScala.filter(m => p(m.name)).toList.sortBy(_.name) - def findAsmMethod(c: ClassNode, name: String) = findAsmMethods(c, _ == name).head + def getAsmMethods(c: ClassNode, name: String): List[MethodNode] = + getAsmMethods(c, _ == name) + + def getAsmMethod(c: ClassNode, name: String): MethodNode = { + val List(m) = getAsmMethods(c, name) + m + } + + def getMethods(c: ClassNode, name: String): List[Method] = + getAsmMethods(c, name).map(convertMethod) + + def getMethod(c: ClassNode, name: String): Method = + convertMethod(getAsmMethod(c, name)) + + def getInstructions(c: ClassNode, name: String): List[Instruction] = + getMethod(c, name).instructions /** * Instructions that match `query` when textified. * If `query` starts with a `+`, the next instruction is returned. */ - def findInstr(method: MethodNode, query: String): List[AbstractInsnNode] = { + def findInstrs(method: MethodNode, query: String): List[AbstractInsnNode] = { val useNext = query(0) == '+' val instrPart = if (useNext) query.drop(1) else query val insns = method.instructions.iterator.asScala.filter(i => textify(i) contains instrPart).toList if (useNext) insns.map(_.getNext) else insns } + /** + * Instruction that matches `query` when textified. + * If `query` starts with a `+`, the next instruction is returned. + */ + def findInstr(method: MethodNode, query: String): AbstractInsnNode = { + val List(i) = findInstrs(method, query) + i + } + def assertHandlerLabelPostions(h: ExceptionHandler, instructions: List[Instruction], startIndex: Int, endIndex: Int, handlerIndex: Int): Unit = { val insVec = instructions.toVector assertTrue(h.start == insVec(startIndex) && h.end == insVec(endIndex) && h.handler == insVec(handlerIndex)) diff --git a/test/junit/scala/tools/testing/RunTesting.scala b/test/junit/scala/tools/testing/RunTesting.scala new file mode 100644 index 0000000000..1320db4230 --- /dev/null +++ b/test/junit/scala/tools/testing/RunTesting.scala @@ -0,0 +1,17 @@ +package scala.tools.testing + +import scala.reflect.runtime._ +import scala.tools.reflect.ToolBox + +trait RunTesting extends ClearAfterClass { + def compilerArgs = "" // to be overridden + val runner = cached("toolbox", () => Runner.make(compilerArgs)) +} + +class Runner(val toolBox: ToolBox[universe.type]) { + def run[T](code: String): T = toolBox.eval(toolBox.parse(code)).asInstanceOf[T] +} + +object Runner { + def make(compilerArgs: String) = new Runner(universe.runtimeMirror(getClass.getClassLoader).mkToolBox(options = compilerArgs)) +} |