Skip to content

Commit

Permalink
Emit mixin forwarders as bridges to avoid needing generic signatures
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
smarter committed Mar 12, 2019
1 parent 8b510ca commit 3e1f47d
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 29 deletions.
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/transform/Mixin.scala
Expand Up @@ -169,7 +169,7 @@ abstract class Mixin extends Transform with ast.TreeDSL with AccessorSynthesis {
clazz.info.decls enter member setFlag MIXEDIN resetFlag JAVA_DEFAULTMETHOD
}
def cloneAndAddMember(mixinClass: Symbol, mixinMember: Symbol, clazz: Symbol): Symbol =
addMember(clazz, cloneBeforeErasure(mixinClass, mixinMember, clazz))
addMember(clazz, cloneBeforeErasure(mixinClass, mixinMember, clazz).setFlag(BRIDGE))

def cloneBeforeErasure(mixinClass: Symbol, mixinMember: Symbol, clazz: Symbol): Symbol = {
val newSym = enteringErasure {
Expand Down
8 changes: 4 additions & 4 deletions test/files/neg/t4749.check
Expand Up @@ -37,13 +37,13 @@ t4749.scala:28: warning: Fail6 has a valid main method (args: Array[String])Unit

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

object Win3 extends WinBippy[Unit] { }
^
def main(args: Array[String]): T = null.asInstanceOf[T]
^
error: No warnings can be incurred under -Xfatal-warnings.
7 warnings found
one error found
14 changes: 0 additions & 14 deletions test/files/run/mixin-bridge-methods.scala

This file was deleted.

14 changes: 7 additions & 7 deletions test/files/run/mixin-signatures.check
@@ -1,19 +1,19 @@
class Test$bar1$ {
public java.lang.String Test$bar1$.f(java.lang.Object)
public java.lang.Object Test$bar1$.f(java.lang.Object) <bridge> <synthetic>
public java.lang.String Test$bar1$.f(java.lang.Object) <bridge> <synthetic>
public java.lang.String Test$bar1$.g(java.lang.String)
public java.lang.Object Test$bar1$.g(java.lang.Object) <bridge> <synthetic>
public java.lang.String Test$bar1$.g(java.lang.Object) <bridge> <synthetic>
public java.lang.Object Test$bar1$.h(java.lang.Object)
public java.lang.Object Test$bar1$.h(java.lang.Object) <bridge> <synthetic>
}

class Test$bar2$ {
public java.lang.Object Test$bar2$.f(java.lang.String)
public java.lang.Object Test$bar2$.f(java.lang.Object) <bridge> <synthetic>
public java.lang.Object Test$bar2$.f(java.lang.String) <bridge> <synthetic>
public java.lang.String Test$bar2$.g(java.lang.String)
public java.lang.Object Test$bar2$.g(java.lang.Object) <bridge> <synthetic>
public java.lang.Object Test$bar2$.g(java.lang.String) <bridge> <synthetic>
public java.lang.Object Test$bar2$.h(java.lang.Object)
public java.lang.Object Test$bar2$.h(java.lang.Object) <bridge> <synthetic>
}

class Test$bar3$ {
Expand All @@ -23,7 +23,7 @@ class Test$bar3$ {
public java.lang.String Test$bar3$.g(java.lang.String)
public java.lang.Object Test$bar3$.g(java.lang.Object) <bridge> <synthetic>
public java.lang.String Test$bar3$.g(java.lang.Object) <bridge> <synthetic>
public java.lang.Object Foo3.h(java.lang.Object)
public java.lang.Object Foo3.h(java.lang.Object) <bridge> <synthetic>
}

class Test$bar4$ {
Expand All @@ -33,7 +33,7 @@ class Test$bar4$ {
public java.lang.String Test$bar4$.g(java.lang.String)
public java.lang.Object Test$bar4$.g(java.lang.Object) <bridge> <synthetic>
public java.lang.Object Test$bar4$.g(java.lang.String) <bridge> <synthetic>
public java.lang.Object Foo4.h(java.lang.Object)
public java.lang.Object Foo4.h(java.lang.Object) <bridge> <synthetic>
}

class Test$bar5$ {
Expand All @@ -45,7 +45,7 @@ class Test$bar5$ {
public java.lang.Object Test$bar5$.g(java.lang.Object) <bridge> <synthetic>
public java.lang.Object Test$bar5$.g(java.lang.String) <bridge> <synthetic>
public java.lang.String Test$bar5$.g(java.lang.Object) <bridge> <synthetic>
public java.lang.Object Test$bar5$.h(java.lang.Object)
public java.lang.Object Test$bar5$.h(java.lang.Object) <bridge> <synthetic>
}

interface Foo1 {
Expand Down
6 changes: 3 additions & 3 deletions test/files/run/t7932.check
@@ -1,10 +1,10 @@
public Category<?> C.category()
public Category<scala.Tuple2> C.category1()
public Category C.category()
public Category C.category1()
public default Category<java.lang.Object> M1.category()
public default Category<scala.Tuple2> M1.category1()
public static Category M1.category$(M1)
public static Category M1.category1$(M1)
public default Category<java.lang.Object> M2.category()
public default Category<scala.Tuple2> M2.category1()
public static Category M2.category$(M2)
public static Category M2.category1$(M2)
public static Category M2.category1$(M2)
9 changes: 9 additions & 0 deletions test/files/run/t8905/DoubleRDD.scala
@@ -0,0 +1,9 @@
import java.util.Comparator

trait RDDLike[T] {
def max(comp: Comparator[T]): T = {
(1.0).asInstanceOf[T]
}
}

class DoubleRDD extends RDDLike[java.lang.Double] { }
20 changes: 20 additions & 0 deletions test/files/run/t8905/Test.java
@@ -0,0 +1,20 @@
import java.util.Comparator;

public class Test {
private static class DoubleComparator implements Comparator<Double> {
public int compare(Double o1, Double o2) {
return o1.compareTo(o2);
}
}

public static void main(String[] args) {
DoubleRDD rdd = new DoubleRDD();
RDDLike<Double> rddLike = rdd;

// This call works fine:
double rddLikeMax = rddLike.max(new DoubleComparator());
// In Scala 2.10.4, this code compiles but this call fails at runtime:
// java.lang.NoSuchMethodError: DoubleRDD.max(Ljava/util/Comparator;)Ljava/lang/Double;
double rddMax = rdd.max(new DoubleComparator());
}
}

0 comments on commit 3e1f47d

Please sign in to comment.