diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2016-04-05 22:01:43 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2016-04-12 12:01:31 +0200 |
commit | 33e71061d63d08ee23e28d9a43ad601afa74e043 (patch) | |
tree | 83c4279524ae3aa6d5a270fc6bd1662102742a26 /src | |
parent | b932419f07c0d747d868ebc3b51ccc54573a5827 (diff) | |
download | scala-33e71061d63d08ee23e28d9a43ad601afa74e043.tar.gz scala-33e71061d63d08ee23e28d9a43ad601afa74e043.tar.bz2 scala-33e71061d63d08ee23e28d9a43ad601afa74e043.zip |
SD-98 don't emit unnecessary mixin forwarders
In most cases when a class inherits a concrete method from a trait we
don't need to generate a forwarder to the default method in the class.
t5148 is moved to pos as it compiles without error now. the error
message ("missing or invalid dependency") is still tested by t6440b.
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Mixin.scala | 38 |
1 files changed, 35 insertions, 3 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index ed7ef0d8fd..03935c3d67 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -47,7 +47,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { sym.isMethod && (!sym.hasFlag(DEFERRED | SUPERACCESSOR) || (sym hasFlag lateDEFERRED)) && sym.owner.isTrait - && sym.isMethod && (!sym.isModule || sym.hasFlag(PRIVATE | LIFTED)) && (!(sym hasFlag (ACCESSOR | SUPERACCESSOR)) || sym.isLazy) && !sym.isPrivate @@ -240,8 +239,41 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { for (member <- mixinClass.info.decls ; if isImplementedStatically(member)) { member overridingSymbol clazz match { case NoSymbol => - if (clazz.info.findMember(member.name, 0, 0L, stableOnly = false).alternatives contains member) - cloneAndAddMixinMember(mixinClass, member).asInstanceOf[TermSymbol] setAlias member + 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 + // `clazz`, and the method is not overridden in `clazz`. A forwarder is needed if: + // + // - A non-trait base class defines 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 + // 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 + // C.f to T2.f non-ambiguously. See jvms-5.4.3.3, "maximally-specific method". + // trait U1 {def f = 1}; trait U2 {self:U1 => override def f = 2}; class D extends U2 + // 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) + cloneAndAddMixinMember(mixinClass, member).asInstanceOf[TermSymbol] setAlias member + } + case _ => } } |