Skip to content

Commit 1d8db24

Browse files
committed
Gen bridge for inherited methods with narrowed types.
1 parent 6062192 commit 1d8db24

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
@@ -610,6 +610,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {
610610
genTraitConstructorDefDef(dd)
611611
else
612612
genStaticForwarderForDefDef(dd)
613+
genInterfaceMethodBridgeForDefDef(dd)
613614
genDefDef(dd)
614615
else
615616
genDefDef(dd)
@@ -690,6 +691,48 @@ trait BCodeSkelBuilder extends BCodeHelpers {
690691
).transform(dd.rhs)
691692
})
692693

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+
693736
private def genStaticForwarderForDefDef(dd: DefDef): Unit =
694737
val forwarderDef = makeStaticForwarder(dd)
695738
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)