-
Notifications
You must be signed in to change notification settings - Fork 21
case class companion object generates two apply methods #11207
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
Hmm, this is quite likely an unintended consequence of scala/scala#7035. |
I've faced the same problem while upgrading to 2.12.7 |
Commented here for the reason we get more forwarders: https://github.com/scala/scala/pull/7035/files#r226274350 |
However, @DieBauer and @martin-g, I cannot reproduce the problem that you are having with javac. For me, javac compiles the
Which version of Java are you using? Where do you get the error: command line / build tool / IDE? |
I had the problem both in Sbt and IDEA. Let me try to reproduce it! |
I also was not able to reproduce it in a mini app. |
Another workaround is to explicitly add a companion object (this prevents it from tacitly extending a |
Alright, it was a bit more complex than I initial thought. I think the gist is that the java types are not primitives, but boxed (hence the selection of the Object constructor). I've created a reproducer: https://github.com/DieBauer/reproducer-scala on 2.12.6 in build sbt it compiles, setting it to 2.12.7 it doesn't.
I'm using com.oracle.jdk8u162 edit: simplified reproducer in repository |
@DieBauer thanks! To summarize it here: Scala: case class MyClass(a: Int) Java: MyClass.apply(Integer.valueOf(1));
So javac picks the I think it's limited to the case of auto-unboxing. For non-primitives, the bridge method is less specific than the non-bridge, so javac should pick the non-bridge. Also it looks like there's no issue with return types, the following compiles fine: Scala: abstract class A[T] { def f: T }
object B extends A[Int] { def f = 1 } Java: final int a = B.f();
final Integer b = B.f();
final Object c = B.f(); So it looks like the scope of the bug is quite limited. I'm a bit worried to fix it for 2.12.8, because it would remove methods that exist in 2.12.7, which is binary incompatible. Since it's already fixed in 2.13, I think we should just do nothing. Unfortunately... |
Our project uses a big hierarchy of case classes which is processed and transformed across many stages by both Scala and Java code, and this breaks a lot of our code. |
hmm, maybe a 2.12-only flag that would let people opt in to the fix, if they are confident doing so won't cause headaches? |
That's an idea, we could backport the 2.13 fix under a flag. But it wouldn't help for libraries fetched from maven (that are compiled without that flag). |
By the way, if you have a case class that has a mix of class X
case class MyClass(a: Int, aa: Int, b: String, c: X) final MyClass myClass = MyClass.apply(1, Integer.valueOf(1), "bla", new X());
So I think the potential impact is that any library that gets compiled with 2.12.7 (and if this is not rolled back, further future 2.12.x releases) which is used from a Java project and passes boxed primitives to the apply method is broken. |
once we have a plan, we should probably publicize it on https://contributors.scala-lang.org/t/library-authors-rebuild-on-2-12-7-to-improve-callability-from-java-on-jdk-11/2465/7 |
We discussed this regression internally today. @adriaanm and @retronym are less conservative than me and would prefer release 2.12.8 soon with a fix for this bug that restores the 2.12.6 behavior. After all, the bug only affects Java code that uses Scala libraries (the static accessors cannot be used from Scala code). The majority of such Java code is application code, not libraries published to maven. So the risk for binary incompatibilities is small. |
This also causes serialization surprises. https://users.scala-lang.org/t/serialversionuid-change-between-scala-2-12-6-and-2-12-7/3478 |
In 2.12.7, scala#7035 added the `bridge` flag to static forwarders that are generated for bridge methods. (2.13 geneartes no forwarders for bridges, but we wanted to stay binary compatible in 2.12.) Unfortunately the change caused even more bridges to be generated, namely for bridge methods that implement an abstract member. Now we exclude them again, which brings the binary interface back to the state of 2.12.6. Fixes scala/bug#11207
In 2.12.7, scala#7035 added the `bridge` flag to static forwarders that are generated for bridge methods. (2.13 geneartes no forwarders for bridges, but we wanted to stay binary compatible in 2.12.) Unfortunately the change caused even more bridges to be generated, namely for bridge methods that implement an abstract member. Now we exclude them again, which brings the binary interface back to the state of 2.12.6. Fixes scala/bug#11207
In 2.12.7, scala#7035 added the `bridge` flag to static forwarders that are generated for bridge methods. (2.13 geneartes no forwarders for bridges, but we wanted to stay binary compatible in 2.12.) Unfortunately the change caused even more bridges to be generated, namely for bridge methods that implement an abstract member. Now we exclude them again, which brings the binary interface back to the state of 2.12.6. Fixes scala/bug#11207
Fixed in scala/scala#7383. |
Uh oh!
There was an error while loading. Please reload this page.
I've encountered an issue when upgrading the compiler to 2.12.7.
I have a piece of java code that uses the apply method of a scala case class.
When using
MyClass
compiled with Scala 2.12.7, I get:incompatible types: java.lang.Object cannot be converted to MyClass.
Where, before it compiled fine.
I'm now looking into the generated bytecode and can see this.
Test.scala:
When doing the same exercise on scala 2.12.6 I get:
A duplicate
apply
method is generated in scala 2.12.7 with the following signature:public static java.lang.Object apply(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);
and it seems this one is being picked in my Java project, causing the exception.
It seems that this is an unintended breaking change between these two versions.
Of course a workaround is using the new keyword:
The text was updated successfully, but these errors were encountered: