Skip to content

Commit 8f89bd5

Browse files
committed
ResolveSuper: add missing methods overrides for disambiguation
In mixin-overrides.scala, when we compute the overrides for QInt in ResolveSuper, we need to add an override for Baz#op because it matches the concrete method Bar#op (otherwise we'll get a "Conflicting default methods" error at runtime). Before this commit, this did not happen because Baz#op was not considered to match Bar#op, because one refers to Baz.this.A and the other to Bar.this.A. We fix this by calling `matchingDenotation` with a `targetType` corresponding to the current class (`QInt` here) instead of the trait where the denotation is defined. This also allows us to remove the PrimitiveForwarders mini-phase which was apparently doing a subset of this work and is now redundant.
1 parent 7a9ae7c commit 8f89bd5

File tree

6 files changed

+24
-70
lines changed

6 files changed

+24
-70
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ class Compiler {
8383
new ElimOuterSelect, // Expand outer selections
8484
new AugmentScala2Traits, // Expand traits defined in Scala 2.x to simulate old-style rewritings
8585
new ResolveSuper, // Implement super accessors and add forwarders to trait methods
86-
new PrimitiveForwarders, // Add forwarders to trait methods that have a mismatch between generic and primitives
8786
new FunctionXXLForwarders, // Add forwarders for FunctionXXL apply method
8887
new ArrayConstructors) :: // Intercept creation of (non-generic) arrays and intrinsify.
8988
List(new Erasure) :: // Rewrite types to JVM model, erasing all type parameters, abstract types and refinements.

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,10 +1125,10 @@ object SymDenotations {
11251125
final def memberCanMatchInheritedSymbols(implicit ctx: Context): Boolean =
11261126
!isConstructor && !is(Private)
11271127

1128-
/** The symbol, in class `inClass`, that is overridden by this denotation. */
1129-
final def overriddenSymbol(inClass: ClassSymbol)(implicit ctx: Context): Symbol =
1128+
/** The symbol, in class `inClass`, that is overridden by this denotation in class `siteClass`.*/
1129+
final def overriddenSymbol(inClass: ClassSymbol, siteClass: ClassSymbol = owner.asClass)(implicit ctx: Context): Symbol =
11301130
if (!canMatchInheritedSymbols && (owner ne inClass)) NoSymbol
1131-
else matchingDecl(inClass, owner.thisType)
1131+
else matchingDecl(inClass, siteClass.thisType)
11321132

11331133
/** All symbols overridden by this denotation. */
11341134
final def allOverriddenSymbols(implicit ctx: Context): Iterator[Symbol] =
@@ -1142,7 +1142,7 @@ object SymDenotations {
11421142

11431143
private def overriddenFromType(tp: Type)(implicit ctx: Context): Iterator[Symbol] =
11441144
tp.baseClasses match {
1145-
case _ :: inherited => inherited.iterator map overriddenSymbol filter (_.exists)
1145+
case _ :: inherited => inherited.iterator.map(overriddenSymbol(_)).filter(_.exists)
11461146
case Nil => Iterator.empty
11471147
}
11481148

compiler/src/dotty/tools/dotc/transform/MixinOps.scala

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -72,28 +72,6 @@ class MixinOps(cls: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Cont
7272
meth.annotations.nonEmpty && JUnit4Annotations.exists(annot => meth.hasAnnotation(annot))
7373
}
7474

75-
/** Get `sym` of the method that needs a forwarder
76-
* Method needs a forwarder in those cases:
77-
* - there is a trait that defines a primitive version of implemented polymorphic method.
78-
* - there is a trait that defines a polymorphic version of implemented primitive method.
79-
*/
80-
def needsPrimitiveForwarderTo(meth: Symbol): Option[Symbol] = {
81-
def hasPrimitiveMissMatch(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match {
82-
case (tp1: MethodicType, tp2: MethodicType) =>
83-
hasPrimitiveMissMatch(tp1.resultType, tp2.resultType) ||
84-
tp1.paramInfoss.flatten.zip(tp1.paramInfoss.flatten).exists(args => hasPrimitiveMissMatch(args._1, args._2))
85-
case _ =>
86-
def isPrimitiveOrValueClass(sym: Symbol): Boolean = sym.isPrimitiveValueClass || sym.isValueClass
87-
isPrimitiveOrValueClass(tp1.typeSymbol) ^ isPrimitiveOrValueClass(tp2.typeSymbol)
88-
}
89-
90-
def needsPrimitiveForwarder(m: Symbol): Boolean =
91-
m.owner != cls && !m.is(Deferred) && hasPrimitiveMissMatch(meth.info, m.info)
92-
93-
if (!meth.is(Method | Deferred, butNot = PrivateOrAccessor) || meth.overriddenSymbol(cls).exists || needsForwarder(meth)) None
94-
else competingMethodsIterator(meth).find(needsPrimitiveForwarder)
95-
}
96-
9775
final val PrivateOrAccessor: FlagSet = Private | Accessor
9876
final val PrivateOrAccessorOrDeferred: FlagSet = Private | Accessor | Deferred
9977

@@ -104,7 +82,7 @@ class MixinOps(cls: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Cont
10482
private def competingMethodsIterator(meth: Symbol): Iterator[Symbol] = {
10583
cls.baseClasses.iterator
10684
.filter(_ ne meth.owner)
107-
.map(meth.overriddenSymbol)
85+
.map(base => meth.overriddenSymbol(base, cls))
10886
.filter(_.exists)
10987
}
11088
}

compiler/src/dotty/tools/dotc/transform/PrimitiveForwarders.scala

Lines changed: 0 additions & 41 deletions
This file was deleted.

docs/docs/internals/overall-structure.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,6 @@ phases. The current list of phases is specified in class [Compiler] as follows:
142142
new ElimOuterSelect, // Expand outer selections
143143
new AugmentScala2Traits, // Expand traits defined in Scala 2.x to simulate old-style rewritings
144144
new ResolveSuper, // Implement super accessors and add forwarders to trait methods
145-
new PrimitiveForwarders, // Add forwarders to trait methods that have a mismatch between generic and primitives
146145
new FunctionXXLForwarders, // Add forwarders for FunctionXXL apply method
147146
new ArrayConstructors) :: // Intercept creation of (non-generic) arrays and intrinsify.
148147
List(new Erasure) :: // Rewrite types to JVM model, erasing all type parameters, abstract types and refinements.

tests/run/mixin-overrides.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
trait Foo[A] {
2+
def op(x: A): Int
3+
}
4+
trait Bar[A] extends Foo[A] {
5+
override def op(x: A): Int = 1
6+
}
7+
trait Baz[A] extends Foo[A] {
8+
override def op(x: A): Int = 2
9+
}
10+
trait Qux[A] extends Bar[A] with Baz[A]
11+
12+
class QInt extends Qux[Int]
13+
14+
object Test {
15+
def main(args: Array[String]): Unit = {
16+
val qint = new QInt
17+
assert(qint.op(1) == 2) // Used to fail with java.lang.IncompatibleClassChangeError: Conflicting default methods: Bar.op Baz.op
18+
}
19+
}

0 commit comments

Comments
 (0)