diff options
author | Miguel Garcia <miguelalfredo.garcia@epfl.ch> | 2013-05-23 16:00:28 +0200 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2013-05-26 19:13:57 -0700 |
commit | 6eeafe587b31c2c007ba6ae1d166769140913eea (patch) | |
tree | 0d2a25a2fd20734c45dc90fa813153cbbe7b6627 | |
parent | bf2b753698cc7e3f053476085c0b37ce1d9b5cb3 (diff) | |
download | scala-6eeafe587b31c2c007ba6ae1d166769140913eea.tar.gz scala-6eeafe587b31c2c007ba6ae1d166769140913eea.tar.bz2 scala-6eeafe587b31c2c007ba6ae1d166769140913eea.zip |
eliding what the constructor phase elides but with less effort (1 of 2)
For now both old and new implementations of elision coexist,
allowing cross-checking their results.
In the next commit only the new one will remain.
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Constructors.scala | 69 |
1 files changed, 67 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index cbf95de369..581df9b4d2 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -258,14 +258,71 @@ abstract class Constructors extends Transform with ast.TreeDSL { * */ + val isDelayedInitSubclass = (clazz isSubClass DelayedInitClass) + + def isParamCandidateForElision(sym: Symbol) = (sym.isParamAccessor && sym.isPrivateLocal) + def isOuterCandidateForElision(sym: Symbol) = (sym.isOuterAccessor && sym.owner.isEffectivelyFinal && !sym.isOverridingSymbol) + + val paramCandidatesForElision: Set[ /*Field*/ Symbol] = (clazz.info.decls.toSet filter isParamCandidateForElision) + val outerCandidatesForElision: Set[ /*Method*/ Symbol] = (clazz.info.decls.toSet filter isOuterCandidateForElision) + + /* + * Initially populated with all elision candidates. + * Trees are traversed, and those candidates are removed which are actually needed. + * After that, `omittables` doesn't shrink anymore: each symbol it contains can be unlinked from clazz.info.decls. + */ + val omittables = mutable.Set.empty[Symbol] ++ paramCandidatesForElision ++ outerCandidatesForElision + if(isDelayedInitSubclass) { omittables.clear } + + val bodyOfOuterAccessor: Map[Symbol, DefDef] = { + val outers = (defBuf collect { case dd: DefDef if outerCandidatesForElision.contains(dd.symbol) => dd }) + Map(outers.map { dd => (dd.symbol, dd) } : _*) + } + + class UsagesDetector extends Traverser { + var done = false + override def traverse(tree: Tree) { + if (done) { return } + tree match { + case DefDef(_, _, _, _, _, body) if outerCandidatesForElision.contains(tree.symbol) => + () // don't mark as "needed" the field supporting this outer-accessor, ie not just yet. + case Select(_, _) => + val sym = tree.symbol + if (omittables contains sym) { + debuglog("omittables -= " + sym.fullName) + omittables -= sym + bodyOfOuterAccessor.get(sym) match { + case Some(dd) => traverse(dd.rhs) // recursive call to mark as needed the field supporting the outer-accessor-method. + case _ => () + } + if (omittables.isEmpty) { + done = true + return // no point traversing further, all candidates ruled out already. + } + } + super.traverse(tree) + case _ => + super.traverse(tree) + } + } + } + + if (omittables.nonEmpty) { + val usagesDetector = new UsagesDetector + + for (stat <- defBuf.iterator ++ auxConstructorBuf.iterator) { + usagesDetector.traverse(stat) + } + } + + // TODO for now both old and new implementations of elision coexist, allowing cross-checking their results. In the next commit only the new one will remain. + // A sorted set of symbols that are known to be accessed outside the primary constructor. val accessedSyms = new TreeSet[Symbol]((x, y) => x isLess y) // a list of outer accessor symbols and their bodies var outerAccessors: List[(Symbol, Tree)] = List() - val isDelayedInitSubclass = (clazz isSubClass DelayedInitClass) - // Could symbol's definition be omitted, provided it is not accessed? // This is the case if the symbol is defined in the current class, and // ( the symbol is an object private parameter accessor field, or @@ -313,6 +370,14 @@ abstract class Constructors extends Transform with ast.TreeDSL { for ((accSym, accBody) <- outerAccessors) if (mustbeKept(accSym)) accessTraverser.traverse(accBody) + // TODO cross-checking with new implementation. + for(sym <- clazz.info.decls.toList) { + val oldImplSays = mustbeKept(sym) + val newImplSays = !omittables(sym) + + assert(oldImplSays == newImplSays) + } + // Initialize all parameters fields that must be kept. val paramInits = paramAccessors filter mustbeKept map { acc => // Check for conflicting symbol amongst parents: see bug #1960. |