From 49156c41a711917275e82e2a10433aa3164290bb Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Fri, 25 Jan 2019 21:16:56 +0100 Subject: [PATCH 1/6] Fix #5776: Allow explicitly adding a parent that is added by desugaring --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 7 ++++++- tests/neg/duplicate-parents.scala | 2 ++ tests/pos/duplicate-parents.scala | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 tests/neg/duplicate-parents.scala create mode 100644 tests/pos/duplicate-parents.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 49236ad4c890..2def5eab5011 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1606,6 +1606,11 @@ class Typer extends Namer var result = if (isTreeType(tree)) typedType(tree)(superCtx) else typedExpr(tree)(superCtx) val psym = result.tpe.dealias.typeSymbol if (seenParents.contains(psym) && !cls.isRefinementClass) { + // Desugaring can adds parents to classes, but we don't want to emit an + // error if the same parent was explicitly added in user code. + if (!tree.span.isSourceDerived) + return EmptyTree + if (!ctx.isAfterTyper) ctx.error(i"$psym is extended twice", tree.sourcePos) } else seenParents += psym @@ -1640,7 +1645,7 @@ class Typer extends Namer completeAnnotations(cdef, cls) val constr1 = typed(constr).asInstanceOf[DefDef] - val parentsWithClass = ensureFirstTreeIsClass(parents mapconserve typedParent, cdef.nameSpan) + val parentsWithClass = ensureFirstTreeIsClass(parents.mapconserve(typedParent).filterConserve(!_.isEmpty), cdef.nameSpan) val parents1 = ensureConstrCall(cls, parentsWithClass)(superCtx) var self1 = typed(self)(ctx.outer).asInstanceOf[ValDef] // outer context where class members are not visible diff --git a/tests/neg/duplicate-parents.scala b/tests/neg/duplicate-parents.scala new file mode 100644 index 000000000000..810b7cdc669e --- /dev/null +++ b/tests/neg/duplicate-parents.scala @@ -0,0 +1,2 @@ +case class Foo1(x: Int) extends Serializable with Serializable // error +case class Foo2(x: Int) extends scala.Serializable with Serializable // error diff --git a/tests/pos/duplicate-parents.scala b/tests/pos/duplicate-parents.scala new file mode 100644 index 000000000000..1f4625cd40eb --- /dev/null +++ b/tests/pos/duplicate-parents.scala @@ -0,0 +1,14 @@ +case class Foo1(x: Int) extends Serializable +case class Foo2(x: Int) extends scala.Serializable +case class Foo3(x: Int) extends Product + +case object Foo4 extends Serializable + +object Scope { + class Serializable + case class Foo5(x: Int) extends Serializable + + val f = Foo5(1) + f: Scope.Serializable + f: scala.Serializable +} From 33b989478c1b0ee8ce69691f9dde427ba94d8dab Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Fri, 25 Jan 2019 21:24:58 +0100 Subject: [PATCH 2/6] 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 https://github.com/scala/scala-dev/issues/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 #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. --- .../src/dotty/tools/dotc/ast/Desugar.scala | 9 ++-- compiler/src/dotty/tools/dotc/ast/Trees.scala | 3 +- .../xsbt/ExtractUsedNamesSpecification.scala | 54 +++++++++++-------- scala-backend | 2 +- 4 files changed, 41 insertions(+), 27 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index df3809b64281..dd15a25031d5 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -341,8 +341,9 @@ object desugar { case _ => false } - val isCaseClass = mods.is(Case) && !mods.is(Module) - val isCaseObject = mods.is(Case) && mods.is(Module) + val isObject = mods.is(Module) + val isCaseClass = mods.is(Case) && !isObject + val isCaseObject = mods.is(Case) && isObject val isImplicit = mods.is(Implicit) val isInstance = isImplicit && mods.mods.exists(_.isInstanceOf[Mod.Instance]) val isEnum = mods.isEnumClass && !mods.is(Module) @@ -527,13 +528,13 @@ object desugar { else Nil } - // Case classes and case objects get Product parents - // Enum cases get an inferred parent if no parents are given var parents1 = parents if (isEnumCase && parents.isEmpty) parents1 = enumClassTypeRef :: Nil if (isCaseClass | isCaseObject) parents1 = parents1 :+ scalaDot(str.Product.toTypeName) :+ scalaDot(nme.Serializable.toTypeName) + else if (isObject) + parents1 = parents1 :+ scalaDot(nme.Serializable.toTypeName) if (isEnum) parents1 = parents1 :+ ref(defn.EnumType) diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 6cc697bfb5d6..1d20f20e5d89 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -887,7 +887,8 @@ object Trees { // ----- Generic Tree Instances, inherited from `tpt` and `untpd`. - abstract class Instance[T >: Untyped <: Type] { inst => + // FIXME: Work around cyclic reference by writing `Types.Type` instead of `Type` + abstract class Instance[T >: Untyped <: Types.Type] { inst => type Tree = Trees.Tree[T] type TypTree = Trees.TypTree[T] diff --git a/sbt-bridge/test/xsbt/ExtractUsedNamesSpecification.scala b/sbt-bridge/test/xsbt/ExtractUsedNamesSpecification.scala index befe2dd433d3..9106d9f5304a 100644 --- a/sbt-bridge/test/xsbt/ExtractUsedNamesSpecification.scala +++ b/sbt-bridge/test/xsbt/ExtractUsedNamesSpecification.scala @@ -79,10 +79,10 @@ class ExtractUsedNamesSpecification { val usedNames = compilerForTesting.extractUsedNamesFromSrc(srcA, srcB, srcC, srcD) val scalaVersion = scala.util.Properties.versionNumberString val namesA = standardNames ++ Set("Nothing", "Any") - val namesAX = standardNames ++ Set("x", "T", "A", "Nothing", "Any") + val namesAX = standardNames ++ objectStandardNames ++ Set("x", "T", "A", "Nothing", "Any", "scala") val namesB = Set("A", "Int", "A;init;", "Unit") - val namesC = Set("B;init;", "B", "Unit") - val namesD = standardNames ++ Set("C", "X", "foo", "Int", "T") + val namesC = objectStandardNames ++ Set("B;init;", "B", "Unit") + val namesD = standardNames ++ objectStandardNames ++ Set("C", "X", "foo", "Int", "T") assertEquals(namesA, usedNames("A")) assertEquals(namesAX, usedNames("A.X")) assertEquals(namesB, usedNames("B")) @@ -130,23 +130,30 @@ class ExtractUsedNamesSpecification { |""".stripMargin val compilerForTesting = new ScalaCompilerForUnitTesting val usedNames = compilerForTesting.extractUsedNamesFromSrc(src1, src2) - val expectedNames_lista = standardNames ++ Set("B", "lista", "List", "A") - val expectedNames_at = standardNames ++ Set("B", "at", "A", "T", "X0", "X1") - val expectedNames_as = standardNames ++ Set("B", "as", "S", "Y") - val expectedNames_foo = standardNames ++ Set("B", - "foo", - "M", - "N", - "Predef", - "???", - "Nothing") - val expectedNames_bar = standardNames ++ Set("B", - "bar", - "P1", - "P0", - "Predef", - "???", - "Nothing") + val expectedNames_lista = + standardNames ++ objectStandardNames ++ Set("B", "lista", "List", "A") + val expectedNames_at = + standardNames ++ objectStandardNames ++ Set("B", "at", "A", "T", "X0", "X1") + val expectedNames_as = + standardNames ++ objectStandardNames ++ Set("B", "as", "S", "Y") + val expectedNames_foo = + standardNames ++ objectStandardNames ++ + Set("B", + "foo", + "M", + "N", + "Predef", + "???", + "Nothing") + val expectedNames_bar = + standardNames ++ objectStandardNames ++ + Set("B", + "bar", + "P1", + "P0", + "Predef", + "???", + "Nothing") assertEquals(expectedNames_lista, usedNames("Test_lista")) assertEquals(expectedNames_at, usedNames("Test_at")) assertEquals(expectedNames_as, usedNames("Test_as")) @@ -167,7 +174,7 @@ class ExtractUsedNamesSpecification { |""".stripMargin val compilerForTesting = new ScalaCompilerForUnitTesting val usedNames = compilerForTesting.extractUsedNamesFromSrc(srcFoo, srcBar) - val expectedNames = standardNames ++ Set("Outer", "TypeInner", "Inner", "Int") + val expectedNames = standardNames ++ objectStandardNames ++ Set("Outer", "TypeInner", "Inner", "Int") assertEquals(expectedNames, usedNames("Bar")) } @@ -302,4 +309,9 @@ class ExtractUsedNamesSpecification { // the return type of the default constructor is Unit "Unit" ) + + private val objectStandardNames = Set( + // all Dotty objects extend scala.Serializable + "scala", "Serializable" + ) } diff --git a/scala-backend b/scala-backend index 9ef70dd9b9ee..1447a7fbbc5d 160000 --- a/scala-backend +++ b/scala-backend @@ -1 +1 @@ -Subproject commit 9ef70dd9b9eeec11cfb72dabb57c61198fa18a20 +Subproject commit 1447a7fbbc5dd51a5e561c57bc873576e1ba542c From fc3ba61ed8093845244eace411cf64bda81d6d7c Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Sun, 3 Feb 2019 16:50:20 +0100 Subject: [PATCH 3/6] Fix cyclic reference in Trees.scala The previous commit added _root_.scala.Serializable as a parent to every object, this lead to a cyclic reference manifesting itselfs as "not found: type Type" in Trees.scala that we worked around by replace `Type` with `Types.Type`. This commit fixes this properly by adding a shortcut in typedIdent when typing `_root_` which avoids forcing imports. --- compiler/src/dotty/tools/dotc/ast/Trees.scala | 3 +-- compiler/src/dotty/tools/dotc/typer/Typer.scala | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 1d20f20e5d89..6cc697bfb5d6 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -887,8 +887,7 @@ object Trees { // ----- Generic Tree Instances, inherited from `tpt` and `untpd`. - // FIXME: Work around cyclic reference by writing `Types.Type` instead of `Type` - abstract class Instance[T >: Untyped <: Types.Type] { inst => + abstract class Instance[T >: Untyped <: Type] { inst => type Tree = Trees.Tree[T] type TypTree = Trees.TypTree[T] diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 2def5eab5011..b557fde92235 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -361,6 +361,11 @@ class Typer extends Namer if (untpd.isVarPattern(tree) && name.isTermName) return typed(desugar.patternVar(tree), pt) } + // Shortcut for the root package, this is not just a performance + // optimization, it also avoids forcing imports thus potentially avoiding + // cyclic references. + if (name == nme.ROOTPKG) + return tree.withType(defn.RootPackage.termRef) val rawType = { val saved1 = unimported From 4925332750ebf9ef382c1dd20923afea0ae3eec4 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Fri, 25 Jan 2019 16:42:55 +0100 Subject: [PATCH 4/6] Mark all specialized Function interfaces as Serializable These interfaces are only used when creating closures with no explicit SAM types, and those closures should always be serializable. --- library/src/scala/compat/java8/JFunction0.java | 2 +- library/src/scala/compat/java8/JFunction1.java | 2 +- library/src/scala/compat/java8/JFunction10.java | 2 +- library/src/scala/compat/java8/JFunction11.java | 2 +- library/src/scala/compat/java8/JFunction12.java | 2 +- library/src/scala/compat/java8/JFunction13.java | 2 +- library/src/scala/compat/java8/JFunction14.java | 2 +- library/src/scala/compat/java8/JFunction15.java | 2 +- library/src/scala/compat/java8/JFunction16.java | 2 +- library/src/scala/compat/java8/JFunction17.java | 2 +- library/src/scala/compat/java8/JFunction18.java | 2 +- library/src/scala/compat/java8/JFunction19.java | 2 +- library/src/scala/compat/java8/JFunction2.java | 2 +- library/src/scala/compat/java8/JFunction20.java | 2 +- library/src/scala/compat/java8/JFunction21.java | 2 +- library/src/scala/compat/java8/JFunction22.java | 2 +- library/src/scala/compat/java8/JFunction3.java | 2 +- library/src/scala/compat/java8/JFunction4.java | 2 +- library/src/scala/compat/java8/JFunction5.java | 2 +- library/src/scala/compat/java8/JFunction6.java | 2 +- library/src/scala/compat/java8/JFunction7.java | 2 +- library/src/scala/compat/java8/JFunction8.java | 2 +- library/src/scala/compat/java8/JFunction9.java | 2 +- library/src/scala/compat/java8/JProcedure0.java | 2 +- library/src/scala/compat/java8/JProcedure1.java | 2 +- library/src/scala/compat/java8/JProcedure10.java | 2 +- library/src/scala/compat/java8/JProcedure11.java | 2 +- library/src/scala/compat/java8/JProcedure12.java | 2 +- library/src/scala/compat/java8/JProcedure13.java | 2 +- library/src/scala/compat/java8/JProcedure14.java | 2 +- library/src/scala/compat/java8/JProcedure15.java | 2 +- library/src/scala/compat/java8/JProcedure16.java | 2 +- library/src/scala/compat/java8/JProcedure17.java | 2 +- library/src/scala/compat/java8/JProcedure18.java | 2 +- library/src/scala/compat/java8/JProcedure19.java | 2 +- library/src/scala/compat/java8/JProcedure2.java | 2 +- library/src/scala/compat/java8/JProcedure20.java | 2 +- library/src/scala/compat/java8/JProcedure21.java | 2 +- library/src/scala/compat/java8/JProcedure22.java | 2 +- library/src/scala/compat/java8/JProcedure3.java | 2 +- library/src/scala/compat/java8/JProcedure4.java | 2 +- library/src/scala/compat/java8/JProcedure5.java | 2 +- library/src/scala/compat/java8/JProcedure6.java | 2 +- library/src/scala/compat/java8/JProcedure7.java | 2 +- library/src/scala/compat/java8/JProcedure8.java | 2 +- library/src/scala/compat/java8/JProcedure9.java | 2 +- 46 files changed, 46 insertions(+), 46 deletions(-) diff --git a/library/src/scala/compat/java8/JFunction0.java b/library/src/scala/compat/java8/JFunction0.java index 4937d5578ea0..87a9e26f8b61 100644 --- a/library/src/scala/compat/java8/JFunction0.java +++ b/library/src/scala/compat/java8/JFunction0.java @@ -6,7 +6,7 @@ package scala.compat.java8; @FunctionalInterface -public interface JFunction0 extends scala.Function0 { +public interface JFunction0 extends scala.Function0, java.io.Serializable { default void $init$() { }; default void apply$mcV$sp() { diff --git a/library/src/scala/compat/java8/JFunction1.java b/library/src/scala/compat/java8/JFunction1.java index ed22c91eb96f..d1b526d5b5b8 100644 --- a/library/src/scala/compat/java8/JFunction1.java +++ b/library/src/scala/compat/java8/JFunction1.java @@ -6,7 +6,7 @@ package scala.compat.java8; @FunctionalInterface -public interface JFunction1 extends scala.Function1 { +public interface JFunction1 extends scala.Function1, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction10.java b/library/src/scala/compat/java8/JFunction10.java index 63e392a8e449..a31517e551fe 100644 --- a/library/src/scala/compat/java8/JFunction10.java +++ b/library/src/scala/compat/java8/JFunction10.java @@ -6,7 +6,7 @@ package scala.compat.java8; @FunctionalInterface -public interface JFunction10 extends scala.Function10 { +public interface JFunction10 extends scala.Function10, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction11.java b/library/src/scala/compat/java8/JFunction11.java index 0dd20546192b..123ae015361b 100644 --- a/library/src/scala/compat/java8/JFunction11.java +++ b/library/src/scala/compat/java8/JFunction11.java @@ -6,7 +6,7 @@ package scala.compat.java8; @FunctionalInterface -public interface JFunction11 extends scala.Function11 { +public interface JFunction11 extends scala.Function11, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction12.java b/library/src/scala/compat/java8/JFunction12.java index c992cc43f1b1..9da50de2edbd 100644 --- a/library/src/scala/compat/java8/JFunction12.java +++ b/library/src/scala/compat/java8/JFunction12.java @@ -6,7 +6,7 @@ package scala.compat.java8; @FunctionalInterface -public interface JFunction12 extends scala.Function12 { +public interface JFunction12 extends scala.Function12, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction13.java b/library/src/scala/compat/java8/JFunction13.java index cca43006f26c..76c78158ab44 100644 --- a/library/src/scala/compat/java8/JFunction13.java +++ b/library/src/scala/compat/java8/JFunction13.java @@ -6,7 +6,7 @@ package scala.compat.java8; @FunctionalInterface -public interface JFunction13 extends scala.Function13 { +public interface JFunction13 extends scala.Function13, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction14.java b/library/src/scala/compat/java8/JFunction14.java index 3e69530a603e..74c37e64571f 100644 --- a/library/src/scala/compat/java8/JFunction14.java +++ b/library/src/scala/compat/java8/JFunction14.java @@ -6,7 +6,7 @@ package scala.compat.java8; @FunctionalInterface -public interface JFunction14 extends scala.Function14 { +public interface JFunction14 extends scala.Function14, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction15.java b/library/src/scala/compat/java8/JFunction15.java index 76d70174c876..68dd9b7cfcc3 100644 --- a/library/src/scala/compat/java8/JFunction15.java +++ b/library/src/scala/compat/java8/JFunction15.java @@ -6,7 +6,7 @@ package scala.compat.java8; @FunctionalInterface -public interface JFunction15 extends scala.Function15 { +public interface JFunction15 extends scala.Function15, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction16.java b/library/src/scala/compat/java8/JFunction16.java index c11b461f5495..73aa9328b36e 100644 --- a/library/src/scala/compat/java8/JFunction16.java +++ b/library/src/scala/compat/java8/JFunction16.java @@ -6,7 +6,7 @@ package scala.compat.java8; @FunctionalInterface -public interface JFunction16 extends scala.Function16 { +public interface JFunction16 extends scala.Function16, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction17.java b/library/src/scala/compat/java8/JFunction17.java index c088f9dce7d6..fb225de5ed1a 100644 --- a/library/src/scala/compat/java8/JFunction17.java +++ b/library/src/scala/compat/java8/JFunction17.java @@ -6,7 +6,7 @@ package scala.compat.java8; @FunctionalInterface -public interface JFunction17 extends scala.Function17 { +public interface JFunction17 extends scala.Function17, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction18.java b/library/src/scala/compat/java8/JFunction18.java index 25600da3ffe1..a1f796df9030 100644 --- a/library/src/scala/compat/java8/JFunction18.java +++ b/library/src/scala/compat/java8/JFunction18.java @@ -6,7 +6,7 @@ package scala.compat.java8; @FunctionalInterface -public interface JFunction18 extends scala.Function18 { +public interface JFunction18 extends scala.Function18, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction19.java b/library/src/scala/compat/java8/JFunction19.java index cacc66d08e9e..c446f6c21815 100644 --- a/library/src/scala/compat/java8/JFunction19.java +++ b/library/src/scala/compat/java8/JFunction19.java @@ -6,7 +6,7 @@ package scala.compat.java8; @FunctionalInterface -public interface JFunction19 extends scala.Function19 { +public interface JFunction19 extends scala.Function19, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction2.java b/library/src/scala/compat/java8/JFunction2.java index 5ece8c62aea7..2984a9746335 100644 --- a/library/src/scala/compat/java8/JFunction2.java +++ b/library/src/scala/compat/java8/JFunction2.java @@ -8,7 +8,7 @@ import scala.MatchError; @FunctionalInterface -public interface JFunction2 extends scala.Function2 { +public interface JFunction2 extends scala.Function2, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction20.java b/library/src/scala/compat/java8/JFunction20.java index f34574f7f77f..82fe356f57f3 100644 --- a/library/src/scala/compat/java8/JFunction20.java +++ b/library/src/scala/compat/java8/JFunction20.java @@ -6,7 +6,7 @@ package scala.compat.java8; @FunctionalInterface -public interface JFunction20 extends scala.Function20 { +public interface JFunction20 extends scala.Function20, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction21.java b/library/src/scala/compat/java8/JFunction21.java index 0af8db2db3b7..8b6b476da1d4 100644 --- a/library/src/scala/compat/java8/JFunction21.java +++ b/library/src/scala/compat/java8/JFunction21.java @@ -6,7 +6,7 @@ package scala.compat.java8; @FunctionalInterface -public interface JFunction21 extends scala.Function21 { +public interface JFunction21 extends scala.Function21, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction22.java b/library/src/scala/compat/java8/JFunction22.java index fcd83a05fefd..7e635391798f 100644 --- a/library/src/scala/compat/java8/JFunction22.java +++ b/library/src/scala/compat/java8/JFunction22.java @@ -6,7 +6,7 @@ package scala.compat.java8; @FunctionalInterface -public interface JFunction22 extends scala.Function22 { +public interface JFunction22 extends scala.Function22, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction3.java b/library/src/scala/compat/java8/JFunction3.java index 9122f68198c9..5147e73600d9 100644 --- a/library/src/scala/compat/java8/JFunction3.java +++ b/library/src/scala/compat/java8/JFunction3.java @@ -8,7 +8,7 @@ import scala.MatchError; @FunctionalInterface -public interface JFunction3 extends scala.Function3 { +public interface JFunction3 extends scala.Function3, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction4.java b/library/src/scala/compat/java8/JFunction4.java index d7356a0f8f32..6d39a3a06cd4 100644 --- a/library/src/scala/compat/java8/JFunction4.java +++ b/library/src/scala/compat/java8/JFunction4.java @@ -8,7 +8,7 @@ import scala.MatchError; @FunctionalInterface -public interface JFunction4 extends scala.Function4 { +public interface JFunction4 extends scala.Function4, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction5.java b/library/src/scala/compat/java8/JFunction5.java index 1e0414bc5dce..9a36af977387 100644 --- a/library/src/scala/compat/java8/JFunction5.java +++ b/library/src/scala/compat/java8/JFunction5.java @@ -8,7 +8,7 @@ import scala.MatchError; @FunctionalInterface -public interface JFunction5 extends scala.Function5 { +public interface JFunction5 extends scala.Function5, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction6.java b/library/src/scala/compat/java8/JFunction6.java index 112c21cbe977..6cd79beaeb8f 100644 --- a/library/src/scala/compat/java8/JFunction6.java +++ b/library/src/scala/compat/java8/JFunction6.java @@ -8,7 +8,7 @@ import scala.MatchError; @FunctionalInterface -public interface JFunction6 extends scala.Function6 { +public interface JFunction6 extends scala.Function6, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction7.java b/library/src/scala/compat/java8/JFunction7.java index 1f59bc7affd9..34f48cc31114 100644 --- a/library/src/scala/compat/java8/JFunction7.java +++ b/library/src/scala/compat/java8/JFunction7.java @@ -8,7 +8,7 @@ import scala.MatchError; @FunctionalInterface -public interface JFunction7 extends scala.Function7 { +public interface JFunction7 extends scala.Function7, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction8.java b/library/src/scala/compat/java8/JFunction8.java index 10825347af38..af7d5a99bdf9 100644 --- a/library/src/scala/compat/java8/JFunction8.java +++ b/library/src/scala/compat/java8/JFunction8.java @@ -8,7 +8,7 @@ import scala.MatchError; @FunctionalInterface -public interface JFunction8 extends scala.Function8 { +public interface JFunction8 extends scala.Function8, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JFunction9.java b/library/src/scala/compat/java8/JFunction9.java index 02fe323c56c6..9157c23a80a3 100644 --- a/library/src/scala/compat/java8/JFunction9.java +++ b/library/src/scala/compat/java8/JFunction9.java @@ -6,7 +6,7 @@ package scala.compat.java8; @FunctionalInterface -public interface JFunction9 extends scala.Function9 { +public interface JFunction9 extends scala.Function9, java.io.Serializable { default void $init$() { }; diff --git a/library/src/scala/compat/java8/JProcedure0.java b/library/src/scala/compat/java8/JProcedure0.java index 8361252c63a1..1cb975e2a781 100644 --- a/library/src/scala/compat/java8/JProcedure0.java +++ b/library/src/scala/compat/java8/JProcedure0.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure0 extends JFunction0 { +public interface JProcedure0 extends JFunction0, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure1.java b/library/src/scala/compat/java8/JProcedure1.java index 189e451cd0d3..b524810614c3 100644 --- a/library/src/scala/compat/java8/JProcedure1.java +++ b/library/src/scala/compat/java8/JProcedure1.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure1 extends JFunction1 { +public interface JProcedure1 extends JFunction1, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure10.java b/library/src/scala/compat/java8/JProcedure10.java index 63a7543c5c0d..4a94f53951f7 100644 --- a/library/src/scala/compat/java8/JProcedure10.java +++ b/library/src/scala/compat/java8/JProcedure10.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure10 extends JFunction10 { +public interface JProcedure10 extends JFunction10, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure11.java b/library/src/scala/compat/java8/JProcedure11.java index 1f530fba9699..bdf09102062c 100644 --- a/library/src/scala/compat/java8/JProcedure11.java +++ b/library/src/scala/compat/java8/JProcedure11.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure11 extends JFunction11 { +public interface JProcedure11 extends JFunction11, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure12.java b/library/src/scala/compat/java8/JProcedure12.java index 454868e664a6..fc6033f593cc 100644 --- a/library/src/scala/compat/java8/JProcedure12.java +++ b/library/src/scala/compat/java8/JProcedure12.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure12 extends JFunction12 { +public interface JProcedure12 extends JFunction12, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure13.java b/library/src/scala/compat/java8/JProcedure13.java index 4db2cd866931..8db24920b21c 100644 --- a/library/src/scala/compat/java8/JProcedure13.java +++ b/library/src/scala/compat/java8/JProcedure13.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure13 extends JFunction13 { +public interface JProcedure13 extends JFunction13, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure14.java b/library/src/scala/compat/java8/JProcedure14.java index 9d1c4b89faa2..7cc807a87d9d 100644 --- a/library/src/scala/compat/java8/JProcedure14.java +++ b/library/src/scala/compat/java8/JProcedure14.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure14 extends JFunction14 { +public interface JProcedure14 extends JFunction14, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure15.java b/library/src/scala/compat/java8/JProcedure15.java index c49f042e7158..456671e5d004 100644 --- a/library/src/scala/compat/java8/JProcedure15.java +++ b/library/src/scala/compat/java8/JProcedure15.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure15 extends JFunction15 { +public interface JProcedure15 extends JFunction15, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure16.java b/library/src/scala/compat/java8/JProcedure16.java index aad602dfa972..cb06658e4c68 100644 --- a/library/src/scala/compat/java8/JProcedure16.java +++ b/library/src/scala/compat/java8/JProcedure16.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure16 extends JFunction16 { +public interface JProcedure16 extends JFunction16, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure17.java b/library/src/scala/compat/java8/JProcedure17.java index cdc30b9ee7a6..7924877ced54 100644 --- a/library/src/scala/compat/java8/JProcedure17.java +++ b/library/src/scala/compat/java8/JProcedure17.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure17 extends JFunction17 { +public interface JProcedure17 extends JFunction17, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure18.java b/library/src/scala/compat/java8/JProcedure18.java index 2e03d8f807de..dec8ee18382f 100644 --- a/library/src/scala/compat/java8/JProcedure18.java +++ b/library/src/scala/compat/java8/JProcedure18.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure18 extends JFunction18 { +public interface JProcedure18 extends JFunction18, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure19.java b/library/src/scala/compat/java8/JProcedure19.java index 5e4fcb9aa1e3..ce92050b67e6 100644 --- a/library/src/scala/compat/java8/JProcedure19.java +++ b/library/src/scala/compat/java8/JProcedure19.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure19 extends JFunction19 { +public interface JProcedure19 extends JFunction19, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure2.java b/library/src/scala/compat/java8/JProcedure2.java index 36e84d8ddd98..256cb0efa00e 100644 --- a/library/src/scala/compat/java8/JProcedure2.java +++ b/library/src/scala/compat/java8/JProcedure2.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure2 extends JFunction2 { +public interface JProcedure2 extends JFunction2, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure20.java b/library/src/scala/compat/java8/JProcedure20.java index d6598c312ab2..11dbda1b0712 100644 --- a/library/src/scala/compat/java8/JProcedure20.java +++ b/library/src/scala/compat/java8/JProcedure20.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure20 extends JFunction20 { +public interface JProcedure20 extends JFunction20, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure21.java b/library/src/scala/compat/java8/JProcedure21.java index c85cb540cef2..e59b6074768e 100644 --- a/library/src/scala/compat/java8/JProcedure21.java +++ b/library/src/scala/compat/java8/JProcedure21.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure21 extends JFunction21 { +public interface JProcedure21 extends JFunction21, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure22.java b/library/src/scala/compat/java8/JProcedure22.java index a1653ae61140..2a39864e1ef6 100644 --- a/library/src/scala/compat/java8/JProcedure22.java +++ b/library/src/scala/compat/java8/JProcedure22.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure22 extends JFunction22 { +public interface JProcedure22 extends JFunction22, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure3.java b/library/src/scala/compat/java8/JProcedure3.java index f2b1e498a565..ed13ae0d6b03 100644 --- a/library/src/scala/compat/java8/JProcedure3.java +++ b/library/src/scala/compat/java8/JProcedure3.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure3 extends JFunction3 { +public interface JProcedure3 extends JFunction3, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure4.java b/library/src/scala/compat/java8/JProcedure4.java index 7a3457b57069..d4840458fd99 100644 --- a/library/src/scala/compat/java8/JProcedure4.java +++ b/library/src/scala/compat/java8/JProcedure4.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure4 extends JFunction4 { +public interface JProcedure4 extends JFunction4, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure5.java b/library/src/scala/compat/java8/JProcedure5.java index e9d25854ae76..c8e9f7e1bd4a 100644 --- a/library/src/scala/compat/java8/JProcedure5.java +++ b/library/src/scala/compat/java8/JProcedure5.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure5 extends JFunction5 { +public interface JProcedure5 extends JFunction5, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure6.java b/library/src/scala/compat/java8/JProcedure6.java index d1675bd24410..15f0adf9f348 100644 --- a/library/src/scala/compat/java8/JProcedure6.java +++ b/library/src/scala/compat/java8/JProcedure6.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure6 extends JFunction6 { +public interface JProcedure6 extends JFunction6, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure7.java b/library/src/scala/compat/java8/JProcedure7.java index 1348e051bef3..f81ae878acf9 100644 --- a/library/src/scala/compat/java8/JProcedure7.java +++ b/library/src/scala/compat/java8/JProcedure7.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure7 extends JFunction7 { +public interface JProcedure7 extends JFunction7, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure8.java b/library/src/scala/compat/java8/JProcedure8.java index df944ca6e87a..77bfec22802e 100644 --- a/library/src/scala/compat/java8/JProcedure8.java +++ b/library/src/scala/compat/java8/JProcedure8.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure8 extends JFunction8 { +public interface JProcedure8 extends JFunction8, java.io.Serializable { default void $init$() { } diff --git a/library/src/scala/compat/java8/JProcedure9.java b/library/src/scala/compat/java8/JProcedure9.java index 47ad5d23425f..ebeb59f522ed 100644 --- a/library/src/scala/compat/java8/JProcedure9.java +++ b/library/src/scala/compat/java8/JProcedure9.java @@ -8,7 +8,7 @@ import scala.runtime.BoxedUnit; @FunctionalInterface -public interface JProcedure9 extends JFunction9 { +public interface JProcedure9 extends JFunction9, java.io.Serializable { default void $init$() { } From b4f1e44fdea0b7ba34f04690a42bb7ed59cb9adb Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Fri, 25 Jan 2019 17:13:11 +0100 Subject: [PATCH 5/6] Make various methods that check if a class is a Function return true for FunctionXXL This only makes a difference after erasure, and I believe this is less surprising than the previous behavior. This necessitated a slight refactoring in GenericSignature to avoid an infinite loop now that `isXXLFunctionClass` returns true for scala.FunctionXXL and not just for the classes that erase to scala.FunctionXXL. --- .../dotty/tools/dotc/core/Definitions.scala | 13 +- .../src/dotty/tools/dotc/core/NameOps.scala | 4 +- .../src/dotty/tools/dotc/core/StdNames.scala | 1 + .../dotc/transform/GenericSignatures.scala | 111 +++++++++--------- 4 files changed, 70 insertions(+), 59 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 77922d677354..2332a9b8204e 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1001,6 +1001,7 @@ class Definitions { tp.derivesFrom(NothingClass) || tp.derivesFrom(NullClass) /** Is a function class. + * - FunctionXXL * - FunctionN for N >= 0 * - ImplicitFunctionN for N >= 0 * - ErasedFunctionN for N > 0 @@ -1020,15 +1021,21 @@ class Definitions { */ def isErasedFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).isErasedFunction - /** Is a class that will be erased to FunctionXXL + /** Is either FunctionXXL or a class that will be erased to FunctionXXL + * - FunctionXXL * - FunctionN for N >= 22 * - ImplicitFunctionN for N >= 22 */ - def isXXLFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).functionArity > MaxImplementedFunctionArity + def isXXLFunctionClass(cls: Symbol): Boolean = { + val name = scalaClassName(cls) + (name eq tpnme.FunctionXXL) || name.functionArity > MaxImplementedFunctionArity + } /** Is a synthetic function class * - FunctionN for N > 22 - * - ImplicitFunctionN for N > 0 + * - ImplicitFunctionN for N >= 0 + * - ErasedFunctionN for N > 0 + * - ErasedImplicitFunctionN for N > 0 */ def isSyntheticFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).isSyntheticFunction diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 4b2d6f5ad216..7bb897c0d73b 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -183,9 +183,9 @@ object NameOps { if (n == 0) -1 else n } - /** Is a function name, i.e one of FunctionN, ImplicitFunctionN for N >= 0 or ErasedFunctionN, ErasedImplicitFunctionN for N > 0 + /** Is a function name, i.e one of FunctionXXL, FunctionN, ImplicitFunctionN for N >= 0 or ErasedFunctionN, ErasedImplicitFunctionN for N > 0 */ - def isFunction: Boolean = functionArity >= 0 + def isFunction: Boolean = (name eq tpnme.FunctionXXL) || functionArity >= 0 /** Is an implicit function name, i.e one of ImplicitFunctionN for N >= 0 or ErasedImplicitFunctionN for N > 0 */ diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index e702a47ce8eb..3d3da013af4b 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -205,6 +205,7 @@ object StdNames { final val Singleton: N = "Singleton" final val Throwable: N = "Throwable" final val IOOBException: N = "IndexOutOfBoundsException" + final val FunctionXXL: N = "FunctionXXL" final val ClassfileAnnotation: N = "ClassfileAnnotation" final val ClassManifest: N = "ClassManifest" diff --git a/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala b/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala index bdd339482ab3..b465452f4bdf 100644 --- a/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala +++ b/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala @@ -123,6 +123,60 @@ object GenericSignatures { builder.append('L').append(name) } + def classSig(sym: Symbol, pre: Type = NoType, args: List[Type] = Nil): Unit = { + def argSig(tp: Type): Unit = + tp match { + case bounds: TypeBounds => + if (!(defn.AnyType <:< bounds.hi)) { + builder.append('+') + boxedSig(bounds.hi) + } + else if (!(bounds.lo <:< defn.NothingType)) { + builder.append('-') + boxedSig(bounds.lo) + } + else builder.append('*') + case PolyType(_, res) => + builder.append('*') // scala/bug#7932 + case _: HKTypeLambda => + fullNameInSig(tp.typeSymbol) + builder.append(';') + case _ => + boxedSig(tp) + } + + if (pre.exists) { + val preRebound = pre.baseType(sym.owner) // #2585 + if (needsJavaSig(preRebound, Nil)) { + val i = builder.length() + jsig(preRebound) + if (builder.charAt(i) == 'L') { + builder.delete(builder.length() - 1, builder.length())// delete ';' + // If the prefix is a module, drop the '$'. Classes (or modules) nested in modules + // are separated by a single '$' in the filename: `object o { object i }` is o$i$. + if (preRebound.typeSymbol.is(ModuleClass)) + builder.delete(builder.length() - 1, builder.length()) + + // Ensure every '.' in the generated signature immediately follows + // a close angle bracket '>'. Any which do not are replaced with '$'. + // This arises due to multiply nested classes in the face of the + // rewriting explained at rebindInnerClass. + + // TODO revisit this. Does it align with javac for code that can be expressed in both languages? + val delimiter = if (builder.charAt(builder.length() - 1) == '>') '.' else '$' + builder.append(delimiter).append(sanitizeName(sym.name.asSimpleName)) + } else fullNameInSig(sym) + } else fullNameInSig(sym) + } else fullNameInSig(sym) + + if (args.nonEmpty) { + builder.append('<') + args foreach argSig + builder.append('>') + } + builder.append(';') + } + @noinline def jsig(tp0: Type, toplevel: Boolean = false, primitiveOK: Boolean = true): Unit = { @@ -133,57 +187,6 @@ object GenericSignatures { typeParamSig(ref.paramName.lastPart) case RefOrAppliedType(sym, pre, args) => - def argSig(tp: Type): Unit = - tp match { - case bounds: TypeBounds => - if (!(defn.AnyType <:< bounds.hi)) { - builder.append('+') - boxedSig(bounds.hi) - } - else if (!(bounds.lo <:< defn.NothingType)) { - builder.append('-') - boxedSig(bounds.lo) - } - else builder.append('*') - case PolyType(_, res) => - builder.append('*') // scala/bug#7932 - case _: HKTypeLambda => - fullNameInSig(tp.typeSymbol) - builder.append(';') - case _ => - boxedSig(tp) - } - def classSig: Unit = { - val preRebound = pre.baseType(sym.owner) // #2585 - if (needsJavaSig(preRebound, Nil)) { - val i = builder.length() - jsig(preRebound) - if (builder.charAt(i) == 'L') { - builder.delete(builder.length() - 1, builder.length())// delete ';' - // If the prefix is a module, drop the '$'. Classes (or modules) nested in modules - // are separated by a single '$' in the filename: `object o { object i }` is o$i$. - if (preRebound.typeSymbol.is(ModuleClass)) - builder.delete(builder.length() - 1, builder.length()) - - // Ensure every '.' in the generated signature immediately follows - // a close angle bracket '>'. Any which do not are replaced with '$'. - // This arises due to multiply nested classes in the face of the - // rewriting explained at rebindInnerClass. - - // TODO revisit this. Does it align with javac for code that can be expressed in both languages? - val delimiter = if (builder.charAt(builder.length() - 1) == '>') '.' else '$' - builder.append(delimiter).append(sanitizeName(sym.name.asSimpleName)) - } else fullNameInSig(sym) - } else fullNameInSig(sym) - - if (args.nonEmpty) { - builder.append('<') - args foreach argSig - builder.append('>') - } - builder.append(';') - } - // If args isEmpty, Array is being used as a type constructor if (sym == defn.ArrayClass && args.nonEmpty) { if (unboundedGenericArrayLevel(tp) == 1) jsig(defn.ObjectType) @@ -215,14 +218,14 @@ object GenericSignatures { val unboxed = ValueClasses.valueClassUnbox(sym.asClass).info.finalResultType val unboxedSeen = tp.memberInfo(ValueClasses.valueClassUnbox(sym.asClass)).finalResultType if (unboxedSeen.isPrimitiveValueType && !primitiveOK) - classSig + classSig(sym, pre, args) else jsig(unboxedSeen, toplevel, primitiveOK) } else if (defn.isXXLFunctionClass(sym)) - jsig(defn.FunctionXXLType, toplevel, primitiveOK) + classSig(defn.FunctionXXLClass) else if (sym.isClass) - classSig + classSig(sym, pre, args) else jsig(erasure(tp), toplevel, primitiveOK) From 5fc21199cc6ead57844742857e97a7e40c63885c Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Tue, 22 Jan 2019 17:37:06 +0100 Subject: [PATCH 6/6] Fix #4442: Add support for lambda serialization In Scala, lambdas whose SAM extend Serializable as well as lambdas whose SAM is simply scala.Function* should be serializable but this was not the case in Dotty so far. On the JVM, lambdas instantiated using invokedynamic calls require some special handling to be serializable: 1. We need to use the invokedynamic bootstrap method `LambdaMetaFactory#altMetafactory` instead of `LambdaMetaFactory#metafactory`, this allows us to pass the FLAG_SERIALIZABLE flag. This is implemented in the backend submodule commit included in this commit (see https://github.com/lampepfl/scala/pull/39). 2. In the enclosing class where the lambda is defined, a $deserializeLambda$ method needs to be generated, this is implemented in this commit. Most of the logic for $deserializeLambda$ is implemented in the Scala 2.12 standard libraries class scala.runtime.LambdaDeserialize and scala.runtime.LambdaDeserializer which can be used here as-is, the only logic we actually need to implement here is: 1. In `collectSerializableLambdas`, we collect all serializable lambdas. Unlike scalac, our backend does not do any inlining currently so our implementation is more straightfoward than theirs. 2. In `addLambdaDeserialize`, we implement the actual $deserializeLambda$ method, the implementation here is directly copied from scalac, it's complex because it needs to work around a limitation of bootstrap methods (they cannot take more than 251 arguments). Since some of this code comes from scalac, this is: Co-Authored-By: Jason Zaugg Co-Authored-By: Lukas Rytz --- .../backend/jvm/DottyBackendInterface.scala | 4 + .../dotty/tools/backend/jvm/GenBCode.scala | 98 ++- tests/run/inlineAddDeserializeLambda.scala | 20 + tests/run/lambda-serialization-gc.scala | 40 ++ tests/run/lambda-serialization-others.scala | 67 ++ tests/run/lambda-serialization-security.scala | 47 ++ tests/run/lambda-serialization.scala | 66 ++ tests/run/serialization-new.check | 283 ++++++++ tests/run/serialization-new.scala | 622 ++++++++++++++++++ tests/run/t10232.scala | 275 ++++++++ tests/run/t6260-delambdafy.check | 1 + tests/run/tasty-extractors-2.check | 8 +- 12 files changed, 1525 insertions(+), 6 deletions(-) create mode 100644 tests/run/inlineAddDeserializeLambda.scala create mode 100644 tests/run/lambda-serialization-gc.scala create mode 100644 tests/run/lambda-serialization-others.scala create mode 100644 tests/run/lambda-serialization-security.scala create mode 100644 tests/run/lambda-serialization.scala create mode 100644 tests/run/serialization-new.check create mode 100644 tests/run/serialization-new.scala create mode 100644 tests/run/t10232.scala diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 4e32634ae274..8c8ec5f9270b 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -706,6 +706,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma def isJavaEntryPoint: Boolean = CollectEntryPoints.isJavaEntryPoint(sym) def isClassConstructor: Boolean = toDenot(sym).isClassConstructor + def isSerializable: Boolean = toDenot(sym).isSerializable /** * True for module classes of modules that are top-level or owned only by objects. Module classes @@ -855,6 +856,9 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma def samMethod(): Symbol = toDenot(sym).info.abstractTermMembers.headOption.getOrElse(toDenot(sym).info.member(nme.apply)).symbol + + def isFunctionClass: Boolean = + defn.isFunctionClass(sym) } diff --git a/compiler/src/dotty/tools/backend/jvm/GenBCode.scala b/compiler/src/dotty/tools/backend/jvm/GenBCode.scala index daabf824cead..d94f82180c48 100644 --- a/compiler/src/dotty/tools/backend/jvm/GenBCode.scala +++ b/compiler/src/dotty/tools/backend/jvm/GenBCode.scala @@ -6,6 +6,7 @@ import dotty.tools.dotc.ast.tpd import dotty.tools.dotc.core.Phases.Phase import scala.collection.mutable +import scala.collection.JavaConverters._ import scala.tools.asm.CustomAttr import scala.tools.nsc.backend.jvm._ import dotty.tools.dotc.transform.SymUtils._ @@ -23,6 +24,7 @@ import java.io.DataOutputStream import scala.tools.asm +import scala.tools.asm.Handle import scala.tools.asm.tree._ import tpd._ import StdNames._ @@ -304,10 +306,98 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter class Worker2 { // lazy val localOpt = new LocalOpt(new Settings()) - def localOptimizations(classNode: ClassNode): Unit = { + private def localOptimizations(classNode: ClassNode): Unit = { // BackendStats.timed(BackendStats.methodOptTimer)(localOpt.methodOptimizations(classNode)) } + + /* Return an array of all serializable lambdas in this class */ + private def collectSerializableLambdas(classNode: ClassNode): Array[Handle] = { + val indyLambdaBodyMethods = new mutable.ArrayBuffer[Handle] + for (m <- classNode.methods.asScala) { + val iter = m.instructions.iterator + while (iter.hasNext) { + val insn = iter.next() + insn match { + case indy: InvokeDynamicInsnNode + // No need to check the exact bsmArgs because we only generate + // altMetafactory indy calls for serializable lambdas. + if indy.bsm == BCodeBodyBuilder.lambdaMetaFactoryAltMetafactoryHandle => + val implMethod = indy.bsmArgs(1).asInstanceOf[Handle] + indyLambdaBodyMethods += implMethod + case _ => + } + } + } + indyLambdaBodyMethods.toArray + } + + /* + * Add: + * + * private static Object $deserializeLambda$(SerializedLambda l) { + * try return indy[scala.runtime.LambdaDeserialize.bootstrap, targetMethodGroup$0](l) + * catch { + * case i: IllegalArgumentException => + * try return indy[scala.runtime.LambdaDeserialize.bootstrap, targetMethodGroup$1](l) + * catch { + * case i: IllegalArgumentException => + * ... + * return indy[scala.runtime.LambdaDeserialize.bootstrap, targetMethodGroup${NUM_GROUPS-1}](l) + * } + * + * We use invokedynamic here to enable caching within the deserializer without needing to + * host a static field in the enclosing class. This allows us to add this method to interfaces + * that define lambdas in default methods. + * + * SI-10232 we can't pass arbitrary number of method handles to the final varargs parameter of the bootstrap + * method due to a limitation in the JVM. Instead, we emit a separate invokedynamic bytecode for each group of target + * methods. + */ + private def addLambdaDeserialize(classNode: ClassNode, implMethodsArray: Array[Handle]): Unit = { + import asm.Opcodes._ + import BCodeBodyBuilder._ + import bTypes._ + import coreBTypes._ + + val cw = classNode + + // Make sure to reference the ClassBTypes of all types that are used in the code generated + // here (e.g. java/util/Map) are initialized. Initializing a ClassBType adds it to + // `classBTypeFromInternalNameMap`. When writing the classfile, the asm ClassWriter computes + // stack map frames and invokes the `getCommonSuperClass` method. This method expects all + // ClassBTypes mentioned in the source code to exist in the map. + + val serlamObjDesc = MethodBType(jliSerializedLambdaRef :: Nil, ObjectReference).descriptor + + val mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$deserializeLambda$", serlamObjDesc, null, null) + def emitLambdaDeserializeIndy(targetMethods: Seq[Handle]): Unit = { + mv.visitVarInsn(ALOAD, 0) + mv.visitInvokeDynamicInsn("lambdaDeserialize", serlamObjDesc, lambdaDeserializeBootstrapHandle, targetMethods: _*) + } + + val targetMethodGroupLimit = 255 - 1 - 3 // JVM limit. See See MAX_MH_ARITY in CallSite.java + val groups: Array[Array[Handle]] = implMethodsArray.grouped(targetMethodGroupLimit).toArray + val numGroups = groups.length + + import scala.tools.asm.Label + val initialLabels = Array.fill(numGroups - 1)(new Label()) + val terminalLabel = new Label + def nextLabel(i: Int) = if (i == numGroups - 2) terminalLabel else initialLabels(i + 1) + + for ((label, i) <- initialLabels.iterator.zipWithIndex) { + mv.visitTryCatchBlock(label, nextLabel(i), nextLabel(i), jlIllegalArgExceptionRef.internalName) + } + for ((label, i) <- initialLabels.iterator.zipWithIndex) { + mv.visitLabel(label) + emitLambdaDeserializeIndy(groups(i)) + mv.visitInsn(ARETURN) + } + mv.visitLabel(terminalLabel) + emitLambdaDeserializeIndy(groups(numGroups - 1)) + mv.visitInsn(ARETURN) + } + def run(): Unit = { while (true) { val item = q2.poll @@ -317,7 +407,11 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter } else { try { - localOptimizations(item.plain.classNode) + val plainNode = item.plain.classNode + localOptimizations(plainNode) + val serializableLambdas = collectSerializableLambdas(plainNode) + if (serializableLambdas.nonEmpty) + addLambdaDeserialize(plainNode, serializableLambdas) addToQ3(item) } catch { case ex: Throwable => diff --git a/tests/run/inlineAddDeserializeLambda.scala b/tests/run/inlineAddDeserializeLambda.scala new file mode 100644 index 000000000000..0b97b2583ef0 --- /dev/null +++ b/tests/run/inlineAddDeserializeLambda.scala @@ -0,0 +1,20 @@ +class C { inline final def f: Int => Int = (x: Int) => x + 1 } + +object Test extends App { + import java.io._ + + def serialize(obj: AnyRef): Array[Byte] = { + val buffer = new ByteArrayOutputStream + val out = new ObjectOutputStream(buffer) + out.writeObject(obj) + buffer.toByteArray + } + def deserialize(a: Array[Byte]): AnyRef = { + val in = new ObjectInputStream(new ByteArrayInputStream(a)) + in.readObject + } + + def serializeDeserialize[T <: AnyRef](obj: T) = deserialize(serialize(obj)).asInstanceOf[T] + + assert(serializeDeserialize((new C).f).isInstanceOf[Function1[_, _]]) +} diff --git a/tests/run/lambda-serialization-gc.scala b/tests/run/lambda-serialization-gc.scala new file mode 100644 index 000000000000..4d156c421013 --- /dev/null +++ b/tests/run/lambda-serialization-gc.scala @@ -0,0 +1,40 @@ +import java.io._ + +import java.net.URLClassLoader + +class C { + def serializeDeserialize[T <: AnyRef](obj: T) = { + val buffer = new ByteArrayOutputStream + val out = new ObjectOutputStream(buffer) + out.writeObject(obj) + val in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray)) + in.readObject.asInstanceOf[T] + } + + serializeDeserialize((c: String) => c.length) +} + +object Test { + def main(args: Array[String]): Unit = { + test() + } + + def test(): Unit = { + val loader = getClass.getClassLoader.asInstanceOf[URLClassLoader] + val loaderCClass = classOf[C] + def deserializedInThrowawayClassloader = { + val throwawayLoader: java.net.URLClassLoader = new java.net.URLClassLoader(loader.getURLs, ClassLoader.getSystemClassLoader) { + val maxMemory = Runtime.getRuntime.maxMemory() + val junk = new Array[Long]((maxMemory / 8 / 4).toInt) + } + val clazz = throwawayLoader.loadClass("C") + assert(clazz != loaderCClass) + clazz.newInstance() + } + (1 to 5) foreach { i => + // This would OOM by the fifth iteration if we leaked `throwawayLoader` during + // deserialization. + deserializedInThrowawayClassloader + } + } +} diff --git a/tests/run/lambda-serialization-others.scala b/tests/run/lambda-serialization-others.scala new file mode 100644 index 000000000000..38b63d499e7d --- /dev/null +++ b/tests/run/lambda-serialization-others.scala @@ -0,0 +1,67 @@ +import java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream, PrintWriter, StringWriter} +import java.lang.invoke.{MethodHandleInfo, SerializedLambda} + +class C1 { + val xxlfun = ((x1: Int, + x2: String, + x3: Int, + x4: Int, + x5: Int, + x6: Int, + x7: Int, + x8: Int, + x9: Int, + x10: Int, + x11: Int, + x12: Int, + x13: Int, + x14: Int, + x15: Int, + x16: Int, + x17: Int, + x18: Int, + x19: Int, + x20: Int, + x21: Int, + x22: Int, + x23: Int, + x24: Int, + x25: Int, + x26: Int) => x2 + x1) + + val depfun: (x1: Int) => List[x1.type] = x1 => List(x1) + + val erasedfun: erased Int => Int = erased (x1) => 0 +} + +class C2 + extends Serializable /* Needed because of #5866 */ { + val impfun: given Int => Int = given x1 => x1 + + val impdepfun: given (x1: Int) => List[x1.type] = given x1 => List(x1) + + val erasedimpfun: given erased Int => Int = given erased (x1) => 0 +} + +object Test { + def main(args: Array[String]): Unit = { + val c1 = new C1 + serializeDeserialize(c1.xxlfun) + serializeDeserialize(c1.erasedfun) + + val c2 = new C2 + serializeDeserialize[given Int => Int](c2.impfun) + // Won't compile until #5841 is merged + // serializeDeserialize[given Int => Int](c2.impdepfun) + serializeDeserialize[given Int => Int](c2.erasedimpfun) + } + + def serializeDeserialize[T <: AnyRef](obj: T): Unit = { + val buffer = new ByteArrayOutputStream + val out = new ObjectOutputStream(buffer) + out.writeObject(obj) + val in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray)) + in.readObject.asInstanceOf[T] + } +} + diff --git a/tests/run/lambda-serialization-security.scala b/tests/run/lambda-serialization-security.scala new file mode 100644 index 000000000000..08e235b1cb9b --- /dev/null +++ b/tests/run/lambda-serialization-security.scala @@ -0,0 +1,47 @@ +import java.io.{ByteArrayInputStream, ObjectInputStream, ObjectOutputStream, ByteArrayOutputStream} + +trait IntToString extends java.io.Serializable { def apply(i: Int): String } + +object Test { + def main(args: Array[String]): Unit = { + roundTrip() + roundTripIndySam() + } + + def roundTrip(): Unit = { + val c = new Capture("Capture") + val lambda = (p: Param) => ("a", p, c) + val reconstituted1 = serializeDeserialize(lambda).asInstanceOf[Object => Any] + val p = new Param + assert(reconstituted1.apply(p) == ("a", p, c)) + val reconstituted2 = serializeDeserialize(lambda).asInstanceOf[Object => Any] + assert(reconstituted1.getClass == reconstituted2.getClass) + + val reconstituted3 = serializeDeserialize(reconstituted1) + assert(reconstituted3.apply(p) == ("a", p, c)) + + val specializedLambda = (p: Int) => List(p, c).length + assert(serializeDeserialize(specializedLambda).apply(42) == 2) + assert(serializeDeserialize(serializeDeserialize(specializedLambda)).apply(42) == 2) + } + + // lambda targeting a SAM, not a FunctionN (should behave the same way) + def roundTripIndySam(): Unit = { + val lambda: IntToString = (x: Int) => "yo!" * x + val reconstituted1 = serializeDeserialize(lambda).asInstanceOf[IntToString] + val reconstituted2 = serializeDeserialize(reconstituted1).asInstanceOf[IntToString] + assert(reconstituted1.apply(2) == "yo!yo!") + assert(reconstituted1.getClass == reconstituted2.getClass) + } + + def serializeDeserialize[T <: AnyRef](obj: T) = { + val buffer = new ByteArrayOutputStream + val out = new ObjectOutputStream(buffer) + out.writeObject(obj) + val in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray)) + in.readObject.asInstanceOf[T] + } +} + +case class Capture(s: String) extends Serializable +class Param diff --git a/tests/run/lambda-serialization.scala b/tests/run/lambda-serialization.scala new file mode 100644 index 000000000000..e1419c5ff394 --- /dev/null +++ b/tests/run/lambda-serialization.scala @@ -0,0 +1,66 @@ +import java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream, PrintWriter, StringWriter} +import java.lang.invoke.{MethodHandleInfo, SerializedLambda} + +class C extends java.io.Serializable { + val fs = List( + () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => () ,() => (), () => (), () => (), () => (), () => (), + () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => () ,() => (), () => (), () => (), () => (), () => (), + () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => () ,() => (), () => (), () => (), () => (), () => (), + () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => () ,() => (), () => (), () => (), () => (), () => (), + () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => () ,() => (), () => (), () => (), () => (), () => (), + () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => () ,() => (), () => (), () => (), () => (), () => (), + () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => () ,() => (), () => (), () => (), () => (), () => (), + () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => () ,() => (), () => (), () => (), () => (), () => (), + () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => () ,() => (), () => (), () => (), () => (), () => (), + () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => () ,() => (), () => (), () => (), () => (), () => (), + () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => () ,() => (), () => (), () => (), () => (), () => (), + () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => () ,() => (), () => (), () => (), () => (), () => (), + () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => () ,() => (), () => (), () => (), () => (), () => (), + () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => () ,() => (), () => (), () => (), () => (), () => (), + () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => (), () => () ,() => (), () => (), () => (), () => (), () => () + ) + private def foo(): Unit = { + assert(false, "should not be called!!!") + } +} + +trait FakeSam { def apply(): Unit } + +object Test { + def main(args: Array[String]): Unit = { + allRealLambdasRoundTrip() + fakeLambdaFailsToDeserialize() + } + + def allRealLambdasRoundTrip(): Unit = { + new C().fs.map(x => serializeDeserialize(x).apply()) + } + + def fakeLambdaFailsToDeserialize(): Unit = { + val fake = new SerializedLambda(classOf[C], classOf[FakeSam].getName, "apply", "()V", + MethodHandleInfo.REF_invokeVirtual, classOf[C].getName, "foo", "()V", "()V", Array(new C)) + try { + serializeDeserialize(fake).asInstanceOf[FakeSam].apply() + assert(false) + } catch { + case ex: Exception => + val stackTrace = stackTraceString(ex) + assert(stackTrace.contains("Illegal lambda deserialization"), stackTrace) + } + } + + def serializeDeserialize[T <: AnyRef](obj: T) = { + val buffer = new ByteArrayOutputStream + val out = new ObjectOutputStream(buffer) + out.writeObject(obj) + val in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray)) + in.readObject.asInstanceOf[T] + } + + def stackTraceString(ex: Throwable): String = { + val writer = new StringWriter + ex.printStackTrace(new PrintWriter(writer)) + writer.toString + } +} + diff --git a/tests/run/serialization-new.check b/tests/run/serialization-new.check new file mode 100644 index 000000000000..40646e993a0b --- /dev/null +++ b/tests/run/serialization-new.check @@ -0,0 +1,283 @@ +a1 = Array[1,2,3] +_a1 = Array[1,2,3] +arrayEquals(a1, _a1): true + +e1 = Left(1) +_e1 = Left(1) +e1 eq _e1: false, _e1 eq e1: false +e1 equals _e1: true, _e1 equals e1: true + +x7 = RoundingMode +y7 = RoundingMode +x7 eq y7: true, y7 eq x7: true +x7 equals y7: true, y7 equals x7: true + +x8 = WeekDay +y8 = WeekDay +x8 eq y8: true, y8 eq x8: true +x8 equals y8: true, y8 equals x8: true + +x9 = UP +y9 = UP +x9 eq y9: true, y9 eq x9: true +x9 equals y9: true, y9 equals x9: true + +x10 = Monday +y10 = Monday +x10 eq y10: true, y10 eq x10: true +x10 equals y10: true, y10 equals x10: true + +x9 eq x10: false, x10 eq x9: false +x9 equals x10: false, x10 equals x9: false +x9 eq y10: false, y10 eq x9: false +x9 equals y10: false, y10 equals x9: false + +f1 = +_f1 = +f1(2): 4, _f1(2): 4 + +xs0 = List(1, 2, 3) +_xs0 = List(1, 2, 3) +xs0 eq _xs0: false, _xs0 eq xs0: false +xs0 equals _xs0: true, _xs0 equals xs0: true + +xs1 = List() +_xs1 = List() +xs1 eq _xs1: true, _xs1 eq xs1: true + +o1 = None +_o1 = None +o1 eq _o1: true, _o1 eq o1: true + +o2 = Some(1) +_o2 = Some(1) +o2 eq _o2: false, _o2 eq o2: false +o2 equals _o2: true, _o2 equals o2: true + +s1 = 'hello +_s1 = 'hello +s1 eq _s1: true, _s1 eq s1: true +s1 equals _s1: true, _s1 equals s1: true + +t1 = (BannerLimit,12345) +_t1 = (BannerLimit,12345) +t1 eq _t1: false, _t1 eq t1: false +t1 equals _t1: true, _t1 equals t1: true + +x = BitSet(1, 2) +y = BitSet(1, 2) +x equals y: true, y equals x: true + +x = BitSet(2, 3) +y = BitSet(2, 3) +x equals y: true, y equals x: true + +x = Map(1 -> A, 2 -> B, 3 -> C) +y = Map(1 -> A, 2 -> B, 3 -> C) +x equals y: true, y equals x: true + +x = Set(1, 2) +y = Set(1, 2) +x equals y: true, y equals x: true + +x = List((buffers,20), (layers,2), (title,3)) +y = List((buffers,20), (layers,2), (title,3)) +x equals y: true, y equals x: true + +x = ListMap(buffers -> 20, layers -> 2, title -> 3) +y = ListMap(buffers -> 20, layers -> 2, title -> 3) +x equals y: true, y equals x: true + +x = ListSet(3, 5) +y = ListSet(3, 5) +x equals y: true, y equals x: true + +x = Queue(a, b, c) +y = Queue(a, b, c) +x equals y: true, y equals x: true + +x = Range 0 until 10 +y = Range 0 until 10 +x equals y: true, y equals x: true + +x = NumericRange 0 until 10 +y = NumericRange 0 until 10 +x equals y: true, y equals x: true + +x = Map(1 -> A, 2 -> B, 3 -> C) +y = Map(1 -> A, 2 -> B, 3 -> C) +x equals y: true, y equals x: true + +x = TreeSet(1, 2, 3) +y = TreeSet(1, 2, 3) +x equals y: true, y equals x: true + +x = Stack(c, b, a) +y = Stack(c, b, a) +x equals y: true, y equals x: true + +x = Stream(0, ?) +y = Stream(0, ?) +x equals y: true, y equals x: true + +x = Map(42 -> FortyTwo) +y = Map(42 -> FortyTwo) +x equals y: true, y equals x: true + +x = TreeSet(0, 2) +y = TreeSet(0, 2) +x equals y: true, y equals x: true + +x = Vector('a, 'b, 'c) +y = Vector('a, 'b, 'c) +x equals y: true, y equals x: true + +x = ArrayBuffer(one, two) +y = ArrayBuffer(one, two) +x equals y: true, y equals x: true + +x = ArrayBuilder.ofLong +y = ArrayBuilder.ofLong +x equals y: true, y equals x: true + +x = ArrayBuilder.ofFloat +y = ArrayBuilder.ofFloat +x equals y: true, y equals x: true + +x = ArraySeq(1, 2, 3) +y = ArraySeq(1, 2, 3) +x equals y: true, y equals x: true + +x = ArrayStack(3, 2, 20) +y = ArrayStack(3, 2, 20) +x equals y: true, y equals x: true + +x = BitSet(0, 8, 9) +y = BitSet(0, 8, 9) +x equals y: true, y equals x: true + +x = Map(A -> 1, C -> 3, B -> 2) +y = Map(A -> 1, C -> 3, B -> 2) +x equals y: true, y equals x: true + +x = Set(buffers, title, layers) +y = Set(buffers, title, layers) +x equals y: true, y equals x: true + +x = History() +y = History() +x equals y: true, y equals x: true + +x = Map(Linked -> 1, Hash -> 2, Map -> 3) +y = Map(Linked -> 1, Hash -> 2, Map -> 3) +x equals y: true, y equals x: true + +x = ArrayBuffer((Linked,1), (Hash,2), (Map,3)) +y = ArrayBuffer((Linked,1), (Hash,2), (Map,3)) +x equals y: true, y equals x: true + +x = ArrayBuffer((Linked,1), (Hash,2), (Map,3)) +y = List((Linked,1), (Hash,2), (Map,3)) +x equals y: true, y equals x: true + +x = Set(layers, buffers, title) +y = Set(layers, buffers, title) +x equals y: true, y equals x: true + +x = ArrayBuffer(layers, buffers, title) +y = ArrayBuffer(layers, buffers, title) +x equals y: true, y equals x: true + +x = ArrayBuffer(layers, buffers, title) +y = List(layers, buffers, title) +x equals y: true, y equals x: true + +x = ListBuffer(white, black) +y = ListBuffer(white, black) +x equals y: true, y equals x: true + +x = Queue(20, 2, 3) +y = Queue(20, 2, 3) +x equals y: true, y equals x: true + +x = Stack(3, 2, 20) +y = Stack(3, 2, 20) +x equals y: true, y equals x: true + +x = abc +y = abc +x equals y: true, y equals x: true + +x = WrappedArray(1, 2, 3) +y = WrappedArray(1, 2, 3) +x equals y: true, y equals x: true + +x = TreeSet(1, 2, 3) +y = TreeSet(1, 2, 3) +x equals y: true, y equals x: true + +x = TrieMap(1 -> one, 2 -> two, 3 -> three) +y = TrieMap(1 -> one, 2 -> two, 3 -> three) +x equals y: true, y equals x: true + +x = Tim +y = Tim +x equals y: true, y equals x: true + +x = Bob +y = Bob +x equals y: true, y equals x: true + +x = John +y = John +x equals y: true, y equals x: true + +x = Bill +y = Bill +x equals y: true, y equals x: true + +x = Paul +y = Paul +x equals y: true, y equals x: true + +1 +2 +1 +2 + +x = UnrolledBuffer(one, two) +y = UnrolledBuffer(one, two) +x equals y: true, y equals x: true + +x = ParArray(abc, def, etc) +y = ParArray(abc, def, etc) +x equals y: true, y equals x: true + +x = ParHashMap(2 -> 4, 1 -> 2) +y = ParHashMap(2 -> 4, 1 -> 2) +x equals y: true, y equals x: true + +x = ParTrieMap(1 -> 2, 2 -> 4) +y = ParTrieMap(1 -> 2, 2 -> 4) +x equals y: true, y equals x: true + +x = ParHashSet(1, 2, 3) +y = ParHashSet(1, 2, 3) +x equals y: true, y equals x: true + +x = ParRange 0 to 4 +y = ParRange 0 to 4 +x equals y: true, y equals x: true + +x = ParRange 0 until 4 +y = ParRange 0 until 4 +x equals y: true, y equals x: true + +x = ParMap(5 -> 1, 10 -> 2) +y = ParMap(5 -> 1, 10 -> 2) +x equals y: true, y equals x: true + +x = ParSet(two, one) +y = ParSet(two, one) +x equals y: true, y equals x: true + diff --git a/tests/run/serialization-new.scala b/tests/run/serialization-new.scala new file mode 100644 index 000000000000..8da9d4b3db30 --- /dev/null +++ b/tests/run/serialization-new.scala @@ -0,0 +1,622 @@ +//############################################################################ +// Serialization +//############################################################################ + +object Serialize { + @throws(classOf[java.io.IOException]) + def write[A](o: A): Array[Byte] = { + val ba = new java.io.ByteArrayOutputStream(512) + val out = new java.io.ObjectOutputStream(ba) + out.writeObject(o) + out.close() + ba.toByteArray() + } + @throws(classOf[java.io.IOException]) + @throws(classOf[ClassNotFoundException]) + def read[A](buffer: Array[Byte]): A = { + val in = + new java.io.ObjectInputStream(new java.io.ByteArrayInputStream(buffer)) + in.readObject().asInstanceOf[A] + } + def check[A, B](x: A, y: B): Unit = { + println("x = " + x) + println("y = " + y) + println("x equals y: " + (x equals y) + ", y equals x: " + (y equals x)) + assert((x equals y) && (y equals x)) + println() + } +} +import Serialize._ + +//############################################################################ +// Test classes in package "scala" + +object Test1_scala { + + private def arrayToString[A](arr: Array[A]): String = + arr.mkString("Array[",",","]") + + private def arrayEquals[A, B](a1: Array[A], a2: Array[B]): Boolean = + (a1.length == a2.length) && + (Iterator.range(0, a1.length) forall { i => a1(i) == a2(i) }) + + object WeekDay extends Enumeration { + type WeekDay = Value + val Monday, Tuesday, Wednesday, Thusday, Friday, Saturday, Sunday = Value + } + import WeekDay._, BigDecimal._, RoundingMode._ + + // in alphabetic order + try { + // Array + val a1 = Array(1, 2, 3) + val _a1: Array[Int] = read(write(a1)) + println("a1 = " + arrayToString(a1)) + println("_a1 = " + arrayToString(_a1)) + println("arrayEquals(a1, _a1): " + arrayEquals(a1, _a1)) + println() + + // Either + val e1 = Left(1) + val _e1: Either[Int, String] = read(write(e1)) + println("e1 = " + e1) + println("_e1 = " + _e1) + println("e1 eq _e1: " + (e1 eq _e1) + ", _e1 eq e1: " + (_e1 eq e1)) + println("e1 equals _e1: " + (e1 equals _e1) + ", _e1 equals e1: " + (_e1 equals e1)) + println() + + // Enumeration + val x7 = BigDecimal.RoundingMode + val y7: RoundingMode.type = read(write(x7)) + println("x7 = " + x7) + println("y7 = " + y7) + println("x7 eq y7: " + (x7 eq y7) + ", y7 eq x7: " + (y7 eq x7)) + println("x7 equals y7: " + (x7 equals y7) + ", y7 equals x7: " + (y7 equals x7)) + println() + + val x8 = WeekDay + val y8: WeekDay.type = read(write(x8)) + println("x8 = " + x8) + println("y8 = " + y8) + println("x8 eq y8: " + (x8 eq y8) + ", y8 eq x8: " + (y8 eq x8)) + println("x8 equals y8: " + (x8 equals y8) + ", y8 equals x8: " + (y8 equals x8)) + println() + + val x9 = UP + val y9: RoundingMode = read(write(x9)) + println("x9 = " + x9) + println("y9 = " + y9) + println("x9 eq y9: " + (x9 eq y9) + ", y9 eq x9: " + (y9 eq x9)) + println("x9 equals y9: " + (x9 equals y9) + ", y9 equals x9: " + (y9 equals x9)) + println() + + val x10 = Monday + val y10: WeekDay = read(write(x10)) + println("x10 = " + x10) + println("y10 = " + y10) + println("x10 eq y10: " + (x10 eq y10) + ", y10 eq x10: " + (y10 eq x10)) + println("x10 equals y10: " + (x10 equals y10) + ", y10 equals x10: " + (y10 equals x10)) + println() + + println("x9 eq x10: " + (x9 eq x10) + ", x10 eq x9: " + (x10 eq x9)) + println("x9 equals x10: " + (x9 equals x10) + ", x10 equals x9: " + (x10 equals x9)) + println("x9 eq y10: " + (x9 eq y10) + ", y10 eq x9: " + (y10 eq x9)) + println("x9 equals y10: " + (x9 equals y10) + ", y10 equals x9: " + (y10 equals x9)) + println() + + // Function + val f1 = { x: Int => 2 * x } + val _f1: Function[Int, Int] = read(write(f1)) + println("f1 = ") + println("_f1 = ") + println("f1(2): " + f1(2) + ", _f1(2): " + _f1(2)) + println() + + // List + val xs0 = List(1, 2, 3) + val _xs0: List[Int] = read(write(xs0)) + println("xs0 = " + xs0) + println("_xs0 = " + _xs0) + println("xs0 eq _xs0: " + (xs0 eq _xs0) + ", _xs0 eq xs0: " + (_xs0 eq xs0)) + println("xs0 equals _xs0: " + (xs0 equals _xs0) + ", _xs0 equals xs0: " + (_xs0 equals xs0)) + println() + + val xs1 = Nil + val _xs1: List[Nothing] = read(write(xs1)) + println("xs1 = " + xs1) + println("_xs1 = " + _xs1) + println("xs1 eq _xs1: " + (xs1 eq _xs1) + ", _xs1 eq xs1: " + (_xs1 eq xs1)) + println() + + // Option + val o1 = None + val _o1: Option[Nothing] = read(write(o1)) + println("o1 = " + o1) + println("_o1 = " + _o1) + println("o1 eq _o1: " + (o1 eq _o1) + ", _o1 eq o1: " + (_o1 eq o1)) + println() + + val o2 = Some(1) + val _o2: Option[Int] = read(write(o2)) + println("o2 = " + o2) + println("_o2 = " + _o2) + println("o2 eq _o2: " + (o2 eq _o2) + ", _o2 eq o2: " + (_o2 eq o2)) + println("o2 equals _o2: " + (o2 equals _o2) + ", _o2 equals o2: " + (_o2 equals o2)) + println() +/* + // Responder + val r1 = Responder.constant("xyz") + val _r1: Responder[String] = read(write(r1)) + check(r1, _r1) +*/ + // Symbol + val s1 = Symbol("hello") + val _s1: Symbol = read(write(s1)) + println("s1 = " + s1) + println("_s1 = " + _s1) + println("s1 eq _s1: " + (s1 eq _s1) + ", _s1 eq s1: " + (_s1 eq s1)) + println("s1 equals _s1: " + (s1 equals _s1) + ", _s1 equals s1: " + (_s1 equals s1)) + println() + + // Tuple + val t1 = ("BannerLimit", 12345) + val _t1: (String, Int) = read(write(t1)) + println("t1 = " + t1) + println("_t1 = " + _t1) + println("t1 eq _t1: " + (t1 eq _t1) + ", _t1 eq t1: " + (_t1 eq t1)) + println("t1 equals _t1: " + (t1 equals _t1) + ", _t1 equals t1: " + (_t1 equals t1)) + println() + } + catch { + case e: Exception => + println("Error in Test1_scala: " + e) + throw e + } +} + +//############################################################################ +// Test classes in package "scala.collection.immutable" + +object Test2_immutable { + import scala.collection.immutable.{ + BitSet, HashMap, HashSet, ListMap, ListSet, Queue, Range, SortedMap, + SortedSet, Stack, Stream, TreeMap, TreeSet, Vector} + + // in alphabetic order + try { + // BitSet + val bs1 = BitSet.empty + 1 + 2 + val _bs1: BitSet = read(write(bs1)) + check(bs1, _bs1) + + val bs2 = { + val bs = new collection.mutable.BitSet() + bs += 2; bs += 3 + bs.toImmutable + } + val _bs2: BitSet = read(write(bs2)) + check(bs2, _bs2) + + // HashMap + val hm1 = new HashMap[Int, String] + (1 -> "A", 2 -> "B", 3 -> "C") + val _hm1: HashMap[Int, String] = read(write(hm1)) + check(hm1, _hm1) + + // HashSet + val hs1 = new HashSet[Int] + 1 + 2 + val _hs1: HashSet[Int] = read(write(hs1)) + check(hs1, _hs1) + + // List + val xs1 = List(("buffers", 20), ("layers", 2), ("title", 3)) + val _xs1: List[(String, Int)] = read(write(xs1)) + check(xs1, _xs1) + + // ListMap + val lm1 = new ListMap[String, Int] + ("buffers" -> 20, "layers" -> 2, "title" -> 3) + val _lm1: ListMap[String, Int] = read(write(lm1)) + check(lm1, _lm1) + + // ListSet + val ls1 = new ListSet[Int] + 3 + 5 + val _ls1: ListSet[Int] = read(write(ls1)) + check(ls1, _ls1) + + // Queue + val q1 = Queue("a", "b", "c") + val _q1: Queue[String] = read(write(q1)) + check(q1, _q1) + + // Range + val r1 = 0 until 10 + val _r1: Range = read(write(r1)) + check(r1, _r1) + + val r2 = Range.Long(0L, 10L, 1) + val _r2: r2.type = read(write(r2)) + check(r2, _r2) + + // SortedMap + val sm1 = SortedMap.empty[Int, String] + (2 -> "B", 3 -> "C", 1 -> "A") + val _sm1: SortedMap[Int, String] = read(write(sm1)) + check(sm1, _sm1) + + // SortedSet + val ss1 = SortedSet.empty[Int] + 2 + 3 + 1 + val _ss1: SortedSet[Int] = read(write(ss1)) + check(ss1, _ss1) + + // Stack + val s1 = new Stack().push("a", "b", "c") + val _s1: Stack[String] = read(write(s1)) + check(s1, _s1) + + // Stream + val st1 = Stream.range(0, 10) + val _st1: Stream[Int] = read(write(st1)) + check(st1, _st1) + + // TreeMap + val tm1 = new TreeMap[Int, String] + (42 -> "FortyTwo") + val _tm1: TreeMap[Int, String] = read(write(tm1)) + check(tm1, _tm1) + + // TreeSet + val ts1 = new TreeSet[Int]() + 2 + 0 + val _ts1: TreeSet[Int] = read(write(ts1)) + check(ts1, _ts1) + + // Vector + val v1 = Vector(Symbol("a"), Symbol("b"), Symbol("c")) + val _v1: Vector[Symbol] = read(write(v1)) + check(v1, _v1) + } + catch { + case e: Exception => + println("Error in Test2_immutable: " + e) + throw e + } +} + +//############################################################################ +// Test classes in package "scala.collection.mutable" + +object Test3_mutable { + import scala.reflect.ClassTag + import scala.collection.mutable.{ + ArrayBuffer, ArrayBuilder, ArraySeq, ArrayStack, BitSet, DoubleLinkedList, + HashMap, HashSet, History, LinkedHashMap, LinkedHashSet, LinkedList, ListBuffer, + Publisher, Queue, Stack, StringBuilder, WrappedArray, TreeSet} + import scala.collection.concurrent.TrieMap + + // in alphabetic order + try { + // ArrayBuffer + val ab1 = new ArrayBuffer[String] + ab1 ++= List("one", "two") + val _ab1: ArrayBuffer[String] = read(write(ab1)) + check(ab1, _ab1) + + // ArrayBuilder + val abu1 = ArrayBuilder.make[Long] + val _abu1: ArrayBuilder[ClassTag[Long]] = read(write(abu1)) + check(abu1, _abu1) + + val abu2 = ArrayBuilder.make[Float] + val _abu2: ArrayBuilder[ClassTag[Float]] = read(write(abu2)) + check(abu2, _abu2) + + // ArraySeq + val aq1 = ArraySeq(1, 2, 3) + val _aq1: ArraySeq[Int] = read(write(aq1)) + check(aq1, _aq1) + + // ArrayStack + val as1 = new ArrayStack[Int] + as1 ++= List(20, 2, 3).iterator + val _as1: ArrayStack[Int] = read(write(as1)) + check(as1, _as1) + + // BitSet + val bs1 = new BitSet() + bs1 += 0 + bs1 += 8 + bs1 += 9 + val _bs1: BitSet = read(write(bs1)) + check(bs1, _bs1) +/* + // DoubleLinkedList + val dl1 = new DoubleLinkedList[Int](2, null) + dl1.append(new DoubleLinkedList(3, null)) + val _dl1: DoubleLinkedList[Int] = read(write(dl1)) + check(dl1, _dl1) +*/ + // HashMap + val hm1 = new HashMap[String, Int] + hm1 ++= List(("A", 1), ("B", 2), ("C", 3)).iterator + val _hm1: HashMap[String, Int] = read(write(hm1)) + check(hm1, _hm1) + + // HashSet + val hs1 = new HashSet[String] + hs1 ++= List("layers", "buffers", "title").iterator + val _hs1: HashSet[String] = read(write(hs1)) + check(hs1, _hs1) + + val h1 = new History[String, Int] + val _h1: History[String, Int] = read(write(h1)) + check(h1, _h1) + + // LinkedHashMap + { val lhm1 = new LinkedHashMap[String, Int] + val list = List(("Linked", 1), ("Hash", 2), ("Map", 3)) + lhm1 ++= list.iterator + val _lhm1: LinkedHashMap[String, Int] = read(write(lhm1)) + check(lhm1, _lhm1) + check(lhm1.toSeq, _lhm1.toSeq) // check elements order + check(lhm1.toSeq, list) // check elements order + } + + // LinkedHashSet + { val lhs1 = new LinkedHashSet[String] + val list = List("layers", "buffers", "title") + lhs1 ++= list.iterator + val _lhs1: LinkedHashSet[String] = read(write(lhs1)) + check(lhs1, _lhs1) + check(lhs1.toSeq, _lhs1.toSeq) // check elements order + check(lhs1.toSeq, list) // check elements order + } +/* + // LinkedList + val ll1 = new LinkedList[Int](2, null) + ll1.append(new LinkedList(3, null)) + val _ll1: LinkedList[Int] = read(write(ll1)) + check(ll1, _ll1) +*/ + // ListBuffer + val lb1 = new ListBuffer[String] + lb1 ++= List("white", "black") + val _lb1: ListBuffer[String] = read(write(lb1)) + check(lb1, _lb1) + + // Queue + val q1 = new Queue[Int] + q1 ++= List(20, 2, 3).iterator + val _q1: Queue[Int] = read(write(q1)) + check(q1, _q1) + + // Stack + val s1 = new Stack[Int] + s1 pushAll q1 + val _s1: Stack[Int] = read(write(s1)) + check(s1, _s1) + + // StringBuilder + val sb1 = new StringBuilder + sb1 append "abc" + val _sb1: StringBuilder = read(write(sb1)) + check(sb1, _sb1) + + // WrappedArray + val wa1 = WrappedArray.make(Array(1, 2, 3)) + val _wa1: WrappedArray[Int] = read(write(wa1)) + check(wa1, _wa1) + + // TreeSet + val ts1 = TreeSet[Int]() ++= Array(1, 2, 3) + val _ts1: TreeSet[Int] = read(write(ts1)) + check(ts1, _ts1) + + // concurrent.TrieMap + val ct1 = TrieMap[Int, String]() ++= Array(1 -> "one", 2 -> "two", 3 -> "three") + val _ct1: TrieMap[Int, String] = read(write(ct1)) + check(ct1, _ct1) + } + catch { + case e: Exception => + println("Error in Test3_mutable: " + e) + throw e + } +} + +//############################################################################ +// Test user-defined classes WITHOUT nesting + +class Person(_name: String) extends Serializable { + private var name = _name + override def toString() = name + override def equals(that: Any): Boolean = + that.isInstanceOf[Person] && + (name == that.asInstanceOf[Person].name) +} + +class Employee(_name: String) extends Serializable { + private var name = _name + override def toString() = name +} + +object bob extends Employee("Bob") + +object Test5 { + val x1 = new Person("Tim") + val x2 = bob + + try { + val y1: Person = read(write(x1)) + val y2: Employee = read(write(x2)) + + check(x1, y1) + check(x2, y2) + } + catch { + case e: Exception => + println("Error in Test5: " + e) + } +} + +//############################################################################ +// Test user-defined classes WITH nesting + +object Test6 { + object bill extends Employee("Bill") { + val x = paul + } + object paul extends Person("Paul") { + val x = 4 // bill; => StackOverflowException !!! + } + val x1 = new Person("John") + val x2 = bill + val x3 = paul + + try { + val y1: Person = read(write(x1)) + val y2: Employee = read(write(x2)) + val y3: Person = read(write(x3)) + + check(x1, y1) + check(x2, y2) + check(x3, y3) + } + catch { + case e: Exception => + println("Error in Test6: " + e) + } +} + +//############################################################################ +// Nested objects cannot get readresolve automatically because after deserialization +// they would be null (they are treated as lazy vals) +class Outer extends Serializable { + object Inner extends Serializable +} + +object Test7 { + val x = new Outer + val _ = x.Inner // initialize + val y:Outer = read(write(x)) + if (y.Inner == null) + println("Inner object is null") +} + +// Verify that transient lazy vals don't get serialized +class WithTransient extends Serializable { + @transient lazy val a1 = 1 + @transient private lazy val a2 = 2 + @transient object B extends Serializable + @transient private object C extends Serializable + + def test = { + println(a1) + println(a2) + if (B == null || C == null) + println("Transient nested object failed to serialize properly") + } +} + +object Test8 { + val x = new WithTransient + x.test + try { + val y:WithTransient = read(write(x)) + y.test + } + catch { + case e: Exception => + println("Error in Test8: " + e) + } +} + +//############################################################################ +// Test code + +object Test { + def main(args: Array[String]): Unit = { + Test1_scala + Test2_immutable + Test3_mutable + Test5 + Test6 + Test7 + Test8 + Test9_parallel + Test10_util + } +} + +//############################################################################ + + +//############################################################################ +// Test classes in package "scala.collection.parallel" and subpackages +object Test9_parallel { + import scala.collection.parallel._ + + try { + println() + + // UnrolledBuffer + val ub = new collection.mutable.UnrolledBuffer[String] + ub ++= List("one", "two") + val _ub: collection.mutable.UnrolledBuffer[String] = read(write(ub)) + check(ub, _ub) + + // mutable.ParArray + val pa = mutable.ParArray("abc", "def", "etc") + val _pa: mutable.ParArray[String] = read(write(pa)) + check(pa, _pa) + + // mutable.ParHashMap + val mpm = mutable.ParHashMap(1 -> 2, 2 -> 4) + val _mpm: mutable.ParHashMap[Int, Int] = read(write(mpm)) + check(mpm, _mpm) + + // mutable.ParTrieMap + val mpc = mutable.ParTrieMap(1 -> 2, 2 -> 4) + val _mpc: mutable.ParTrieMap[Int, Int] = read(write(mpc)) + check(mpc, _mpc) + + // mutable.ParHashSet + val mps = mutable.ParHashSet(1, 2, 3) + val _mps: mutable.ParHashSet[Int] = read(write(mps)) + check(mps, _mps) + + // immutable.ParRange + val pr1 = immutable.ParRange(0, 4, 1, true) + val _pr1: immutable.ParRange = read(write(pr1)) + check(pr1, _pr1) + + val pr2 = immutable.ParRange(0, 4, 1, false) + val _pr2: immutable.ParRange = read(write(pr2)) + check(pr2, _pr2) + + // immutable.ParHashMap + val ipm = immutable.ParHashMap(5 -> 1, 10 -> 2) + val _ipm: immutable.ParHashMap[Int, Int] = read(write(ipm)) + check(ipm, _ipm) + + // immutable.ParHashSet + val ips = immutable.ParHashSet("one", "two") + val _ips: immutable.ParHashSet[String] = read(write(ips)) + check(ips, _ips) + + } catch { + case e: Exception => + println("Error in Test5_parallel: " + e) + throw e + } +} + +//############################################################################ +// Test classes in package scala.util + +object Test10_util { + import scala.util.Random + def rep[A](n: Int)(f: => A): Unit = { if (n > 0) { f; rep(n-1)(f) } } + + { + val random = new Random(345) + val random2: Random = read(write(random)) + rep(5) { assert(random.nextInt == random2.nextInt) } + } +} + diff --git a/tests/run/t10232.scala b/tests/run/t10232.scala new file mode 100644 index 000000000000..3b3a8e7fad26 --- /dev/null +++ b/tests/run/t10232.scala @@ -0,0 +1,275 @@ +import java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream} + +object Test { + val lambdas: List[Any => String] = List( + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" }, + { (t: Any) => "ab" } + ) + + def main(args: Array[String]): Unit = { + for (lambda <- lambdas) { + val outStream = new ByteArrayOutputStream + val oo = new ObjectOutputStream(outStream) + oo.writeObject(lambda) + + val inStream = new ByteArrayInputStream(outStream.toByteArray) + val oi = new ObjectInputStream(inStream) + val lambda2 = oi.readObject().asInstanceOf[Any => String] + assert(lambda2(1) == "ab") + } + } +} diff --git a/tests/run/t6260-delambdafy.check b/tests/run/t6260-delambdafy.check index b3ec1b3cc667..ed107b4c8132 100644 --- a/tests/run/t6260-delambdafy.check +++ b/tests/run/t6260-delambdafy.check @@ -2,3 +2,4 @@ f(C@2e) apply get$Lambda +writeReplace diff --git a/tests/run/tasty-extractors-2.check b/tests/run/tasty-extractors-2.check index d566b57c87dc..68b0372d7d9e 100644 --- a/tests/run/tasty-extractors-2.check +++ b/tests/run/tasty-extractors-2.check @@ -25,7 +25,7 @@ Type.OrType(Type.SymRef(IsClassSymbol(), Type.SymRef(IsPackageSymbol( Term.Inlined(None, Nil, Term.Block(List(ClassDef("Foo", DefDef("", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil)), Nil, None, Nil)), Term.Literal(Constant.Unit()))) Type.SymRef(IsClassSymbol(), Type.ThisType(Type.SymRef(IsPackageSymbol(), NoPrefix()))) -Term.Inlined(None, Nil, Term.Block(List(ValDef("Foo", TypeTree.Ident("Foo$"), Some(Term.Apply(Term.Select(Term.New(TypeTree.Ident("Foo$")), ""), Nil))), ClassDef("Foo$", DefDef("", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil)), Nil, Some(ValDef("_", TypeTree.Singleton(Term.Ident("Foo")), None)), Nil)), Term.Literal(Constant.Unit()))) +Term.Inlined(None, Nil, Term.Block(List(ValDef("Foo", TypeTree.Ident("Foo$"), Some(Term.Apply(Term.Select(Term.New(TypeTree.Ident("Foo$")), ""), Nil))), ClassDef("Foo$", DefDef("", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil), TypeTree.Select(Term.Select(Term.Ident("_root_"), "scala"), "Serializable")), Nil, Some(ValDef("_", TypeTree.Singleton(Term.Ident("Foo")), None)), Nil)), Term.Literal(Constant.Unit()))) Type.SymRef(IsClassSymbol(), Type.ThisType(Type.SymRef(IsPackageSymbol(), NoPrefix()))) Term.Inlined(None, Nil, Term.Block(List(TypeDef("Foo", TypeBoundsTree(TypeTree.Inferred(), TypeTree.Inferred()))), Term.Literal(Constant.Unit()))) @@ -49,7 +49,7 @@ Type.SymRef(IsClassSymbol(), Type.ThisType(Type.SymRef(IsPackageSymb Term.Inlined(None, Nil, Term.Block(List(ClassDef("Foo", DefDef("", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil)), Nil, None, List(DefDef("a", Nil, Nil, TypeTree.Inferred(), Some(Term.Literal(Constant.Int(0))))))), Term.Literal(Constant.Unit()))) Type.SymRef(IsClassSymbol(), Type.ThisType(Type.SymRef(IsPackageSymbol(), NoPrefix()))) -Term.Inlined(None, Nil, Term.Block(List(ClassDef("Foo", DefDef("", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil), TypeTree.Select(Term.Select(Term.Ident("_root_"), "scala"), "Product"), TypeTree.Select(Term.Select(Term.Ident("_root_"), "scala"), "Serializable")), Nil, None, List(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()), ""), List(Term.Apply(Term.Select(Term.Ident("n"), "toString"), Nil)))))))))), 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")), ""), 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()), ""), Nil))))), ValDef("Foo", TypeTree.Ident("Foo$"), Some(Term.Apply(Term.Select(Term.New(TypeTree.Ident("Foo$")), ""), Nil))), ClassDef("Foo$", DefDef("", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), 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()), ""), Nil))), DefDef("unapply", Nil, List(List(ValDef("x$1", TypeTree.Inferred(), None))), TypeTree.Inferred(), Some(Term.Literal(Constant.Boolean(true))))))), Term.Literal(Constant.Unit()))) +Term.Inlined(None, Nil, Term.Block(List(ClassDef("Foo", DefDef("", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil), TypeTree.Select(Term.Select(Term.Ident("_root_"), "scala"), "Product"), TypeTree.Select(Term.Select(Term.Ident("_root_"), "scala"), "Serializable")), Nil, None, List(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()), ""), List(Term.Apply(Term.Select(Term.Ident("n"), "toString"), Nil)))))))))), 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")), ""), 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()), ""), Nil))))), ValDef("Foo", TypeTree.Ident("Foo$"), Some(Term.Apply(Term.Select(Term.New(TypeTree.Ident("Foo$")), ""), Nil))), ClassDef("Foo$", DefDef("", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil), TypeTree.Applied(TypeTree.Inferred(), List(TypeTree.Inferred())), TypeTree.Select(Term.Select(Term.Ident("_root_"), "scala"), "Serializable")), 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()), ""), Nil))), DefDef("unapply", Nil, List(List(ValDef("x$1", TypeTree.Inferred(), None))), TypeTree.Inferred(), Some(Term.Literal(Constant.Boolean(true))))))), Term.Literal(Constant.Unit()))) Type.SymRef(IsClassSymbol(), Type.ThisType(Type.SymRef(IsPackageSymbol(), NoPrefix()))) Term.Inlined(None, Nil, Term.Block(List(ClassDef("Foo1", DefDef("", Nil, List(List(ValDef("a", TypeTree.Ident("Int"), None))), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil)), Nil, None, List(ValDef("a", TypeTree.Inferred(), None)))), Term.Literal(Constant.Unit()))) @@ -58,13 +58,13 @@ Type.SymRef(IsClassSymbol(), Type.ThisType(Type.SymRef(IsPackageSymb Term.Inlined(None, Nil, Term.Block(List(ClassDef("Foo2", DefDef("", Nil, List(List(ValDef("b", TypeTree.Ident("Int"), None))), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil)), Nil, None, List(ValDef("b", TypeTree.Inferred(), None)))), Term.Literal(Constant.Unit()))) Type.SymRef(IsClassSymbol(), Type.ThisType(Type.SymRef(IsPackageSymbol(), NoPrefix()))) -Term.Inlined(None, Nil, Term.Block(List(ClassDef("Foo3", DefDef("", Nil, List(List(ValDef("a", TypeTree.Ident("Int"), None))), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil)), Nil, None, List(ValDef("a", TypeTree.Inferred(), None))), ValDef("Foo3", TypeTree.Ident("Foo3$"), Some(Term.Apply(Term.Select(Term.New(TypeTree.Ident("Foo3$")), ""), Nil))), ClassDef("Foo3$", DefDef("", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil)), Nil, Some(ValDef("_", TypeTree.Singleton(Term.Ident("Foo3")), None)), List(DefDef("$lessinit$greater$default$1", Nil, Nil, TypeTree.Inferred(), Some(Term.Literal(Constant.Int(5))))))), Term.Literal(Constant.Unit()))) +Term.Inlined(None, Nil, Term.Block(List(ClassDef("Foo3", DefDef("", Nil, List(List(ValDef("a", TypeTree.Ident("Int"), None))), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil)), Nil, None, List(ValDef("a", TypeTree.Inferred(), None))), ValDef("Foo3", TypeTree.Ident("Foo3$"), Some(Term.Apply(Term.Select(Term.New(TypeTree.Ident("Foo3$")), ""), Nil))), ClassDef("Foo3$", DefDef("", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil), TypeTree.Select(Term.Select(Term.Ident("_root_"), "scala"), "Serializable")), Nil, Some(ValDef("_", TypeTree.Singleton(Term.Ident("Foo3")), None)), List(DefDef("$lessinit$greater$default$1", Nil, Nil, TypeTree.Inferred(), Some(Term.Literal(Constant.Int(5))))))), Term.Literal(Constant.Unit()))) Type.SymRef(IsClassSymbol(), Type.ThisType(Type.SymRef(IsPackageSymbol(), NoPrefix()))) Term.Inlined(None, Nil, Term.Block(List(ClassDef("Foo4", DefDef("", Nil, List(List(ValDef("a", TypeTree.Ident("Int"), None)), List(ValDef("b", TypeTree.Ident("Int"), None))), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil)), Nil, None, List(ValDef("a", TypeTree.Inferred(), None), ValDef("b", TypeTree.Inferred(), None)))), Term.Literal(Constant.Unit()))) Type.SymRef(IsClassSymbol(), Type.ThisType(Type.SymRef(IsPackageSymbol(), NoPrefix()))) -Term.Inlined(None, Nil, Term.Block(List(ClassDef("Foo5", DefDef("", Nil, List(List(ValDef("a", TypeTree.Ident("Int"), None)), List(ValDef("b", TypeTree.Ident("Int"), None))), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil)), Nil, None, List(ValDef("a", TypeTree.Inferred(), None), ValDef("b", TypeTree.Inferred(), None))), ValDef("Foo5", TypeTree.Ident("Foo5$"), Some(Term.Apply(Term.Select(Term.New(TypeTree.Ident("Foo5$")), ""), Nil))), ClassDef("Foo5$", DefDef("", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil)), Nil, Some(ValDef("_", TypeTree.Singleton(Term.Ident("Foo5")), None)), List(DefDef("$lessinit$greater$default$2", Nil, List(List(ValDef("a", TypeTree.Ident("Int"), None))), TypeTree.Inferred(), Some(Term.Ident("a")))))), Term.Literal(Constant.Unit()))) +Term.Inlined(None, Nil, Term.Block(List(ClassDef("Foo5", DefDef("", Nil, List(List(ValDef("a", TypeTree.Ident("Int"), None)), List(ValDef("b", TypeTree.Ident("Int"), None))), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil)), Nil, None, List(ValDef("a", TypeTree.Inferred(), None), ValDef("b", TypeTree.Inferred(), None))), ValDef("Foo5", TypeTree.Ident("Foo5$"), Some(Term.Apply(Term.Select(Term.New(TypeTree.Ident("Foo5$")), ""), Nil))), ClassDef("Foo5$", DefDef("", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil), TypeTree.Select(Term.Select(Term.Ident("_root_"), "scala"), "Serializable")), Nil, Some(ValDef("_", TypeTree.Singleton(Term.Ident("Foo5")), None)), List(DefDef("$lessinit$greater$default$2", Nil, List(List(ValDef("a", TypeTree.Ident("Int"), None))), TypeTree.Inferred(), Some(Term.Ident("a")))))), Term.Literal(Constant.Unit()))) Type.SymRef(IsClassSymbol(), Type.ThisType(Type.SymRef(IsPackageSymbol(), NoPrefix()))) Term.Inlined(None, Nil, Term.Block(List(ClassDef("Foo6", DefDef("", Nil, List(List(ValDef("a", TypeTree.Ident("Int"), None)), List(ValDef("b", TypeTree.Singleton(Term.Ident("a")), None))), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil)), Nil, None, List(ValDef("a", TypeTree.Inferred(), None), ValDef("b", TypeTree.Inferred(), None)))), Term.Literal(Constant.Unit())))