bug
bug copied to clipboard
AbstractMethodError with separate compilation of subclass of trait containing inner class
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)
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
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
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).
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
@som-snytt what is the new repro code / steps?
@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