- 
                Notifications
    You must be signed in to change notification settings 
- Fork 21
Closed
Description
We are using Eclipse 3.5 Build id 20090920-1017 and Scala Eclipse plug-in 2.8.0.r19132-b20091019023339.
When declaring a method that returns an inner class object of a specific instantiation of a type parameterized class, the generated byte code is missing a signature describing the actual type instantiation.
Consider these classes
class Outer[T](val t: T) {
  class Inner {
    def getT : T = t
  }
}
class OuterImpl(x: X) extends Outer(x) {
  def newInner = new Inner
}
class X {
  def getI : OuterImpl#Inner = {
    val oImpl = new OuterImpl(this)
    new oImpl.Inner
  }
}Inspecting the class file for class X, looking at the method "getI" reveals:
// Method descriptor SI-12 ()Ltest/scala/Outer$$Inner;
// Stack: 3, Locals: 2
public test.scala.Outer.Inner getI();Calling the class from Scala works fine. Functions 'getT' and 'getI' have the expected return types and can be chained forever.
class TestFromScala {
  val x = new X
  val o = new OuterImpl(x)
  val i = o.newInner
  val i2 = i.getT.getI.getT.getI
}However, calling from Java causes problems:
public class TestFromJava {
  void test() {
    final X x = new X();
    final OuterImpl o = new OuterImpl(x);
    
    final OuterImpl.Inner i1 = o.newInner();
    i1.getT().getI().getT().getI();  // <--- Error: "The method getI() is undefined for the type Object"
   
    final Outer<X>.Inner i2 = o.newInner();
    i2.getT().getI().getT().getI(); // <--- Error: "The method getI() is undefined for the type Object"
  }
}Implementing the same classes in Java looks like this:
public class Outer<T> {
  private final T t;
  public Outer(T t) {
    this.t = t;
  }
  
  public class Inner {
    public T getT() {
      return t;
    }
  }
}
 
public class OuterImpl extends Outer<X> {
  public OuterImpl(X x) {
    super(x);
  }
  
  public OuterImpl.Inner newInner() {
    return this.new Inner();
  }
}
public class X {
  OuterImpl.Inner getI() {
    final OuterImpl oImpl = new OuterImpl(this);
    return oImpl.newInner();
  }
}The signature for 'X.getI()' looks like this:
// Method descriptor SI-15 ()Ltest/java/Outer$$Inner;
// Signature: ()Ltest/java/Outer<Ltest/java/X;>.Inner;
// Stack: 3, Locals: 2
test.java.Outer.Inner getI();Please note the "// Signature" line. And now everythings works from Java:
public class TestFromJava {
  void test() {
    final X x = new X();
    final OuterImpl o = new OuterImpl(x);
    
    final OuterImpl.Inner i1 = o.newInner();
    i1.getT().getI().getT().getI(); // <--- Works fine.
    
    final Outer<X>.Inner i2 = o.newInner();
    i2.getT().getI().getT().getI(); // <--- Works fine.
  }
}