Skip to content
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

Emit all classes as public to avoid object deserialization issues #14686

Merged
merged 1 commit into from Mar 21, 2022

Conversation

smarter
Copy link
Member

@smarter smarter commented Mar 14, 2022

This aligns our behavior with Scala 2 and fixes the issue encountered in
typelevel/cats-effect#2360 (comment).

Alternatively, we could change ModuleSerializationProxy upstream to call
setAccessible(true) on the MODULE$ field, but this wouldn't work if the object
in question is inside a Java 9+ module.

@smarter
Copy link
Member Author

smarter commented Mar 14, 2022

For reference, all classes in Scala 2 are public in the backend because of this line: https://github.com/scala/scala/blob/ce95d6ca26179e5c189c2b1b40e68d4bc8738cfe/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala#L391

@smarter
Copy link
Member Author

smarter commented Mar 14, 2022

Technically this isn't a forward-compatible ABI change, but since these classes aren't really part of our public API I think it's fine to ignore that:

Error:  scala3-library-bootstrapped: Failed binary compatibility check against org.scala-lang:scala3-library_3:3.1.1! Found 3 potential problems (filtered 697)
Error:   * private class scala.quoted.FromExpr#PrimitiveFromExpr is inaccessible in other version, it must be public.

@smarter smarter requested a review from sjrd March 14, 2022 18:15
smarter added a commit to dotty-staging/scalatest that referenced this pull request Mar 14, 2022
After scala/scala3#14686, Scala 3 emits all
classes (even local classes) as public, just like Scala 2. But unlike Scala 2,
the local class TestSpec in XmlSocketReporterSpec will be emitted with a
zero-argument constructor (in Scala 2 its constructor takes an
XmlSocketReporterSpec outer parameter which is never used which seems like a
bug). This matters because Scalatest considers a test suite "rerunnable" if it
has a zero argument public constructor. So to get the test suite to pass, we
need to check for the presence of this constructor just like SuiteRerunner does.
Comment on lines 299 to 302
// Classes are always emitted as public. This matches the behavior of Scala 2
// and is necessary for object deserialization to work properly, otherwise
// ModuleSerializationProxy may fail with an accessiblity error (see
// tests/run/serialize.scala).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps add a reference to the issue as well?

@sjrd
Copy link
Member

sjrd commented Mar 21, 2022

Technically this isn't a forward-compatible ABI change, but since these classes aren't really part of our public API I think it's fine to ignore that:

Yes, this is fine. It will also apply in libraries that have a forward compatibility policy, but in those libraries there should also only be a difference for Scala-private classes, which would be ignorable there as well.

smarter added a commit to smarter/scalatest that referenced this pull request Mar 21, 2022
After scala/scala3#14686, Scala 3 emits all
classes (even local classes) as public, just like Scala 2. But unlike Scala 2,
the local class TestSpec in XmlSocketReporterSpec will be emitted with a
zero-argument constructor (in Scala 2 its constructor takes an
XmlSocketReporterSpec outer parameter which is never used which seems like a
bug). This matters because Scalatest considers a test suite "rerunnable" if it
has a zero argument public constructor. So to get the test suite to pass, we
need to check for the presence of this constructor just like SuiteRerunner does.
@smarter smarter enabled auto-merge March 21, 2022 12:01
smarter added a commit to dotty-staging/scalatest that referenced this pull request Mar 21, 2022
After scala/scala3#14686, Scala 3 emits all
classes (even local classes) as public, just like Scala 2. But unlike Scala 2,
the local class TestSpec in XmlSocketReporterSpec will be emitted with a
zero-argument constructor (in Scala 2 its constructor takes an
XmlSocketReporterSpec outer parameter which is never used which seems like a
bug). This matters because Scalatest considers a test suite "rerunnable" if it
has a zero argument public constructor. So to get the test suite to pass, we
need to check for the presence of this constructor just like SuiteRerunner does.
This aligns our behavior with Scala 2 and fixes the issue encountered in
typelevel/cats-effect#2360 (comment).

Alternatively, we could change ModuleSerializationProxy upstream to call
`setAccessible(true)` on the MODULE$ field, but this wouldn't work if the object
in question is inside a Java 9+ module.
@smarter smarter merged commit 1d13e17 into scala:main Mar 21, 2022
@smarter smarter deleted the emit-class-public branch March 21, 2022 21:54
nicolasstucki pushed a commit to dotty-staging/scalatest that referenced this pull request Mar 24, 2022
After scala/scala3#14686, Scala 3 emits all
classes (even local classes) as public, just like Scala 2. But unlike Scala 2,
the local class TestSpec in XmlSocketReporterSpec will be emitted with a
zero-argument constructor (in Scala 2 its constructor takes an
XmlSocketReporterSpec outer parameter which is never used which seems like a
bug). This matters because Scalatest considers a test suite "rerunnable" if it
has a zero argument public constructor. So to get the test suite to pass, we
need to check for the presence of this constructor just like SuiteRerunner does.
@Kordyjan Kordyjan added this to the 3.1.3 milestone Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants