Skip to content

Commit c7cea46

Browse files
committed
Move generatation of trait bridges to Erasure
1 parent 9c01e1b commit c7cea46

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
@@ -688,7 +688,6 @@ trait BCodeSkelBuilder extends BCodeHelpers {
688688
genTraitConstructorDefDef(dd)
689689
else
690690
genStaticForwarderForDefDef(dd)
691-
genInterfaceMethodBridgeForDefDef(dd)
692691
genDefDef(dd)
693692
else
694693
genDefDef(dd)
@@ -769,48 +768,6 @@ trait BCodeSkelBuilder extends BCodeHelpers {
769768
).transform(dd.rhs)
770769
})
771770

772-
/** Creates a bridges for interfece inherited and narrowed methods,
773-
* to workaround JVM limitations when using LambdaMetaFactory (see issue #15402)
774-
* Example:
775-
* ```
776-
* trait Foo:
777-
* def self: Foo
778-
*
779-
* trait Bar extends Foo:
780-
* def self: Bar = this
781-
* def SAM(x: Any): Any
782-
*
783-
* def usage(x: List[Foo]) = x.map(_.self)
784-
* ```
785-
* We need to define a bridge in trait Bar `def self: Foo = Bar.this.self`
786-
* in order to prevent JVM runtime exceptions. Otherwise at the time of
787-
* accessing `_.self` in the SAM instance created based on the `trait Bar`
788-
* it will complain about missing implementation of `def self: Foo`.
789-
* Javac compiler does exactly the same.
790-
*/
791-
private def genInterfaceMethodBridgeForDefDef(dd: DefDef): Unit =
792-
val sym = dd.symbol
793-
sym.owner.directlyInheritedTraits
794-
.flatMap { parent =>
795-
val inheritedSym = parent.info.decl(sym.name)
796-
Option.when(
797-
inheritedSym.exists &&
798-
sym.signature != inheritedSym.signature &&
799-
sym.info <:< inheritedSym.info
800-
)(inheritedSym.symbol.asTerm)
801-
}.distinctBy(_.signature)
802-
.foreach(genInterfaceMethodBridge(sym.asTerm, _))
803-
804-
private def genInterfaceMethodBridge(sym: TermSymbol, inheritedSym: TermSymbol): Unit =
805-
assert(sym.name == inheritedSym.name, "Not an override")
806-
val owner = sym.owner.asClass
807-
val bridgeSym = inheritedSym.copy(owner = owner, flags = sym.flags).asTerm
808-
val bridge = tpd.DefDef(bridgeSym, {paramss =>
809-
val params = paramss.head
810-
tpd.Apply(tpd.This(owner).select(sym), params)
811-
})
812-
genDefDef(bridge)
813-
814771
private def genStaticForwarderForDefDef(dd: DefDef): Unit =
815772
val forwarderDef = makeStaticForwarder(dd)
816773
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)
@@ -172,9 +174,14 @@ class Bridges(root: ClassSymbol, thisPhase: DenotTransformer)(using Context) {
172174
* time deferred methods in `stats` that are replaced by a bridge with the same signature.
173175
*/
174176
def add(stats: List[untpd.Tree]): List[untpd.Tree] =
177+
// When adding bridges to traits ignore non-public methods
178+
// see `DottyBackendTests.invocationReceivers`
175179
val opc = inContext(preErasureCtx) { new BridgesCursor }
176180
while opc.hasNext do
177-
if !opc.overriding.is(Deferred) then
181+
if
182+
!opc.overriding.is(Deferred) &&
183+
(!root.is(Trait) || opc.overridden.isPublic)
184+
then
178185
addBridgeIfNeeded(opc.overriding, opc.overridden)
179186
opc.next()
180187
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
@@ -1104,5 +1104,5 @@ object Erasure {
11041104
}
11051105

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

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)