Skip to content

Commit d99a491

Browse files
committed
Merge pull request scala#3224 from soc/SI-7971
SI-7971 Handle static field initializers correctly
2 parents b5ef79f + f7f80e8 commit d99a491

File tree

3 files changed

+73
-49
lines changed

3 files changed

+73
-49
lines changed

src/compiler/scala/tools/nsc/transform/CleanUp.scala

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import Flags._
1111
import scala.collection._
1212
import scala.language.postfixOps
1313

14-
abstract class CleanUp extends Transform with ast.TreeDSL {
14+
abstract class CleanUp extends Statics with Transform with ast.TreeDSL {
1515
import global._
1616
import definitions._
1717
import CODE._
@@ -35,7 +35,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
3535
protected def newTransformer(unit: CompilationUnit): Transformer =
3636
new CleanUpTransformer(unit)
3737

38-
class CleanUpTransformer(unit: CompilationUnit) extends Transformer {
38+
class CleanUpTransformer(unit: CompilationUnit) extends StaticsTransformer {
3939
private val newStaticMembers = mutable.Buffer.empty[Tree]
4040
private val newStaticInits = mutable.Buffer.empty[Tree]
4141
private val symbolsStoredAsStatic = mutable.Map.empty[String, Symbol]
@@ -49,7 +49,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
4949
clearStatics()
5050
val newBody = transformTrees(body)
5151
val templ = deriveTemplate(tree)(_ => transformTrees(newStaticMembers.toList) ::: newBody)
52-
try addStaticInits(templ) // postprocess to include static ctors
52+
try addStaticInits(templ, newStaticInits, localTyper) // postprocess to include static ctors
5353
finally clearStatics()
5454
}
5555
private def mkTerm(prefix: String): TermName = unit.freshTermName(prefix)
@@ -557,44 +557,6 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
557557
})
558558
}
559559

560-
/* finds the static ctor DefDef tree within the template if it exists. */
561-
private def findStaticCtor(template: Template): Option[Tree] =
562-
template.body find {
563-
case defdef @ DefDef(_, nme.CONSTRUCTOR, _, _, _, _) => defdef.symbol.hasStaticFlag
564-
case _ => false
565-
}
566-
567-
/* changes the template for the class so that it contains a static constructor with symbol fields inits,
568-
* augments an existing static ctor if one already existed.
569-
*/
570-
private def addStaticInits(template: Template): Template = {
571-
if (newStaticInits.isEmpty)
572-
template
573-
else {
574-
val newCtor = findStaticCtor(template) match {
575-
// in case there already were static ctors - augment existing ones
576-
// currently, however, static ctors aren't being generated anywhere else
577-
case Some(ctor @ DefDef(_,_,_,_,_,_)) =>
578-
// modify existing static ctor
579-
deriveDefDef(ctor) {
580-
case block @ Block(stats, expr) =>
581-
// need to add inits to existing block
582-
treeCopy.Block(block, newStaticInits.toList ::: stats, expr)
583-
case term: TermTree =>
584-
// need to create a new block with inits and the old term
585-
treeCopy.Block(term, newStaticInits.toList, term)
586-
}
587-
case _ =>
588-
// create new static ctor
589-
val staticCtorSym = currentClass.newStaticConstructor(template.pos)
590-
val rhs = Block(newStaticInits.toList, Literal(Constant(())))
591-
592-
localTyper.typedPos(template.pos)(DefDef(staticCtorSym, rhs))
593-
}
594-
deriveTemplate(template)(newCtor :: _)
595-
}
596-
}
597-
598560
} // CleanUpTransformer
599561

600562
}

src/compiler/scala/tools/nsc/transform/Constructors.scala

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import symtab.Flags._
1313
/** This phase converts classes with parameters into Java-like classes with
1414
* fields, which are assigned to from constructors.
1515
*/
16-
abstract class Constructors extends Transform with ast.TreeDSL {
16+
abstract class Constructors extends Statics with Transform with ast.TreeDSL {
1717
import global._
1818
import definitions._
1919

@@ -199,7 +199,7 @@ abstract class Constructors extends Transform with ast.TreeDSL {
199199
detectUsages walk auxConstructorBuf
200200
}
201201
}
202-
def mustbeKept(sym: Symbol) = !omittables(sym)
202+
def mustBeKept(sym: Symbol) = !omittables(sym)
203203

204204
} // OmittablesHelper
205205

@@ -458,7 +458,7 @@ abstract class Constructors extends Transform with ast.TreeDSL {
458458
} // GuardianOfCtorStmts
459459

