[SI-8899] Scalatra existing builds suffer java.lang.AbstractMethodError with Scala 2.11.3 Created: 12/Oct/14  Updated: 04/Nov/14  Resolved: 04/Nov/14

Status: CLOSED
Project: Scala Programming Language
Component/s: None
Affects Version/s: Scala 2.11.3
Fix Version/s: Scala 2.11.4

Type: Bug Priority: Blocker
Reporter: Kazuhiro Sera Assignee: Lukas Rytz
Resolution: Fixed Votes: 3
Labels: None
Environment:

Scala 2.11.3



 Description   

Scalatra 2.3.0 works fine on Scala 2.11.0 , 2.11.1 and 2.11.2. However, it suffers java.lang.AbstractMethodError with Scala 2.11.3.

2014-10-12 12:30:50,627 ERROR [qtp1562951302-64] controller.Controllers$members$ org.scalatra.ScalatraParams.filterImpl(Lscala/Function1;Z)Ljava/lang/Object;
java.lang.AbstractMethodError: org.scalatra.ScalatraParams.filterImpl(Lscala/Function1;Z)Ljava/lang/Object;
    at scala.collection.TraversableLike$class.filter(TraversableLike.scala:270) ~[scala-library-2.11.3.jar:na]
    at org.scalatra.ScalatraParams.filter(ScalatraContext.scala:9) ~[scalatra_2.11-2.3.0.jar:2.3.0]
    at skinny.StrongParameters.permit(StrongParameters.scala:18) ~[skinny-common_2.11-1.3.3.jar:1.3.3]
    at skinny.controller.Params.permit(Params.scala:46) ~[skinny-framework_2.11-1.3.3.jar:1.3.3]
    at skinny.controller.SkinnyResourceActions$$anonfun$createResource$1.apply(SkinnyResourceActions.scala:139) ~[skinny-framework_2.11-1.3.3.jar:1.3.3]
    at skinny.controller.SkinnyControllerBase$class.withFormat(SkinnyControllerBase.scala:108) ~[skinny-framework_2.11-1.3.3.jar:1.3.3]
    at skinny.controller.SkinnyController.withFormat(SkinnyController.scala:6) [skinny-framework_2.11-1.3.3.jar:1.3.3]
    at skinny.controller.SkinnyResourceActions$class.createResource(SkinnyResourceActions.scala:135) ~[skinny-framework_2.11-1.3.3.jar:1.3.3]
    at controller.MembersController.createResource(MembersController.scala:8) ~[classes/:na]

I just tried Scalatra builds with the 2.11.3 compiler. They works fine.

See also for details:
https://github.com/skinny-framework/skinny-framework/issues/193



 Comments   
Comment by Jason Zaugg [ 12/Oct/14 ]

Lukas, looks like this stems from 9276a1205f74fdec74206209712831913e93f359. Did we reason incorrectly about the binary compatibilty of that change?

Comment by kenji yoshida [ 12/Oct/14 ]

more simple example

https://github.com/xuwei-k/SI-8899

Comment by Takashi Kawachi [ 12/Oct/14 ]

As kenji shown in the sample code, it's not specific to Scalatra. It seems to be caused when it extends standard collection.

Comment by kenji yoshida [ 12/Oct/14 ]

another examples

Comment by kenji yoshida [ 12/Oct/14 ]

also https://github.com/playframework/playframework/blob/2.3.5/framework/src/play/src/main/scala/play/api/mvc/Http.scala#L683

Comment by Grzegorz Kossakowski [ 12/Oct/14 ]

The related PR is: https://github.com/scala/scala/pull/3949

Comment by Lukas Rytz [ 12/Oct/14 ]

Making filterImpl non-private in PR #3949 was indeed not binary compatible. The problem is that making a trait method non-private changes its calling convention. Here's an example:

trait Tl {
  private def f1Impl = 0
  def f1 = f1Impl
 
  private[p] def f2Impl = 0
  def f2 = f2Impl
}
 
class Mp extends Tl

The point is that the invocation of f1Impl is statically known. So the compiler optimizes it and directly invokes the static method f1Impl in the trait implementation class Tl$class.

Method f2Impl on the other hand may be overwritten in subclasses of Tl, therefore the invocation is compiled as an invoke-interface of the method f2Impl in interface Tl. In the subclass Mp, a mixin is generated for f2Impl.

 
public abstract interface p/Tl {
  // NOTE: f1Impl is missing - it's private!
  public abstract f1()I
  public abstract f2Impl()I
  public abstract f2()I
}
 
public abstract class p/Tl$class {
  private static f1Impl(Lp/Tl;)I
  public static f1(Lp/Tl;)I
    ALOAD 0
    INVOKESTATIC p/Tl$class.f1Impl (Lp/Tl;)I  // Directly invokes the static method
 
  public static f2Impl(Lp/Tl;)I
  public static f2(Lp/Tl;)I
    ALOAD 0
    INVOKEINTERFACE p/Tl.f2Impl ()I  // Interface method
}
 
public class p/Mp implements p/Tl  {
  // generated mixins (forward to the static functions in Tl$class)
  public f1()I
  public f2Impl()I
  public f2()I
}

The manifestation: subclasses of TraversableLike compiled with 2.11.2 don't have a mixin for filterImpl, but the standard library of 2.11.3 invokes the interface method.

Comment by Lukas Rytz [ 12/Oct/14 ]

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

Comment by Paolo G. Giarrusso [ 15/Oct/14 ]

If anybody is wondering (like me) why MIMA didn't catch it, don't worry, MIMA is fine:
https://github.com/lrytz/scala/commit/9276a1205f74fdec74206209712831913e93f359

The corresponding mima-failures can be whitelisted, as the changes are only to private[scala].

Generated at Sat Oct 20 05:07:09 CEST 2018 using JIRA 7.9.1#79001-sha1:60970b42586a2ec2760ed6cfe825b26961e62b9e.