diff options
6 files changed, 67 insertions, 10 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala index 7b2686e7a9..f6b640bea4 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala @@ -1145,8 +1145,7 @@ object BTypes { final case class InlineInfo(isEffectivelyFinal: Boolean, sam: Option[String], methodInfos: Map[String, MethodInlineInfo], - warning: Option[ClassInlineInfoWarning]) { - } + warning: Option[ClassInlineInfoWarning]) val EmptyInlineInfo = InlineInfo(false, None, Map.empty, None) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala index 1a4590e7d1..e0f0f269cb 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala @@ -557,9 +557,16 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes { var warning = Option.empty[ClassSymbolInfoFailureSI9111] + def keepMember(sym: Symbol) = sym.isMethod && !scalaPrimitives.isPrimitive(sym) + val classMethods = classSym.info.decls.iterator.filter(keepMember) + val methods = if (!classSym.isJavaDefined) classMethods else { + val staticMethods = classSym.companionModule.info.decls.iterator.filter(m => !m.isConstructor && keepMember(m)) + staticMethods ++ classMethods + } + // Primitive methods cannot be inlined, so there's no point in building a MethodInlineInfo. Also, some // primitive methods (e.g., `isInstanceOf`) have non-erased types, which confuses [[typeToBType]]. - val methodInlineInfos = classSym.info.decls.iterator.filter(m => m.isMethod && !scalaPrimitives.isPrimitive(m)).flatMap({ + val methodInlineInfos = methods.flatMap({ case methodSym => if (completeSilentlyAndCheckErroneous(methodSym)) { // Happens due to SI-9111. Just don't provide any MethodInlineInfo for that method, we don't need fail the compiler. diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala b/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala index 7b640ac54f..72a371cabc 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala @@ -96,8 +96,8 @@ object BackendReporting { val missingClassWarning = missingClass match { case None => "" case Some(c) => - if (c.definedInJavaSource) s"\nNote that the parent class ${c.internalName} is defined in a Java source (mixed compilation), no bytecode is available." - else s"\nNote that the parent class ${c.internalName} could not be found on the classpath." + if (c.definedInJavaSource) s"\nNote that class ${c.internalName} is defined in a Java source (mixed compilation), no bytecode is available." + else s"\nNote that class ${c.internalName} could not be found on the classpath." } s"The method $name$descriptor could not be found in the class $ownerInternalName or any of its parents." + missingClassWarning 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 a691d63471..6f098e1432 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala @@ -2,18 +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 scala.collection.JavaConverters._ import scala.collection.generic.Clearable +import scala.tools.nsc.backend.jvm.BTypes.MethodInlineInfo import scala.tools.nsc.backend.jvm.BackendReporting._ import scala.tools.testing.BytecodeTesting @RunWith(classOf[JUnit4]) class InlineInfoTest extends BytecodeTesting { - import compiler.global + import compiler._ import global.genBCode.bTypes override def compilerArgs = "-opt:l:classpath" @@ -59,4 +61,20 @@ class InlineInfoTest extends BytecodeTesting { assert(fromSyms == fromAttrs) } + + @Test // scala-dev#20 + def javaStaticMethodsInlineInfoInMixedCompilation(): Unit = { + val jCode = + """public class A { + | public static final int bar() { return 100; } + | public final int baz() { return 100; } + |} + """.stripMargin + compileClasses("class C { new A }", javaCode = List((jCode, "A.java"))) + val info = global.genBCode.bTypes.classBTypeFromInternalName("A").info.get.inlineInfo + assertEquals(info.methodInfos, Map( + "bar()I" -> MethodInlineInfo(true,false,false), + "<init>()V" -> MethodInlineInfo(false,false,false), + "baz()I" -> MethodInlineInfo(true,false,false))) + } } 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 5254d7e1f2..5bd2ce68f1 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala @@ -75,12 +75,12 @@ class InlineWarningTest extends BytecodeTesting { 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 parent class A is defined in a Java source (mixed compilation), no bytecode is available.""".stripMargin, + |Note that class A is defined in a Java source (mixed compilation), no bytecode is available.""".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 parent class A is defined in a Java source (mixed compilation), no bytecode is available.""".stripMargin) + |Note that class A is defined in a Java source (mixed compilation), no bytecode is available.""".stripMargin) var c = 0 val List(b) = compileToBytes(scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; warns.tail.exists(i.msg contains _)}) @@ -168,4 +168,37 @@ class InlineWarningTest extends BytecodeTesting { compileToBytes(code, allowMessage = i => { c += 1; i.msg contains warn }) assert(c == 1, c) } + + @Test // scala-dev#20 + def mixedCompilationSpuriousWarning(): Unit = { + val jCode = + """public class A { + | public static final int bar() { return 100; } + | public final int baz() { return 100; } + |} + """.stripMargin + + val sCode = + """class C { + | @inline final def foo = A.bar() + | @inline final def fii(a: A) = a.baz() + | def t = foo + fii(new A) + |} + """.stripMargin + + val warns = List( + """C::foo()I is annotated @inline but could not be inlined: + |Failed to check if C::foo()I can be safely inlined to C 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 class A is defined in a Java source (mixed compilation), no bytecode is available.""".stripMargin, + + """C::fii(LA;)I is annotated @inline but could not be inlined: + |Failed to check if C::fii(LA;)I can be safely inlined to C without causing an IllegalAccessError. Checking instruction INVOKEVIRTUAL A.baz ()I failed: + |The method baz()I could not be found in the class A or any of its parents. + |Note that class A is defined in a Java source (mixed compilation), no bytecode is available.""".stripMargin + ) + var c = 0 + compileClasses(sCode, javaCode = List((jCode, "A.java")), allowMessage = i => { c += 1; warns.exists(i.msg.contains)}) + assert(c == 2) + } } 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 f531ce9322..0f292517ef 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala @@ -416,7 +416,7 @@ class InlinerTest extends BytecodeTesting { """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 parent class A is defined in a Java source (mixed compilation), no bytecode is available.""".stripMargin + |Note that 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; i.msg contains warn}) @@ -819,7 +819,7 @@ class InlinerTest extends BytecodeTesting { val warn = """failed to determine if <init> should be inlined: |The method <init>()V could not be found in the class A$Inner or any of its parents. - |Note that the parent class A$Inner could not be found on the classpath.""".stripMargin + |Note that class A$Inner could not be found on the classpath.""".stripMargin var c = 0 |