summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-03-12 07:39:54 -0700
committerPaul Phillips <paulp@improving.org>2013-03-12 09:31:25 -0700
commit089cad8f436e1bc0935218937590897f5b9cbae4 (patch)
tree1d43901950f88f918a9d76b17f1c64ec2d49c677 /src/compiler
parenta41c79bb5b2f16d8f37e253737f67171e5764bb9 (diff)
downloadscala-089cad8f436e1bc0935218937590897f5b9cbae4.tar.gz
scala-089cad8f436e1bc0935218937590897f5b9cbae4.tar.bz2
scala-089cad8f436e1bc0935218937590897f5b9cbae4.zip
Warn about locally identifiable init order issues.
This warns about a subset of initialization order issues which can easily be identified by inspection, such as val x = y val y = 5 The likelihood of this formulation being intentional is miniscule.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala35
1 files changed, 35 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index a4a6c3ff31..886c790ec0 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -34,6 +34,41 @@ abstract class Constructors extends Transform with ast.TreeDSL {
val stats = impl.body // the transformed template body
val localTyper = typer.atOwner(impl, clazz)
+ // Inspect for obvious out-of-order initialization; concrete, eager vals or vars,
+ // declared in this class, for which a reference to the member precedes its definition.
+ def checkableForInit(sym: Symbol) = (
+ (sym ne null)
+ && (sym.isVal || sym.isVar)
+ && !(sym hasFlag LAZY | DEFERRED | SYNTHETIC)
+ )
+ val uninitializedVals = mutable.Set[Symbol](
+ stats collect { case vd: ValDef if checkableForInit(vd.symbol) => vd.symbol.accessedOrSelf }: _*
+ )
+ if (uninitializedVals.nonEmpty)
+ log("Checking constructor for init order issues among: " + uninitializedVals.map(_.name).mkString(", "))
+
+ for (stat <- stats) {
+ // Checking the qualifier symbol is necessary to prevent a selection on
+ // another instance of the same class from potentially appearing to be a forward
+ // reference on the member in the current class.
+ def check(tree: Tree) = {
+ for (t <- tree) t match {
+ case t: RefTree if uninitializedVals(t.symbol.accessedOrSelf) && t.qualifier.symbol == clazz =>
+ unit.warning(t.pos, s"Reference to uninitialized ${t.symbol.accessedOrSelf}")
+ case _ =>
+ }
+ }
+ stat match {
+ case vd: ValDef =>
+ // doing this first allows self-referential vals, which to be a conservative
+ // warner we will do because it's possible though difficult for it to be useful.
+ uninitializedVals -= vd.symbol.accessedOrSelf
+ if (!vd.symbol.isLazy)
+ check(vd.rhs)
+ case _: MemberDef => // skip other member defs
+ case t => check(t) // constructor body statement
+ }
+ }
val specializedFlag: Symbol = clazz.info.decl(nme.SPECIALIZED_INSTANCE)
val shouldGuard = (specializedFlag != NoSymbol) && !clazz.hasFlag(SPECIALIZED)