Scala Programming Language
  1. Scala Programming Language
  2. SI-3452

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

    Details

      Description

      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

        Issue Links

          Activity

          Hide
          Paul Phillips added a comment -

          And going two thousand and more notches in the other direction, see also SI-6050.

          Show
          Paul Phillips added a comment - And going two thousand and more notches in the other direction, see also SI-6050 .
          Hide
          Paul Phillips added a comment -

          See also SI-6414 .

          Show
          Paul Phillips added a comment - See also SI-6414 .
          Hide
          Paolo G. Giarrusso added a comment -

          It seems too late for a proper fix in 2.10.0... would it be worth to resubmit just the part which checks generic signatures and omits the erroneous ones?

          Show
          Paolo G. Giarrusso added a comment - It seems too late for a proper fix in 2.10.0... would it be worth to resubmit just the part which checks generic signatures and omits the erroneous ones?
          Hide
          Jason Zaugg added a comment -

          I'm considering this approach:

          https://github.com/scala/scala/pull/3493

          The key dilemna is what to do about mixin signatures. We should really add bridges. But that has proved really tough to implement. So as a stopgap measure, I'm weakening the as-seen-from the subclass generic signature if it doesn't erase to the same signature as the trait forwarder.

          By doing this conditionally, I can at least maintain backwards compatibility with code that didn't previously result in a LinkageError.

          Show
          Jason Zaugg added a comment - I'm considering this approach: https://github.com/scala/scala/pull/3493 The key dilemna is what to do about mixin signatures. We should really add bridges. But that has proved really tough to implement. So as a stopgap measure, I'm weakening the as-seen-from the subclass generic signature if it doesn't erase to the same signature as the trait forwarder. By doing this conditionally, I can at least maintain backwards compatibility with code that didn't previously result in a LinkageError.
          Hide
          Jason Zaugg added a comment - - edited

          Closing as the problems with trait forwarders and static forwarders has been fixed in 2.11.0, by emitting weaker signatures if the exact one won't be coherent with the erasure.

          I'm hopeful we'll find a more refined approach in the future. I've outlined the ideas for that: SI-8293

          If I have missed any residual signature issues that weren't related to forwarders, please open a new ticket and link it to this one.

          Show
          Jason Zaugg added a comment - - edited Closing as the problems with trait forwarders and static forwarders has been fixed in 2.11.0, by emitting weaker signatures if the exact one won't be coherent with the erasure. I'm hopeful we'll find a more refined approach in the future. I've outlined the ideas for that: SI-8293 If I have missed any residual signature issues that weren't related to forwarders, please open a new ticket and link it to this one.

            People

            • Assignee:
              Jason Zaugg
              Reporter:
              Johannes Rudolph
              TracCC:
              Paul Phillips, Stefan Endrullis
            • Votes:
              4 Vote for this issue
              Watchers:
              12 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development