-
Notifications
You must be signed in to change notification settings - Fork 21
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
Bug overriding varargs method defined both in Scala class and Java interface, while also narrowing return type #11944
Comments
Scala can handle overriding Java varargs with Scala varargs. I'm going to illustrate the problem by replacing varargs with their corresponding implementations (and translate everything to Scala). trait JRequest {
def addAttrs(entries: Array[play.libs.typedmap.TypedEntry[_]])play.mvc.Http.Request
}
class RequestHeaderImpl {
def addAttrs(entries: Seq[play.libs.typedmap.TypedEntry[_]])play.mvc.Http.RequestHeader
} then I believe that is the issue here. someone else can jump in and correct me if I'm way off mark |
@NthPortal Is there maybe a chance to workaround this with the help of the |
@mkurz no, that annotation is just to make the compiler generate a java-compatible varargs forwarder, which is done automatically if you're overriding a java varargs method |
I knew it generates an array forwarder method, but didn't know such a method is generated automatically anyway when overriding java varargs (so |
so, a possible workaround would be to create a Scala trait that extends // you can really name this trait whatever
// sealed so that lack of implementation can't be accidentally used elsewhere
sealed trait RequestImplHelper extends JRequest {
override def addAttrs(entries: play.libs.typedmap.TypedEntry[_]*)play.mvc.Http.Request = ???
} this (in theory) will create a trait that has an class RequestImpl(request: Request[RequestBody])
extends RequestHeaderImpl(request)
with RequestImplHelper { ... } of course, now that you're adding a new trait, you're jumping into bincompat hell, so good luck |
I'm actually going to leave this ticket open, on the thought that there is still something that can be improved here. at the very least, we can improve the error message so it indicates that the two incompatible method signatures use different kinds of varargs. however, it's not actually obvious to me that you shouldn't be able to override two different kinds of varargs at once. it seems like Scala otherwise does its best to paper over the difference, so shouldn't it do that here too? |
More minimal repro: // T1.java
package test;
import scala.collection.immutable.Seq;
interface T1 {
Seq<String> va(String... strings);
} // L.java
package test;
import scala.collection.immutable.List;
interface L extends T1 {
List<String> va(String... strings);
} // R_T2.scala
package test
class R extends T1 {
override def va(strings: String*): Seq[String] = strings
}
class T2 extends R with L {
override def va(strings: String*): List[String] = strings.toList
} $ scalac T1.java L.java R_T2.scala
R_T2.scala:7: error: incompatible type in overriding
def va(strings: String*): List[String] (defined in trait L)
with override def va(strings: String*): Seq[String] (defined in class R);
found : (strings: String*)Seq[String]
required: (strings: String*)List[String]
class T2 extends R with L {
^
one error found minimal repro with workaround: replace // R_L2_T2.scala
package test
class R extends T1 {
override def va(strings: String*): Seq[String] = strings
}
sealed trait L2 extends L {
override def va(strings: String*): List[String] = ???
}
class T2 extends R with L2 {
override def va(strings: String*): List[String] = strings.toList
} |
There has to be 4 methods in play (🤡 ): the Seq returning, the List returning, and their varargs-forwarding buddies. My guess is the part of the compiler that deals with making sure the forwarder is emitted isn't remembering about covariant return types. |
There's also the "concrete overrides abstract" issue. In Scala 3, this was changed to follow Java scala/scala3#4770 but I don't have all the plates in the air to see how it interacts with this ticket. Edit:
similarly
|
... it didn't exist in Play 2.8 and makes too many troubles: scala/bug#11944
... it didn't exist in Play 2.8 and makes too many troubles: scala/bug#11944
reproduction steps
(see #11944 (comment) for minimal repro)
Clone my fork of the Play Framework and checkout the
addAttrs
branch (according pull request):Try to compile:
problem
Because of this commit compilation fails:
I am pretty sure this is a bug in the Scala compiler.
All the commit does it adds the method
addAttrs
with a varargs param to Java interfaces and Scala classes that extend from those interfaces (and from each other).If you look at the commit you will see there is an existing
addAttr
method (withouts
and the end) already, just above theaddAttrs
method I want to add. This existing method follows the exact same scheme (e.g. return type) like the method I want to add. ForaddAttr
the code compiles,addAttrs
makes it fail. That's why I think this has to be a bug in the Scala compiler which is caused by the varargs param.Effects Scala 2.13.1 and 2.12.11.
I am using AdoptOpenJDK 11, also tried with 8.
expectation
Code compiles.
The text was updated successfully, but these errors were encountered: