Skip to content

Commit cd7f12f

Browse files
committed
Emit mixin forwarders as bridges to remove the need for generic signatures
The compiler spends a lot of effort trying to generate correct generic signatures for mixin forwarders, but is still not correct as witnessed by scala/bug#8905 among others. However, it seems that if we just emit them with the BRIDGE flag set, both javac and ecj (the Eclipse Java Compiler) will be smart enough to go look for the signature in the overridden methods, which is exactly what we want. This means that we should be able to get rid of `cloneBeforeErasure` and related code, though that would conflict with scala#7752. Because history always repeats itself, it turns out that this used to be how mixin forwarders were emitted until fe94bc7 changed this 7 years ago. The commit only says that this "has deleterious effects since many tools ignore bridge methods" which is too vague for me to do anything about. Fixes scala/bug#8905 and probably countless others.
1 parent 2c32023 commit cd7f12f

File tree

7 files changed

+45
-16
lines changed

7 files changed

+45
-16
lines changed

src/compiler/scala/tools/nsc/transform/Mixin.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ abstract class Mixin extends Transform with ast.TreeDSL with AccessorSynthesis {
169169
clazz.info.decls enter member setFlag MIXEDIN resetFlag JAVA_DEFAULTMETHOD
170170
}
171171
def cloneAndAddMember(mixinClass: Symbol, mixinMember: Symbol, clazz: Symbol): Symbol =
172-
addMember(clazz, cloneBeforeErasure(mixinClass, mixinMember, clazz))
172+
addMember(clazz, cloneBeforeErasure(mixinClass, mixinMember, clazz).setFlag(BRIDGE))
173173

