Skip to content

Static methods in objects extending an abstract class, or classes with covariant-overriding mxins, get inconsistent java generics signature #3452

Closed
@scabug

Description

@scabug

See this [http://scala-programming-language.1934581.n4.nabble.com/valid-code-throws-NoSuchMethodError-at-runtime-td2222685.html#a2222685 thread]

Compiling this with scalac (tested 2.8.0.RC2):

abstract class BulkSearch {
       type R   <: Row
       type Rel <: Relation [R]
       type Corr <: Correspondence[R]

       def searchFor(input: Rel): Mapping[Corr] = null
}

object BulkSearchInstance extends BulkSearch {
       type R   = UpRow
       type Rel = UpRelation
       type Corr = UpCorrespondence
}

class Row
class UpRow extends Row

class Relation [R <: Row]
class UpRelation extends Relation [UpRow]

class Correspondence [R <: Row]
class UpCorrespondence extends Correspondence [UpRow]

class Mapping[MC <: Correspondence[_]]

and compiling this with javac:

public class JavaApp {
       public static void main(String[] args) {
               BulkSearchInstance.searchFor(new UpRelation());
       }
}

produces no compile-time errors but a runtime error later on:

Exception in thread "main" java.lang.NoSuchMethodError: bugs.BulkSearchInstance.searchFor(Lbugs/UpRelation;)Lbugs/Mapping;
       at bugs.JavaApp.main(JavaApp.java:15)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:597)
       at com.intellij.rt.execution.application.AppMain.main(AppMain.java:110)

After some analysis, I found out that is probably due to an inconsistent generic signature being generated for the static method delegate in BulkSearchInstance.class.

Scalac generates these signatures for BulkSearchInstance.searchFor:

method_info.descriptor (see  4.3 JVM spec): (LRelation;)LMapping;
attribute 'Signature' (see JSR 014): (LUpRelation;)LMapping<LUpCorrespondence;>;

When javac sees that, it produces something strange (i.e. not matching the descriptor found in BulkSearchInstance.class):

invokestatic    SI-4; //Method BulkSearchInstance.searchFor:(LUpRelation;)LMapping;

which looks like the erasure of the generic signature. However, JVM's linker looks for the exact descriptor when looking for methods. I think the solution should be

  1. Always generate consistent descriptor and generic signature
  2. At least, in the case of the static delegator method in the object class, generate the most specific type possible. The method can't be overridden anyways.

Workaround: use a trait instead of an abstract class

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions