summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/files/run/colltest1.scala2
-rw-r--r--test/files/run/compiler-asSeenFrom.scala2
-rw-r--r--test/files/run/existentials-in-compiler.scala2
-rw-r--r--test/files/run/is-valid-num.scala2
-rw-r--r--test/files/run/iterator-from.scala2
-rw-r--r--test/files/run/mapConserve.scala2
-rw-r--r--test/files/run/pc-conversions.scala2
-rw-r--r--test/files/run/stringinterpolation_macro-run.scala2
-rw-r--r--test/files/run/synchronized.check4
-rw-r--r--test/files/run/t7096.scala2
-rw-r--r--test/files/run/t7582.check4
-rw-r--r--test/files/run/t7582b.check4
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala44
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala4
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala8
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala23
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala4
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala146
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala4
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerSeparateCompilationTest.scala3
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala84
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala3
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala3
23 files changed, 304 insertions, 52 deletions
diff --git a/test/files/run/colltest1.scala b/test/files/run/colltest1.scala
index e0ec378585..de8780a050 100644
--- a/test/files/run/colltest1.scala
+++ b/test/files/run/colltest1.scala
@@ -1,5 +1,5 @@
/*
- * filter: inliner warnings; re-run with -Yinline-warnings for details
+ * filter: inliner warnings; re-run with
*/
import scala.collection._
import scala.language.postfixOps
diff --git a/test/files/run/compiler-asSeenFrom.scala b/test/files/run/compiler-asSeenFrom.scala
index 677dd40ddc..a60c2e8925 100644
--- a/test/files/run/compiler-asSeenFrom.scala
+++ b/test/files/run/compiler-asSeenFrom.scala
@@ -1,5 +1,5 @@
/*
- * filter: inliner warning; re-run with -Yinline-warnings for details
+ * filter: inliner warning; re-run with
*/
import scala.tools.nsc._
import scala.tools.partest.DirectTest
diff --git a/test/files/run/existentials-in-compiler.scala b/test/files/run/existentials-in-compiler.scala
index dfc7048b31..e516eddf95 100644
--- a/test/files/run/existentials-in-compiler.scala
+++ b/test/files/run/existentials-in-compiler.scala
@@ -1,5 +1,5 @@
/*
- * filter: inliner warnings; re-run with -Yinline-warnings for details
+ * filter: inliner warnings; re-run with
*/
import scala.tools.nsc._
import scala.tools.partest.CompilerTest
diff --git a/test/files/run/is-valid-num.scala b/test/files/run/is-valid-num.scala
index 4ab2fac8dd..156121cab5 100644
--- a/test/files/run/is-valid-num.scala
+++ b/test/files/run/is-valid-num.scala
@@ -1,5 +1,5 @@
/*
- * filter: inliner warnings; re-run with -Yinline-warnings for details
+ * filter: inliner warnings; re-run with
*/
object Test {
def x = BigInt("10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
diff --git a/test/files/run/iterator-from.scala b/test/files/run/iterator-from.scala
index e2ca5864ea..e7ba1aeb28 100644
--- a/test/files/run/iterator-from.scala
+++ b/test/files/run/iterator-from.scala
@@ -1,5 +1,5 @@
/* This file tests iteratorFrom, keysIteratorFrom, and valueIteratorFrom on various sorted sets and maps
- * filter: inliner warnings; re-run with -Yinline-warnings for details
+ * filter: inliner warnings; re-run with
*/
import scala.util.{Random => R}
diff --git a/test/files/run/mapConserve.scala b/test/files/run/mapConserve.scala
index f52af3b9f4..c17754283a 100644
--- a/test/files/run/mapConserve.scala
+++ b/test/files/run/mapConserve.scala
@@ -1,5 +1,5 @@
/*
- * filter: inliner warnings; re-run with -Yinline-warnings for details
+ * filter: inliner warnings; re-run with
*/
import scala.annotation.tailrec
import scala.collection.mutable.ListBuffer
diff --git a/test/files/run/pc-conversions.scala b/test/files/run/pc-conversions.scala
index 5fecac9d94..d4ae305aa7 100644
--- a/test/files/run/pc-conversions.scala
+++ b/test/files/run/pc-conversions.scala
@@ -1,5 +1,5 @@
/*
- * filter: inliner warning; re-run with -Yinline-warnings for details
+ * filter: inliner warning; re-run with
*/
import collection._
diff --git a/test/files/run/stringinterpolation_macro-run.scala b/test/files/run/stringinterpolation_macro-run.scala
index e18375d521..ae7c0e5d7a 100644
--- a/test/files/run/stringinterpolation_macro-run.scala
+++ b/test/files/run/stringinterpolation_macro-run.scala
@@ -1,5 +1,5 @@
/*
- * filter: inliner warnings; re-run with -Yinline-warnings for details
+ * filter: inliner warnings; re-run with
*/
object Test extends App {
diff --git a/test/files/run/synchronized.check b/test/files/run/synchronized.check
index eab191b4ed..9add05ea0c 100644
--- a/test/files/run/synchronized.check
+++ b/test/files/run/synchronized.check
@@ -1,4 +1,8 @@
+#partest !-Ybackend:GenBCode
warning: there were 14 inliner warnings; re-run with -Yinline-warnings for details
+#partest -Ybackend:GenBCode
+warning: there were 14 inliner warnings; re-run with -Yopt-warnings for details
+#partest
.|. c1.f1: OK
.|. c1.fi: OK
.|... c1.fv: OK
diff --git a/test/files/run/t7096.scala b/test/files/run/t7096.scala
index 872562dd4d..f723d70abe 100644
--- a/test/files/run/t7096.scala
+++ b/test/files/run/t7096.scala
@@ -1,5 +1,5 @@
/*
- * filter: inliner warning; re-run with -Yinline-warnings for details
+ * filter: inliner warning; re-run with
*/
import scala.tools.partest._
import scala.tools.nsc._
diff --git a/test/files/run/t7582.check b/test/files/run/t7582.check
index cd951d8d4f..2a11210000 100644
--- a/test/files/run/t7582.check
+++ b/test/files/run/t7582.check
@@ -1,2 +1,6 @@
+#partest !-Ybackend:GenBCode
warning: there was one inliner warning; re-run with -Yinline-warnings for details
+#partest -Ybackend:GenBCode
+warning: there was one inliner warning; re-run with -Yopt-warnings for details
+#partest
2
diff --git a/test/files/run/t7582b.check b/test/files/run/t7582b.check
index cd951d8d4f..2a11210000 100644
--- a/test/files/run/t7582b.check
+++ b/test/files/run/t7582b.check
@@ -1,2 +1,6 @@
+#partest !-Ybackend:GenBCode
warning: there was one inliner warning; re-run with -Yinline-warnings for details
+#partest -Ybackend:GenBCode
+warning: there was one inliner warning; re-run with -Yopt-warnings for details
+#partest
2
diff --git a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala
index c64f6e7f10..5d5215d887 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala
@@ -6,11 +6,12 @@ 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, LabelNode, ClassNode, MethodNode}
+import scala.tools.asm.tree.{ClassNode, MethodNode}
import scala.tools.cmd.CommandLineParser
import scala.tools.nsc.backend.jvm.opt.LocalOpt
import scala.tools.nsc.io.AbstractFile
-import scala.tools.nsc.settings.{MutableSettings, ScalaSettings}
+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._
@@ -52,7 +53,7 @@ object CodeGenTools {
val settings = new Settings()
val args = (CommandLineParser tokenize defaultArgs) ++ (CommandLineParser tokenize extraArgs)
settings.processArguments(args, processAll = true)
- new Global(settings)
+ new Global(settings, new StoreReporter)
}
def newRun(compiler: Global): compiler.Run = {
@@ -61,6 +62,8 @@ object CodeGenTools {
new compiler.Run()
}
+ 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])] = {
@@ -75,9 +78,18 @@ object CodeGenTools {
files(outDir)
}
- def compile(compiler: Global)(scalaCode: String, javaCode: List[(String, String)] = Nil): List[(String, Array[Byte])] = {
+ 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)
}
@@ -90,7 +102,7 @@ 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 = ""): List[(String, Array[Byte])] = {
+ def compileSeparately(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"
@@ -98,6 +110,8 @@ object CodeGenTools {
for (code <- codes) {
val compiler = newCompilerWithoutVirtualOutdir(extraArgs = argsWithOutDir)
new compiler.Run().compileSources(List(makeSourceFile(code, "unitTestSource.scala")))
+ checkReport(compiler, allowMessage)
+ afterEach(outDir)
}
val classfiles = getGeneratedClassfiles(outDir)
@@ -105,29 +119,29 @@ object CodeGenTools {
classfiles
}
- def compileClassesSeparately(codes: List[String], extraArgs: String = "") = {
- readAsmClasses(compileSeparately(codes, extraArgs))
+ def compileClassesSeparately(codes: List[String], extraArgs: String = "", allowMessage: StoreReporter#Info => Boolean = _ => false, afterEach: AbstractFile => Unit = _ => ()) = {
+ readAsmClasses(compileSeparately(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): List[ClassNode] = {
- readAsmClasses(compile(compiler)(code, javaCode))
+ 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): List[MethodNode] = {
- compileClasses(compiler)(s"class C { $code }").head.methods.asScala.toList.filterNot(_.name == "<init>")
+ 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): List[Instruction] = {
- val List(m) = compileMethods(compiler)(code)
+ 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): Method = {
- val List(m) = compileMethods(compiler)(code)
+ def singleMethod(compiler: Global)(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): Method = {
+ val List(m) = compileMethods(compiler)(code, allowMessage = allowMessage)
convertMethod(m)
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala b/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala
index 94877fb037..4086f7dd7b 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala
@@ -89,6 +89,10 @@ class DirectCompileTest extends ClearAfterClass {
case Invoke(_, "B", "f", _, _) => true
case _ => false
}, ins)
+ }
+ @Test
+ def compileErroneous(): Unit = {
+ compileClasses(compiler)("class C { def f: String = 1 }", allowMessage = _.msg contains "type mismatch")
}
}
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 761f214f82..1b6c080234 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala
@@ -15,6 +15,8 @@ import CodeGenTools._
import scala.tools.partest.ASMConverters
import ASMConverters._
+import BackendReporting._
+
import scala.collection.convert.decorateAsScala._
@RunWith(classOf[JUnit4])
@@ -39,7 +41,7 @@ class BTypesFromClassfileTest {
if (checked(fromSym.internalName)) checked
else {
assert(fromSym == fromClassfile, s"$fromSym != $fromClassfile")
- sameInfo(fromSym.info, fromClassfile.info, checked + fromSym.internalName)
+ sameInfo(fromSym.info.get, fromClassfile.info.get, checked + fromSym.internalName)
}
}
@@ -73,7 +75,7 @@ class BTypesFromClassfileTest {
// and anonymous classes as members of the outer class. But not for unpickled symbols).
// The fromClassfile info has all nested classes, including anonymous and local. So we filter
// them out: member classes are identified by having the `outerName` defined.
- val memberClassesFromClassfile = fromClassfile.nestedClasses.filter(_.info.nestedInfo.get.outerName.isDefined)
+ val memberClassesFromClassfile = fromClassfile.nestedClasses.filter(_.info.get.nestedInfo.get.outerName.isDefined)
// Sorting is required: the backend sorts all InnerClass entries by internalName before writing
// them to the classfile (to make it deterministic: the entries are collected in a Set during
// code generation).
@@ -85,7 +87,7 @@ class BTypesFromClassfileTest {
clearCache()
val fromSymbol = classBTypeFromSymbol(classSym)
clearCache()
- val fromClassfile = bTypes.classBTypeFromParsedClassfile(fromSymbol.internalName).get
+ val fromClassfile = bTypes.classBTypeFromParsedClassfile(fromSymbol.internalName)
sameBType(fromSymbol, fromClassfile)
}
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 d7344ae61f..9fda034a04 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala
@@ -11,27 +11,29 @@ import org.junit.Assert._
import scala.tools.asm.tree._
import scala.tools.asm.tree.analysis._
+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.convert.decorateAsScala._
@RunWith(classOf[JUnit4])
class CallGraphTest {
- val compiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:inline-global")
+ val compiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:inline-global -Yopt-warnings")
import compiler.genBCode.bTypes._
// allows inspecting the caches after a compilation run
val notPerRun: List[Clearable] = List(classBTypeFromInternalName, byteCodeRepository.classes, callGraph.callsites)
notPerRun foreach compiler.perRunCaches.unrecordCache
- def compile(code: String): List[ClassNode] = {
+ def compile(code: String, allowMessage: StoreReporter#Info => Boolean): List[ClassNode] = {
notPerRun.foreach(_.clear())
- compileClasses(compiler)(code)
+ compileClasses(compiler)(code, allowMessage = allowMessage)
}
def callsInMethod(methodNode: MethodNode): List[MethodInsnNode] = methodNode.instructions.iterator.asScala.collect({
@@ -69,7 +71,20 @@ class CallGraphTest {
// Get the ClassNodes from the code repo (don't use the unparsed ClassNodes returned by compile).
// The callGraph.callsites map is indexed by instructions of those ClassNodes.
- val List(cCls, cMod, dCls, testCls) = compile(code).map(c => byteCodeRepository.classNode(c.name).get)
+
+ val ok = Set(
+ "D::f1()I is annotated @inline but cannot be inlined: the method is not final and may be overridden", // only one warning for D.f1: C.f1 is not annotated @inline
+ "C::f3()I is annotated @inline but cannot be inlined: the method is not final and may be overridden", // only one warning for C.f3: D.f3 does not have @inline (and it would also be safe to inline)
+ "C::f7()I is annotated @inline but cannot be inlined: the method is not final and may be overridden", // two warnings (the error message mentions C.f7 even if the receiver type is D, because f7 is inherited from C)
+ "operand stack at the callsite in Test::t1(LC;)I contains more values",
+ "operand stack at the callsite in Test::t2(LD;)I contains more values")
+ var msgCount = 0
+ val checkMsg = (m: StoreReporter#Info) => {
+ msgCount += 1
+ ok exists (m.msg contains _)
+ }
+ val List(cCls, cMod, dCls, testCls) = compile(code, checkMsg).map(c => byteCodeRepository.classNode(c.name).get)
+ assert(msgCount == 6, msgCount)
val List(cf1, cf2, cf3, cf4, cf5, cf6, cf7) = cCls.methods.iterator.asScala.filter(_.name.startsWith("f")).toList.sortBy(_.name)
val List(df1, df3) = dCls.methods.iterator.asScala.filter(_.name.startsWith("f")).toList.sortBy(_.name)
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 4e12ed757e..57088bdd2f 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala
@@ -14,6 +14,8 @@ import ASMConverters._
import AsmUtils._
import scala.tools.testing.ClearAfterClass
+import BackendReporting._
+
import scala.collection.convert.decorateAsScala._
object InlineInfoTest extends ClearAfterClass.Clearable {
@@ -53,7 +55,7 @@ class InlineInfoTest {
|class C extends T with U
""".stripMargin
val classes = compile(code)
- val fromSyms = classes.map(c => compiler.genBCode.bTypes.classBTypeFromInternalName(c.name).info.inlineInfo)
+ val fromSyms = classes.map(c => compiler.genBCode.bTypes.classBTypeFromInternalName(c.name).info.get.inlineInfo)
val fromAttrs = classes.map(c => {
assert(c.attrs.asScala.exists(_.isInstanceOf[InlineInfoAttribute]), c.attrs)
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala
new file mode 100644
index 0000000000..fedc074a15
--- /dev/null
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala
@@ -0,0 +1,146 @@
+package scala.tools.nsc
+package backend.jvm
+package opt
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Test
+import scala.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.backend.jvm.opt.BytecodeUtils.AsmAnalyzer
+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.convert.decorateAsScala._
+import scala.tools.testing.ClearAfterClass
+
+object InlineWarningTest extends ClearAfterClass.Clearable {
+ val argsNoWarn = "-Ybackend:GenBCode -Yopt:l:classpath"
+ val args = argsNoWarn + " -Yopt-warnings"
+ var compiler = newCompiler(extraArgs = args)
+ def clear(): Unit = { compiler = null }
+}
+
+@RunWith(classOf[JUnit4])
+class InlineWarningTest extends ClearAfterClass {
+ ClearAfterClass.stateToClear = InlineWarningTest
+
+ val compiler = InlineWarningTest.compiler
+
+ def compile(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] = {
+ compileClasses(compiler)(scalaCode, javaCode, allowMessage)
+ }
+
+ @Test
+ def nonFinal(): Unit = {
+ val code =
+ """class C {
+ | @inline def m1 = 1
+ |}
+ |trait T {
+ | @inline def m2 = 1
+ |}
+ |class D extends C with T
+ |
+ |class Test {
+ | def t1(c: C, t: T, d: D) = c.m1 + t.m2 + d.m1 + d.m2
+ |}
+ """.stripMargin
+ var count = 0
+ val warns = Set(
+ "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 _)})
+ assert(count == 4, count)
+ }
+
+ @Test
+ def traitMissingImplClass(): Unit = {
+ val codeA = "trait T { @inline final def f = 1 }"
+ val codeB = "class C { def t1(t: T) = t.f }"
+
+ val removeImpl = (outDir: AbstractFile) => {
+ val f = outDir.lookupName("T$class.class", directory = false)
+ if (f != null) f.delete()
+ }
+
+ val warn =
+ """T::f()I is annotated @inline but cannot be inlined: the trait method call could not be rewritten to the static implementation method. Possible reason:
+ |The method f(LT;)I could not be found in the class T$class or any of its parents.
+ |Note that the following parent classes could not be found on the classpath: T$class""".stripMargin
+
+ var c = 0
+ compileSeparately(List(codeA, codeB), extraArgs = InlineWarningTest.args, afterEach = removeImpl, allowMessage = i => {c += 1; i.msg contains warn})
+ assert(c == 1, c)
+
+ // only summary here
+ compileSeparately(List(codeA, codeB), extraArgs = InlineWarningTest.argsNoWarn, afterEach = removeImpl, allowMessage = _.msg contains "there was one inliner warning")
+ }
+
+ @Test
+ def handlerNonEmptyStack(): Unit = {
+ val code =
+ """class C {
+ | @noinline def q = 0
+ | @inline final def foo = try { q } catch { case e: Exception => 2 }
+ | def t1 = println(foo) // inline warning here: foo cannot be inlined on top of a non-empty stack
+ |}
+ """.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"})
+ assert(c == 1, c)
+ }
+
+ @Test
+ def mixedWarnings(): Unit = {
+ val javaCode =
+ """public class A {
+ | public static final int bar() { return 100; }
+ |}
+ """.stripMargin
+
+ val scalaCode =
+ """class B {
+ | @inline final def flop = A.bar
+ | def g = flop
+ |}
+ """.stripMargin
+
+ val warns = List(
+ """failed to determine if bar should be inlined:
+ |The method bar()I could not be found in the class A or any of its parents.
+ |Note that the following parent classes are defined in Java sources (mixed compilation), no bytecode is available: A""".stripMargin,
+
+ """B::flop()I is annotated @inline but could not be inlined:
+ |Failed to check if B::flop()I can be safely inlined to B without causing an IllegalAccessError. Checking instruction INVOKESTATIC A.bar ()I failed:
+ |The method bar()I could not be found in the class A or any of its parents.
+ |Note that the following parent classes are defined in Java sources (mixed compilation), no bytecode is available: A""".stripMargin)
+
+ var c = 0
+ val List(b) = compile(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 = InlineWarningTest.argsNoWarn + " -Yopt-warnings:none"))(scalaCode, List((javaCode, "A.java")))
+
+ c = 0
+ compileClasses(newCompiler(extraArgs = InlineWarningTest.argsNoWarn + " -Yopt-warnings:no-inline-mixed"))(scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; warns.exists(i.msg contains _)})
+ assert(c == 2, 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 91404acba7..03d2f2f108 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala
@@ -59,7 +59,7 @@ class InlinerIllegalAccessTest extends ClearAfterClass {
def check(classNode: ClassNode, test: Option[AbstractInsnNode] => Unit) = {
for (m <- methods)
- test(inliner.findIllegalAccess(m.instructions, classBTypeFromParsedClassfile(classNode.name).get))
+ test(inliner.findIllegalAccess(m.instructions, classBTypeFromParsedClassfile(classNode.name)).map(_._1))
}
check(cClass, assertEmpty)
@@ -153,7 +153,7 @@ class InlinerIllegalAccessTest extends ClearAfterClass {
val List(rbD, rcD, rfD, rgD) = dCl.methods.asScala.toList.filter(_.name(0) == 'r').sortBy(_.name)
def check(method: MethodNode, dest: ClassNode, test: Option[AbstractInsnNode] => Unit): Unit = {
- test(inliner.findIllegalAccess(method.instructions, classBTypeFromParsedClassfile(dest.name).get))
+ test(inliner.findIllegalAccess(method.instructions, classBTypeFromParsedClassfile(dest.name)).map(_._1))
}
val cOrDOwner = (_: Option[AbstractInsnNode] @unchecked) match {
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 58a262c401..5c9bd1c188 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerSeparateCompilationTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerSeparateCompilationTest.scala
@@ -43,7 +43,8 @@ class InlinerSeparateCompilationTest {
|}
""".stripMargin
- val List(c, o, oMod, t, tCls) = compileClassesSeparately(List(codeA, codeB), args)
+ 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, tCls) = compileClassesSeparately(List(codeA, codeB), args + " -Yopt-warnings", _.msg contains warn)
assertInvoke(getSingleMethod(c, "t1"), "T", "f")
assertNoInvoke(getSingleMethod(c, "t2"))
assertNoInvoke(getSingleMethod(c, "t3"))
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 7f58f77b15..d32c1b2958 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
@@ -15,6 +15,7 @@ import scala.tools.asm.tree._
import scala.tools.asm.tree.analysis._
import scala.tools.nsc.backend.jvm.opt.BytecodeUtils.AsmAnalyzer
import scala.tools.nsc.io._
+import scala.tools.nsc.reporters.StoreReporter
import scala.tools.testing.AssertUtil._
import CodeGenTools._
@@ -22,11 +23,13 @@ import scala.tools.partest.ASMConverters
import ASMConverters._
import AsmUtils._
+import BackendReporting._
+
import scala.collection.convert.decorateAsScala._
import scala.tools.testing.ClearAfterClass
object InlinerTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:classpath")
+ var compiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:classpath -Yopt-warnings")
// allows inspecting the caches after a compilation run
def notPerRun: List[Clearable] = List(compiler.genBCode.bTypes.classBTypeFromInternalName, compiler.genBCode.bTypes.byteCodeRepository.classes, compiler.genBCode.bTypes.callGraph.callsites)
@@ -61,9 +64,9 @@ class InlinerTest extends ClearAfterClass {
val compiler = InlinerTest.compiler
import compiler.genBCode.bTypes._
- def compile(scalaCode: String, javaCode: List[(String, String)] = Nil): List[ClassNode] = {
+ def compile(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] = {
InlinerTest.notPerRun.foreach(_.clear())
- compileClasses(compiler)(scalaCode, javaCode)
+ compileClasses(compiler)(scalaCode, javaCode, allowMessage)
}
def checkCallsite(callsite: callGraph.Callsite, callee: MethodNode) = {
@@ -76,10 +79,10 @@ class InlinerTest extends ClearAfterClass {
}
// inline first invocation of f into g in class C
- def inlineTest(code: String, mod: ClassNode => Unit = _ => ()): (MethodNode, Option[String]) = {
+ def inlineTest(code: String, mod: ClassNode => Unit = _ => ()): (MethodNode, Option[CannotInlineWarning]) = {
val List(cls) = compile(code)
mod(cls)
- val clsBType = classBTypeFromParsedClassfile(cls.name).get
+ val clsBType = classBTypeFromParsedClassfile(cls.name)
val List(f, g) = cls.methods.asScala.filter(m => Set("f", "g")(m.name)).toList.sortBy(_.name)
val fCall = g.instructions.iterator.asScala.collect({ case i: MethodInsnNode if i.name == "f" => i }).next()
@@ -166,7 +169,7 @@ class InlinerTest extends ClearAfterClass {
val f = cls.methods.asScala.find(_.name == "f").get
f.access |= ACC_SYNCHRONIZED
})
- assert(can.get contains "synchronized", can)
+ assert(can.get.isInstanceOf[SynchronizedMethod], can)
}
@Test
@@ -192,7 +195,7 @@ class InlinerTest extends ClearAfterClass {
|}
""".stripMargin
val (_, r) = inlineTest(code)
- assert(r.get contains "operand stack at the callsite", r)
+ assert(r.get.isInstanceOf[MethodWithHandlerCalledOnNonEmptyStack], r)
}
@Test
@@ -213,8 +216,8 @@ class InlinerTest extends ClearAfterClass {
val List(c, d) = compile(code)
- val cTp = classBTypeFromParsedClassfile(c.name).get
- val dTp = classBTypeFromParsedClassfile(d.name).get
+ val cTp = classBTypeFromParsedClassfile(c.name)
+ val dTp = classBTypeFromParsedClassfile(d.name)
val g = c.methods.asScala.find(_.name == "g").get
val h = d.methods.asScala.find(_.name == "h").get
@@ -234,7 +237,7 @@ class InlinerTest extends ClearAfterClass {
receiverKnownNotNull = true,
keepLineNumbers = true)
- assert(r.get contains "would cause an IllegalAccessError", r)
+ assert(r.get.isInstanceOf[IllegalAccessInstruction], r)
}
@Test
@@ -373,7 +376,7 @@ class InlinerTest extends ClearAfterClass {
val List(c) = compile(code)
val f = c.methods.asScala.find(_.name == "f").get
val callsiteIns = f.instructions.iterator().asScala.collect({ case c: MethodInsnNode => c }).next()
- val clsBType = classBTypeFromParsedClassfile(c.name).get
+ val clsBType = classBTypeFromParsedClassfile(c.name)
val analyzer = new AsmAnalyzer(f, clsBType.internalName)
val integerClassBType = classBTypeFromInternalName("java/lang/Integer")
@@ -457,8 +460,15 @@ class InlinerTest extends ClearAfterClass {
|}
""".stripMargin
+ val warn =
+ """B::flop()I is annotated @inline but could not be inlined:
+ |Failed to check if B::flop()I can be safely inlined to B without causing an IllegalAccessError. Checking instruction INVOKESTATIC A.bar ()I failed:
+ |The method bar()I could not be found in the class A or any of its parents.
+ |Note that the following parent classes are defined in Java sources (mixed compilation), no bytecode is available: A""".stripMargin
- val List(b) = compile(scalaCode, List((javaCode, "A.java")))
+ 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 invokeFlop = Invoke(INVOKEVIRTUAL, "B", "flop", "()I", false)
assert(ins contains invokeFlop, ins.stringLines)
@@ -526,7 +536,12 @@ class InlinerTest extends ClearAfterClass {
| def t2 = this.f
|}
""".stripMargin
- val List(c, t, tClass) = compile(code)
+ val warns = Set(
+ "C::f()I is annotated @inline but cannot be inlined: the method is not final and may be overridden",
+ "T::f()I is annotated @inline but cannot be inlined: the method is not final and may be overridden")
+ var count = 0
+ val List(c, t, tClass) = 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")
}
@@ -561,7 +576,10 @@ class InlinerTest extends ClearAfterClass {
| def t3(t: T) = t.f // no inlining here
|}
""".stripMargin
- val List(c, oMirror, oModule, t, tClass) = compile(code)
+ val warn = "T::f()I is annotated @inline but cannot be inlined: the method is not final and may be overridden"
+ var count = 0
+ val List(c, oMirror, oModule, t, tClass) = compile(code, allowMessage = i => {count += 1; i.msg contains warn})
+ assert(count == 1, count)
assertNoInvoke(getSingleMethod(oModule, "f"))
@@ -663,7 +681,11 @@ class InlinerTest extends ClearAfterClass {
| def m5b(t: T2b) = t.f // re-written to T2b$class.f, inlined, ICONST_1
|}
""".stripMargin
- val List(ca, cb, t1, t1C, t2a, t2aC, t2b, t2bC) = compile(code)
+
+ val warning = "T1::f()I is annotated @inline but cannot be inlined: the method is not final and may be overridden"
+ var count = 0
+ val List(ca, cb, t1, t1C, t2a, t2aC, t2b, t2bC) = compile(code, allowMessage = i => {count += 1; i.msg contains warning})
+ assert(count == 4, count) // see comments, f is not inlined 4 times
val t2aCfDesc = t2aC.methods.asScala.find(_.name == "f").get.desc
assert(t2aCfDesc == "(LT1;)I", t2aCfDesc) // self-type of T2a is T1
@@ -737,4 +759,36 @@ class InlinerTest extends ClearAfterClass {
val cast = TypeOp(CHECKCAST, "C")
Set(t1, t2).foreach(m => assert(m.instructions.contains(cast), m.instructions))
}
+
+ @Test
+ def abstractMethodWarning(): Unit = {
+ val code =
+ """abstract class C {
+ | @inline def foo: Int
+ |}
+ |class T {
+ | def t1(c: C) = c.foo
+ |}
+ """.stripMargin
+ val warn = "C::foo()I is annotated @inline but cannot be inlined: the method is not final and may be overridden"
+ var c = 0
+ compile(code, allowMessage = i => {c += 1; i.msg contains warn})
+ assert(c == 1, c)
+ }
+
+ @Test
+ def abstractFinalMethodError(): Unit = {
+ val code =
+ """abstract class C {
+ | @inline final def foo: Int
+ |}
+ |trait T {
+ | @inline final def bar: Int
+ |}
+ """.stripMargin
+ val err = "abstract member may not have final modifier"
+ var i = 0
+ compile(code, allowMessage = info => {i += 1; info.msg contains err})
+ assert(i == 2, i)
+ }
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala
index 2c71e9d533..1ce1b88ff2 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala
@@ -31,7 +31,8 @@ class MethodLevelOpts extends ClearAfterClass {
@Test
def eliminateEmptyTry(): Unit = {
val code = "def f = { try {} catch { case _: Throwable => 0; () }; 1 }"
- assertSameCode(singleMethodInstructions(methodOptCompiler)(code), wrapInDefault(Op(ICONST_1), Op(IRETURN)))
+ val warn = "a pure expression does nothing in statement position"
+ assertSameCode(singleMethodInstructions(methodOptCompiler)(code, allowMessage = _.msg contains warn), wrapInDefault(Op(ICONST_1), Op(IRETURN)))
}
@Test
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 c2e2a1b883..da9853148b 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala
@@ -154,7 +154,8 @@ class UnreachableCodeTest extends ClearAfterClass {
assertSameCode(noDce.dropNonOp, List(Op(ICONST_1), Op(IRETURN), Op(ATHROW), Op(ATHROW)))
// when NOT computing stack map frames, ASM's ClassWriter does not replace dead code by NOP/ATHROW
- val noDceNoFrames = singleMethodInstructions(noOptNoFramesCompiler)(code)
+ val warn = "target:jvm-1.5 is deprecated"
+ val noDceNoFrames = singleMethodInstructions(noOptNoFramesCompiler)(code, allowMessage = _.msg contains warn)
assertSameCode(noDceNoFrames.dropNonOp, List(Op(ICONST_1), Op(IRETURN), Op(ICONST_2), Op(IRETURN)))
}