scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
230 stars 21 forks source link

Bad bridge methods for f-bound traits (?) #6414

Open scabug opened 11 years ago

scabug commented 11 years ago

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)
scabug commented 11 years ago

Imported From: https://issues.scala-lang.org/browse/SI-6414?orig=1 Reporter: marius a. eriksen (mariusae) Affected Versions: 2.9.1, 2.10.0-M7 See #3452

scabug commented 11 years ago

marius a. eriksen (mariusae) said: This is x.java:

class Foo {
  public static void main(String[] args) {
    C c = new C();
    c = c.b().a();
  }
}
scabug commented 11 years ago

@paulp said: This is a variation of #3452.

SethTisue commented 6 years ago

closing stale backend tickets; comment/reopen if you have evidence this is still applicable

lrytz commented 6 years ago

No more crash at least, both cases the java code no longer compiles.