diff options
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/nsc/settings/Warnings.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Mixin.scala | 39 |
2 files changed, 25 insertions, 16 deletions
diff --git a/src/compiler/scala/tools/nsc/settings/Warnings.scala b/src/compiler/scala/tools/nsc/settings/Warnings.scala index 79795bcc17..310025a336 100644 --- a/src/compiler/scala/tools/nsc/settings/Warnings.scala +++ b/src/compiler/scala/tools/nsc/settings/Warnings.scala @@ -25,6 +25,8 @@ trait Warnings { // currently considered too noisy for general use val warnUnusedImport = BooleanSetting("-Ywarn-unused-import", "Warn when imports are unused.") + val nowarnDefaultJunitMethods = BooleanSetting("-Ynowarn-default-junit-methods", "Don't warn when a JUnit @Test method is generated as a default method (not supported in JUnit 4).") + // Experimental lint warnings that are turned off, but which could be turned on programmatically. // They are not activated by -Xlint and can't be enabled on the command line because they are not // created using the standard factory methods. diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 03935c3d67..19ba9345fa 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -8,6 +8,7 @@ package transform import symtab._ import Flags._ +import scala.annotation.tailrec import scala.collection.mutable abstract class Mixin extends InfoTransform with ast.TreeDSL { @@ -241,22 +242,16 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { case NoSymbol => val isMemberOfClazz = clazz.info.findMember(member.name, 0, 0L, stableOnly = false).alternatives.contains(member) if (isMemberOfClazz) { - val competingMethods = clazz.baseClasses.iterator - .filter(_ ne mixinClass) - .map(member.overriddenSymbol) - .filter(_.exists) - .toList - - // `member` is a concrete `method` defined in `mixinClass`, which is a base class of + // `member` is a concrete method defined in `mixinClass`, which is a base class of // `clazz`, and the method is not overridden in `clazz`. A forwarder is needed if: // - // - A non-trait base class defines matching method. Example: + // - A non-trait base class of `clazz` defines a matching method. Example: // class C {def f: Int}; trait T extends C {def f = 1}; class D extends T // Even if C.f is abstract, the forwarder in D is needed, otherwise the JVM would // resolve `D.f` to `C.f`, see jvms-6.5.invokevirtual. // - // - There exists another concrete, matching method in any of the base classes, and - // the `mixinClass` does not itself extend that base class. In this case the + // - There exists another concrete, matching method in a parent interface `p` of + // `clazz`, and the `mixinClass` does not itself extend `p`. In this case the // forwarder is needed to disambiguate. Example: // trait T1 {def f = 1}; trait T2 extends T1 {override def f = 2}; class C extends T2 // In C we don't need a forwarder for f because T2 extends T1, so the JVM resolves @@ -265,13 +260,25 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { // In D the forwarder is needed, the interfaces U1 and U2 are unrelated at the JVM // level. - lazy val mixinSuperInterfaces = mixinClass.ancestors.filter(_.isTraitOrInterface) - val needsForwarder = competingMethods.exists(m => { - !m.owner.isTraitOrInterface || - (!m.isDeferred && !mixinSuperInterfaces.contains(m.owner)) - }) - if (needsForwarder) + @tailrec + def existsCompetingMethod(baseClasses: List[Symbol]): Boolean = baseClasses match { + case baseClass :: rest => + if (baseClass ne mixinClass) { + val m = member.overriddenSymbol(baseClass) + val isCompeting = m.exists && { + !m.owner.isTraitOrInterface || + (!m.isDeferred && !mixinClass.isNonBottomSubClass(m.owner)) + } + isCompeting || existsCompetingMethod(rest) + } else existsCompetingMethod(rest) + + case _ => false + } + + if (existsCompetingMethod(clazz.baseClasses)) cloneAndAddMixinMember(mixinClass, member).asInstanceOf[TermSymbol] setAlias member + else if (!settings.nowarnDefaultJunitMethods && JUnitTestClass.exists && member.hasAnnotation(JUnitTestClass)) + warning(member.pos, "JUnit tests in traits that are compiled as default methods are not executed by JUnit 4. JUnit 5 will fix this issue.") } case _ => |