diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-12-18 16:02:02 -0800 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-12-18 16:02:02 -0800 |
commit | d99a4919e0fa4894829c752a8f881d7b103d8cda (patch) | |
tree | bd904a29d8c3e3b99796b939d34477cac1b8b359 | |
parent | b5ef79f2f8bc010220d2920a890352d96ad84b45 (diff) | |
parent | f7f80e8b27c9255590ef8598c97601957a962adf (diff) | |
download | scala-d99a4919e0fa4894829c752a8f881d7b103d8cda.tar.gz scala-d99a4919e0fa4894829c752a8f881d7b103d8cda.tar.bz2 scala-d99a4919e0fa4894829c752a8f881d7b103d8cda.zip |
Merge pull request #3224 from soc/SI-7971
SI-7971 Handle static field initializers correctly
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/CleanUp.scala | 44 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Constructors.scala | 26 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Statics.scala | 52 |
3 files changed, 73 insertions, 49 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 3ecce8d7b1..9738769db9 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -11,7 +11,7 @@ import Flags._ import scala.collection._ import scala.language.postfixOps -abstract class CleanUp extends Transform with ast.TreeDSL { +abstract class CleanUp extends Statics with Transform with ast.TreeDSL { import global._ import definitions._ import CODE._ @@ -35,7 +35,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { protected def newTransformer(unit: CompilationUnit): Transformer = new CleanUpTransformer(unit) - class CleanUpTransformer(unit: CompilationUnit) extends Transformer { + class CleanUpTransformer(unit: CompilationUnit) extends StaticsTransformer { private val newStaticMembers = mutable.Buffer.empty[Tree] private val newStaticInits = mutable.Buffer.empty[Tree] private val symbolsStoredAsStatic = mutable.Map.empty[String, Symbol] @@ -49,7 +49,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { clearStatics() val newBody = transformTrees(body) val templ = deriveTemplate(tree)(_ => transformTrees(newStaticMembers.toList) ::: newBody) - try addStaticInits(templ) // postprocess to include static ctors + try addStaticInits(templ, newStaticInits, localTyper) // postprocess to include static ctors finally clearStatics() } private def mkTerm(prefix: String): TermName = unit.freshTermName(prefix) @@ -557,44 +557,6 @@ abstract class CleanUp extends Transform with ast.TreeDSL { }) } - /* finds the static ctor DefDef tree within the template if it exists. */ - private def findStaticCtor(template: Template): Option[Tree] = - template.body find { - case defdef @ DefDef(_, nme.CONSTRUCTOR, _, _, _, _) => defdef.symbol.hasStaticFlag - case _ => false - } - - /* changes the template for the class so that it contains a static constructor with symbol fields inits, - * augments an existing static ctor if one already existed. - */ - private def addStaticInits(template: Template): Template = { - if (newStaticInits.isEmpty) - template - else { - val newCtor = findStaticCtor(template) match { - // in case there already were static ctors - augment existing ones - // currently, however, static ctors aren't being generated anywhere else - case Some(ctor @ DefDef(_,_,_,_,_,_)) => - // modify existing static ctor - deriveDefDef(ctor) { - case block @ Block(stats, expr) => - // need to add inits to existing block - treeCopy.Block(block, newStaticInits.toList ::: stats, expr) - case term: TermTree => - // need to create a new block with inits and the old term - treeCopy.Block(term, newStaticInits.toList, term) - } - case _ => - // create new static ctor - val staticCtorSym = currentClass.newStaticConstructor(template.pos) - val rhs = Block(newStaticInits.toList, Literal(Constant(()))) - - localTyper.typedPos(template.pos)(DefDef(staticCtorSym, rhs)) - } - deriveTemplate(template)(newCtor :: _) - } - } - } // CleanUpTransformer } diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index b97b1e3527..391bce5abb 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -13,7 +13,7 @@ import symtab.Flags._ /** This phase converts classes with parameters into Java-like classes with * fields, which are assigned to from constructors. */ -abstract class Constructors extends Transform with ast.TreeDSL { +abstract class Constructors extends Statics with Transform with ast.TreeDSL { import global._ import definitions._ @@ -199,7 +199,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { detectUsages walk auxConstructorBuf } } - def mustbeKept(sym: Symbol) = !omittables(sym) + def mustBeKept(sym: Symbol) = !omittables(sym) } // OmittablesHelper @@ -458,7 +458,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { } // GuardianOfCtorStmts private class TemplateTransformer(val unit: CompilationUnit, val impl: Template) - extends Transformer + extends StaticsTransformer with DelayedInitHelper with OmittablesHelper with GuardianOfCtorStmts { @@ -607,7 +607,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { // follow the primary constructor val auxConstructorBuf = new ListBuffer[Tree] - // The list of statements that go into constructor after and including the superclass constructor call + // The list of statements that go into the constructor after and including the superclass constructor call val constrStatBuf = new ListBuffer[Tree] // The list of early initializer statements that go into constructor before the superclass constructor call @@ -616,6 +616,9 @@ abstract class Constructors extends Transform with ast.TreeDSL { // The early initialized field definitions of the class (these are the class members) val presupers = treeInfo.preSuperFields(stats) + // The list of statements that go into the class initializer + val classInitStatBuf = new ListBuffer[Tree] + // generate code to copy pre-initialized fields for (stat <- constrBody.stats) { constrStatBuf += stat @@ -644,7 +647,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { else if (stat.symbol.isConstructor) auxConstructorBuf += stat else defBuf += stat } - case ValDef(_, _, _, rhs) => + case ValDef(mods, _, _, rhs) if !mods.hasStaticFlag => // val defs with constant right-hand sides are eliminated. // for all other val defs, an empty valdef goes into the template and // the initializer goes as an assignment into the constructor @@ -659,6 +662,11 @@ abstract class Constructors extends Transform with ast.TreeDSL { } defBuf += deriveValDef(stat)(_ => EmptyTree) } + case ValDef(_, _, _, rhs) => + // Add static initializer statements to classInitStatBuf and remove the rhs from the val def. + classInitStatBuf += mkAssign(stat.symbol, rhs) + defBuf += deriveValDef(stat)(_ => EmptyTree) + case ClassDef(_, _, _, _) => // classes are treated recursively, and left in the template defBuf += new ConstructorTransformer(unit).transform(stat) @@ -670,7 +678,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { populateOmittables() // Initialize all parameters fields that must be kept. - val paramInits = paramAccessors filter mustbeKept map { acc => + val paramInits = paramAccessors filter mustBeKept map { acc => // Check for conflicting symbol amongst parents: see bug #1960. // It would be better to mangle the constructor parameter name since // it can only be used internally, but I think we need more robust name @@ -710,11 +718,13 @@ abstract class Constructors extends Transform with ast.TreeDSL { defBuf ++= auxConstructorBuf // Unlink all fields that can be dropped from class scope - for (sym <- clazz.info.decls ; if !mustbeKept(sym)) + for (sym <- clazz.info.decls ; if !mustBeKept(sym)) clazz.info.decls unlink sym // Eliminate all field definitions that can be dropped from template - val transformed: Template = deriveTemplate(impl)(_ => defBuf.toList filter (stat => mustbeKept(stat.symbol))) + val templateWithoutOmittables: Template = deriveTemplate(impl)(_ => defBuf.toList filter (stat => mustBeKept(stat.symbol))) + // Add the static initializers + val transformed: Template = addStaticInits(templateWithoutOmittables, classInitStatBuf, localTyper) } // TemplateTransformer diff --git a/src/compiler/scala/tools/nsc/transform/Statics.scala b/src/compiler/scala/tools/nsc/transform/Statics.scala new file mode 100644 index 0000000000..e2508b8d08 --- /dev/null +++ b/src/compiler/scala/tools/nsc/transform/Statics.scala @@ -0,0 +1,52 @@ +package scala.tools.nsc +package transform + +import symtab._ +import Flags._ + +import collection.mutable.Buffer + +abstract class Statics extends Transform with ast.TreeDSL { + import global._ + + class StaticsTransformer extends Transformer { + + /** finds the static ctor DefDef tree within the template if it exists. */ + def findStaticCtor(template: Template): Option[Tree] = + template.body find { + case defdef @ DefDef(_, nme.CONSTRUCTOR, _, _, _, _) => defdef.symbol.hasStaticFlag + case _ => false + } + + /** changes the template for the class so that it contains a static constructor with symbol fields inits, + * augments an existing static ctor if one already existed. + */ + def addStaticInits(template: Template, newStaticInits: Buffer[Tree], localTyper: analyzer.Typer): Template = { + if (newStaticInits.isEmpty) + template + else { + val newCtor = findStaticCtor(template) match { + // in case there already were static ctors - augment existing ones + // currently, however, static ctors aren't being generated anywhere else + case Some(ctor @ DefDef(_,_,_,_,_,_)) => + // modify existing static ctor + deriveDefDef(ctor) { + case block @ Block(stats, expr) => + // need to add inits to existing block + treeCopy.Block(block, newStaticInits.toList ::: stats, expr) + case term: TermTree => + // need to create a new block with inits and the old term + treeCopy.Block(term, newStaticInits.toList, term) + } + case _ => + // create new static ctor + val staticCtorSym = currentClass.newStaticConstructor(template.pos) + val rhs = Block(newStaticInits.toList, Literal(Constant(()))) + + localTyper.typedPos(template.pos)(DefDef(staticCtorSym, rhs)) + } + deriveTemplate(template)(newCtor :: _) + } + } + } +} |