Skip to content

Commit b68a7ac

Browse files
authored
Merge pull request #5734 from dotty-staging/make-case-class-serializable
Make case classes Serializable
2 parents 5f7cf22 + 7705113 commit b68a7ac

9 files changed

+49
-10
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ object desugar {
521521
if (isEnumCase && parents.isEmpty)
522522
parents1 = enumClassTypeRef :: Nil
523523
if (isCaseClass | isCaseObject)
524-
parents1 = parents1 :+ scalaDot(str.Product.toTypeName)
524+
parents1 = parents1 :+ scalaDot(str.Product.toTypeName) :+ scalaDot(nme.Serializable.toTypeName)
525525
if (isEnum)
526526
parents1 = parents1 :+ ref(defn.EnumType)
527527

compiler/src/dotty/tools/dotc/printing/DecompilerPrinter.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ class DecompilerPrinter(_ctx: Context) extends RefinedPrinter(_ctx) {
5757
def isSynthetic(parent: Tree): Boolean = {
5858
val sym = parent.symbol
5959
sym.maybeOwner == defn.ObjectClass ||
60-
(sym == defn.ProductClass && impl.symbol.owner.is(Case))
60+
(sym == defn.ProductClass && impl.symbol.owner.is(Case)) ||
61+
(sym == defn.SerializableClass && impl.symbol.owner.is(Case))
6162
}
6263
val parents = impl.parents.filterNot(isSynthetic)
6364
val body = impl.body.filterNot(_.symbol.is(ParamAccessor))

library/src/scala/tasty/reflect/Printers.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,7 @@ trait Printers
598598
val parents1 = parents.filter {
599599
case IsTerm(Term.Apply(Term.Select(Term.New(tpt), _), _)) => !Types.JavaLangObject.unapply(tpt.tpe)
600600
case IsTypeTree(TypeTree.Select(Term.Select(Term.Ident("_root_"), "scala"), "Product")) => false
601+
case IsTypeTree(TypeTree.Select(Term.Select(Term.Ident("_root_"), "scala"), "Serializable")) => false
601602
case _ => true
602603
}
603604
if (parents1.nonEmpty)

tests/neg/typeclass-derivation2.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ object Pair {
170170
}
171171
}
172172

173-
sealed trait Either[+L, +R] extends Product // derives Eq, Pickler, Show
173+
sealed trait Either[+L, +R] extends Product with Serializable // derives Eq, Pickler, Show
174174
case class Left[L](x: L) extends Either[L, Nothing]
175175
case class Right[R](x: R) extends Either[Nothing, R]
176176

@@ -275,4 +275,4 @@ object Test extends App {
275275
|
276276
|But no implicit values were found that match type Show[Pair[Int]].
277277
*/
278-
}
278+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
case class Foo(s: String)
2+
3+
object Test {
4+
def main(args: Array[String]): Unit = {
5+
val foo = Foo("bar")
6+
assert(foo.isInstanceOf[Serializable])
7+
assert(SerDes.serializeDeserialize[Foo](foo) == foo)
8+
}
9+
}
10+
11+
// From https://github.com/scala/scala/pull/5278
12+
object SerDes {
13+
import java.io._
14+
15+
def assertNotSerializable(a: AnyRef): Unit = {
16+
try {
17+
serialize(a)
18+
assert(false)
19+
} catch {
20+
case _: NotSerializableException => // okay
21+
}
22+
}
23+
24+
def serialize(obj: AnyRef): Array[Byte] = {
25+
val buffer = new ByteArrayOutputStream
26+
val out = new ObjectOutputStream(buffer)
27+
out.writeObject(obj)
28+
buffer.toByteArray
29+
}
30+
31+
def deserialize(a: Array[Byte]): AnyRef = {
32+
val in = new ObjectInputStream(new ByteArrayInputStream(a))
33+
in.readObject
34+
}
35+
36+
def serializeDeserialize[T <: AnyRef](obj: T) = deserialize(serialize(obj)).asInstanceOf[T]
37+
}

tests/run/tasty-extractors-2.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Type.SymRef(IsClassSymbol(<scala.Unit>), Type.ThisType(Type.SymRef(IsPackageSymb
4949
Term.Inlined(None, Nil, Term.Block(List(ClassDef("Foo", DefDef("<init>", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), "<init>"), Nil)), Nil, None, List(DefDef("a", Nil, Nil, TypeTree.Inferred(), Some(Term.Literal(Constant.Int(0))))))), Term.Literal(Constant.Unit())))
5050
Type.SymRef(IsClassSymbol(<scala.Unit>), Type.ThisType(Type.SymRef(IsPackageSymbol(<scala>), NoPrefix())))
5151

52-
Term.Inlined(None, Nil, Term.Block(List(ClassDef("Foo", DefDef("<init>", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), "<init>"), Nil), TypeTree.Select(Term.Select(Term.Ident("_root_"), "scala"), "Product")), Nil, None, List(DefDef("productElementName", Nil, List(List(ValDef("x$1", TypeTree.Select(Term.Select(Term.Ident("_root_"), "scala"), "Int"), None))), TypeTree.Select(Term.Select(Term.Ident("java"), "lang"), "String"), Some(Term.Match(Term.Ident("x$1"), List(CaseDef(Pattern.Value(Term.Ident("_")), None, Term.Apply(Term.Ident("throw"), List(Term.Apply(Term.Select(Term.New(TypeTree.Select(Term.Select(Term.Ident("java"), "lang"), "IndexOutOfBoundsException")), "<init>"), List(Term.Apply(Term.Select(Term.Select(Term.Select(Term.Ident("java"), "lang"), "String"), "valueOf"), List(Term.Ident("x$1")))))))))))), DefDef("copy", Nil, List(Nil), TypeTree.Inferred(), Some(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), "<init>"), Nil))), DefDef("hashCode", Nil, List(Nil), TypeTree.Inferred(), Some(Term.Literal(Constant.Int(394005536)))), DefDef("equals", Nil, List(List(ValDef("x$0", TypeTree.Inferred(), None))), TypeTree.Inferred(), Some(Term.Apply(Term.Select(Term.Apply(Term.Select(Term.This(Some(Id("Foo"))), "eq"), List(Term.TypeApply(Term.Select(Term.Ident("x$0"), "asInstanceOf"), List(TypeTree.Inferred())))), "||"), List(Term.Match(Term.Ident("x$0"), List(CaseDef(Pattern.Bind("x$0", Pattern.TypeTest(TypeTree.Inferred())), None, Term.Literal(Constant.Boolean(true))), CaseDef(Pattern.Value(Term.Ident("_")), None, Term.Literal(Constant.Boolean(false))))))))), DefDef("toString", Nil, List(Nil), TypeTree.Inferred(), Some(Term.Apply(Term.Ident("_toString"), List(Term.This(Some(Id("Foo"))))))), DefDef("canEqual", Nil, List(List(ValDef("that", TypeTree.Inferred(), None))), TypeTree.Inferred(), Some(Term.TypeApply(Term.Select(Term.Ident("that"), "isInstanceOf"), List(TypeTree.Inferred())))), DefDef("productArity", Nil, Nil, TypeTree.Inferred(), Some(Term.Literal(Constant.Int(0)))), DefDef("productPrefix", Nil, Nil, TypeTree.Inferred(), Some(Term.Literal(Constant.String("Foo")))), DefDef("productElement", Nil, List(List(ValDef("n", TypeTree.Inferred(), None))), TypeTree.Inferred(), Some(Term.Match(Term.Ident("n"), List(CaseDef(Pattern.Value(Term.Ident("_")), None, Term.Apply(Term.Ident("throw"), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), "<init>"), List(Term.Apply(Term.Select(Term.Ident("n"), "toString"), Nil)))))))))))), ValDef("Foo", TypeTree.Ident("Foo$"), Some(Term.Apply(Term.Select(Term.New(TypeTree.Ident("Foo$")), "<init>"), Nil))), ClassDef("Foo$", DefDef("<init>", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), "<init>"), Nil), TypeTree.Applied(TypeTree.Inferred(), List(TypeTree.Inferred()))), Nil, Some(ValDef("_", TypeTree.Singleton(Term.Ident("Foo")), None)), List(DefDef("apply", Nil, List(Nil), TypeTree.Inferred(), Some(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), "<init>"), Nil))), DefDef("unapply", Nil, List(List(ValDef("x$1", TypeTree.Inferred(), None))), TypeTree.Inferred(), Some(Term.Literal(Constant.Boolean(true))))))), Term.Literal(Constant.Unit())))
52+
Term.Inlined(None, Nil, Term.Block(List(ClassDef("Foo", DefDef("<init>", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), "<init>"), Nil), TypeTree.Select(Term.Select(Term.Ident("_root_"), "scala"), "Product"), TypeTree.Select(Term.Select(Term.Ident("_root_"), "scala"), "Serializable")), Nil, None, List(DefDef("productElementName", Nil, List(List(ValDef("x$1", TypeTree.Select(Term.Select(Term.Ident("_root_"), "scala"), "Int"), None))), TypeTree.Select(Term.Select(Term.Ident("java"), "lang"), "String"), Some(Term.Match(Term.Ident("x$1"), List(CaseDef(Pattern.Value(Term.Ident("_")), None, Term.Apply(Term.Ident("throw"), List(Term.Apply(Term.Select(Term.New(TypeTree.Select(Term.Select(Term.Ident("java"), "lang"), "IndexOutOfBoundsException")), "<init>"), List(Term.Apply(Term.Select(Term.Select(Term.Select(Term.Ident("java"), "lang"), "String"), "valueOf"), List(Term.Ident("x$1")))))))))))), DefDef("copy", Nil, List(Nil), TypeTree.Inferred(), Some(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), "<init>"), Nil))), DefDef("hashCode", Nil, List(Nil), TypeTree.Inferred(), Some(Term.Literal(Constant.Int(394005536)))), DefDef("equals", Nil, List(List(ValDef("x$0", TypeTree.Inferred(), None))), TypeTree.Inferred(), Some(Term.Apply(Term.Select(Term.Apply(Term.Select(Term.This(Some(Id("Foo"))), "eq"), List(Term.TypeApply(Term.Select(Term.Ident("x$0"), "asInstanceOf"), List(TypeTree.Inferred())))), "||"), List(Term.Match(Term.Ident("x$0"), List(CaseDef(Pattern.Bind("x$0", Pattern.TypeTest(TypeTree.Inferred())), None, Term.Literal(Constant.Boolean(true))), CaseDef(Pattern.Value(Term.Ident("_")), None, Term.Literal(Constant.Boolean(false))))))))), DefDef("toString", Nil, List(Nil), TypeTree.Inferred(), Some(Term.Apply(Term.Ident("_toString"), List(Term.This(Some(Id("Foo"))))))), DefDef("canEqual", Nil, List(List(ValDef("that", TypeTree.Inferred(), None))), TypeTree.Inferred(), Some(Term.TypeApply(Term.Select(Term.Ident("that"), "isInstanceOf"), List(TypeTree.Inferred())))), DefDef("productArity", Nil, Nil, TypeTree.Inferred(), Some(Term.Literal(Constant.Int(0)))), DefDef("productPrefix", Nil, Nil, TypeTree.Inferred(), Some(Term.Literal(Constant.String("Foo")))), DefDef("productElement", Nil, List(List(ValDef("n", TypeTree.Inferred(), None))), TypeTree.Inferred(), Some(Term.Match(Term.Ident("n"), List(CaseDef(Pattern.Value(Term.Ident("_")), None, Term.Apply(Term.Ident("throw"), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), "<init>"), List(Term.Apply(Term.Select(Term.Ident("n"), "toString"), Nil)))))))))))), ValDef("Foo", TypeTree.Ident("Foo$"), Some(Term.Apply(Term.Select(Term.New(TypeTree.Ident("Foo$")), "<init>"), Nil))), ClassDef("Foo$", DefDef("<init>", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), "<init>"), Nil), TypeTree.Applied(TypeTree.Inferred(), List(TypeTree.Inferred()))), Nil, Some(ValDef("_", TypeTree.Singleton(Term.Ident("Foo")), None)), List(DefDef("apply", Nil, List(Nil), TypeTree.Inferred(), Some(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), "<init>"), Nil))), DefDef("unapply", Nil, List(List(ValDef("x$1", TypeTree.Inferred(), None))), TypeTree.Inferred(), Some(Term.Literal(Constant.Boolean(true))))))), Term.Literal(Constant.Unit())))
5353
Type.SymRef(IsClassSymbol(<scala.Unit>), Type.ThisType(Type.SymRef(IsPackageSymbol(<scala>), NoPrefix())))
5454

5555
Term.Inlined(None, Nil, Term.Block(List(ClassDef("Foo1", DefDef("<init>", Nil, List(List(ValDef("a", TypeTree.Ident("Int"), None))), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), "<init>"), Nil)), Nil, None, List(ValDef("a", TypeTree.Inferred(), None)))), Term.Literal(Constant.Unit())))

tests/run/typeclass-derivation2.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ object Pair {
179179
implicit def derived$Show[T: Show]: Show[Pair[T]] = Show.derived
180180
}
181181

182-
sealed trait Either[+L, +R] extends Product // derives Eq, Pickler, Show
182+
sealed trait Either[+L, +R] extends Product with Serializable // derives Eq, Pickler, Show
183183
case class Left[L](x: L) extends Either[L, Nothing]
184184
case class Right[R](x: R) extends Either[Nothing, R]
185185

@@ -486,4 +486,4 @@ object Test extends App {
486486
val zs1 = copy(zs)
487487
showPrintln(zs1)
488488
assert(eql(zs, zs1))
489-
}
489+
}

tests/run/typeclass-derivation2a.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ object Pair {
179179
implicit def derived$Show[T: Show]: Show[Pair[T]] = Show.derived
180180
}
181181

182-
sealed trait Either[+L, +R] extends Product // derives Eq, Pickler, Show
182+
sealed trait Either[+L, +R] extends Product with Serializable // derives Eq, Pickler, Show
183183
case class Left[L](x: L) extends Either[L, Nothing]
184184
case class Right[R](x: R) extends Either[Nothing, R]
185185

tests/run/typeclass-derivation3.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ object datatypes {
1616
case class Pair[T](x: T, y: T) derives Eq, Pickler, Show
1717

1818
// another ADT
19-
sealed trait Either[+L, +R] extends Product derives Eq, Pickler, Show
19+
sealed trait Either[+L, +R] extends Product with Serializable derives Eq, Pickler, Show
2020
case class Left[L](x: L) extends Either[L, Nothing]
2121
case class Right[R](x: R) extends Either[Nothing, R]
2222
}
@@ -311,4 +311,4 @@ object Test extends App {
311311
val zss1 = pklList.unpickle(buf)
312312
assert(eql(zss, zss1))
313313
showPrintln(zss1)
314-
}
314+
}

0 commit comments

Comments
 (0)