Skip to content

Commit 8ff2d4f

Browse files
committed
Move generatation of trait bridges to Erasure
1 parent 2a99b4f commit 8ff2d4f

File tree

4 files changed

+14
-52
lines changed

4 files changed

+14
-52
lines changed

compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,6 @@ trait BCodeSkelBuilder extends BCodeHelpers {
610610
genTraitConstructorDefDef(dd)
611611
else
612612
genStaticForwarderForDefDef(dd)
613-
genInterfaceMethodBridgeForDefDef(dd)
614613
genDefDef(dd)
615614
else
616615
genDefDef(dd)
@@ -691,48 +690,6 @@ trait BCodeSkelBuilder extends BCodeHelpers {
691690
).transform(dd.rhs)
692691
})
693692

694-
/** Creates a bridges for interfece inherited and narrowed methods,
695-
* to workaround JVM limitations when using LambdaMetaFactory (see issue #15402)
696-
* Example:
697-
* ```
698-
* trait Foo:
699-
* def self: Foo
700-
*
701-
* trait Bar extends Foo:
702-
* def self: Bar = this
703-
* def SAM(x: Any): Any
704-
*
705-
* def usage(x: List[Foo]) = x.map(_.self)
706-
* ```
707-
* We need to define a bridge in trait Bar `def self: Foo = Bar.this.self`
708-
* in order to prevent JVM runtime exceptions. Otherwise at the time of
709-
* accessing `_.self` in the SAM instance created based on the `trait Bar`
710-
* it will complain about missing implementation of `def self: Foo`.
711-
* Javac compiler does exactly the same.
712-
*/
713-
private def genInterfaceMethodBridgeForDefDef(dd: DefDef): Unit =
714-
val sym = dd.symbol
715-
sym.owner.directlyInheritedTraits
716-
.flatMap { parent =>
717-
val inheritedSym = parent.info.decl(sym.name)
718-
Option.when(
719-
inheritedSym.exists &&
720-
sym.signature != inheritedSym.signature &&
721-
sym.info <:< inheritedSym.info
722-
)(inheritedSym.symbol.asTerm)
723-
}.distinctBy(_.signature)
724-
.foreach(genInterfaceMethodBridge(sym.asTerm, _))
725-
726-
private def genInterfaceMethodBridge(sym: TermSymbol, inheritedSym: TermSymbol): Unit =
727-
assert(sym.name == inheritedSym.name, "Not an override")
728-
val owner = sym.owner.asClass
729-
val bridgeSym = inheritedSym.copy(owner = owner, flags = sym.flags).asTerm
730-
val bridge = tpd.DefDef(bridgeSym, {paramss =>
731-
val params = paramss.head
732-
tpd.Apply(tpd.This(owner).select(sym), params)
733-
})
734-
genDefDef(bridge)
735-
736693
private def genStaticForwarderForDefDef(dd: DefDef): Unit =
737694
val forwarderDef = makeStaticForwarder(dd)
738695
genDefDef(forwarderDef)

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,12 @@ class Bridges(root: ClassSymbol, thisPhase: DenotTransformer)(using Context) {
3131

3232
/** Only use the superclass of `root` as a parent class. This means
3333
* overriding pairs that have a common implementation in a trait parent
34-
* are also counted. This is necessary because we generate bridge methods
35-
* only in classes, never in traits.
34+
* are also counted. The only exception is generation of bridges for traits,
35+
* where we want to be able to deduplicate bridges already defined in parents.
3636
*/
37-
override def parents = Array(root.superClass)
37+
override lazy val parents =
38+
if(root.is(Trait)) super.parents
39+
else Array(root.superClass)
3840

3941
override def exclude(sym: Symbol) =
4042
!sym.isOneOf(MethodOrModule) || sym.isAllOf(Module | JavaDefined) || super.exclude(sym)
@@ -170,9 +172,14 @@ class Bridges(root: ClassSymbol, thisPhase: DenotTransformer)(using Context) {
170172
* time deferred methods in `stats` that are replaced by a bridge with the same signature.
171173
*/
172174
def add(stats: List[untpd.Tree]): List[untpd.Tree] =
175+
// When adding bridges to traits ignore non-public methods
176+
// see `DottyBackendTests.invocationReceivers`
173177
val opc = inContext(preErasureCtx) { new BridgesCursor }
174178
while opc.hasNext do
175-
if !opc.overriding.is(Deferred) then
179+
if
180+
!opc.overriding.is(Deferred) &&
181+
(!root.is(Trait) || opc.overridden.isPublic)
182+
then
176183
addBridgeIfNeeded(opc.overriding, opc.overridden)
177184
opc.next()
178185
if bridges.isEmpty then stats

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1065,5 +1065,5 @@ object Erasure {
10651065
}
10661066

10671067
private def takesBridges(sym: Symbol)(using Context): Boolean =
1068-
sym.isClass && !sym.isOneOf(Flags.Trait | Flags.Package)
1068+
sym.isClass && !sym.is(Flags.Package)
10691069
}

tests/run/mixin-signatures.check

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,9 @@ class Test$bar5$ {
4949
}
5050

5151
interface Foo1 {
52-
public abstract java.lang.Object Base.f(java.lang.Object)
53-
generic: public abstract R Base.f(T)
5452
public default java.lang.String Foo1.f(java.lang.Object)
5553
generic: public default java.lang.String Foo1.f(T)
54+
public default java.lang.Object Foo1.f(java.lang.Object) <bridge> <synthetic>
5655
public abstract java.lang.Object Base.g(java.lang.Object)
5756
generic: public abstract R Base.g(T)
5857
public abstract java.lang.String Foo1.g(java.lang.Object)
@@ -62,10 +61,9 @@ interface Foo1 {
6261
}
6362

6463
interface Foo2 {
65-
public abstract java.lang.Object Base.f(java.lang.Object)
66-
generic: public abstract R Base.f(T)
6764
public default java.lang.Object Foo2.f(java.lang.String)
6865
generic: public default R Foo2.f(java.lang.String)
66+
public default java.lang.Object Foo2.f(java.lang.Object) <bridge> <synthetic>
6967
public abstract java.lang.Object Base.g(java.lang.Object)
7068
generic: public abstract R Base.g(T)
7169
public abstract java.lang.Object Foo2.g(java.lang.String)

0 commit comments

Comments
 (0)