diff options
author | Lukas Rytz <lukas.rytz@epfl.ch> | 2010-11-30 15:38:56 +0000 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@epfl.ch> | 2010-11-30 15:38:56 +0000 |
commit | 4be5e11cccace4974ed9a449052455392570139f (patch) | |
tree | 88c86bc65b88df08b48584ed791acd1619983c0c /src/compiler | |
parent | 402d96dd3fab6ae677966a9a258c00b3f34a37ed (diff) | |
download | scala-4be5e11cccace4974ed9a449052455392570139f.tar.gz scala-4be5e11cccace4974ed9a449052455392570139f.tar.bz2 scala-4be5e11cccace4974ed9a449052455392570139f.zip |
Deprecated the @serializable annotation, introd...
Deprecated the @serializable annotation, introduce a new trait
"scala.Serializable" which has to be extended instead (cross-platform).
Known issues:
- Companion objects of serializable classes (including case classes) are automatically made serializable. However, they don't extend "Serializable" statically because of the known difficulty (should be done before typing, but hard).
- Writing "case class C() extends Serializable" gives "error: trait Serializable is inherited twice"
- Functions are serializable, but don't extend Serializable dynamically (could be fixed by making FunctionN Serializable - shouldn't we?)
Note that @SerialVersionUID continues to be an annotation; it generates
a static field, which is not possible otherwise in scala.
Review by dragos, extempore.
Question to dragos: in JavaPlatform.isMaybeBoxed, why is there a test
for "JavaSerializableClass"? Is that correct?
Diffstat (limited to 'src/compiler')
12 files changed, 48 insertions, 41 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index 2acfa20c50..1ac2c3442a 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -26,6 +26,7 @@ abstract class TreeGen { def scalaUnitConstr = scalaDot(nme.Unit.toTypeName) def scalaScalaObjectConstr = scalaDot(nme.ScalaObject.toTypeName) def productConstr = scalaDot(nme.Product.toTypeName) + def serializableConstr = scalaDot(nme.Serializable.toTypeName) private def isRootOrEmptyPackageClass(s: Symbol) = s.isRoot || s.isEmptyPackageClass diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 751c7b5d13..09f1db7249 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2498,7 +2498,7 @@ self => parents = parents ::: List(scalaScalaObjectConstr) if (parents.isEmpty) parents = List(scalaAnyRefConstr) - if (mods.isCase) parents = parents ::: List(productConstr) + if (mods.isCase) parents = parents ::: List(productConstr, serializableConstr) val tstart0 = if (body.isEmpty && in.lastOffset < tstart) in.lastOffset else tstart atPos(tstart0) { Template(parents, self, constrMods, vparamss, argss, body, o2p(tstart)) diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 7a3321f6eb..de5f342a7d 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -29,6 +29,7 @@ abstract class TreeBuilder { def scalaUnitConstr = gen.scalaUnitConstr def scalaScalaObjectConstr = gen.scalaScalaObjectConstr def productConstr = gen.productConstr + def serializableConstr = gen.serializableConstr /** Convert all occurrences of (lower-case) variables in a pattern as follows: * x becomes x @ _ diff --git a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala index ec367b61bb..8d77eef488 100644 --- a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala +++ b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala @@ -36,7 +36,7 @@ trait JavaPlatform extends Platform[AbstractFile] { def isMaybeBoxed(sym: Symbol): Boolean = { import definitions._ (sym == ObjectClass) || - (sym == SerializableClass) || + (sym == JavaSerializableClass) || (sym == ComparableClass) || (sym isNonBottomSubClass BoxedNumberClass) || (sym isNonBottomSubClass BoxedCharacterClass) diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index a468e81b3e..5a4fa51899 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -169,11 +169,12 @@ trait Definitions extends reflect.generic.StandardDefinitions { def scalaRuntimeSameElements = getMember(ScalaRunTimeModule, nme.sameElements) // classes with special meanings - lazy val NotNullClass = getClass("scala.NotNull") - lazy val TypeConstraintClass = getClass("scala.TypeConstraint") - lazy val SingletonClass = newClass(ScalaPackageClass, nme.Singleton, anyparam) setFlag (ABSTRACT | TRAIT | FINAL) - lazy val SerializableClass = getClass(sn.Serializable) - lazy val ComparableClass = getClass("java.lang.Comparable") + lazy val NotNullClass = getClass("scala.NotNull") + lazy val TypeConstraintClass = getClass("scala.TypeConstraint") + lazy val SingletonClass = newClass(ScalaPackageClass, nme.Singleton, anyparam) setFlag (ABSTRACT | TRAIT | FINAL) + lazy val SerializableClass = getClass("scala.Serializable") + lazy val JavaSerializableClass = getClass(sn.JavaSerializable) + lazy val ComparableClass = getClass("java.lang.Comparable") lazy val RepeatedParamClass = newCovariantPolyClass( ScalaPackageClass, @@ -486,7 +487,7 @@ trait Definitions extends reflect.generic.StandardDefinitions { lazy val ScalaNumberClass: Symbol = getClass("scala.math.ScalaNumber") lazy val ScalaStrictFPAttr: Symbol = getClass("scala.annotation.strictfp") lazy val SerialVersionUIDAttr: Symbol = getClass("scala.SerialVersionUID") - lazy val SerializableAttr: Symbol = getClass("scala.serializable") + lazy val SerializableAttr: Symbol = getClass("scala.annotation.serializable") // @serializable is deprecated lazy val TraitSetterAnnotationClass: Symbol = getClass("scala.runtime.TraitSetter") lazy val TransientAttr: Symbol = getClass("scala.transient") lazy val VolatileAttr: Symbol = getClass("scala.volatile") diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index 11773dae4c..64dc254f28 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -197,6 +197,7 @@ trait StdNames extends reflect.generic.StdNames with NameManglers { val ScalaObject = newTermName("ScalaObject") val ScalaRunTime = newTermName("ScalaRunTime") val Seq = newTermName("Seq") + val Serializable = newTermName("Serializable") val Short = newTermName("Short") val Singleton = newTermName("Singleton") val Some = newTermName("Some") @@ -379,7 +380,7 @@ trait StdNames extends reflect.generic.StdNames with NameManglers { val NLRControl : Name = newTermName("scala.runtime.NonLocalReturnControl") val NPException : Name // NullPointerException val Object : Name - val Serializable : Name + val JavaSerializable : Name val String : Name val Throwable : Name val ValueType : Name @@ -446,7 +447,7 @@ trait StdNames extends reflect.generic.StdNames with NameManglers { final val MethodAsObject = newTermName("System.Reflection.MethodInfo") final val NPException = newTermName("System.NullReferenceException") final val Object = newTermName("System.Object") - final val Serializable = nme.NOSYMBOL + final val JavaSerializable = nme.NOSYMBOL final val String = newTermName("System.String") final val Throwable = newTermName("System.Exception") final val ValueType = newTermName("System.ValueType") @@ -467,7 +468,7 @@ trait StdNames extends reflect.generic.StdNames with NameManglers { final val BeanProperty = newTermName("scala.reflect.BeanProperty") final val BooleanBeanProperty = newTermName("scala.reflect.BooleanBeanProperty") final val Code = newTermName("scala.reflect.Code") - final val Serializable = newTermName("java.io.Serializable") + final val JavaSerializable = newTermName("java.io.Serializable") } lazy val sn: SymbolNames = diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index 8aa9c716c9..824d047d6b 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -80,9 +80,6 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable => annots1 } - def setSerializable(): Unit = - addAnnotation(AnnotationInfo(SerializableAttr.tpe, Nil, Nil)) - def setAnnotations(annots: List[AnnotationInfoBase]): this.type = { this.rawannots = annots this @@ -402,7 +399,7 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable => } def isStrictFP = hasAnnotation(ScalaStrictFPAttr) || (enclClass hasAnnotation ScalaStrictFPAttr) - def isSerializable = hasAnnotation(SerializableAttr) + def isSerializable = info.baseClasses.exists(p => p == SerializableClass || p == JavaSerializableClass) || hasAnnotation(SerializableAttr) // last part can be removed, @serializable annotation is deprecated def isDeprecated = hasAnnotation(DeprecatedAttr) def deprecationMessage = getAnnotation(DeprecatedAttr) flatMap { _.stringArg(0) } // !!! when annotation arguments are not literal strings, but any sort of @@ -955,6 +952,19 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable => setInfo(completer) } + /** + * Adds the interface scala.Serializable to the parents of a ClassInfoType. + * Note that the tree also has to be updated accordingly. + */ + def makeSerializable() { + info match { + case ci @ ClassInfoType(_, _, _) => + updateInfo(ci.copy(parents = ci.parents ::: List(SerializableClass.tpe))) + case i => + abort("Only ClassInfoTypes can be made serializable: "+ i) + } + } + // Comparisons ---------------------------------------------------------------- /** A total ordering between symbols that refines the class diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index f8f185e6d8..943960c3f7 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -561,19 +561,6 @@ abstract class CleanUp extends Transform with ast.TreeDSL { typedWithPos(theTry.pos)(BLOCK(VAL(tempVar) === EmptyTree, newTry, Ident(tempVar))) - /* Adds @serializable annotation to anonymous function classes */ - case cdef @ ClassDef(mods, name, tparams, impl) => - /** XXX This check is overly specific and bound to break if it hasn't already. */ - if (settings.target.value == "jvm-1.5") { - val sym = cdef.symbol - // is this an anonymous function class? - if (sym.isAnonymousFunction && !sym.isSerializable) { - sym.setSerializable() - sym addAnnotation serialVersionUIDAnnotation - } - } - super.transform(tree) - /* * This transformation should identify Scala symbol invocations in the tree and replace them * with references to a static member. Also, whenever a class has at least a single symbol invocation diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index ed4808ebbd..34015ef092 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -346,7 +346,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ def specializeClass(clazz: Symbol, outerEnv: TypeEnv): List[Symbol] = { def specializedClass(env: TypeEnv, normMembers: List[Symbol]): Symbol = { - val cls = clazz.owner.newClass(clazz.pos, specializedName(clazz, env)) + val cls = clazz.owner.newClass(clazz.pos, specializedName(clazz, env).toTypeName) .setFlag(SPECIALIZED | clazz.flags) .resetFlag(CASE) cls.sourceFile = clazz.sourceFile @@ -545,7 +545,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } else if (m.isClass) { val specClass: Symbol = m.cloneSymbol(cls).setFlag(SPECIALIZED) typeEnv(specClass) = fullEnv - specClass.name = specializedName(specClass, fullEnv) + specClass.name = specializedName(specClass, fullEnv).toTypeName enterMember(specClass) log("entered specialized class " + specClass.fullName) info(specClass) = SpecializedInnerClass(m, fullEnv) @@ -581,6 +581,14 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val spc = specializedClass(env, decls1) log("entered " + spc + " in " + clazz.owner) hasSubclasses = true + val existing = clazz.owner.info.decl(spc.name) + // a symbol for the specialized class already exists if there's a classfile for it. + // keeping both crashes the compiler on test/files/pos/spec-Function1.scala + if (existing != NoSymbol) { + log("removing existing symbol for "+ existing) + clazz.owner.info.decls.unlink(existing) + } + atPhase(phase.next)(clazz.owner.info.decls enter spc) //!! assumes fully specialized classes } if (hasSubclasses) clazz.resetFlag(FINAL) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index ddc14cd95b..0d87ba1203 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -327,8 +327,8 @@ abstract class UnCurry extends InfoTransform with TypingTransformers with ast.Tr val (formals, restpe) = (targs.init, targs.last) val anonClass = owner newAnonymousFunctionClass fun.pos setFlag (FINAL | SYNTHETIC | inConstructorFlag) def parents = - if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe)) - else List(ObjectClass.tpe, fun.tpe) + if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe) + else List(ObjectClass.tpe, fun.tpe, SerializableClass.tpe) anonClass setInfo ClassInfoType(parents, new Scope, anonClass) val applyMethod = anonClass.newMethod(fun.pos, nme.apply) setFlag FINAL diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index d4cb11b122..1c8414671c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -243,8 +243,6 @@ trait SyntheticMethods extends ast.TreeDSL { if (!phase.erasedTypes) try { if (clazz.isCase) { val isTop = clazz.ancestors forall (x => !x.isCase) - // case classes are automatically marked serializable - clazz.setSerializable() if (isTop) { // If this case class has fields with less than public visibility, their getter at this @@ -295,12 +293,6 @@ trait SyntheticMethods extends ast.TreeDSL { } if (clazz.isModuleClass) { - if (!clazz.isSerializable) { - val comp = companionClassOf(clazz, context) - if (comp.isCase || comp.isSerializable) - clazz.setSerializable() - } - def hasReadResolve = { val sym = clazz.info member nme.readResolve // any member, including private sym.isTerm && !sym.isDeferred diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 33db7424bc..03c5d2958c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1337,10 +1337,16 @@ trait Typers { self: Analyzer => for (c <- linkedClass.info.decl(nme.CONSTRUCTOR).alternatives) c.initialize val clazz = mdef.symbol.moduleClass + val maybeAddSerializable = (l: List[Tree]) => + if(linkedClass == NoSymbol || !linkedClass.isSerializable || clazz.isSerializable) l + else { + clazz.makeSerializable() + l ::: List(TypeTree(SerializableClass.tpe)) + } val typedMods = removeAnnotations(mdef.mods) assert(clazz != NoSymbol) val impl1 = newTyper(context.make(mdef.impl, clazz, new Scope)) - .typedTemplate(mdef.impl, parentTypes(mdef.impl)) + .typedTemplate(mdef.impl, maybeAddSerializable(parentTypes(mdef.impl))) val impl2 = typerAddSyntheticMethods(impl1, clazz, context) if (mdef.name == nme.PACKAGEkw) |