-
Notifications
You must be signed in to change notification settings - Fork 21
NoSuchMethodError when accessing an override val via super #12715
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
Comments
This stuff requires spec lawyering to even figure out what the behavior should be (though obviously it shouldn't be As I understand it, the relevant spec sections are SLS 5.4 https://scala-lang.org/files/archive/spec/2.13/05-classes-and-objects.html#overriding which says:
and SLS 6.5 https://scala-lang.org/files/archive/spec/2.13/06-expressions.html#this-and-super which says:
|
I just reported a super crasher to dotty, based on a forum post. That was a restriction in scala 2. I'm not sure how this wound up as a "corner" of the language. (Like the corners of tables that need those plastic bumpers so toddlers don't strike their heads; or the corner of a room into which one paints oneself.) Would I remember if there were a FAQ entry on "When should I prefer a trait or a class?" that mentions these limits to mixability? |
Thanks for the spec pointers. So the resolution of scala> trait A { def f: String }
| trait B extends A { def f: String = "B" }
| trait C extends A { override def f: String = "C" }
| trait D extends B { def d = super.f }
| (new B with C with D).d + " - " + (new B with D with C).d
|
val res6: String = C - B To implement super calls to "default" (concrete) methods in interface classfiles, every such method gets a static "super accessor" method next it, e.g., for public static /*synthetic*/ int f$(T $this) { return $this.f(); } // invokespecial, prevents dynamic dispatch
default public int f() { return 1 } Fields in traits are a different story, as interface classfiles cannot have fields. The interface gets an abstract getter method, the field is generated in the subclass classfile with a concrete getter. Thinking about all this, I believe the example should be disallowed at compile time. Two observations:
trait A {
def f: String
}
trait B extends A {
def f = "B";
}
trait C extends A {
// override val f = "C"
override def f = "C"
}
trait D extends C {
// override val f = "D"
override def f = "D"
}
trait E extends A with B {
def d = super.f
}
object O1 extends B with C with D with E // `O1.d` is "D"
object O2 extends B with C with E with D // `O2.d` is "C"
object O3 extends B with E with C with D // `O3.d` is "B" If we change the two overrides to be |
I tend to agree that we should disallow it. |
Reproduction steps
Scala version: 2.13.10
See https://scastie.scala-lang.org/2L5tOgBESIu7v9D9yyK7gQ
Problem
This bug is similar to #10308, but this one can be reproduced without
abstract override
.The text was updated successfully, but these errors were encountered: