Skip to content

Commit b7263b7

Browse files
committed
Make all objects Serializable
To avoid deadlocks when combining objects, lambdas and multi-threading, lambdas in objects are compiled to instance methods of the module class instead of static methods (see tests/run/deadlock.scala and scala/scala-dev#195 for details). This has worked well for us so far but this is problematic for serialization: serializing a lambda requires serializing all the values it captures, if this lambda is in an object, this means serializing the enclosing object, which fails if the object does not extend Serializable. Because serializing objects is basically free since scala#5775, it seems like the simplest solution is to simply make all objects Serializable, this certainly seems preferable to deadlocks. This commit causes a cyclic reference to happen in some cases, we add a workaround to avoid this in Trees.scala and fix it properly in the commit.
1 parent 45a51d8 commit b7263b7

File tree

4 files changed

+41
-27
lines changed

4 files changed

+41
-27
lines changed

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -340,8 +340,9 @@ object desugar {
340340
case _ => false
341341
}
342342

343-
val isCaseClass = mods.is(Case) && !mods.is(Module)
344-
val isCaseObject = mods.is(Case) && mods.is(Module)
343+
val isObject = mods.is(Module)
344+
val isCaseClass = mods.is(Case) && !isObject
345+
val isCaseObject = mods.is(Case) && isObject
345346
val isImplicit = mods.is(Implicit)
346347
val isInstance = isImplicit && mods.mods.exists(_.isInstanceOf[Mod.Instance])
347348
val isEnum = mods.isEnumClass && !mods.is(Module)
@@ -526,13 +527,13 @@ object desugar {
526527
else Nil
527528
}
528529

529-
// Case classes and case objects get Product parents
530-
// Enum cases get an inferred parent if no parents are given
531530
var parents1 = parents
532531
if (isEnumCase && parents.isEmpty)
533532
parents1 = enumClassTypeRef :: Nil
534533
if (isCaseClass | isCaseObject)
535534
parents1 = parents1 :+ scalaDot(str.Product.toTypeName) :+ scalaDot(nme.Serializable.toTypeName)
535+
else if (isObject)
536+
parents1 = parents1 :+ scalaDot(nme.Serializable.toTypeName)
536537
if (isEnum)
537538
parents1 = parents1 :+ ref(defn.EnumType)
538539

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,8 @@ object Trees {
887887

888888
// ----- Generic Tree Instances, inherited from `tpt` and `untpd`.
889889

890-
abstract class Instance[T >: Untyped <: Type] { inst =>
890+
// FIXME: Work around cyclic reference by writing `Types.Type` instead of `Type`
891+
abstract class Instance[T >: Untyped <: Types.Type] { inst =>
891892

892893
type Tree = Trees.Tree[T]
893894
type TypTree = Trees.TypTree[T]

sbt-bridge/test/xsbt/ExtractUsedNamesSpecification.scala

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,10 @@ class ExtractUsedNamesSpecification {
7979
val usedNames = compilerForTesting.extractUsedNamesFromSrc(srcA, srcB, srcC, srcD)
8080
val scalaVersion = scala.util.Properties.versionNumberString
8181
val namesA = standardNames ++ Set("Nothing", "Any")
82-
val namesAX = standardNames ++ Set("x", "T", "A", "Nothing", "Any")
82+
val namesAX = standardNames ++ objectStandardNames ++ Set("x", "T", "A", "Nothing", "Any", "scala")
8383
val namesB = Set("A", "Int", "A;init;", "Unit")
84-
val namesC = Set("B;init;", "B", "Unit")
85-
val namesD = standardNames ++ Set("C", "X", "foo", "Int", "T")
84+
val namesC = objectStandardNames ++ Set("B;init;", "B", "Unit")
85+
val namesD = standardNames ++ objectStandardNames ++ Set("C", "X", "foo", "Int", "T")
8686
assertEquals(namesA, usedNames("A"))
8787
assertEquals(namesAX, usedNames("A.X"))
8888
assertEquals(namesB, usedNames("B"))
@@ -130,23 +130,30 @@ class ExtractUsedNamesSpecification {
130130
|""".stripMargin
131131
val compilerForTesting = new ScalaCompilerForUnitTesting
132132
val usedNames = compilerForTesting.extractUsedNamesFromSrc(src1, src2)
133-
val expectedNames_lista = standardNames ++ Set("B", "lista", "List", "A")
134-
val expectedNames_at = standardNames ++ Set("B", "at", "A", "T", "X0", "X1")
135-
val expectedNames_as = standardNames ++ Set("B", "as", "S", "Y")
136-
val expectedNames_foo = standardNames ++ Set("B",
137-
"foo",
138-
"M",
139-
"N",
140-
"Predef",
141-
"???",
142-
"Nothing")
143-
val expectedNames_bar = standardNames ++ Set("B",
144-
"bar",
145-
"P1",
146-
"P0",
147-
"Predef",
148-
"???",
149-
"Nothing")
133+
val expectedNames_lista =
134+
standardNames ++ objectStandardNames ++ Set("B", "lista", "List", "A")
135+
val expectedNames_at =
136+
standardNames ++ objectStandardNames ++ Set("B", "at", "A", "T", "X0", "X1")
137+
val expectedNames_as =
138+
standardNames ++ objectStandardNames ++ Set("B", "as", "S", "Y")
139+
val expectedNames_foo =
140+
standardNames ++ objectStandardNames ++
141+
Set("B",
142+
"foo",
143+
"M",
144+
"N",
145+
"Predef",
146+
"???",
147+
"Nothing")
148+
val expectedNames_bar =
149+
standardNames ++ objectStandardNames ++
150+
Set("B",
151+
"bar",
152+
"P1",
153+
"P0",
154+
"Predef",
155+
"???",
156+
"Nothing")
150157
assertEquals(expectedNames_lista, usedNames("Test_lista"))
151158
assertEquals(expectedNames_at, usedNames("Test_at"))
152159
assertEquals(expectedNames_as, usedNames("Test_as"))
@@ -167,7 +174,7 @@ class ExtractUsedNamesSpecification {
167174
|""".stripMargin
168175
val compilerForTesting = new ScalaCompilerForUnitTesting
169176
val usedNames = compilerForTesting.extractUsedNamesFromSrc(srcFoo, srcBar)
170-
val expectedNames = standardNames ++ Set("Outer", "TypeInner", "Inner", "Int")
177+
val expectedNames = standardNames ++ objectStandardNames ++ Set("Outer", "TypeInner", "Inner", "Int")
171178
assertEquals(expectedNames, usedNames("Bar"))
172179
}
173180

@@ -302,4 +309,9 @@ class ExtractUsedNamesSpecification {
302309
// the return type of the default constructor is Unit
303310
"Unit"
304311
)
312+
313+
private val objectStandardNames = Set(
314+
// all Dotty objects extend scala.Serializable
315+
"scala", "Serializable"
316+
)
305317
}

0 commit comments

Comments
 (0)