diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index 2c63ac4d32bc..3b31ffe7b363 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -83,7 +83,6 @@ class Compiler { new ElimOuterSelect, // Expand outer selections new AugmentScala2Traits, // Expand traits defined in Scala 2.x to simulate old-style rewritings new ResolveSuper, // Implement super accessors and add forwarders to trait methods - new PrimitiveForwarders, // Add forwarders to trait methods that have a mismatch between generic and primitives new FunctionXXLForwarders, // Add forwarders for FunctionXXL apply method new ArrayConstructors) :: // Intercept creation of (non-generic) arrays and intrinsify. List(new Erasure) :: // Rewrite types to JVM model, erasing all type parameters, abstract types and refinements. diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 778177b578d6..9e08f4c4f821 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1125,10 +1125,10 @@ object SymDenotations { final def memberCanMatchInheritedSymbols(implicit ctx: Context): Boolean = !isConstructor && !is(Private) - /** The symbol, in class `inClass`, that is overridden by this denotation. */ - final def overriddenSymbol(inClass: ClassSymbol)(implicit ctx: Context): Symbol = + /** The symbol, in class `inClass`, that is overridden by this denotation in class `siteClass`.*/ + final def overriddenSymbol(inClass: ClassSymbol, siteClass: ClassSymbol = owner.asClass)(implicit ctx: Context): Symbol = if (!canMatchInheritedSymbols && (owner ne inClass)) NoSymbol - else matchingDecl(inClass, owner.thisType) + else matchingDecl(inClass, siteClass.thisType) /** All symbols overridden by this denotation. */ final def allOverriddenSymbols(implicit ctx: Context): Iterator[Symbol] = @@ -1142,7 +1142,7 @@ object SymDenotations { private def overriddenFromType(tp: Type)(implicit ctx: Context): Iterator[Symbol] = tp.baseClasses match { - case _ :: inherited => inherited.iterator map overriddenSymbol filter (_.exists) + case _ :: inherited => inherited.iterator.map(overriddenSymbol(_)).filter(_.exists) case Nil => Iterator.empty } diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 33439b1770df..d18d2c9a15ea 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -2103,7 +2103,7 @@ object messages { case _ /* Signature.FullMatch */ => "\nThe definitions have matching type signatures after erasure." } } else "" - hl"${decl.showLocated} is already defined as ${previousDecl.showDcl} at line ${previousDecl.pos.line + 1}." + details + hl"${decl.showLocated} is already defined as ${previousDecl.showDcl} ${if (previousDecl.pos.exists) s"at line ${previousDecl.pos.line + 1}" else ""}." + details } val explanation: String = "" } diff --git a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala index 785f1d0bbf36..35a6aa1b30f5 100644 --- a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala +++ b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala @@ -72,28 +72,6 @@ class MixinOps(cls: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Cont meth.annotations.nonEmpty && JUnit4Annotations.exists(annot => meth.hasAnnotation(annot)) } - /** Get `sym` of the method that needs a forwarder - * Method needs a forwarder in those cases: - * - there is a trait that defines a primitive version of implemented polymorphic method. - * - there is a trait that defines a polymorphic version of implemented primitive method. - */ - def needsPrimitiveForwarderTo(meth: Symbol): Option[Symbol] = { - def hasPrimitiveMissMatch(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match { - case (tp1: MethodicType, tp2: MethodicType) => - hasPrimitiveMissMatch(tp1.resultType, tp2.resultType) || - tp1.paramInfoss.flatten.zip(tp1.paramInfoss.flatten).exists(args => hasPrimitiveMissMatch(args._1, args._2)) - case _ => - def isPrimitiveOrValueClass(sym: Symbol): Boolean = sym.isPrimitiveValueClass || sym.isValueClass - isPrimitiveOrValueClass(tp1.typeSymbol) ^ isPrimitiveOrValueClass(tp2.typeSymbol) - } - - def needsPrimitiveForwarder(m: Symbol): Boolean = - m.owner != cls && !m.is(Deferred) && hasPrimitiveMissMatch(meth.info, m.info) - - if (!meth.is(Method | Deferred, butNot = PrivateOrAccessor) || meth.overriddenSymbol(cls).exists || needsForwarder(meth)) None - else competingMethodsIterator(meth).find(needsPrimitiveForwarder) - } - final val PrivateOrAccessor: FlagSet = Private | Accessor final val PrivateOrAccessorOrDeferred: FlagSet = Private | Accessor | Deferred @@ -104,7 +82,7 @@ class MixinOps(cls: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Cont private def competingMethodsIterator(meth: Symbol): Iterator[Symbol] = { cls.baseClasses.iterator .filter(_ ne meth.owner) - .map(meth.overriddenSymbol) + .map(base => meth.overriddenSymbol(base, cls)) .filter(_.exists) } } diff --git a/compiler/src/dotty/tools/dotc/transform/PrimitiveForwarders.scala b/compiler/src/dotty/tools/dotc/transform/PrimitiveForwarders.scala deleted file mode 100644 index 051d4307367a..000000000000 --- a/compiler/src/dotty/tools/dotc/transform/PrimitiveForwarders.scala +++ /dev/null @@ -1,41 +0,0 @@ -package dotty.tools.dotc -package transform - -import core._ -import MegaPhase._ -import Contexts.Context -import Symbols._ -import DenotTransformers._ - -/** This phase adds forwarder where mixedin generic and primitive typed methods have a missmatch. - * In particular for every method that is declared both as generic with a primitive type and with a primitive type - * ` def f[Ts](ps1)...(psN): U` in trait M` and - * ` def f[Ts](ps1)...(psN): V = ...` in implemented in N` - * where U is a primitive and V a polymorphic type (or vice versa) needs: - * - * def f[Ts](ps1)...(psN): U = super[N].f[Ts](ps1)...(psN) - * - * IMPORTANT: When\If Valhalla happens, we'll need to move mixin before erasure and than this code will need to be rewritten - * as it will instead change super-class. - */ -class PrimitiveForwarders extends MiniPhase with IdentityDenotTransformer { thisPhase => - import ast.tpd._ - - override def phaseName: String = "primitiveForwarders" - - override def runsAfter: Set[String] = Set(ResolveSuper.name) - - override def changesMembers: Boolean = true // the phase adds primitive forwarders - - override def transformTemplate(impl: Template)(implicit ctx: Context): Template = { - val cls = impl.symbol.owner.asClass - val ops = new MixinOps(cls, thisPhase) - import ops._ - - def methodPrimitiveForwarders: List[Tree] = - for (meth <- mixins.flatMap(_.info.decls.toList.flatMap(needsPrimitiveForwarderTo)).distinct) - yield polyDefDef(implementation(meth.asTerm), forwarder(meth)) - - cpy.Template(impl)(body = methodPrimitiveForwarders ::: impl.body) - } -} diff --git a/docs/docs/internals/overall-structure.md b/docs/docs/internals/overall-structure.md index 2115bfeb52b6..59245f08608f 100644 --- a/docs/docs/internals/overall-structure.md +++ b/docs/docs/internals/overall-structure.md @@ -142,7 +142,6 @@ phases. The current list of phases is specified in class [Compiler] as follows: new ElimOuterSelect, // Expand outer selections new AugmentScala2Traits, // Expand traits defined in Scala 2.x to simulate old-style rewritings new ResolveSuper, // Implement super accessors and add forwarders to trait methods - new PrimitiveForwarders, // Add forwarders to trait methods that have a mismatch between generic and primitives new FunctionXXLForwarders, // Add forwarders for FunctionXXL apply method new ArrayConstructors) :: // Intercept creation of (non-generic) arrays and intrinsify. List(new Erasure) :: // Rewrite types to JVM model, erasing all type parameters, abstract types and refinements. diff --git a/tests/run/mixin-overrides.scala b/tests/run/mixin-overrides.scala new file mode 100644 index 000000000000..5fc1d9c28491 --- /dev/null +++ b/tests/run/mixin-overrides.scala @@ -0,0 +1,19 @@ +trait Foo[A] { + def op(x: A): Int +} +trait Bar[A] extends Foo[A] { + override def op(x: A): Int = 1 +} +trait Baz[A] extends Foo[A] { + override def op(x: A): Int = 2 +} +trait Qux[A] extends Bar[A] with Baz[A] + +class QInt extends Qux[Int] + +object Test { + def main(args: Array[String]): Unit = { + val qint = new QInt + assert(qint.op(1) == 2) // Used to fail with java.lang.IncompatibleClassChangeError: Conflicting default methods: Bar.op Baz.op + } +}