Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NoSuchMethodError when creating abstract override val #10308

Closed
Atry opened this issue May 11, 2017 · 5 comments · Fixed by scala/scala#10268
Closed

NoSuchMethodError when creating abstract override val #10308

Atry opened this issue May 11, 2017 · 5 comments · Fixed by scala/scala#10268

Comments

@Atry
Copy link

Atry commented May 11, 2017

Welcome to Scala 2.12.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_102).
Type in expressions for evaluation. Or try :help.

scala> :paste
// Entering paste mode (ctrl-D to finish)

class A(override val f: Float) extends B

trait B {
 def f: Float = 1.0f
}

trait C extends B {
 abstract override val f = super.f + 100.0f
}

trait D extends B {
 abstract override val f = super.f + 1000.0f
}

new A(10.0f) with C with D {}

// Exiting paste mode, now interpreting.

java.lang.NoSuchMethodError: C.f$(LC;)F
  at $anon$1.$line3$$read$D$$super$f(<console>:29)
  at D.$init$(<console>:24)
  ... 30 elided
@Atry
Copy link
Author

Atry commented May 11, 2017

The same code doesn't crash 2.11.11

@lrytz
Copy link
Member

lrytz commented Jun 30, 2017

This goes deep into the corner cases of mixin and fields.

Note that in 2.11.11, (new A(10.0f) with C with D {}).f is 1000f. Not sure if this is a bug, it's a result of the wiring of the C$/D$_super_$f and C$/D$super$f accessors generated in the anonymous class.

// from 2.11
public final class Test..anon extends A implements C, D {
    private final float f;

    public float f() {
        return this.f;
    }

    public /* synthetic */ float D$$super$f() {
        return this.f();
    }

    public void D$_setter_$f_$eq(float x$1) {
        this.f = x$1;
    }

    public /* synthetic */ float C$$super$f() {
        return super.f();
    }

    public void C$_setter_$f_$eq(float x$1) { }

    public Test..anon() {
        super(10.0f);        // sets the field in A
        C$class.$init$(this);  // gets `10` through C$$super$f(), adds 100, call C$_setter_$f_$eq, which discards it
        D$class.$init$(this); // gets `0` through D$$super$f, adds 1000, calls D$_setter_$f_$eq, stores in Test$anon.f
    }
}

In 2.12, the C$$super$f method attempts to invoke super[D].f, which is translated in the backend to INVOKESTATIC D.f$, but this method doesn't exist because the getter D.f is abstract. We didn't see any super calls to abstract methods before, so this is not special-cased. But also, the getter symbol D.f doesn't have the deferred flag.

@Atry
Copy link
Author

Atry commented Jun 30, 2017

You are right. It would make more sense if the result is 1110.0f.

@lrytz
Copy link
Member

lrytz commented Jun 30, 2017

@adriaanm might be able to tell what is the expected/spec'd behavior

@SethTisue
Copy link
Member

#notfixedindotty

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants