Open
Description
When using traits that are F-bounded:
trait A[This <: A[This]] {
def copy(): This
def a(): This = copy()
}
trait B[This <: B[This]] extends A[This] {
def b(): This = copy()
}
class C extends A[C] with B[C] {
def copy() = this
}
The bridge methods generated in C
are:
// class version 49.0 (49)
// access flags 0x21
// signature Ljava/lang/Object;LA<LC;>;LB<LC;>;Lscala/ScalaObject;
// declaration: C implements A<C>, B<C>, scala.ScalaObject
public class C implements A B scala/ScalaObject {
@Lscala/reflect/ScalaSignature;(bytes="\u0006\u0001\u00052A!\u0001\u0002\u0001\u000b\u0009\u00091IC\u0001\u0004\u0003\u001daT-\u001c9usz\u001a\u0001aE\u0003\u0001\r9\u0019b\u0003\u0005\u0002\u0008\u00195\u0009\u0001B\u0003\u0002\n\u0015\u0005!A.\u00198h\u0015\u0005Y\u0011\u0001\u00026bm\u0006L!!\u0004\u0005\u0003\r=\u0013'.Z2u!\ry\u0001CE\u0007\u0002\u0005%\u0011\u0011C\u0001\u0002\u0002\u0003B\u0011q\u0002\u0001\u0009\u0004\u001fQ\u0011\u0012BA\u000b\u0003\u0005\u0005\u0011\u0005CA\u000c\u001b\u001b\u0005A\"\"A\r\u0002\u000bM\u001c\u0017\r\\1\n\u0005mA\"aC*dC2\u000cwJ\u00196fGRDQ!\u0008\u0001\u0005\u0002y\u0009a\u0001P5oSRtD#\u0001\n\u0009\u000b\u0001\u0002A\u0011\u0001\u0010\u0002\u0009\r|\u0007/\u001f")
ATTRIBUTE ScalaSig : unknown
// access flags 0x41
public volatile bridge b()LB;
ALOAD 0
INVOKESTATIC B$class.b (LB;)LB;
ARETURN
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x41
public volatile bridge a()LA;
ALOAD 0
INVOKESTATIC A$class.a (LA;)LA;
ARETURN
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1
public copy()LC;
ALOAD 0
ARETURN
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x41
public volatile bridge copy()LA;
ALOAD 0
INVOKEVIRTUAL C.copy ()LC;
ARETURN
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1
public <init>()V
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
ALOAD 0
INVOKESTATIC A$class.$init$ (LA;)V
ALOAD 0
INVOKESTATIC B$class.$init$ (LB;)V
RETURN
MAXSTACK = 1
MAXLOCALS = 1
}
Note that these are typed returning A
and B
objects instead of C
. This makes it impossible to write, in Java:
class Foo {
static {
C c = new C();
c = c.b().a();
}
}
Though it works in Scala (I suspect due to ScalaSigs).
However, when a throwaway type parameter is introduced on each method:
trait A[This <: A[This]] {
def copy(): This
def a[SADPANDA](): This = copy()
}
trait B[This <: B[This]] extends A[This] {
def b[SADPANDA](): This = copy()
}
class C extends A[C] with B[C] {
def copy() = this
}
It works, I suspect due to the fact that this furnishes the bridges with java signatures:
// class version 49.0 (49)
// access flags 0x21
// signature Ljava/lang/Object;LA<LC;>;LB<LC;>;Lscala/ScalaObject;
// declaration: C implements A<C>, B<C>, scala.ScalaObject
public class C implements A B scala/ScalaObject {
@Lscala/reflect/ScalaSignature;(bytes="\u0006\u0001\u00052A!\u0001\u0002\u0001\u000b\u0009\u00091IC\u0001\u0004\u0003\u001daT-\u001c9usz\u001a\u0001aE\u0003\u0001\r9\u0019b\u0003\u0005\u0002\u0008\u00195\u0009\u0001B\u0003\u0002\n\u0015\u0005!A.\u00198h\u0015\u0005Y\u0011\u0001\u00026bm\u0006L!!\u0004\u0005\u0003\r=\u0013'.Z2u!\ry\u0001CE\u0007\u0002\u0005%\u0011\u0011C\u0001\u0002\u0002\u0003B\u0011q\u0002\u0001\u0009\u0004\u001fQ\u0011\u0012BA\u000b\u0003\u0005\u0005\u0011\u0005CA\u000c\u001b\u001b\u0005A\"\"A\r\u0002\u000bM\u001c\u0017\r\\1\n\u0005mA\"aC*dC2\u000cwJ\u00196fGRDQ!\u0008\u0001\u0005\u0002y\u0009a\u0001P5oSRtD#\u0001\n\u0009\u000b\u0001\u0002A\u0011\u0001\u0010\u0002\u0009\r|\u0007/\u001f")
ATTRIBUTE ScalaSig : unknown
// access flags 0x41
// signature <SADPANDA:Ljava/lang/Object;>()LC;
// declaration: C b<SADPANDA>()
public volatile bridge b()LB;
ALOAD 0
INVOKESTATIC B$class.b (LB;)LB;
ARETURN
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x41
// signature <SADPANDA:Ljava/lang/Object;>()LC;
// declaration: C a<SADPANDA>()
public volatile bridge a()LA;
ALOAD 0
INVOKESTATIC A$class.a (LA;)LA;
ARETURN
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1
public copy()LC;
ALOAD 0
ARETURN
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x41
public volatile bridge copy()LA;
ALOAD 0
INVOKEVIRTUAL C.copy ()LC;
ARETURN
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1
public <init>()V
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
ALOAD 0
INVOKESTATIC A$class.$init$ (LA;)V
ALOAD 0
INVOKESTATIC B$class.$init$ (LB;)V
RETURN
MAXSTACK = 1
MAXLOCALS = 1
}
Producing divergent java signatures, and so attempting to actually run the above code (which now compiles) results in a runtime error:
Exception in thread "main" java.lang.NoSuchMethodError: C.b()LC;
at Foo.main(x.java:4)