Skip to content

Commit 28d11d6

Browse files
committed
Erasure: Don't generate forwarders to abstract members.
Those forwarders may disrupt method resolution.
1 parent a37d233 commit 28d11d6

File tree

2 files changed

+68
-28
lines changed

2 files changed

+68
-28
lines changed

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

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -614,38 +614,44 @@ object Erasure extends TypeTestsCasts{
614614
val newSymbol = member.symbol(ctx)
615615
assert(oldSymbol.name(beforeCtx) == newSymbol.name,
616616
s"${oldSymbol.name(beforeCtx)} bridging with ${newSymbol.name}")
617-
val newOverridden = oldSymbol.denot.allOverriddenSymbols.toSet // TODO: clarify new <-> old in a comment; symbols are swapped here
618-
val oldOverridden = newSymbol.allOverriddenSymbols(beforeCtx).toSet // TODO: can we find a more efficient impl? newOverridden does not have to be a set!
619-
def stillInBaseClass(sym: Symbol) = ctx.owner derivesFrom sym.owner
620-
val neededBridges = (oldOverridden -- newOverridden).filter(stillInBaseClass)
621-
622-
var minimalSet = Set[Symbol]()
623-
// compute minimal set of bridges that are needed:
624-
for (bridge <- neededBridges) {
625-
val isRequired = minimalSet.forall(nxtBridge => !(bridge.info =:= nxtBridge.info))
626-
627-
if (isRequired) {
628-
// check for clashes
629-
val clash: Option[Symbol] = oldSymbol.owner.info.decls.lookupAll(bridge.name).find {
630-
sym =>
631-
(sym.name eq bridge.name) && sym.info.widen =:= bridge.info.widen
632-
}.orElse(
633-
emittedBridges.find(stat => (stat.name == bridge.name) && stat.tpe.widen =:= bridge.info.widen)
634-
.map(_.symbol))
635-
clash match {
636-
case Some(cl) =>
637-
ctx.error(i"bridge for method ${newSymbol.showLocated(beforeCtx)} of type ${newSymbol.info(beforeCtx)}\n" +
638-
i"clashes with ${cl.symbol.showLocated(beforeCtx)} of type ${cl.symbol.info(beforeCtx)}\n" +
639-
i"both have same type after erasure: ${bridge.symbol.info}")
640-
case None => minimalSet += bridge
617+
if (!oldMember.symbol.is(Flags.Deferred)) {
618+
val newOverridden = oldSymbol.denot.allOverriddenSymbols.toSet
619+
// TODO: clarify new <-> old in a comment; symbols are swapped here
620+
val oldOverridden = newSymbol.allOverriddenSymbols(beforeCtx).toSet
621+
622+
// TODO: can we find a more efficient impl? newOverridden does not have to be a set!
623+
def stillInBaseClass(sym: Symbol) = ctx.owner derivesFrom sym.owner
624+
625+
val neededBridges = (oldOverridden -- newOverridden).filter(stillInBaseClass)
626+
627+
var minimalSet = Set[Symbol]()
628+
// compute minimal set of bridges that are needed:
629+
for (bridge <- neededBridges) {
630+
val isRequired = minimalSet.forall(nxtBridge => !(bridge.info =:= nxtBridge.info))
631+
632+
if (isRequired) {
633+
// check for clashes
634+
val clash: Option[Symbol] = oldSymbol.owner.info.decls.lookupAll(bridge.name).find {
635+
sym =>
636+
(sym.name eq bridge.name) && sym.info.widen =:= bridge.info.widen
637+
}.orElse(
638+
emittedBridges.find(stat => (stat.name == bridge.name) && stat.tpe.widen =:= bridge.info.widen)
639+
.map(_.symbol))
640+
clash match {
641+
case Some(cl) =>
642+
ctx.error(i"bridge for method ${newSymbol.showLocated(beforeCtx)} of type ${newSymbol.info(beforeCtx)}\n" +
643+
i"clashes with ${cl.symbol.showLocated(beforeCtx)} of type ${cl.symbol.info(beforeCtx)}\n" +
644+
i"both have same type after erasure: ${bridge.symbol.info}")
645+
case None => minimalSet += bridge
646+
}
641647
}
642648
}
643-
}
644649

645-
val bridgeImplementations = minimalSet.map {
646-
sym => makeBridgeDef(member, sym)(ctx)
650+
val bridgeImplementations = minimalSet.map {
651+
sym => makeBridgeDef(member, sym)(ctx)
652+
}
653+
emittedBridges ++= bridgeImplementations
647654
}
648-
emittedBridges ++= bridgeImplementations
649655
} catch {
650656
case ex: MergeError => ctx.error(ex.getMessage, member.pos)
651657
}

tests/run/i2337.scala

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
Minimized from collection strawman
3+
This issue has a lot to do with both mixin and bridge generation and subtleties in JVM spec
4+
if something breaks in this test, this is not a minor issue. Be careful. Here be dragons.
5+
*/
6+
7+
trait Define[A] {
8+
protected def coll: Define[A]
9+
def s = coll
10+
}
11+
12+
trait Iterable[A] extends Define[A] {
13+
protected def coll: this.type = this
14+
}
15+
16+
trait Seq[A] extends Iterable[A]
17+
18+
trait Super1[A] {
19+
protected def coll: Iterable[A]
20+
}
21+
22+
trait Super2[A] extends Super1[A] {
23+
override protected def coll: Seq[A]
24+
}
25+
26+
class Foo[T] extends Seq[T] with Super2[T] {
27+
}
28+
29+
object Test {
30+
def main(args: Array[String]): Unit = {
31+
val foo = new Foo[Int]
32+
foo.s
33+
}
34+
}

0 commit comments

Comments
 (0)