diff options
author | Shane Delmore <shane@delmore.io> | 2016-02-04 09:26:05 -0800 |
---|---|---|
committer | Shane Delmore <shane@delmore.io> | 2016-02-04 09:26:05 -0800 |
commit | e5517e67eea79fbbd886110ff6dc993842852cf8 (patch) | |
tree | bba2ca144d47ed69be586af523e5bfbd803ceb15 /test | |
parent | 7137a3bfa6863860b7aee7920f74fb8257e66c01 (diff) | |
parent | 333187a7c020b7d51d68c5435852305e70d89d41 (diff) | |
download | scala-e5517e67eea79fbbd886110ff6dc993842852cf8.tar.gz scala-e5517e67eea79fbbd886110ff6dc993842852cf8.tar.bz2 scala-e5517e67eea79fbbd886110ff6dc993842852cf8.zip |
Merge branch '2.12.x' into SI-9452
Diffstat (limited to 'test')
55 files changed, 573 insertions, 263 deletions
diff --git a/test/files/jvm/t6941.check b/test/files/jvm/t6941.check deleted file mode 100644 index 43f53aba12..0000000000 --- a/test/files/jvm/t6941.check +++ /dev/null @@ -1 +0,0 @@ -bytecode identical diff --git a/test/files/jvm/t6941.flags b/test/files/jvm/t6941.flags deleted file mode 100644 index 49d036a887..0000000000 --- a/test/files/jvm/t6941.flags +++ /dev/null @@ -1 +0,0 @@ --optimize diff --git a/test/files/jvm/t6941/Analyzed_1.flags b/test/files/jvm/t6941/Analyzed_1.flags deleted file mode 100644 index ad51758c39..0000000000 --- a/test/files/jvm/t6941/Analyzed_1.flags +++ /dev/null @@ -1 +0,0 @@ --nowarn diff --git a/test/files/jvm/t6941/Analyzed_1.scala b/test/files/jvm/t6941/Analyzed_1.scala deleted file mode 100644 index b6951f71ee..0000000000 --- a/test/files/jvm/t6941/Analyzed_1.scala +++ /dev/null @@ -1,11 +0,0 @@ -// this class's bytecode, compiled under -optimize is analyzed by the test -// method a's bytecode should be identical to method b's bytecode -class SameBytecode { - def a(xs: List[Int]) = xs match { - case x :: _ => x - } - - def b(xs: List[Int]) = xs match { - case xs: ::[Int] => xs.head - } -}
\ No newline at end of file diff --git a/test/files/jvm/t6941/test.scala b/test/files/jvm/t6941/test.scala deleted file mode 100644 index fceb54487f..0000000000 --- a/test/files/jvm/t6941/test.scala +++ /dev/null @@ -1,15 +0,0 @@ -import scala.tools.partest.{BytecodeTest, ASMConverters} - -import scala.tools.nsc.util.JavaClassPath -import java.io.InputStream -import scala.tools.asm -import asm.ClassReader -import asm.tree.{ClassNode, InsnList} -import scala.collection.JavaConverters._ - -object Test extends BytecodeTest { - def show: Unit = { - val classNode = loadClassNode("SameBytecode") - similarBytecode(getMethod(classNode, "a"), getMethod(classNode, "b"), ASMConverters.equivalentBytecode(_, _)) - } -} diff --git a/test/files/neg/choices.check b/test/files/neg/choices.check index b114394e96..df4f23461f 100644 --- a/test/files/neg/choices.check +++ b/test/files/neg/choices.check @@ -1,2 +1,6 @@ +error: Usage: -Yresolve-term-conflict:<strategy> + where <strategy> choices are package, object, error (default: error) +error: bad option: '-Yresolve-term-conflict' error: bad options: -Yresolve-term-conflict -one error found +error: flags file may only contain compiler options, found: -Yresolve-term-conflict +four errors found diff --git a/test/files/neg/partestInvalidFlag.check b/test/files/neg/partestInvalidFlag.check new file mode 100644 index 0000000000..812191dc22 --- /dev/null +++ b/test/files/neg/partestInvalidFlag.check @@ -0,0 +1,4 @@ +error: bad option: '-badCompilerFlag' +error: bad options: -badCompilerFlag notAFlag -Yopt:badChoice +error: flags file may only contain compiler options, found: -badCompilerFlag notAFlag -Yopt:badChoice +three errors found diff --git a/test/files/neg/partestInvalidFlag.flags b/test/files/neg/partestInvalidFlag.flags new file mode 100644 index 0000000000..68884532b9 --- /dev/null +++ b/test/files/neg/partestInvalidFlag.flags @@ -0,0 +1 @@ +-badCompilerFlag notAFlag -Yopt:badChoice diff --git a/test/files/neg/partestInvalidFlag.scala b/test/files/neg/partestInvalidFlag.scala new file mode 100644 index 0000000000..826a1a5bc2 --- /dev/null +++ b/test/files/neg/partestInvalidFlag.scala @@ -0,0 +1 @@ +class C diff --git a/test/files/pos/t2171.flags b/test/files/pos/t2171.flags deleted file mode 100644 index eb4d19bcb9..0000000000 --- a/test/files/pos/t2171.flags +++ /dev/null @@ -1 +0,0 @@ --optimise
\ No newline at end of file diff --git a/test/files/pos/t2171.scala b/test/files/pos/t2171.scala deleted file mode 100644 index 6c754c76a6..0000000000 --- a/test/files/pos/t2171.scala +++ /dev/null @@ -1,7 +0,0 @@ -final object test { - def logIgnoredException(msg: => String) = - try 0 catch { case ex => println(msg) } - - def main (args: Array[String]): Unit = - while (true) logIgnoredException ("...") -} diff --git a/test/files/pos/t3252.flags b/test/files/pos/t3252.flags deleted file mode 100644 index eb4d19bcb9..0000000000 --- a/test/files/pos/t3252.flags +++ /dev/null @@ -1 +0,0 @@ --optimise
\ No newline at end of file diff --git a/test/files/pos/t3252.scala b/test/files/pos/t3252.scala deleted file mode 100644 index 3ecc1e7cef..0000000000 --- a/test/files/pos/t3252.scala +++ /dev/null @@ -1,15 +0,0 @@ -class A { - def f(x : Boolean) : Thread = { - g { - x match { - case false => - B.h { } - } - } - } - - private def g[T](block : => T) = sys.error("") -} -object B { - def h(block : => Unit) : Nothing = sys.error("") -} diff --git a/test/files/pos/t3420.flags b/test/files/pos/t3420.flags index 4fbafb7e80..397969bb1d 100644 --- a/test/files/pos/t3420.flags +++ b/test/files/pos/t3420.flags @@ -1 +1 @@ --Yopt-warnings Yopt:l:project -Xfatal-warnings
\ No newline at end of file +-Yopt-warnings -Yopt:l:classpath -Xfatal-warnings
\ No newline at end of file diff --git a/test/files/pos/t3430.flags b/test/files/pos/t3430.flags deleted file mode 100644 index eb4d19bcb9..0000000000 --- a/test/files/pos/t3430.flags +++ /dev/null @@ -1 +0,0 @@ --optimise
\ No newline at end of file diff --git a/test/files/pos/t3430.scala b/test/files/pos/t3430.scala deleted file mode 100644 index 3129c6276a..0000000000 --- a/test/files/pos/t3430.scala +++ /dev/null @@ -1,13 +0,0 @@ -// package com.example - -object A { - def f1(f: String => Boolean) = f("a") - - def f2(): Boolean = - f1 { s1 => - f1 { s2 => - while (true) { } - true - } - } -}
\ No newline at end of file diff --git a/test/files/pos/t4579.flags b/test/files/pos/t4579.flags deleted file mode 100644 index 1182725e86..0000000000 --- a/test/files/pos/t4579.flags +++ /dev/null @@ -1 +0,0 @@ --optimize
\ No newline at end of file diff --git a/test/files/pos/t4840.flags b/test/files/pos/t4840.flags index eb4d19bcb9..422d6be431 100644 --- a/test/files/pos/t4840.flags +++ b/test/files/pos/t4840.flags @@ -1 +1 @@ --optimise
\ No newline at end of file +-Yopt:l:classpath
\ No newline at end of file diff --git a/test/files/pos/t6157.flags b/test/files/pos/t6157.flags deleted file mode 100644 index 0ebca3e7af..0000000000 --- a/test/files/pos/t6157.flags +++ /dev/null @@ -1 +0,0 @@ - -optimize diff --git a/test/files/pos/t6157.scala b/test/files/pos/t6157.scala deleted file mode 100644 index 7463989b14..0000000000 --- a/test/files/pos/t6157.scala +++ /dev/null @@ -1,25 +0,0 @@ -// SI-6157 - Compiler crash on inlined function and -optimize option - -object Test { - def main(args: Array[String]) { - Console.println( - ErrorHandler.defaultIfIOException("String")("String") - ) - } -} - -import java.io.IOException - -object ErrorHandler { - - @inline - def defaultIfIOException[T](default: => T)(closure: => T): T = { - try { - closure - } catch { - case e: IOException => - default - } - } -} - diff --git a/test/files/pos/t6547.flags b/test/files/pos/t6547.flags deleted file mode 100644 index c9b68d70dc..0000000000 --- a/test/files/pos/t6547.flags +++ /dev/null @@ -1 +0,0 @@ --optimise diff --git a/test/files/pos/t6547.scala b/test/files/pos/t6547.scala deleted file mode 100644 index 53bd798219..0000000000 --- a/test/files/pos/t6547.scala +++ /dev/null @@ -1,6 +0,0 @@ -trait ConfigurableDefault[@specialized V] { - def fillArray(arr: Array[V], v: V) = (arr: Any) match { - case x: Array[Int] => null - case x: Array[Long] => v.asInstanceOf[Long] - } -} diff --git a/test/files/pos/t8062.flags b/test/files/pos/t8062.flags deleted file mode 100644 index 49d036a887..0000000000 --- a/test/files/pos/t8062.flags +++ /dev/null @@ -1 +0,0 @@ --optimize diff --git a/test/files/pos/t8062/A_1.scala b/test/files/pos/t8062/A_1.scala deleted file mode 100644 index ca0411dae8..0000000000 --- a/test/files/pos/t8062/A_1.scala +++ /dev/null @@ -1,5 +0,0 @@ -package warmup - -object Warmup { - def filter[A](p: Any => Boolean): Any = filter[Any](p) -} diff --git a/test/files/pos/t8062/B_2.scala b/test/files/pos/t8062/B_2.scala deleted file mode 100644 index f0a6761488..0000000000 --- a/test/files/pos/t8062/B_2.scala +++ /dev/null @@ -1,3 +0,0 @@ -object Test { - warmup.Warmup.filter[Any](x => false) -} diff --git a/test/files/pos/t8306.flags b/test/files/pos/t8306.flags deleted file mode 100644 index 49d036a887..0000000000 --- a/test/files/pos/t8306.flags +++ /dev/null @@ -1 +0,0 @@ --optimize diff --git a/test/files/pos/t8306.scala b/test/files/pos/t8306.scala deleted file mode 100644 index e04b054eb9..0000000000 --- a/test/files/pos/t8306.scala +++ /dev/null @@ -1,8 +0,0 @@ -class Si8306 { - def foo: Int = 123 - lazy val extension: Int = - foo match { - case idx if idx != -1 => 15 - case _ => 17 - } -} diff --git a/test/files/pos/t8359-closelim-crash.flags b/test/files/pos/t8359-closelim-crash.flags deleted file mode 100644 index 49d036a887..0000000000 --- a/test/files/pos/t8359-closelim-crash.flags +++ /dev/null @@ -1 +0,0 @@ --optimize diff --git a/test/files/pos/t8359-closelim-crash.scala b/test/files/pos/t8359-closelim-crash.scala deleted file mode 100644 index 1413694d10..0000000000 --- a/test/files/pos/t8359-closelim-crash.scala +++ /dev/null @@ -1,23 +0,0 @@ -package test - -// This is a minimization of code that crashed the compiler during bootstrapping -// in the first iteration of https://github.com/scala/scala/pull/4373, the PR -// that adjusted the order of free and declared params in LambdaLift. - -// Was: -// java.lang.AssertionError: assertion failed: -// Record Record(<$anon: Function1>,Map(value a$1 -> Deref(LocalVar(value b)))) does not contain a field value b$1 -// at scala.tools.nsc.Global.assert(Global.scala:262) -// at scala.tools.nsc.backend.icode.analysis.CopyPropagation$copyLattice$State.getFieldNonRecordValue(CopyPropagation.scala:113) -// at scala.tools.nsc.backend.icode.analysis.CopyPropagation$copyLattice$State.getFieldNonRecordValue(CopyPropagation.scala:122) -// at scala.tools.nsc.backend.opt.ClosureElimination$ClosureElim$$anonfun$analyzeMethod$1$$anonfun$apply$2.replaceFieldAccess$1(ClosureElimination.scala:124) -class Typer { - def bar(a: Boolean, b: Boolean): Unit = { - @inline - def baz(): Unit = { - ((_: Any) => (Typer.this, a, b)).apply("") - } - ((_: Any) => baz()).apply("") - } -} - diff --git a/test/files/pos/t9123.flags b/test/files/pos/t9123.flags deleted file mode 100644 index c16e2f71dc..0000000000 --- a/test/files/pos/t9123.flags +++ /dev/null @@ -1 +0,0 @@ --optimize -Ydelambdafy:method diff --git a/test/files/pos/t9123.scala b/test/files/pos/t9123.scala deleted file mode 100644 index 22d55b4351..0000000000 --- a/test/files/pos/t9123.scala +++ /dev/null @@ -1,10 +0,0 @@ -trait Setting { - type T - def value: T -} - -object Test { - def test(x: Some[Setting]) = x match { - case Some(dep) => Some(dep.value) map (_ => true) - } -} diff --git a/test/files/pos/trait-force-info.flags b/test/files/pos/trait-force-info.flags deleted file mode 100644 index eb4d19bcb9..0000000000 --- a/test/files/pos/trait-force-info.flags +++ /dev/null @@ -1 +0,0 @@ --optimise
\ No newline at end of file diff --git a/test/files/pos/trait-force-info.scala b/test/files/pos/trait-force-info.scala deleted file mode 100644 index c2b33869c3..0000000000 --- a/test/files/pos/trait-force-info.scala +++ /dev/null @@ -1,18 +0,0 @@ -/** This does NOT crash unless it's in the interactive package. - */ - -package scala.tools.nsc -package interactive - -trait MyContextTrees { - val self: Global - val NoContext = self.analyzer.NoContext -} -// -// error: java.lang.AssertionError: assertion failed: trait Contexts.NoContext$ linkedModule: <none>List() -// at scala.Predef$.assert(Predef.scala:160) -// at scala.tools.nsc.symtab.classfile.ClassfileParser$innerClasses$.innerSymbol$1(ClassfileParser.scala:1211) -// at scala.tools.nsc.symtab.classfile.ClassfileParser$innerClasses$.classSymbol(ClassfileParser.scala:1223) -// at scala.tools.nsc.symtab.classfile.ClassfileParser.classNameToSymbol(ClassfileParser.scala:489) -// at scala.tools.nsc.symtab.classfile.ClassfileParser.sig2type$1(ClassfileParser.scala:757) -// at scala.tools.nsc.symtab.classfile.ClassfileParser.sig2type$1(ClassfileParser.scala:789) diff --git a/test/files/run/elidable-opt.scala b/test/files/run/elidable-opt.scala index ebada46de8..a2f29d2caf 100644 --- a/test/files/run/elidable-opt.scala +++ b/test/files/run/elidable-opt.scala @@ -1,6 +1,3 @@ -/* - * filter: inliner warnings; re-run with - */ import annotation._ import elidable._ diff --git a/test/files/run/lisp.check b/test/files/run/lisp.check new file mode 100644 index 0000000000..64053f26d0 --- /dev/null +++ b/test/files/run/lisp.check @@ -0,0 +1,26 @@ +(lambda (x) (+ (* x x) 1)) +(lambda (x) (+ (* x x) 1)) + +( '(1 2 3)) = (1 2 3) +(car '(1 2 3)) = 1 +(cdr '(1 2 3)) = (2 3) +(null? '(2 3)) = 0 +(null? '()) = 1 + +faculty(10) = 3628800 +faculty(10) = 3628800 +foobar = ("a" "bc" "def" "z") + +List('lambda, List('x), List('+, List('*, 'x, 'x), 1)) +(lambda (x) (+ (* x x) 1)) + +( '(1 2 3)) = (1 2 3) +(car '(1 2 3)) = 1 +(cdr '(1 2 3)) = (2 3) +(null? '(2 3)) = 0 +(null? '()) = 1 + +faculty(10) = 3628800 +faculty(10) = 3628800 +foobar = ("a" "bc" "def" "z") + diff --git a/test/files/pos/t4579.scala b/test/files/run/lisp.scala index cd1553f02a..162c7d2599 100644 --- a/test/files/pos/t4579.scala +++ b/test/files/run/lisp.scala @@ -1,5 +1,5 @@ //############################################################################ -// Lisp interpreter (revived as an optimizer test.) +// Lisp interpreter //############################################################################ //############################################################################ diff --git a/test/files/run/t7008-scala-defined.flags b/test/files/run/t7008-scala-defined.flags deleted file mode 100644 index e69de29bb2..0000000000 --- a/test/files/run/t7008-scala-defined.flags +++ /dev/null diff --git a/test/files/run/t7008-scala-defined/Test_3.scala b/test/files/run/t7008-scala-defined/Test_3.scala index 26178142ab..ee7b9d9cde 100644 --- a/test/files/run/t7008-scala-defined/Test_3.scala +++ b/test/files/run/t7008-scala-defined/Test_3.scala @@ -1,6 +1,3 @@ -/* - * filter: inliner warning; re-run with - */ import scala.reflect.runtime.universe._ object Test extends App { diff --git a/test/files/run/t7582.check b/test/files/run/t7582.check index 0cfbf08886..58d0f19f5d 100644 --- a/test/files/run/t7582.check +++ b/test/files/run/t7582.check @@ -1 +1,6 @@ +InlineHolder.scala:9: warning: p1/InlineHolder$::inlinable()I is annotated @inline but could not be inlined: +The callee p1/InlineHolder$::inlinable()I contains the instruction INVOKESTATIC p1/PackageProtectedJava.protectedMethod ()I +that would cause an IllegalAccessError when inlined into class O$. + def x = p1.InlineHolder.inlinable + ^ 2 diff --git a/test/files/run/t7582.flags b/test/files/run/t7582.flags index 422d6be431..1f45833eff 100644 --- a/test/files/run/t7582.flags +++ b/test/files/run/t7582.flags @@ -1 +1 @@ --Yopt:l:classpath
\ No newline at end of file +-Yopt:l:classpath -Yopt-warnings
\ No newline at end of file diff --git a/test/files/run/t7582/InlineHolder.scala b/test/files/run/t7582/InlineHolder.scala index 3cbf233ce1..a18b9effaa 100644 --- a/test/files/run/t7582/InlineHolder.scala +++ b/test/files/run/t7582/InlineHolder.scala @@ -1,6 +1,3 @@ -/* - * filter: inliner warning; re-run with - */ package p1 { object InlineHolder { @inline def inlinable = p1.PackageProtectedJava.protectedMethod() + 1 diff --git a/test/files/run/t7582b.check b/test/files/run/t7582b.check index 0cfbf08886..58d0f19f5d 100644 --- a/test/files/run/t7582b.check +++ b/test/files/run/t7582b.check @@ -1 +1,6 @@ +InlineHolder.scala:9: warning: p1/InlineHolder$::inlinable()I is annotated @inline but could not be inlined: +The callee p1/InlineHolder$::inlinable()I contains the instruction INVOKESTATIC p1/PackageProtectedJava.protectedMethod ()I +that would cause an IllegalAccessError when inlined into class O$. + def x = p1.InlineHolder.inlinable + ^ 2 diff --git a/test/files/run/t7582b.flags b/test/files/run/t7582b.flags index 422d6be431..1f45833eff 100644 --- a/test/files/run/t7582b.flags +++ b/test/files/run/t7582b.flags @@ -1 +1 @@ --Yopt:l:classpath
\ No newline at end of file +-Yopt:l:classpath -Yopt-warnings
\ No newline at end of file diff --git a/test/files/run/t7582b/InlineHolder.scala b/test/files/run/t7582b/InlineHolder.scala index 3cbf233ce1..a18b9effaa 100644 --- a/test/files/run/t7582b/InlineHolder.scala +++ b/test/files/run/t7582b/InlineHolder.scala @@ -1,6 +1,3 @@ -/* - * filter: inliner warning; re-run with - */ package p1 { object InlineHolder { @inline def inlinable = p1.PackageProtectedJava.protectedMethod() + 1 diff --git a/test/files/run/t7807.check b/test/files/run/t7807.check new file mode 100644 index 0000000000..fd22077f2e --- /dev/null +++ b/test/files/run/t7807.check @@ -0,0 +1,3 @@ +... +... +... diff --git a/test/files/run/t7807.scala b/test/files/run/t7807.scala new file mode 100644 index 0000000000..8e3099ec14 --- /dev/null +++ b/test/files/run/t7807.scala @@ -0,0 +1,21 @@ +object Test { + def main(args: Array[String]) { + try { + println("...") + } + finally { + try { + println("...") + } + finally { + try { + println("...") + } + catch { + case ct: scala.util.control.ControlThrowable => throw(ct) + case t: Throwable => t.printStackTrace() + } + } + } + } +} diff --git a/test/junit/scala/collection/ReusableBuildersTest.scala b/test/junit/scala/collection/ReusableBuildersTest.scala new file mode 100644 index 0000000000..8dd1a37adf --- /dev/null +++ b/test/junit/scala/collection/ReusableBuildersTest.scala @@ -0,0 +1,48 @@ +package scala.collection + +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.Test + +/* Tests various maps by making sure they all agree on the same answers. */ +@RunWith(classOf[JUnit4]) +class ReusableBuildersTest { + // GrowingBuilders are NOT reusable but can clear themselves + @Test + def test_SI8648() { + val b = collection.mutable.HashSet.newBuilder[Int] + b += 3 + b.clear + assert(!b.isInstanceOf[collection.mutable.ReusableBuilder[_,_]]) + assert(b.isInstanceOf[collection.mutable.GrowingBuilder[_,_]]) + assert(b.result == Set[Int]()) + } + + // ArrayBuilders ARE reusable, regardless of whether they returned their internal array or not + @Test + def test_SI9564() { + val b = Array.newBuilder[Float] + b += 3f + val three = b.result + b.clear + b ++= (1 to 16).map(_.toFloat) + val sixteen = b.result + b.clear + b += 0f + val zero = b.result + assert(b.isInstanceOf[collection.mutable.ReusableBuilder[_,_]]) + assert(three.toList == 3 :: Nil) + assert(sixteen.toList == (1 to 16)) + assert(zero.toList == 0 :: Nil) + } + + @Test + def test_reusability() { + val bl = List.newBuilder[String] + val bv = Vector.newBuilder[String] + val ba = collection.mutable.ArrayBuffer.newBuilder[String] + assert(bl.isInstanceOf[collection.mutable.ReusableBuilder[_, _]]) + assert(bv.isInstanceOf[collection.mutable.ReusableBuilder[_, _]]) + assert(!ba.isInstanceOf[collection.mutable.ReusableBuilder[_, _]]) + } +} diff --git a/test/junit/scala/issues/OptimizedBytecodeTest.scala b/test/junit/scala/issues/OptimizedBytecodeTest.scala new file mode 100644 index 0000000000..3c6f1ff25e --- /dev/null +++ b/test/junit/scala/issues/OptimizedBytecodeTest.scala @@ -0,0 +1,331 @@ +package scala.issues + +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 + +object OptimizedBytecodeTest extends ClearAfterClass.Clearable { + val args = "-Yopt:l:classpath -Yopt-warnings" + var compiler = newCompiler(extraArgs = args) + def clear(): Unit = { compiler = null } +} + +@RunWith(classOf[JUnit4]) +class OptimizedBytecodeTest extends ClearAfterClass { + ClearAfterClass.stateToClear = OptimizedBytecodeTest + + val compiler = OptimizedBytecodeTest.compiler + + @Test + def t2171(): Unit = { + val code = + """class C { + | final def m(msg: => String) = try 0 catch { case ex: Throwable => println(msg) } + | def t(): Unit = while (true) m("...") + |} + """.stripMargin + val List(c) = compileClasses(compiler)(code) + assertSameCode(getSingleMethod(c, "t").instructions.dropNonOp, List(Label(0), Jump(GOTO, Label(0)))) + } + + @Test + def t3430(): Unit = { + val code = + """class C { + | final def m(f: String => Boolean) = f("a") + | def t(): Boolean = + | m { s1 => + | m { s2 => + | while (true) { } + | true + | } + | } + |} + """.stripMargin + val List(c) = compileClasses(compiler)(code) + + assertEquals( + getSingleMethod(c, "t").instructions.summary, + List(LDC, ASTORE, ALOAD /*0*/, ALOAD /*1*/, "C$$$anonfun$1", IRETURN)) + + assertEquals( + getSingleMethod(c, "C$$$anonfun$1").instructions.summary, + List(LDC, "C$$$anonfun$2", IRETURN)) + + assertEquals( + getSingleMethod(c, "C$$$anonfun$2").instructions.summary, + List(-1 /*A*/, GOTO /*A*/)) + } + + @Test + def t3252(): Unit = { + val code = + """class C { + | def t(x: Boolean): Thread = { + | g { + | x match { + | case false => Tat.h { } + | } + | } + | } + | + | private def g[T](block: => T) = ??? + |} + |object Tat { + | def h(block: => Unit): Nothing = ??? + |} + """.stripMargin + val List(c, t, tMod) = compileClasses(compiler)(code, allowMessage = _.msg.contains("not be exhaustive")) + assertEquals( + getSingleMethod(c, "t").instructions.summary, + List(GETSTATIC, "$qmark$qmark$qmark", ATHROW)) + } + + @Test + def t6157(): Unit = { + val code = + """class C { + | def t = println(ErrorHandler.defaultIfIOException("String")("String")) + |} + |object ErrorHandler { + | import java.io.IOException + | @inline + | def defaultIfIOException[T](default: => T)(closure: => T): T = try closure catch { + | case e: IOException => default + | } + |} + """.stripMargin + + val msg = + """ErrorHandler$::defaultIfIOException(Lscala/Function0;Lscala/Function0;)Ljava/lang/Object; is annotated @inline but could not be inlined: + |The operand stack at the callsite in C::t()V contains more values than the + |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) + } + + @Test + def t6547(): Unit = { // "pos" test -- check that it compiles + val code = + """trait ConfigurableDefault[@specialized V] { + | def fillArray(arr: Array[V], v: V) = (arr: Any) match { + | case x: Array[Int] => null + | case x: Array[Long] => v.asInstanceOf[Long] + | } + |} + """.stripMargin + compileClasses(compiler)(code) + } + + @Test + def t8062(): Unit = { + val c1 = + """package warmup + |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 = OptimizedBytecodeTest.args) + assertInvoke(getSingleMethod(c, "t"), "warmup/Warmup$", "filter") + } + + @Test + def t8306(): Unit = { // "pos" test + val code = + """class C { + | def foo: Int = 123 + | lazy val extension: Int = foo match { + | case idx if idx != -1 => 15 + | case _ => 17 + | } + |} + """.stripMargin + compileClasses(compiler)(code) + } + + @Test + def t8359(): Unit = { // "pos" test + // This is a minimization of code that crashed the compiler during bootstrapping + // in the first iteration of https://github.com/scala/scala/pull/4373, the PR + // that adjusted the order of free and declared params in LambdaLift. + + // Was: + // java.lang.AssertionError: assertion failed: + // Record Record(<$anon: Function1>,Map(value a$1 -> Deref(LocalVar(value b)))) does not contain a field value b$1 + // at scala.tools.nsc.Global.assert(Global.scala:262) + // at scala.tools.nsc.backend.icode.analysis.CopyPropagation$copyLattice$State.getFieldNonRecordValue(CopyPropagation.scala:113) + // at scala.tools.nsc.backend.icode.analysis.CopyPropagation$copyLattice$State.getFieldNonRecordValue(CopyPropagation.scala:122) + // at scala.tools.nsc.backend.opt.ClosureElimination$ClosureElim$$anonfun$analyzeMethod$1$$anonfun$apply$2.replaceFieldAccess$1(ClosureElimination.scala:124) + val code = + """package test + |class Typer { + | def bar(a: Boolean, b: Boolean): Unit = { + | @inline + | def baz(): Unit = { + | ((_: Any) => (Typer.this, a, b)).apply("") + | } + | ((_: Any) => baz()).apply("") + | } + |} + """.stripMargin + compileClasses(compiler)(code) + } + + @Test + def t9123(): Unit = { // "pos" test + val code = + """trait Setting { + | type T + | def value: T + |} + |object Test { + | def test(x: Some[Setting]) = x match { + | case Some(dep) => Some(dep.value) map (_ => true) + | } + |} + """.stripMargin + compileClasses(compiler)(code) + } + + @Test + def traitForceInfo(): Unit = { + // This did NOT crash unless it's in the interactive package. + // error: java.lang.AssertionError: assertion failed: trait Contexts.NoContext$ linkedModule: <none>List() + // at scala.Predef$.assert(Predef.scala:160) + // at scala.tools.nsc.symtab.classfile.ClassfileParser$innerClasses$.innerSymbol$1(ClassfileParser.scala:1211) + // at scala.tools.nsc.symtab.classfile.ClassfileParser$innerClasses$.classSymbol(ClassfileParser.scala:1223) + // at scala.tools.nsc.symtab.classfile.ClassfileParser.classNameToSymbol(ClassfileParser.scala:489) + // at scala.tools.nsc.symtab.classfile.ClassfileParser.sig2type$1(ClassfileParser.scala:757) + // at scala.tools.nsc.symtab.classfile.ClassfileParser.sig2type$1(ClassfileParser.scala:789) + val code = + """package scala.tools.nsc + |package interactive + | + |trait MyContextTrees { + | val self: Global + | val NoContext = self.analyzer.NoContext + |} + """.stripMargin + compileClasses(compiler)(code) + } + + @Test + def t9160(): Unit = { + val code = + """class C { + | def getInt: Int = 0 + | def t(trees: Object): Int = { + | trees match { + | case Some(elems) => + | case tree => getInt + | } + | 55 + | } + |} + """.stripMargin + val List(c) = compileClasses(compiler)(code) + assertEquals( + getSingleMethod(c, "t").instructions.summary, + List( + ALOAD /*1*/, INSTANCEOF /*Some*/, IFNE /*A*/, + ALOAD /*0*/, "getInt", POP, + -1 /*A*/, BIPUSH, IRETURN)) + } + + @Test + def t8796(): Unit = { + val code = + """final class C { + | def pr(): Unit = () + | def t(index: Int): Unit = index match { + | case 0 => pr() + | case 1 => pr() + | case _ => t(index - 2) + | } + |} + """.stripMargin + val List(c) = compileClasses(compiler)(code) + assertEquals( + getSingleMethod(c, "t").instructions.summary, + List( + -1 /*A*/, ILOAD /*1*/, TABLESWITCH, + -1, ALOAD, "pr", RETURN, + -1, ALOAD, "pr", RETURN, + -1, ILOAD, ICONST_2, ISUB, ISTORE, GOTO /*A*/)) + } + + @Test + def t8524(): Unit = { + val c1 = + """package library + |object Library { + | @inline def pleaseInlineMe() = 1 + | object Nested { @inline def pleaseInlineMe() = 2 } + |} + """.stripMargin + + val c2 = + """class C { + | def t = library.Library.pleaseInlineMe() + library.Library.Nested.pleaseInlineMe() + |} + """.stripMargin + + val cls = compileClassesSeparately(List(c1, c2), extraArgs = OptimizedBytecodeTest.args) + val c = cls.find(_.name == "C").get + assertEquals( + getSingleMethod(c, "t").instructions.summary, + 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)) + } + + @Test + def privateInline(): Unit = { + val code = + """final class C { + | private var x1 = false + | var x2 = false + | + | @inline private def wrapper1[T](body: => T): T = { + | val saved = x1 + | x1 = true + | try body + | finally x1 = saved + | } + | + | @inline private def wrapper2[T](body: => T): T = { + | val saved = x2 + | x2 = true + | try body + | finally x2 = saved + | } + | // inlined + | def f1a() = wrapper1(5) + | // not inlined: even after inlining `identity`, the Predef module is already on the stack for the + | // subsequent null check (the receiver of an inlined method, in this case Predef, is checked for + | // nullness, to ensure an NPE is thrown) + | def f1b() = identity(wrapper1(5)) + | + | def f2a() = wrapper2(5) // inlined + | 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") + } +} diff --git a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala index 342f403426..0d353e930e 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala @@ -50,9 +50,11 @@ object CodeGenTools { } def newCompilerWithoutVirtualOutdir(defaultArgs: String = "-usejavacp", extraArgs: String = ""): Global = { - val settings = new Settings() + def showError(s: String) = throw new Exception(s) + val settings = new Settings(showError) val args = (CommandLineParser tokenize defaultArgs) ++ (CommandLineParser tokenize extraArgs) - settings.processArguments(args, processAll = true) + val (_, nonSettingsArgs) = settings.processArguments(args, processAll = true) + if (nonSettingsArgs.nonEmpty) showError("invalid compiler flags: " + nonSettingsArgs.mkString(" ")) new Global(settings, new StoreReporter) } diff --git a/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala b/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala new file mode 100644 index 0000000000..80cde6c9a9 --- /dev/null +++ b/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala @@ -0,0 +1,70 @@ +package scala.tools.nsc +package backend.jvm + +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 + +object StringConcatTest extends ClearAfterClass.Clearable { + var compiler = newCompiler() + def clear(): Unit = { compiler = null } +} + +@RunWith(classOf[JUnit4]) +class StringConcatTest extends ClearAfterClass { + ClearAfterClass.stateToClear = StringConcatTest + val compiler = StringConcatTest.compiler + + val commonPreInstructions = List(Label(0), LineNumber(1, Label(0)), TypeOp(NEW, "java/lang/StringBuilder"), Op(DUP), Invoke(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false), Ldc(LDC, "abc"), Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false), VarOp(ALOAD, 0)) + + val commonPostInstructions = List(Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false), Op(ARETURN), Label(12)) + + def instructionsWithCommonParts(instructions: List[Instruction]) = commonPreInstructions ++ instructions ++ commonPostInstructions + + def instructionsForResultMethod(code: String): List[Instruction] = { + val methods = compileMethods(compiler)(code) + val resultMethod = methods.find(_.name == "result").get + instructionsFromMethod(resultMethod) + } + + @Test + def concatStringToStringBuilder: Unit = { + val code = """ def string = "def"; def result = "abc" + string """ + val actualInstructions = instructionsForResultMethod(code) + val expectedInstructions = instructionsWithCommonParts(List(Invoke(INVOKEVIRTUAL, "C", "string", "()Ljava/lang/String;", false), Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false))) + assertSameCode(actualInstructions, expectedInstructions) + } + + @Test + def concatStringBufferToStringBuilder: Unit = { + val code = """ def stringBuffer = new java.lang.StringBuffer("def"); def result = "abc" + stringBuffer """ + val actualInstructions = instructionsForResultMethod(code) + val expectedInstructions = instructionsWithCommonParts(List(Invoke(INVOKEVIRTUAL, "C", "stringBuffer", "()Ljava/lang/StringBuffer;", false), Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/StringBuffer;)Ljava/lang/StringBuilder;", false))) + assertSameCode(actualInstructions, expectedInstructions) + } + + @Test + def concatCharSequenceToStringBuilder: Unit = { + val code = """ def charSequence: CharSequence = "def"; def result = "abc" + charSequence """ + val actualInstructions = instructionsForResultMethod(code) + val expectedInstructions = instructionsWithCommonParts(List(Invoke(INVOKEVIRTUAL, "C", "charSequence", "()Ljava/lang/CharSequence;", false), Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/CharSequence;)Ljava/lang/StringBuilder;", false))) + assertSameCode(actualInstructions, expectedInstructions) + } + + @Test + def concatIntToStringBuilder: Unit = { + val code = """ def int = 123; def result = "abc" + int """ + val actualInstructions = instructionsForResultMethod(code) + val expectedInstructions = instructionsWithCommonParts(List(Invoke(INVOKEVIRTUAL, "C", "int", "()I", false), Invoke(INVOKESTATIC, "scala/runtime/BoxesRunTime", "boxToInteger", "(I)Ljava/lang/Integer;", false), Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuilder;", false))) + assertSameCode(actualInstructions, expectedInstructions) + } +} 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 a685ae7dd5..99acb318de 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala @@ -96,10 +96,22 @@ class SimplifyJumpsTest { instructionsFromMethod(method), List(VarOp(ILOAD, 1), Jump(IFLT, Label(3))) ::: rest.tail ) - // no label allowed between begin and rest. if there's another label, then there could be a - // branch that label. eliminating the GOTO would change the behavior. - val nonOptMethod = genMethod()(begin ::: Label(22) :: rest: _*) - assertFalse(LocalOptImpls.simplifyJumps(nonOptMethod)) + // branch over goto is OK even if there's a label in between, if that label is not a jump target + val withNonJumpTargetLabel = genMethod()(begin ::: Label(22) :: rest: _*) + assertTrue(LocalOptImpls.simplifyJumps(withNonJumpTargetLabel)) + assertSameCode( + instructionsFromMethod(withNonJumpTargetLabel), + List(VarOp(ILOAD, 1), Jump(IFLT, Label(3)), Label(22)) ::: rest.tail ) + + // if the Label(22) between IFGE and GOTO is the target of some jump, we cannot rewrite the IFGE + // and remove the GOTO: removing the GOTO would change semantics. However, the jump that targets + // Label(22) will be re-written (jump-chain collapsing), so in a second round, the IFGE is still + // rewritten to IFLT + val twoRounds = genMethod()(List(VarOp(ILOAD, 1), Jump(IFLE, Label(22))) ::: begin ::: Label(22) :: rest: _*) + assertTrue(LocalOptImpls.simplifyJumps(twoRounds)) + assertSameCode( + instructionsFromMethod(twoRounds), + List(VarOp(ILOAD, 1), Jump(IFLE, Label(3)), VarOp(ILOAD, 1), Jump(IFLT, Label(3)), Label(22)) ::: rest.tail ) } @Test @@ -167,6 +179,9 @@ class SimplifyJumpsTest { VarOp(ILOAD, 1), Jump(IFGE, Label(target)), + VarOp(ILOAD, 1), // some code to prevent rewriting the conditional jump + Op(IRETURN), + Label(4), Jump(GOTO, Label(3)), diff --git a/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala b/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala index ec4621b230..3fc3144eb2 100644 --- a/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala +++ b/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala @@ -134,4 +134,29 @@ class PatmatBytecodeTest extends ClearAfterClass { NEW, DUP, ALOAD /*1*/, "<init>", ATHROW, /*R*/ -1, ALOAD /*2*/, ARETURN)) } + + @Test + def t6941(): Unit = { + val code = + """class C { + | def a(xs: List[Int]) = xs match { + | case x :: _ => x + | } + | def b(xs: List[Int]) = xs match { + | case xs: ::[Int] => xs.head + | } + |} + """.stripMargin + val c = compileClasses(optCompiler)(code, allowMessage = _.msg.contains("may not be exhaustive")).head + + val expected = List( + ALOAD /*1*/ , INSTANCEOF /*::*/ , IFEQ /*A*/ , + ALOAD, CHECKCAST /*::*/ , "head", "unboxToInt", + ISTORE, GOTO /*B*/ , + -1 /*A*/ , NEW /*MatchError*/ , DUP, ALOAD /*1*/ , "<init>", ATHROW, + -1 /*B*/ , ILOAD, IRETURN) + + assertEquals(textify(findAsmMethod(c, "a")), getSingleMethod(c, "a").instructions.summary, expected) + assertEquals(textify(findAsmMethod(c, "b")), getSingleMethod(c, "b").instructions.summary, expected) + } } diff --git a/test/pending/run/private-inline.check b/test/pending/run/private-inline.check deleted file mode 100644 index e71aec2fcf..0000000000 --- a/test/pending/run/private-inline.check +++ /dev/null @@ -1,13 +0,0 @@ -private-inline.scala:24: warning: Could not inline required method wrapper1 because callee contains exception handlers / finally clause, and is invoked with non-empty operand stack. - def f1b() = identity(wrapper1(5)) - ^ -private-inline.scala:24: warning: At the end of the day, could not inline @inline-marked method wrapper1 - def f1b() = identity(wrapper1(5)) - ^ -private-inline.scala:29: warning: Could not inline required method wrapper2 because callee contains exception handlers / finally clause, and is invoked with non-empty operand stack. - def f2b() = identity(wrapper2(5)) - ^ -private-inline.scala:29: warning: At the end of the day, could not inline @inline-marked method wrapper2 - def f2b() = identity(wrapper2(5)) - ^ -20 diff --git a/test/pending/run/private-inline.flags b/test/pending/run/private-inline.flags deleted file mode 100644 index c550fdce16..0000000000 --- a/test/pending/run/private-inline.flags +++ /dev/null @@ -1 +0,0 @@ --optimise -Yinline-warnings -Ybackend:GenASM diff --git a/test/pending/run/private-inline.scala b/test/pending/run/private-inline.scala deleted file mode 100644 index 60fef9efca..0000000000 --- a/test/pending/run/private-inline.scala +++ /dev/null @@ -1,52 +0,0 @@ - -final class A { - private var x1 = false - var x2 = false - - // manipulates private var - @inline private def wrapper1[T](body: => T): T = { - val saved = x1 - x1 = true - try body - finally x1 = saved - } - // manipulates public var - @inline private def wrapper2[T](body: => T): T = { - val saved = x2 - x2 = true - try body - finally x2 = saved - } - - // not inlined - def f1a() = wrapper1(5) - // inlined! - def f1b() = identity(wrapper1(5)) - - // not inlined - def f2a() = wrapper2(5) - // inlined! - def f2b() = identity(wrapper2(5)) -} - -object Test { - def methodClasses = List("f1a", "f2a") map ("A$$anonfun$" + _ + "$1") - - def main(args: Array[String]): Unit = { - val a = new A - import a._ - println(f1a() + f1b() + f2a() + f2b()) - - // Don't know how else to test this: all these should have been - // inlined, so all should fail. - methodClasses foreach { clazz => - - val foundClass = ( - try Class.forName(clazz) - catch { case _: Throwable => null } - ) - - assert(foundClass == null, foundClass) - } - } -} |