460460
private class TemplateTransformer(val unit: CompilationUnit, val impl: Template)
461-
extends Transformer
461+
extends StaticsTransformer
462462
with DelayedInitHelper
463463
with OmittablesHelper
464464
with GuardianOfCtorStmts {
@@ -607,7 +607,7 @@ abstract class Constructors extends Transform with ast.TreeDSL {
607607
// follow the primary constructor
608608
val auxConstructorBuf = new ListBuffer[Tree]
609609

610-
// The list of statements that go into constructor after and including the superclass constructor call
610+
// The list of statements that go into the constructor after and including the superclass constructor call
611611
val constrStatBuf = new ListBuffer[Tree]
612612

613613
// 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 {
616616
// The early initialized field definitions of the class (these are the class members)
617617
val presupers = treeInfo.preSuperFields(stats)
618618

619+
// The list of statements that go into the class initializer
620+
val classInitStatBuf = new ListBuffer[Tree]
621+
619622
// generate code to copy pre-initialized fields
620623
for (stat <- constrBody.stats) {
621624
constrStatBuf += stat
@@ -644,7 +647,7 @@ abstract class Constructors extends Transform with ast.TreeDSL {
644647
else if (stat.symbol.isConstructor) auxConstructorBuf += stat
645648
else defBuf += stat
646649
}
647-
case ValDef(_, _, _, rhs) =>
650+
case ValDef(mods, _, _, rhs) if !mods.hasStaticFlag =>
648651
// val defs with constant right-hand sides are eliminated.
649652
// for all other val defs, an empty valdef goes into the template and
650653
// the initializer goes as an assignment into the constructor
@@ -659,6 +662,11 @@ abstract class Constructors extends Transform with ast.TreeDSL {
659662
}
660663
defBuf += deriveValDef(stat)(_ => EmptyTree)
661664
}
665+
case ValDef(_, _, _, rhs) =>
666+
// Add static initializer statements to classInitStatBuf and remove the rhs from the val def.
667+
classInitStatBuf += mkAssign(stat.symbol, rhs)
668+
defBuf += deriveValDef(stat)(_ => EmptyTree)
669+
662670
case ClassDef(_, _, _, _) =>
663671
// classes are treated recursively, and left in the template
664672
defBuf += new ConstructorTransformer(unit).transform(stat)
@@ -670,7 +678,7 @@ abstract class Constructors extends Transform with ast.TreeDSL {
670678
populateOmittables()
671679

672680
// Initialize all parameters fields that must be kept.
673-
val paramInits = paramAccessors filter mustbeKept map { acc =>
681+
val paramInits = paramAccessors filter mustBeKept map { acc =>
674682
// Check for conflicting symbol amongst parents: see bug #1960.
675683
// It would be better to mangle the constructor parameter name since
676684
// 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 {
710718
defBuf ++= auxConstructorBuf
711719

712720
// Unlink all fields that can be dropped from class scope
713-
for (sym <- clazz.info.decls ; if !mustbeKept(sym))
721+
for (sym <- clazz.info.decls ; if !mustBeKept(sym))
714722
clazz.info.decls unlink sym
715723

716724
// Eliminate all field definitions that can be dropped from template
717-
val transformed: Template = deriveTemplate(impl)(_ => defBuf.toList filter (stat => mustbeKept(stat.symbol)))
725+
val templateWithoutOmittables: Template = deriveTemplate(impl)(_ => defBuf.toList filter (stat => mustBeKept(stat.symbol)))
726+
// Add the static initializers
727+
val transformed: Template = addStaticInits(templateWithoutOmittables, classInitStatBuf, localTyper)
718728

719729
} // TemplateTransformer
720730

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package scala.tools.nsc
2+
package transform
3+
4+
import symtab._
5+
import Flags._
6+
7+
import collection.mutable.Buffer
8+
9+
abstract class Statics extends Transform with ast.TreeDSL {
10+
import global._
11+
12+
class StaticsTransformer extends Transformer {
13+
14+
/** finds the static ctor DefDef tree within the template if it exists. */
15+
def findStaticCtor(template: Template): Option[Tree] =
16+
template.body find {
17+
case defdef @ DefDef(_, nme.CONSTRUCTOR, _, _, _, _) => defdef.symbol.hasStaticFlag
18+
case _ => false
19+
}
20+
21+
/** changes the template for the class so that it contains a static constructor with symbol fields inits,
22+
* augments an existing static ctor if one already existed.
23+
*/
24+
def addStaticInits(template: Template, newStaticInits: Buffer[Tree], localTyper: analyzer.Typer): Template = {
25+
if (newStaticInits.isEmpty)
26+
template
27+
else {
28+
val newCtor = findStaticCtor(template) match {
29+
// in case there already were static ctors - augment existing ones
30+
// currently, however, static ctors aren't being generated anywhere else
31+
case Some(ctor @ DefDef(_,_,_,_,_,_)) =>
32+
// modify existing static ctor
33+
deriveDefDef(ctor) {
34+
case block @ Block(stats, expr) =>
35+
// need to add inits to existing block
36+
treeCopy.Block(block, newStaticInits.toList ::: stats, expr)
37+
case term: TermTree =>
38+
// need to create a new block with inits and the old term
39+
treeCopy.Block(term, newStaticInits.toList, term)
40+
}
41+
case _ =>
42+
// create new static ctor
43+
val staticCtorSym = currentClass.newStaticConstructor(template.pos)
44+
val rhs = Block(newStaticInits.toList, Literal(Constant(())))
45+
46+
localTyper.typedPos(template.pos)(DefDef(staticCtorSym, rhs))
47+
}
48+
deriveTemplate(template)(newCtor :: _)
49+
}
50+
}
51+
}
52+
}

0 commit comments

Comments
 (0)