summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala136
1 files changed, 74 insertions, 62 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 89b6eb9759..95fb104f5f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -124,7 +124,6 @@ trait SyntheticMethods extends ast.TreeDSL {
m setInfo infoFn(m)
finishMethod(m, f)
}
-
private def cloneInternal(original: Symbol, f: Symbol => Tree, name: Name): Tree = {
val m = original.cloneSymbol(clazz) setPos clazz.pos.focus
m.name = name
@@ -199,8 +198,15 @@ trait SyntheticMethods extends ast.TreeDSL {
)
import synthesizer._
- def accessors = clazz.caseFieldAccessors
- def arity = accessors.size
+ val originalAccessors = clazz.caseFieldAccessors
+ // private ones will have been renamed -- make sure they are entered
+ // in the original order.
+ def accessors = clazz.caseFieldAccessors sortBy { acc =>
+ originalAccessors indexWhere { orig =>
+ (acc.name == orig.name) || (acc.name startsWith (orig.name + "$").toTermName)
+ }
+ }
+ val arity = accessors.size
// If this is ProductN[T1, T2, ...], accessorLub is the lub of T1, T2, ..., .
// !!! Hidden behind -Xexperimental due to bummer type inference bugs.
// Refining from Iterator[Any] leads to types like
@@ -299,28 +305,6 @@ trait SyntheticMethods extends ast.TreeDSL {
argsBody
}
- def newAccessorMethod(ddef: DefDef): Tree = {
- deriveMethod(ddef.symbol, name => context.unit.freshTermName(name + "$")) { newAcc =>
- makeMethodPublic(newAcc)
- newAcc resetFlag (ACCESSOR | PARAMACCESSOR)
- ddef.rhs.duplicate
- }
- }
-
- // A buffer collecting additional methods for the template body
- val ts = new ListBuffer[Tree]
-
- def makeAccessorsPublic() {
- // If this case class has fields with less than public visibility, their getter at this
- // point also has those permissions. In that case we create a new, public accessor method
- // with a new name and remove the CASEACCESSOR flag from the existing getter. This complicates
- // the retrieval of the case field accessors (see def caseFieldAccessors in Symbols.)
- def needsService(s: Symbol) = s.isMethod && s.isCaseAccessor && !s.isPublic
- for (ddef @ DefDef(_, _, _, _, _, _) <- templ.body; if needsService(ddef.symbol)) {
- ts += newAccessorMethod(ddef)
- ddef.symbol resetFlag CASEACCESSOR
- }
- }
/** The _1, _2, etc. methods to implement ProductN.
*/
def productNMethods = {
@@ -355,48 +339,76 @@ trait SyntheticMethods extends ast.TreeDSL {
// Object_equals -> (() => createMethod(Object_equals)(m => This(clazz) ANY_EQ methodArg(m, 0)))
)
- def addReadResolve() {
- /** If you serialize a singleton and then deserialize it twice,
- * you will have two instances of your singleton, unless you implement
- * the readResolve() method (see http://www.javaworld.com/javaworld/
- * jw-04-2003/jw-0425-designpatterns_p.html)
- */
- if (clazz.isSerializable && !hasConcreteImpl(nme.readResolve)) {
- // Aha, I finally decoded the original comment.
- // This method should be generated as private, but apparently if it is, then
- // it is name mangled afterward. (Wonder why that is.) So it's only protected.
- // For sure special methods like "readResolve" should not be mangled.
- ts += createMethod(nme.readResolve, Nil, ObjectClass.tpe) { m =>
- m setFlag PRIVATE
- REF(clazz.sourceModule)
- }
- }
- }
+ /** If you serialize a singleton and then deserialize it twice,
+ * you will have two instances of your singleton, unless you implement
+ * the readResolve() method (see http://www.javaworld.com/javaworld/
+ * jw-04-2003/jw-0425-designpatterns_p.html)
+ */
- def synthesize() = {
- if (clazz.isCase) {
- makeAccessorsPublic()
- val methods = if (clazz.isModuleClass) caseObjectMethods else caseClassMethods
+ // Only nested objects inside objects should get readResolve automatically.
+ // Otherwise, after de-serialization we get null references for lazy accessors
+ // (nested object -> lazy val + class def) since the bitmap gets serialized but
+ // the moduleVar not.
+ def needsReadResolve = (
+ clazz.isModuleClass
+ && clazz.owner.isModuleClass
+ && clazz.isSerializable
+ && !hasConcreteImpl(nme.readResolve)
+ )
- for ((m, impl) <- methods ; if !hasOverridingImplementation(m))
- ts += impl()
- }
- // Only nested objects inside objects should get readResolve automatically.
- // Otherwise, after de-serialization we get null references for lazy accessors
- // (nested object -> lazy val + class def) since the bitmap gets serialized but
- // the moduleVar not.
- if (clazz.isModuleClass && clazz.owner.isModuleClass)
- addReadResolve()
+ def synthesize(): List[Tree] = {
+ val methods = (
+ if (!clazz.isCase) Nil
+ else if (clazz.isModuleClass) caseObjectMethods
+ else caseClassMethods
+ )
+ def impls = for ((m, impl) <- methods ; if !hasOverridingImplementation(m)) yield impl()
+ def extras = (
+ if (needsReadResolve) {
+ // Aha, I finally decoded the original comment.
+ // This method should be generated as private, but apparently if it is, then
+ // it is name mangled afterward. (Wonder why that is.) So it's only protected.
+ // For sure special methods like "readResolve" should not be mangled.
+ List(createMethod(nme.readResolve, Nil, ObjectClass.tpe)(m => { m setFlag PRIVATE ; REF(clazz.sourceModule) }))
+ }
+ else Nil
+ )
+
+ try impls ++ extras
+ catch { case _: TypeError if reporter.hasErrors => Nil }
}
- try synthesize()
- catch { case _: TypeError if reporter.hasErrors => () }
+ /** If this case class has any less than public accessors,
+ * adds new accessors at the correct locations to preserve ordering.
+ * Note that this must be done before the other method synthesis
+ * because synthesized methods need refer to the new symbols.
+ * Care must also be taken to preserve the case accessor order.
+ */
+ def caseTemplateBody(): List[Tree] = {
+ val lb = ListBuffer[Tree]()
+ def isRewrite(sym: Symbol) = sym.isCaseAccessorMethod && !sym.isPublic
+
+ for (ddef @ DefDef(_, _, _, _, _, _) <- templ.body ; if isRewrite(ddef.symbol)) {
+ val original = ddef.symbol
+ val newAcc = deriveMethod(ddef.symbol, name => context.unit.freshTermName(name + "$")) { newAcc =>
+ makeMethodPublic(newAcc)
+ newAcc resetFlag (ACCESSOR | PARAMACCESSOR)
+ ddef.rhs.duplicate
+ }
+ ddef.symbol resetFlag CASEACCESSOR
+ lb += logResult("case accessor new")(newAcc)
+ }
- if (phase.id <= currentRun.typerPhase.id) {
- treeCopy.Template(templ, templ.parents, templ.self,
- if (ts.isEmpty) templ.body else templ.body ++ ts // avoid copying templ.body if empty
- )
+ lb ++= templ.body ++= synthesize() toList
}
- else templ
+
+ if (phase.id > currentRun.typerPhase.id) templ
+ else treeCopy.Template(templ, templ.parents, templ.self,
+ if (clazz.isCase) caseTemplateBody()
+ else synthesize() match {
+ case Nil => templ.body // avoiding unnecessary copy
+ case ms => templ.body ++ ms
+ }
+ )
}
}