AbstractMethodError when mixing in trait nested in object - only when compiled and imported

1.1k views Asked by At

Consider the following code:

object Impls {
  trait ConcreteImpl {
    type Foo = Int
    def foo = 1
  }
}

trait Base {
  type Foo
  def foo: Foo
}

I am interested in the expression

(new Base with Impls.ConcreteImpl).foo

When I paste the above code in the REPL, or run it in a worksheet, and then try the expression -- no problem, it prints res0: Int = 1, as expected.

When I put the code in a file, compile it with scalac, and then use the compiled class files from the REPL in the same directory, I get the same result.

However, when I use the compiled files, and then say from the REPL

import Impls._
(new Base with ConcreteImpl).foo

it throws

java.lang.AbstractMethodError: $anon$1.foo()I

If I paste all code in the REPL, and use the import variant, this does not happen.

What is happening here? Is this even expected behaviour? If relevant, I am using

Scala version 2.11.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_45)
1

There are 1 answers

1
som-snytt On BEST ANSWER

It's clearly a bug.

If you:

java.lang.AbstractMethodError: $line13.$read$$iw$$iw$$iw$$iw$$iw$$iw$$anon$1.foo()I
  ... 33 elided

scala> :javap -p $line13.$read$$iw$$iw$$iw$$iw$$iw$$iw$$anon$1
Compiled from "<console>"
public final class $line13.$read$$iw$$iw$$iw$$iw$$iw$$iw$$anon$1 implements p.Base,p.Impls$ConcreteImpl {
  public java.lang.Object foo();
  public $line13.$read$$iw$$iw$$iw$$iw$$iw$$iw$$anon$1();
}

It doesn't have a foo with result type Int.

Offhand, I can't imagine the difference in the REPL, but we're about to watch a movie... You can try it in Ammonite, however.

Most such bugs are due to the fact that REPL is a resident compiler, but it's not obvious how that affects compilation with existing class files.

Edit:

It works the first time using fully-qualified names, but then after exhibiting the failure, fully-qualified fails again.

scala> (new p.Base with p.Impls.ConcreteImpl).foo // show
//works
res0: Int = 1

scala> import p._
import p._

scala> import Impls._
import Impls._

scala> (new Base with ConcreteImpl).foo // show
// fails
java.lang.AbstractMethodError: $anon$1.foo()I
  ... 33 elided

scala> (new p.Base with p.Impls.ConcreteImpl).foo // show
// also fails
java.lang.AbstractMethodError: $anon$1.foo()I
  ... 33 elided

That's clearly a resident compiler bug. (The classes are in package p here.)

Edit: Actually SI-9689.