summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@typesafe.com>2013-12-18 16:02:02 -0800
committerAdriaan Moors <adriaan.moors@typesafe.com>2013-12-18 16:02:02 -0800
commitd99a4919e0fa4894829c752a8f881d7b103d8cda (patch)
treebd904a29d8c3e3b99796b939d34477cac1b8b359 /src
parentb5ef79f2f8bc010220d2920a890352d96ad84b45 (diff)
parentf7f80e8b27c9255590ef8598c97601957a962adf (diff)
downloadscala-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
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala44
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala26
-rw-r--r--src/compiler/scala/tools/nsc/transform/Statics.scala52
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 :: _)
+ }
+ }
+ }
+}