Skip to content

Commit 3390d07

Browse files
committed
Emit mixin forwarders as bridges
This is the same scheme I proposed in scala/scala#7843 which sidesteps all the issues regarding mixin forwarders and generic signatures, see the discussion in that PR for more information. Tests imported from scalac, some of the comments in them might not be correct for Dotty anymore.
1 parent d226877 commit 3390d07

File tree

20 files changed

+283
-78
lines changed

20 files changed

+283
-78
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
262262
for (meth <- mixin.info.decls.toList if needsMixinForwarder(meth))
263263
yield {
264264
util.Stats.record("mixin forwarders")
265-
transformFollowing(polyDefDef(mkForwarderSym(meth.asTerm), forwarderRhsFn(meth)))
265+
transformFollowing(polyDefDef(mkForwarderSym(meth.asTerm, Bridge), forwarderRhsFn(meth)))
266266
}
267267

268268

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ class MixinOps(cls: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Cont
1818
map(n => ctx.getClassIfDefined("org.junit." + n)).
1919
filter(_.exists)
2020

21-
def mkForwarderSym(member: TermSymbol): TermSymbol = {
21+
def mkForwarderSym(member: TermSymbol, extraFlags: FlagSet = EmptyFlags): TermSymbol = {
2222
val res = member.copy(
2323
owner = cls,
2424
name = member.name.stripScala2LocalSuffix,
25-
flags = member.flags &~ Deferred | Synthetic | Artifact,
25+
flags = member.flags &~ Deferred | Synthetic | Artifact | extraFlags,
2626
info = cls.thisType.memberInfo(member)).enteredAfter(thisPhase).asTerm
2727
res.addAnnotations(member.annotations.filter(_.symbol != defn.TailrecAnnot))
2828
res

compiler/test/dotc/run-test-pickling.blacklist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ derive-generic.scala
1313
deriving-interesting-prefixes.scala
1414
instances.scala
1515
instances-anonymous.scala
16+
mixin-forwarder-overload

tests/run/mixin-bridge-methods.scala

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
case class Foo(x: Int)
2+
3+
trait A[X] {
4+
def concat[Dummy](suffix: Int): Dummy = ???
5+
}
6+
7+
class Bar extends A[Foo] {
8+
def concat(suffix: Int): Foo = Foo(0)
9+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
public class Test {
2+
public static void main(String[] args) {
3+
Bar bar = new Bar();
4+
Foo x = bar.concat(0);
5+
System.out.println(x);
6+
}
7+
}

tests/run/mixin-signatures.check

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
class Test$bar1$ {
2+
public java.lang.Object Test$bar1$.f(java.lang.Object) <bridge> <synthetic>
3+
public java.lang.String Test$bar1$.f(java.lang.Object) <bridge> <synthetic>
4+
public java.lang.String Test$bar1$.g(java.lang.String)
5+
public java.lang.Object Test$bar1$.g(java.lang.Object) <bridge> <synthetic>
6+
public java.lang.String Test$bar1$.g(java.lang.Object) <bridge> <synthetic>
7+
public java.lang.Object Test$bar1$.h(java.lang.Object) <bridge> <synthetic>
8+
}
9+
10+
class Test$bar2$ {
11+
public java.lang.Object Test$bar2$.f(java.lang.Object) <bridge> <synthetic>
12+
public java.lang.Object Test$bar2$.f(java.lang.String) <bridge> <synthetic>
13+
public java.lang.String Test$bar2$.g(java.lang.String)
14+
public java.lang.Object Test$bar2$.g(java.lang.Object) <bridge> <synthetic>
15+
public java.lang.Object Test$bar2$.g(java.lang.String) <bridge> <synthetic>
16+
public java.lang.Object Test$bar2$.h(java.lang.Object) <bridge> <synthetic>
17+
}
18+
19+
class Test$bar3$ {
20+
public java.lang.String Foo3.f(java.lang.Object)
21+
generic: public java.lang.String Foo3.f(T)
22+
public java.lang.Object Foo3.f(java.lang.Object) <bridge> <synthetic>
23+
public java.lang.String Test$bar3$.g(java.lang.String)
24+
public java.lang.Object Test$bar3$.g(java.lang.Object) <bridge> <synthetic>
25+
public java.lang.String Test$bar3$.g(java.lang.Object) <bridge> <synthetic>
26+
public java.lang.Object Foo3.h(java.lang.Object) <bridge> <synthetic>
27+
}
28+
29+
class Test$bar4$ {
30+
public java.lang.Object Foo4.f(java.lang.String)
31+
generic: public R Foo4.f(java.lang.String)
32+
public java.lang.Object Foo4.f(java.lang.Object) <bridge> <synthetic>
33+
public java.lang.String Test$bar4$.g(java.lang.String)
34+
public java.lang.Object Test$bar4$.g(java.lang.Object) <bridge> <synthetic>
35+
public java.lang.Object Test$bar4$.g(java.lang.String) <bridge> <synthetic>
36+
public java.lang.Object Foo4.h(java.lang.Object) <bridge> <synthetic>
37+
}
38+
39+
class Test$bar5$ {
40+
public java.lang.String Test$bar5$.f(java.lang.String)
41+
public java.lang.Object Test$bar5$.f(java.lang.Object) <bridge> <synthetic>
42+
public java.lang.Object Test$bar5$.f(java.lang.String) <bridge> <synthetic>
43+
public java.lang.String Test$bar5$.f(java.lang.Object) <bridge> <synthetic>
44+
public java.lang.String Test$bar5$.g(java.lang.String)
45+
public java.lang.Object Test$bar5$.g(java.lang.Object) <bridge> <synthetic>
46+
public java.lang.Object Test$bar5$.g(java.lang.String) <bridge> <synthetic>
47+
public java.lang.String Test$bar5$.g(java.lang.Object) <bridge> <synthetic>
48+
public java.lang.Object Test$bar5$.h(java.lang.Object) <bridge> <synthetic>
49+
}
50+
51+
interface Foo1 {
52+
public abstract java.lang.Object Base.f(java.lang.Object)
53+
generic: public abstract R Base.f(T)
54+
public default java.lang.String Foo1.f(java.lang.Object)
55+
generic: public default java.lang.String Foo1.f(T)
56+
public abstract java.lang.Object Base.g(java.lang.Object)
57+
generic: public abstract R Base.g(T)
58+
public abstract java.lang.String Foo1.g(java.lang.Object)
59+
generic: public abstract java.lang.String Foo1.g(T)
60+
public default java.lang.Object Base.h(java.lang.Object)
61+
generic: public default R Base.h(T)
62+
}
63+
64+
interface Foo2 {
65+
public abstract java.lang.Object Base.f(java.lang.Object)
66+
generic: public abstract R Base.f(T)
67+
public default java.lang.Object Foo2.f(java.lang.String)
68+
generic: public default R Foo2.f(java.lang.String)
69+
public abstract java.lang.Object Base.g(java.lang.Object)
70+
generic: public abstract R Base.g(T)
71+
public abstract java.lang.Object Foo2.g(java.lang.String)
72+
generic: public abstract R Foo2.g(java.lang.String)
73+
public default java.lang.Object Base.h(java.lang.Object)
74+
generic: public default R Base.h(T)
75+
}
76+
77+
000000000000000000000000000000000000

tests/run/mixin-signatures.scala

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
trait Base[T, R] {
2+
def f(x: T): R
3+
def g(x: T): R
4+
def h(x: T): R = null.asInstanceOf[R]
5+
}
6+
7+
trait Foo1[T] extends Base[T, String] {
8+
def f(x: T): String = null
9+
def g(x: T): String
10+
}
11+
trait Foo2[R] extends Base[String, R] {
12+
def f(x: String): R = { print(x.length) ; null.asInstanceOf[R] }
13+
def g(x: String): R
14+
}
15+
abstract class Foo3[T] extends Base[T, String] {
16+
def f(x: T): String = ""
17+
def g(x: T): String
18+
}
19+
abstract class Foo4[R] extends Base[String, R] {
20+
def f(x: String): R = { print(x.length) ; null.asInstanceOf[R] }
21+
def g(x: String): R
22+
}
23+
24+
object Test {
25+
object bar1 extends Foo1[String] { def g(x: String): String = { print(x.length) ; "" } }
26+
object bar2 extends Foo2[String] { def g(x: String): String = { print(x.length) ; "" } }
27+
object bar3 extends Foo3[String] { def g(x: String): String = { print(x.length) ; "" } }
28+
object bar4 extends Foo4[String] { def g(x: String): String = { print(x.length) ; "" } }
29+
30+
// Notice that in bar5, f and g require THREE bridges, because the final
31+
// implementation is (String)String, but:
32+
//
33+
// inherited abstract signatures: T(R), (T)String, and (String)R
34+
// which erase to: (Object)Object, (Object)String, and (String)Object
35+
//
36+
// each of which must be bridged to the actual (String)String implementation.
37+
//
38+
// public java.lang.String Test$bar5$.g(java.lang.String)
39+
// public java.lang.Object Test$bar5$.g(java.lang.String) <bridge> <synthetic>
40+
// public java.lang.Object Test$bar5$.g(java.lang.Object) <bridge> <synthetic>
41+
// public java.lang.String Test$bar5$.g(java.lang.Object) <bridge> <synthetic>
42+
object bar5 extends Foo1[String] with Foo2[String] {
43+
override def f(x: String): String = { print(x.length) ; x }
44+
def g(x: String): String = { print(x.length) ; x }
45+
}
46+
47+
final def m1[T, R](x: Base[T, R], y: T) = { x.f(y) ; x.g(y) ; x.h(y) }
48+
final def m2[T](x: Base[T, String], y: T) = { x.f(y) ; x.g(y) ; x.h(y) }
49+
final def m3[R](x: Base[String, R]) = { x.f("") ; x.g("") ; x.h("") }
50+
final def m4(x: Base[String, String]) = { x.f("") ; x.g("") ; x.h("") }
51+
52+
final def m11[T](x: Foo1[T], y: T) = { x.f(y) ; x.g(y) ; x.h(y) }
53+
final def m12(x: Foo1[String]) = { x.f("") ; x.g("") ; x.h("") }
54+
final def m21[T](x: Foo2[T], y: T) = { x.f("") ; x.g("") ; x.h("") }
55+
final def m22(x: Foo2[String]) = { x.f("") ; x.g("") ; x.h("") }
56+
final def m31[T](x: Foo3[T], y: T) = { x.f(y) ; x.g(y) ; x.h(y) }
57+
final def m32(x: Foo3[String]) = { x.f("") ; x.g("") ; x.h("") }
58+
final def m41[T](x: Foo4[T], y: T) = { x.f("") ; x.g("") ; x.h("") }
59+
final def m42(x: Foo4[String]) = { x.f("") ; x.g("") ; x.h("") }
60+
61+
def go = {
62+
m1(bar1, "") ; m2(bar1, "") ; m3(bar1) ; m4(bar1)
63+
m1(bar2, "") ; m2(bar2, "") ; m3(bar2) ; m4(bar2)
64+
m1(bar3, "") ; m2(bar3, "") ; m3(bar3) ; m4(bar3)
65+
m1(bar4, "") ; m2(bar4, "") ; m3(bar4) ; m4(bar4)
66+
67+
m11(bar1, "") ; m12(bar1)
68+
m21(bar2, "") ; m22(bar2)
69+
m31(bar3, "") ; m32(bar3)
70+
m41(bar4, "") ; m42(bar4)
71+
""
72+
}
73+
74+
def flagsString(m: java.lang.reflect.Method) = {
75+
val str = List(
76+
if (m.isBridge) "<bridge>" else "",
77+
if (m.isSynthetic) "<synthetic>" else ""
78+
) filterNot (_ == "") mkString " "
79+
80+
if (str == "") "" else " " + str
81+
//
82+
// val flags = scala.reflect.internal.ClassfileConstants.toScalaMethodFlags(m.getModifiers())
83+
// scala.tools.nsc.symtab.Flags.flagsToString(flags)
84+
}
85+
86+
def show(clazz: Class[_]): Unit = {
87+
print(clazz.toString + " {")
88+
clazz.getMethods.sortBy(x => (x.getName, x.isBridge, x.toString)) filter (_.getName.length == 1) foreach { m =>
89+
print("\n " + m + flagsString(m))
90+
if ("" + m != "" + m.toGenericString) {
91+
print("\n generic: " + m.toGenericString)
92+
}
93+
}
94+
println("\n}")
95+
println("")
96+
}
97+
def show(x: AnyRef): Unit = { show(x.getClass) }
98+
def show(x: String): Unit = { show(Class.forName(x)) }
99+
100+
def main(args: Array[String]): Unit = {
101+
List(bar1, bar2, bar3, bar4, bar5) foreach show
102+
List("Foo1", "Foo2") foreach show
103+
println(go)
104+
}
105+
}

tests/run/t3452b-bcode/J_2.java

Lines changed: 0 additions & 6 deletions
This file was deleted.

tests/run/t3452b-bcode/S_1.scala

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)