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
Restrict visibility of copy and apply #5472
Conversation
Make the synthesized copy and apply methods of a case class have the same visibility as its private constructor.
There were two occurrences where we exploited that a case class with a private constructor still had a public apply method. I believe both were mistakes.
I suspect the change to |
That would be good to know, yes. |
It breaks the 2.13 std lib in one place: https://github.com/scala/scala/blob/b846ae5dd600456dd9f4da089bddea8ea5fbb58b/src/library/scala/collection/immutable/VectorMap.scala#L213 I am not sure what was the intention of the author here. cc/ @odd |
I guess |
@adriaanm Opinions on whether this change could also make it to 2.13 or 2.14 ? |
We could do something for 2.13.x (x > 0) under -Xsource to experiment with the community build. We're kind of maxed out for the next few weeks, but happy to accept PRs sooner. |
I agree. Exactly the same mistake was found in dotty's @julienrf @odd Can one of you fix |
This change is required if we want to change the visibility of the synthetic `apply` method in case classes companion to match the visibility of its case class constructor. See also discussion in scala/scala3#5472.
Thanks for the quick fix @julienrf. Can you merge this PR once the 2.13.x fix is in? |
Hmm, If this doesn't get into 2.13, it's going to make cross-compilation harder, since getting your code to compile with Dotty might require a non-binary-compatible change :/. |
I'll discuss with the team to see what we can do here. |
This change is required if we want to change the visibility of the synthetic `apply` method in case classes companion to match the visibility of its case class constructor. See also discussion in scala/scala3#5472.
A possible option would be to not do this under Scala-2 mode. Let's see what Scala 2.14 does. But so far my understanding is that the cases where it matters would be rare
|
@allanrenucci @julienrf Indeed, the intention was to only allow direct calls to the constructor of |
So, arguably, the current behavior is surprising and could be a security risk [i.e. nobody thought that |
So, I don't think we can change this in 2.13 (at least not by default), both because of how close we are to RC1 and due to the unknown amount of breakage this would cause. Cross-compilation should be achievable by explicitly writing the private apply method, right? Since these cases are rare, that doesn't sound like a big burden for added security. |
My informal impression is that a private constructor usually arises when someone is trying to lock down a case class to prevent invalid instances from being constructed. You make the constructor private, and you write a custom public Can I assume that combination (private constructor, custom public apply) will remain supported? |
What happens if the arguments aren't valid? The only use-case I can think of for having a public Also, it would be nice if a private constructor didn't become public in the bytecode and therefore public to Java users (scala/bug#6882). |
https://openjdk.java.net/jeps/181 should make this much easier for Java 11+. |
See also scala/bug#7085 (comment), Java has a strategy for this for inner classes already:
|
I know, but I don't think it's worth changing things now just for Java 8. |
2db2df4
to
d657bd7
Compare
I assume that in whichever version of Scala targets Java 11+ we could change that implementation detail, like when we changed the encoding of functions into lambdas. |
A public user defined |
In the longer term, can |
Make the synthesized copy and apply methods of a case class have the
same visibility as its private constructor.
I believe it would make sense to spec it that way.