diff options
author | Paul Phillips <paulp@improving.org> | 2013-03-12 18:46:52 -0700 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2013-03-12 18:46:52 -0700 |
commit | 2f38bb8e5c69af0db63e05da78301dda916fad6f (patch) | |
tree | 6d2b2d4243b9bb2bb81c2e18eacd436d3026ec04 /src | |
parent | 4cb4852f9b30ad41959118b98b1a0b0486ac8123 (diff) | |
parent | 089cad8f436e1bc0935218937590897f5b9cbae4 (diff) | |
download | scala-2f38bb8e5c69af0db63e05da78301dda916fad6f.tar.gz scala-2f38bb8e5c69af0db63e05da78301dda916fad6f.tar.bz2 scala-2f38bb8e5c69af0db63e05da78301dda916fad6f.zip |
Merge pull request #2240 from paulp/pr/warn-forward-reference
Warn about locally identifiable init order issues.
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Constructors.scala | 35 |
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) |