bug icon indicating copy to clipboard operation
bug copied to clipboard

AbstractMethodError with separate compilation of subclass of trait containing inner class

Open scabug opened this issue 9 years ago • 6 comments

This bug only occurs when separately compiling the two files:

File 1:

trait TypeHints {

  def + (hints: TypeHints): TypeHints = CompositeTypeHints()

  private[TypeHints] case class CompositeTypeHints() extends TypeHints

}

File 2:

class CustomTypeHints extends TypeHints {
}

object Test extends App {
  new CustomTypeHints() + new TypeHints{}
}

Expected output: (no output)

Actual output:

java.lang.AbstractMethodError: CustomTypeHints.TypeHints$$CompositeTypeHints()LTypeHints$CompositeTypeHints$;
        at TypeHints$class.$plus(Bug.scala:3)
        at CustomTypeHints.$plus(Bug2.scala:1)
        at Test$.delayedEndpoint$Test$1(Bug2.scala:5)
        at Test$delayedInit$body.apply(Bug2.scala:4)
        at scala.Function0$class.apply$mcV$sp(Function0.scala:34)
        at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
        at scala.App$$anonfun$main$1.apply(App.scala:76)
        at scala.App$$anonfun$main$1.apply(App.scala:76)
        at scala.collection.immutable.List.foreach(List.scala:381)
        at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:35)
        at scala.App$class.main(App.scala:76)
        at Test$.main(Bug2.scala:4)
        at Test.main(Bug2.scala)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at scala.reflect.internal.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:70)
        at scala.reflect.internal.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:31)
        at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:101)
        at scala.reflect.internal.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:70)
        at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:101)
        at scala.tools.nsc.CommonRunner$class.run(ObjectRunner.scala:22)
        at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:39)
        at scala.tools.nsc.CommonRunner$class.runAndCatch(ObjectRunner.scala:29)
        at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:39)
        at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:65)
        at scala.tools.nsc.MainGenericRunner.run$1(MainGenericRunner.scala:87)
        at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:98)
        at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:103)
        at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)

scabug avatar Oct 05 '16 17:10 scabug

Imported From: https://issues.scala-lang.org/browse/SI-9948?orig=1 Reporter: Robin Green (rdgreen) Affected Versions: 2.11.0, 2.11.8, 2.12.0-RC1

scabug avatar Oct 05 '16 17:10 scabug

somehow got fixed in 2.13.13. perhaps there's some duplicate ticket out there

repro steps I used:

/usr/local/scala/scala-2.13.12/bin/scalac TypeHints.scala
/usr/local/scala/scala-2.13.12/bin/scalac -classpath . Test.scala
/usr/local/scala/scala-2.13.12/bin/scala Test

SethTisue avatar Feb 06 '25 22:02 SethTisue

On 2.13.12

  public default TypeHints $plus(TypeHints);
    descriptor: (LTypeHints;)LTypeHints;
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=2, args_size=2
         0: aload_0
         1: invokeinterface #27,  1           // InterfaceMethod TypeHints$$CompositeTypeHints:()LTypeHints$CompositeTypeHints$;
         6: invokevirtual #31                 // Method TypeHints$CompositeTypeHints$.apply:()LTypeHints$CompositeTypeHints;
         9: areturn

noting that Custom implements

  public TypeHints$CompositeTypeHints$ CompositeTypeHints();

but not

  public abstract TypeHints$CompositeTypeHints$ TypeHints$$CompositeTypeHints();
    descriptor: ()LTypeHints$CompositeTypeHints$;
    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT

and

Exception in thread "main" java.lang.AbstractMethodError: Receiver class CustomTypeHints does not define or inherit an implementation of the resolved method 'abstract TypeHints$CompositeTypeHints$ TypeHints$$CompositeTypeHints()' of interface TypeHints.
        at TypeHints.$plus(t9948a.scala:4)

but on 2.13.13

  public default TypeHints $plus(TypeHints);
    descriptor: (LTypeHints;)LTypeHints;
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=3, locals=2, args_size=2
         0: new           #10                 // class TypeHints$CompositeTypeHints
         3: dup
         4: aload_0
         5: invokespecial #29                 // Method TypeHints$CompositeTypeHints."<init>":(LTypeHints;)V
         8: areturn

so it's not an improvement in bridge methods or implementations but a change in how the new case class works. I don't know what caused the change. (Visibility? Matching members? ASM update?)

It still has the anomaly of the bad abstract method, but it goes uncalled for. The member should be mangled for access (but was not on the implementing side).

som-snytt avatar Feb 07 '25 00:02 som-snytt

I suppose it does less harm to reopen than to ignore it.

The behavior change was due to: https://github.com/scala/scala/pull/10560

The problem with the unimplemented method is a kind of problem, irregardless of how the module fetch in the trait should be implemented. (It can't be overridden, so it shouldn't be delegated for implementation.)

@lrytz heads up. I'll try to learn more.

I had to add irregardless to my browser's dictionary. https://en.wikipedia.org/wiki/List_of_common_misconceptions

Image

som-snytt avatar Feb 07 '25 01:02 som-snytt

@som-snytt what is the new repro code / steps?

SethTisue avatar Feb 07 '25 03:02 SethTisue

@SethTisue I reverted that one-liner and the symptom returned. That line allows the "case apply" call to be rewritten to "new Case" in refchecks, which means the missing method is not invoked, and disaster averted. Reverting it goes back to failing.

So the two questions are whether that fix is quite correct (it may be), and what is the correct fix to the actual missing method? (That is, the method has the unmangled named.)

I tried to get more fuzz because source and release options may matter. I also intended to try with just the newer ASM, as a degree of freedom. With my local build, compile separately then run:

skalac -d /tmp/sandbox -release:11 -Xsource:3 t9948a.scala && skalac -release:11 -Xsource:3 -d /tmp/sandbox -cp /tmp/sandbox t9948b.scala

Also, there is no one to appreciate this test pun:

object `Summoner's Tale`:
  import compiletime.summonFrom // no warn

som-snytt avatar Feb 07 '25 03:02 som-snytt