Description
reproduction steps
(see #11944 (comment) for minimal repro)
Clone my fork of the Play Framework and checkout the addAttrs
branch (according pull request):
git clone git@github.com:mkurz/playframework.git
git checkout addAttrs
Try to compile:
sbt compile
problem
Because of this commit compilation fails:
[error] ./core/play/src/main/scala/play/core/j/JavaHelpers.scala:258:7: incompatible type in overriding
[error] def addAttrs(entries: play.libs.typedmap.TypedEntry[_]*): play.mvc.Http.Request (defined in trait Request)
[error] with override def addAttrs(entries: play.libs.typedmap.TypedEntry[_]*): play.mvc.Http.RequestHeader (defined in class RequestHeaderImpl);
[error] found : (entries: play.libs.typedmap.TypedEntry[_]*)play.mvc.Http.RequestHeader
[error] required: (entries: play.libs.typedmap.TypedEntry[_]*)play.mvc.Http.Request
[error] class RequestImpl(request: Request[RequestBody]) extends RequestHeaderImpl(request) with JRequest {
[error] ^
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 (without s
and the end) already, just above the addAttrs
method I want to add. This existing method follows the exact same scheme (e.g. return type) like the method I want to add. For addAttr
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.
Activity
NthPortal commentedon Apr 18, 2020
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).
then
RequestImpl
tries to inherit from both, and override the varargs method to returnplay.mvc.Http.Request
. but those twoaddAttrs
methods are not compatible, so it can't override both.I believe that is the issue here. someone else can jump in and correct me if I'm way off mark
mkurz commentedon Apr 18, 2020
@NthPortal Is there maybe a chance to workaround this with the help of the
@varargs
annotation? I tried but couldn't make it work unfortunately...NthPortal commentedon Apr 19, 2020
@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
mkurz commentedon Apr 19, 2020
I knew it generates an array forwarder method, but didn't know such a method is generated automatically anyway when overriding java varargs (so
@varargs
wouldn't make any difference), interesting.So I guess there is no workaround for this problem right now?
NthPortal commentedon Apr 20, 2020
so, a possible workaround would be to create a Scala trait that extends
JRequest
and overrides the method with an abstract implementationthis (in theory) will create a trait that has an
addAttrs
method that takes Scala varargs instead of (technically in addition to) the Java varargs. then, you ought to be able to to extendRequestImplHelper
andRequestHeaderImpl
at the same time, since they both have anaddAttrs
method that takes Scala varargs. hopefully.of course, now that you're adding a new trait, you're jumping into bincompat hell, so good luck
NthPortal commentedon Apr 20, 2020
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?
NthPortal commentedon Apr 20, 2020
More minimal repro:
minimal repro with workaround: replace
R_T2.scala
withR_L2_T2.scala
[-]Bug overriding varargs method defined both in Scala class and Java interface[/-][+]Bug overriding varargs method defined both in Scala class and Java interface, while also narrowing return type[/+]dwijnand commentedon Nov 20, 2020
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.
som-snytt commentedon Nov 20, 2020
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
Remove addAttrs(varargs) + its workaround...
Remove addAttrs(varargs) + its workaround...