diff --git a/compiler/src/dotty/tools/dotc/transform/Bridges.scala b/compiler/src/dotty/tools/dotc/transform/Bridges.scala index 104c1fd0a21b..ca9550f09400 100644 --- a/compiler/src/dotty/tools/dotc/transform/Bridges.scala +++ b/compiler/src/dotty/tools/dotc/transform/Bridges.scala @@ -119,7 +119,7 @@ class Bridges(root: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Cont if (!opc.overriding.is(Deferred)) { addBridgeIfNeeded(opc.overriding, opc.overridden) - if (needsImplicitShortcut(opc.overriding)(ectx)) + if (needsImplicitShortcut(opc.overriding)(ectx) && needsImplicitShortcut(opc.overridden)(ectx)) // implicit shortcuts do not show up in the Bridges cursor, since they // are created only when referenced. Therefore we need to generate a bridge // for them specifically, if one is needed for the original methods. diff --git a/tests/run/implicit-shortcut-bridge.scala b/tests/run/implicit-shortcut-bridge.scala new file mode 100644 index 000000000000..97c168bd3c05 --- /dev/null +++ b/tests/run/implicit-shortcut-bridge.scala @@ -0,0 +1,45 @@ +abstract class A[T] { + def foo: T +} +class B extends A[implicit Int => Int] { + // No bridge needed for foo$direct + def foo: implicit Int => Int = 1 +} + +abstract class X[T] extends A[implicit T => T] { + def foo: implicit T => T +} + +class Y extends X[Int] { + def foo: implicit Int => Int = 1 +} + +object Test { + def check(expected: Set[String], cls: Class[_]): Unit = { + val actual = cls.getMethods.filter(_.getName.startsWith("foo")).map(_.toString).toSet + assert(expected == actual, s"[$cls] expected: ${expected}\nactual: $actual") + } + + def main(args: Array[String]): Unit = { + val expectedB = Set( + "public scala.Function1 B.foo()", // user-written method + "public int B.foo$direct(int)", // shortcut added by ShortcutImplicits + "public java.lang.Object B.foo()" // bridge to A#foo + ) + val expectedX = Set( + "public abstract scala.Function1 X.foo()", // user-written method + "public abstract java.lang.Object X.foo$direct(java.lang.Object)", // shortcut + "public abstract java.lang.Object A.foo()" // Inherited from A + ) + val expectedY = Set( + "public scala.Function1 Y.foo()", // user-written method + "public java.lang.Object Y.foo()", // Bridge to A#foo + "public int Y.foo$direct(int)", // shortcut + "public java.lang.Object Y.foo$direct(java.lang.Object)", // bridge to X#foo$direct + ) + + check(expectedB, classOf[B]) + check(expectedX, classOf[X[_]]) + check(expectedY, classOf[Y]) + } +}