174174
def cloneBeforeErasure(mixinClass: Symbol, mixinMember: Symbol, clazz: Symbol): Symbol = {
175175
val newSym = enteringErasure {

test/files/neg/t4749.check

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ t4749.scala:28: warning: Fail6 has a valid main method (args: Array[String])Unit
3737

3838
object Fail6 {
3939
^
40-
t4749.scala:44: warning: not a valid main method for bippy.Win3,
41-
because main methods must have the exact signature (Array[String])Unit.
40+
t4749.scala:42: warning: not a valid main method for bippy.Win3,
41+
because main methods cannot refer to type parameters or abstract types.
4242
To define an entry point, please define the main method as:
4343
def main(args: Array[String]): Unit
4444

45-
object Win3 extends WinBippy[Unit] { }
46-
^
45+
def main(args: Array[String]): T = null.asInstanceOf[T]
46+
^
4747
error: No warnings can be incurred under -Xfatal-warnings.
4848
7 warnings found
4949
one error found

test/files/run/i8905/DoubleRDD.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import java.util.Comparator
2+
3+
trait RDDLike[T] {
4+
def max(comp: Comparator[T]): T = {
5+
(1.0).asInstanceOf[T]
6+
}
7+
}
8+
9+
class DoubleRDD extends RDDLike[java.lang.Double] { }

test/files/run/i8905/Test.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import java.util.Comparator;
2+
3+
public class Test {
4+
private static class DoubleComparator implements Comparator<Double> {
5+
public int compare(Double o1, Double o2) {
6+
return o1.compareTo(o2);
7+
}
8+
}
9+
10+
public static void main(String[] args) {
11+
DoubleRDD rdd = new DoubleRDD();
12+
RDDLike<Double> rddLike = rdd;
13+
14+
// This call works fine:
15+
double rddLikeMax = rddLike.max(new DoubleComparator());
16+
// In Scala 2.10.4, this code compiles but this call fails at runtime:
17+
// java.lang.NoSuchMethodError: DoubleRDD.max(Ljava/util/Comparator;)Ljava/lang/Double;
18+
double rddMax = rdd.max(new DoubleComparator());
19+
}
20+
}

test/files/run/mixin-bridge-methods.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ class Sub extends Foo {
99
object Test {
1010
def main(args: Array[String]): Unit = {
1111
val ms = classOf[Sub].getDeclaredMethods
12-
assert(ms forall (x => !x.isBridge), ms mkString " ")
12+
assert(ms forall (_.isBridge), ms mkString " ")
1313
}
1414
}

test/files/run/mixin-signatures.check

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
class Test$bar1$ {
2-
public java.lang.String Test$bar1$.f(java.lang.Object)
32
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>
44
public java.lang.String Test$bar1$.g(java.lang.String)
55
public java.lang.Object Test$bar1$.g(java.lang.Object) <bridge> <synthetic>
66
public java.lang.String Test$bar1$.g(java.lang.Object) <bridge> <synthetic>
7-
public java.lang.Object Test$bar1$.h(java.lang.Object)
7+
public java.lang.Object Test$bar1$.h(java.lang.Object) <bridge> <synthetic>
88
}
99

1010
class Test$bar2$ {
11-
public java.lang.Object Test$bar2$.f(java.lang.String)
1211
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>
1313
public java.lang.String Test$bar2$.g(java.lang.String)
1414
public java.lang.Object Test$bar2$.g(java.lang.Object) <bridge> <synthetic>
1515
public java.lang.Object Test$bar2$.g(java.lang.String) <bridge> <synthetic>
16-
public java.lang.Object Test$bar2$.h(java.lang.Object)
16+
public java.lang.Object Test$bar2$.h(java.lang.Object) <bridge> <synthetic>
1717
}
1818

1919
class Test$bar3$ {
@@ -23,7 +23,7 @@ class Test$bar3$ {
2323
public java.lang.String Test$bar3$.g(java.lang.String)
2424
public java.lang.Object Test$bar3$.g(java.lang.Object) <bridge> <synthetic>
2525
public java.lang.String Test$bar3$.g(java.lang.Object) <bridge> <synthetic>
26-
public java.lang.Object Foo3.h(java.lang.Object)
26+
public java.lang.Object Foo3.h(java.lang.Object) <bridge> <synthetic>
2727
}
2828

2929
class Test$bar4$ {
@@ -33,7 +33,7 @@ class Test$bar4$ {
3333
public java.lang.String Test$bar4$.g(java.lang.String)
3434
public java.lang.Object Test$bar4$.g(java.lang.Object) <bridge> <synthetic>
3535
public java.lang.Object Test$bar4$.g(java.lang.String) <bridge> <synthetic>
36-
public java.lang.Object Foo4.h(java.lang.Object)
36+
public java.lang.Object Foo4.h(java.lang.Object) <bridge> <synthetic>
3737
}
3838

3939
class Test$bar5$ {
@@ -45,7 +45,7 @@ class Test$bar5$ {
4545
public java.lang.Object Test$bar5$.g(java.lang.Object) <bridge> <synthetic>
4646
public java.lang.Object Test$bar5$.g(java.lang.String) <bridge> <synthetic>
4747
public java.lang.String Test$bar5$.g(java.lang.Object) <bridge> <synthetic>
48-
public java.lang.Object Test$bar5$.h(java.lang.Object)
48+
public java.lang.Object Test$bar5$.h(java.lang.Object) <bridge> <synthetic>
4949
}
5050

5151
interface Foo1 {

test/files/run/t7932.check

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
public Category<?> C.category()
2-
public Category<scala.Tuple2> C.category1()
1+
public Category C.category()
2+
public Category C.category1()
33
public default Category<java.lang.Object> M1.category()
44
public default Category<scala.Tuple2> M1.category1()
55
public static Category M1.category$(M1)
66
public static Category M1.category1$(M1)
77
public default Category<java.lang.Object> M2.category()
88
public default Category<scala.Tuple2> M2.category1()
99
public static Category M2.category$(M2)
10-
public static Category M2.category1$(M2)
10+
public static Category M2.category1$(M2)

0 commit comments

Comments
 (0)