Skip to content

Commit 1d13e17

Browse files
authored
Merge pull request #14686 from dotty-staging/emit-class-public
Emit all classes as public to avoid object deserialization issues
2 parents 0b4e96c + 5e6a3cf commit 1d13e17

File tree

7 files changed

+37
-19
lines changed

7 files changed

+37
-19
lines changed

compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,11 @@ class BTypesFromSymbols[I <: DottyBackendInterface](val int: I) extends BTypes {
296296
*/
297297
final def javaFlags(sym: Symbol): Int = {
298298

299-
val privateFlag = sym.is(Private) || (sym.isPrimaryConstructor && sym.owner.isTopLevelModuleClass)
299+
// Classes are always emitted as public. This matches the behavior of Scala 2
300+
// and is necessary for object deserialization to work properly, otherwise
301+
// ModuleSerializationProxy may fail with an accessiblity error (see
302+
// tests/run/serialize.scala and https://github.com/typelevel/cats-effect/pull/2360).
303+
val privateFlag = !sym.isClass && (sym.is(Private) || (sym.isPrimaryConstructor && sym.owner.isTopLevelModuleClass))
300304

301305
val finalFlag = sym.is(Final) && !toDenot(sym).isClassConstructor && !sym.is(Mutable) && !sym.enclosingClass.is(Trait)
302306

project/MiMaFilters.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ object MiMaFilters {
2121
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.deriving.Mirror.fromTuple"),
2222

2323
// Private to the compiler - needed for forward binary compatibility
24-
ProblemFilters.exclude[MissingClassProblem]("scala.annotation.since")
24+
ProblemFilters.exclude[MissingClassProblem]("scala.annotation.since"),
25+
26+
// Private inner classes, but we emit all classes as public in Java bytecode
27+
ProblemFilters.exclude[InaccessibleClassProblem]("scala.quoted.FromExpr$PrimitiveFromExpr"),
28+
ProblemFilters.exclude[InaccessibleClassProblem]("scala.quoted.Type$ValueOf$"),
29+
ProblemFilters.exclude[InaccessibleClassProblem]("scala.reflect.Selectable$DefaultSelectable"),
2530
)
2631
}

tests/run/i4404a.check

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
false
2-
false
3-
false
4-
true
5-
false
6-
true
7-
true
8-
true
1+
public class Car
2+
public final class Volvo
3+
public final class Car$
4+
public static final class Car$$anon$1

tests/run/i4404a.scala

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,10 @@ object Car {
88
}
99

1010
object Test {
11-
def main(args: Array[String]) = {
12-
List(new Car, new Volvo, Car, Car.car)
13-
.map(_.getClass.getModifiers)
14-
.foreach { m =>
15-
println(Modifier.isPrivate(m))
16-
println(Modifier.isFinal(m))
17-
}
11+
def main(args: Array[String]): Unit = {
12+
val l = List(new Car, new Volvo, Car, Car.car)
13+
.map(_.getClass)
14+
.map(cls => s"${Modifier.toString(cls.getModifiers)} $cls")
15+
println(l.mkString("\n"))
1816
}
1917
}

tests/run/i4404b.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
true
1+
false
22
true

tests/run/serialize.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
package a {
2+
object Outer extends Serializable {
3+
private object Inner extends Serializable
4+
5+
val inner: AnyRef = Inner
6+
}
7+
class Bar extends Serializable {
8+
val x: AnyRef = Outer.inner
9+
}
10+
}
11+
112
object Test {
213
def serializeDeserialize[T <: AnyRef](obj: T): T = {
314
import java.io.*
@@ -26,5 +37,9 @@ object Test {
2637

2738
val baz = serializeDeserialize(Baz)
2839
assert(baz ne Baz)
40+
41+
val bar = new a.Bar
42+
val bar1 = serializeDeserialize(bar)
43+
assert(bar.x eq bar1.x)
2944
}
3045
}

0 commit comments

Comments
 (0)