Skip to content

Commit 9c01e1b

Browse files
committed
Gen bridge for inherited methods with narrowed types.
1 parent 01b404f commit 9c01e1b

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {
688688
genTraitConstructorDefDef(dd)
689689
else
690690
genStaticForwarderForDefDef(dd)
691+
genInterfaceMethodBridgeForDefDef(dd)
691692
genDefDef(dd)
692693
else
693694
genDefDef(dd)
@@ -768,6 +769,48 @@ trait BCodeSkelBuilder extends BCodeHelpers {
768769
).transform(dd.rhs)
769770
})
770771

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+
771814
private def genStaticForwarderForDefDef(dd: DefDef): Unit =
772815
val forwarderDef = makeStaticForwarder(dd)
773816
genDefDef(forwarderDef)

tests/run/i15402.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
trait Named:
2+
def me: Named
3+
4+
trait Foo extends Named:
5+
def me: Foo = this
6+
def foo(x: Named): Named
7+
8+
trait Foo2 extends Foo
9+
10+
class Names(xs: List[Named]):
11+
def mkString = xs.map(_.me).mkString(",")
12+
13+
object Names:
14+
def single[T <: Named](t: T): Names = Names(List(t))
15+
16+
@main def Test() =
17+
Names.single[Foo](identity).mkString
18+
Names.single[Foo2](identity).mkString

0 commit comments

Comments
 (0)