Skip to content

NoSuchMethodError when accessing an override val via super #16704

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

Closed
Atry opened this issue Jan 16, 2023 · 6 comments · Fixed by #16908
Closed

NoSuchMethodError when accessing an override val via super #16704

Atry opened this issue Jan 16, 2023 · 6 comments · Fixed by #16908
Assignees
Milestone

Comments

@Atry
Copy link
Contributor

Atry commented Jan 16, 2023

Compiler version

3.2.0

Minimized code

trait A {
  def f: String
}

trait B extends A {
  def f = "B";
}

trait C extends A {
  override val f = "C"
}

trait D extends A with B {
  def d = super.f
}

object O extends B with C with D

O.f
O.d

Output

java.lang.NoSuchMethodError: 'java.lang.String Playground$C.f$(Playground$C)'
	at Playground$O$.Playground$D$$super$f(main.scala:19)
	at Playground$D.d(main.scala:16)
	at Playground$D.d$(main.scala:15)
	at Playground$O$.d(main.scala:19)
	at Playground$.<clinit>(main.scala:22)
	at Main$.<clinit>(main.scala:27)
	at Main.main(main.scala)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at sbt.Run.invokeMain(Run.scala:143)
	at sbt.Run.execute$1(Run.scala:93)
	at sbt.Run.$anonfun$runWithLoader$5(Run.scala:120)
	at sbt.Run$.executeSuccess(Run.scala:186)
	at sbt.Run.runWithLoader(Run.scala:120)
	at sbt.Run.run(Run.scala:127)
	at com.olegych.scastie.sbtscastie.SbtScastiePlugin$$anon$1.$anonfun$run$1(SbtScastiePlugin.scala:38)
	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
	at sbt.util.InterfaceUtil$$anon$1.get(InterfaceUtil.scala:17)
	at sbt.ScastieTrapExit$App.run(ScastieTrapExit.scala:258)
	at java.base/java.lang.Thread.run(Thread.java:831)

Note that this bug can be reproduced in Scala 2, too. See scala/bug#12715

Expectation

No error

@Atry Atry added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Jan 16, 2023
@Atry Atry changed the title NoSuchMethodError when creating an override val NoSuchMethodError when accessing an override val via super Jan 16, 2023
@odersky
Copy link
Contributor

odersky commented Jan 16, 2023

Observations:

  • The val in trait C is essential. It works with def.
  • The translations of both versions in the transformer pipeline are basically the same. They both produce this implemention of D$$super$f:
     def D$$super$f(): String = super[C].f()
  • It looks like the backend translates the mixin call super[C].f() to a call to an interface method
    C.f$:(LC;)Ljava/lang/String
    
    I did not see a correspondent of this method with either def or val anywhere in the transformation pipeline, so maybe it's the backend that generates the interface method, and fails to do so in the case of val?

@odersky odersky added area:backend and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Jan 16, 2023
@odersky
Copy link
Contributor

odersky commented Jan 16, 2023

@sjrd Maybe you have an idea about what could be the cause of this? Does the JS backend have the same problem?

@lrytz
Copy link
Member

lrytz commented Jan 16, 2023

I can take a look at this one (and its cousin on Scala 2)

@Kordyjan Kordyjan added this to the Future versions milestone Jan 16, 2023
@sjrd
Copy link
Member

sjrd commented Jan 16, 2023

Scala.js has the same issue (most likely from the same cause in an earlier phase):

 Referring to non-existent method C.f()java.lang.String
   called from O$.D$$super$f()java.lang.String
   called from D.d()java.lang.String
   called from O$.d()java.lang.String
   called from Main$.main([java.lang.String)void
   called from static Main.main([java.lang.String)void
   called from core module module initializers
 involving instantiated classes:
   O$
   Main$

@Atry
Copy link
Contributor Author

Atry commented Jan 16, 2023

By the way, I think an override method that does not include a super call should be a lint error, because it silently suppresses the implementation from any super classes, even when the super classes are dynamically determined.

trait A {
  def f: String
}

trait C extends A {
  // What is the purpose? Implementing A.f, or transforming A.f?
  override val f = "C" 
}

If there is a lint error is raised for the above code, the author of C should either remove override:

trait A {
  def f: String
}

trait C extends A {
  // The purpose is implementing A.f
  val f = "C"
}

or add the missing call to super class:

trait A {
  def f: String
}

trait C extends A {
  // The purpose is transforming A.f
  abstract override val f = s"${super.f}/C"
}

@lrytz
Copy link
Member

lrytz commented Jan 17, 2023

I added a comment here: scala/bug#12715 (comment)

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.

6 participants