diff --git a/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala b/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala index f84eb86f2a42..a6d8ad4e7506 100644 --- a/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala +++ b/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala @@ -57,7 +57,7 @@ class LinkScala2Impls extends MiniPhase with IdentityDenotTransformer { thisPhas ) } for (sym <- mixin.info.decls) { - if (needsForwarder(sym) || sym.isConstructor || sym.isGetter && sym.is(Lazy) || sym.is(Method, butNot = Deferred)) + if (needsMixinForwarder(sym) || sym.isConstructor || sym.isGetter && sym.is(Lazy) || sym.is(Method, butNot = Deferred)) newImpl(sym.asTerm).enteredAfter(thisPhase) } // The trait is now fully augmented so the flag isn't needed anymore. diff --git a/compiler/src/dotty/tools/dotc/transform/Mixin.scala b/compiler/src/dotty/tools/dotc/transform/Mixin.scala index 604719b5067d..8a44af8f21f0 100644 --- a/compiler/src/dotty/tools/dotc/transform/Mixin.scala +++ b/compiler/src/dotty/tools/dotc/transform/Mixin.scala @@ -247,7 +247,7 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase => else initial // transformFollowing call is needed to make memoize & lazy vals run - transformFollowing(DefDef(mkForwarder(getter.asTerm), rhs)) + transformFollowing(DefDef(mkForwarderSym(getter.asTerm), rhs)) } else if (isScala2x || was(getter, ParamAccessor | Lazy)) EmptyTree else initial @@ -256,13 +256,13 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase => def setters(mixin: ClassSymbol): List[Tree] = for (setter <- mixin.info.decls.filter(setr => setr.isSetter && !was(setr, Deferred))) - yield transformFollowing(DefDef(mkForwarder(setter.asTerm), unitLiteral.withSpan(cls.span))) + yield transformFollowing(DefDef(mkForwarderSym(setter.asTerm), unitLiteral.withSpan(cls.span))) def mixinForwarders(mixin: ClassSymbol): List[Tree] = - for (meth <- mixin.info.decls.toList if needsForwarder(meth)) + for (meth <- mixin.info.decls.toList if needsMixinForwarder(meth)) yield { util.Stats.record("mixin forwarders") - transformFollowing(polyDefDef(mkForwarder(meth.asTerm), forwarder(meth))) + transformFollowing(polyDefDef(mkForwarderSym(meth.asTerm), forwarderRhsFn(meth))) } diff --git a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala index a5da763ba389..82ffc574441a 100644 --- a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala +++ b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala @@ -18,7 +18,7 @@ class MixinOps(cls: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Cont map(n => ctx.getClassIfDefined("org.junit." + n)). filter(_.exists) - def mkForwarder(member: TermSymbol): TermSymbol = { + def mkForwarderSym(member: TermSymbol): TermSymbol = { val res = member.copy( owner = cls, name = member.name.stripScala2LocalSuffix, @@ -52,7 +52,7 @@ class MixinOps(cls: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Cont * - there's a class defining a method with same signature * - there are multiple traits defining method with same signature */ - def needsForwarder(meth: Symbol): Boolean = { + def needsMixinForwarder(meth: Symbol): Boolean = { lazy val competingMethods = competingMethodsIterator(meth).toList def needsDisambiguation = competingMethods.exists(x=> !(x is Deferred)) // multiple implementations are available @@ -71,9 +71,18 @@ class MixinOps(cls: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Cont final val PrivateOrAccessor: FlagSet = Private | Accessor final val PrivateOrAccessorOrDeferred: FlagSet = Private | Accessor | Deferred - def forwarder(target: Symbol): List[Type] => List[List[Tree]] => Tree = - targs => vrefss => - superRef(target).appliedToTypes(targs).appliedToArgss(vrefss) + def forwarderRhsFn(target: Symbol): List[Type] => List[List[Tree]] => Tree = + targs => vrefss => { + val tapp = superRef(target).appliedToTypes(targs) + vrefss match { + case Nil | List(Nil) => + // Overriding is somewhat loose about `()T` vs `=> T`, so just pick + // whichever makes sense for `target` + tapp.ensureApplied + case _ => + tapp.appliedToArgss(vrefss) + } + } private def competingMethodsIterator(meth: Symbol): Iterator[Symbol] = { cls.baseClasses.iterator diff --git a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala index daf82cbe064b..b77b27fc305c 100644 --- a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala +++ b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala @@ -37,7 +37,7 @@ class ResolveSuper extends MiniPhase with IdentityDenotTransformer { thisPhase = AugmentScala2Traits.name, PruneErasedDefs.name) // Erased decls make `isCurrent` work incorrectly - override def changesMembers: Boolean = true // the phase adds super accessors and method forwarders + override def changesMembers: Boolean = true // the phase adds super accessors override def transformTemplate(impl: Template)(implicit ctx: Context): Template = { val cls = impl.symbol.owner.asClass @@ -48,7 +48,7 @@ class ResolveSuper extends MiniPhase with IdentityDenotTransformer { thisPhase = for (superAcc <- mixin.info.decls.filter(_.isSuperAccessor)) yield { util.Stats.record("super accessors") - polyDefDef(mkForwarder(superAcc.asTerm), forwarder(rebindSuper(cls, superAcc))) + polyDefDef(mkForwarderSym(superAcc.asTerm), forwarderRhsFn(rebindSuper(cls, superAcc))) } val overrides = mixins.flatMap(superAccessors) @@ -63,7 +63,7 @@ class ResolveSuper extends MiniPhase with IdentityDenotTransformer { thisPhase = val cls = meth.owner.asClass val ops = new MixinOps(cls, thisPhase) import ops._ - polyDefDef(meth, forwarder(rebindSuper(cls, meth))) + polyDefDef(meth, forwarderRhsFn(rebindSuper(cls, meth))) } else ddef } @@ -92,7 +92,7 @@ object ResolveSuper { // of the superaccessor's type, see i5433.scala for an example where this matters val otherTp = other.asSeenFrom(base.typeRef).info val accTp = acc.asSeenFrom(base.typeRef).info - if (!(otherTp <:< accTp)) + if (!(otherTp.overrides(accTp, matchLoosely = true))) ctx.error(IllegalSuperAccessor(base, memberName, acc, accTp, other.symbol, otherTp), base.sourcePos) } diff --git a/tests/pos/i6089.scala b/tests/pos/i6089.scala new file mode 100644 index 000000000000..e4237e537ffc --- /dev/null +++ b/tests/pos/i6089.scala @@ -0,0 +1,3 @@ +trait X { override def toString = super.toString + " X" } +trait Y { override def toString = super.toString + " Y" } +class Z extends X with Y