From df7d8914aa139e8961db6ce0651e09b118d8bab2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 11 Feb 2016 09:17:07 +0100 Subject: New phase to drop empty companion objects --- src/dotty/tools/dotc/Compiler.scala | 1 + .../tools/dotc/transform/DropEmptyCompanions.scala | 79 ++++++++++++++++++++++ src/dotty/tools/dotc/transform/Flatten.scala | 1 + 3 files changed, 81 insertions(+) create mode 100644 src/dotty/tools/dotc/transform/DropEmptyCompanions.scala (limited to 'src/dotty/tools') diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index 199657864..987c533e7 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -77,6 +77,7 @@ class Compiler { new GetClass), // getClass transformation should be applied to specialized methods List(new LambdaLift, // in this mini-phase block scopes are incorrect. No phases that rely on scopes should be here new ElimStaticThis, + new DropEmptyCompanions, new Flatten, new RestoreScopes), List(/*new PrivateToStatic,*/ diff --git a/src/dotty/tools/dotc/transform/DropEmptyCompanions.scala b/src/dotty/tools/dotc/transform/DropEmptyCompanions.scala new file mode 100644 index 000000000..05296d93e --- /dev/null +++ b/src/dotty/tools/dotc/transform/DropEmptyCompanions.scala @@ -0,0 +1,79 @@ +package dotty.tools.dotc +package transform + +import core._ +import DenotTransformers.SymTransformer +import Phases.Phase +import Contexts.Context +import Flags._ +import Symbols._ +import SymDenotations.SymDenotation +import ast.Trees._ +import collection.mutable +import Decorators._ +import NameOps._ +import TreeTransforms.{TreeTransform, MiniPhase} +import dotty.tools.dotc.transform.TreeTransforms.TransformerInfo + +/** Remove companion objects that are empty */ +class DropEmptyCompanions extends MiniPhase { thisTransform => + import ast.tpd._ + override def phaseName = "dropEmpty" + val treeTransform = new Transform(Set()) + + class Transform(dropped: Set[Symbol]) extends TreeTransform { + def phase = thisTransform + + /** Is `tree` an empty companion object? */ + private def isEmptyCompanion(tree: Tree)(implicit ctx: Context) = tree match { + case TypeDef(_, impl: Template) => + tree.symbol.is(Module) && + tree.symbol.companionClass.exists && + impl.body.forall(_.symbol.isPrimaryConstructor) + case _ => + false + } + + /** A transform which has all empty companion objects in `stats` + * recorded in its `dropped` set. + */ + private def localTransform(stats: List[Tree])(implicit ctx: Context) = + new Transform(stats.filter(isEmptyCompanion).map(_.symbol).toSet) + + override def prepareForTemplate(tree: Template)(implicit ctx: Context) = + localTransform(tree.body) + + override def prepareForStats(trees: List[Tree])(implicit ctx: Context) = + if (ctx.owner is Package) localTransform(trees) else this + + /** Symbol is a $lzy field representing a module */ + private def isLazyModuleVar(sym: Symbol)(implicit ctx: Context) = + sym.name.isLazyLocal && + sym.owner.info.decl(sym.name.asTermName.nonLazyName).symbol.is(Module) + + /** Symbol should be dropped together with a dropped companion object. + * Such symbols are: + * - lzy fields pointing to modules, + * - vals and getters representing modules. + */ + private def toDrop(sym: Symbol)(implicit ctx: Context): Boolean = + (sym.is(Module) || isLazyModuleVar(sym)) && + dropped.contains(sym.info.resultType.typeSymbol) + + /** Tree should be dropped because it (is associated with) an empty + * companion object. Such trees are + * - module classes of empty companion objects + * - definitions of lazy module variables or assignments to them. + * - vals and getters for empty companion objects + */ + private def toDrop(stat: Tree)(implicit ctx: Context): Boolean = stat match { + case stat: TypeDef => dropped.contains(stat.symbol) + case stat: ValOrDefDef => toDrop(stat.symbol) + case stat: Assign => toDrop(stat.lhs.symbol) + case _ => false + } + + override def transformStats(stats: List[Tree])(implicit ctx: Context, info: TransformerInfo) = + stats.filterNot(toDrop) + } +} diff --git a/src/dotty/tools/dotc/transform/Flatten.scala b/src/dotty/tools/dotc/transform/Flatten.scala index 9a047ef95..f0104e715 100644 --- a/src/dotty/tools/dotc/transform/Flatten.scala +++ b/src/dotty/tools/dotc/transform/Flatten.scala @@ -11,6 +11,7 @@ import collection.mutable import TreeTransforms.MiniPhaseTransform import dotty.tools.dotc.transform.TreeTransforms.TransformerInfo +/** Lift nested classes to toplevel */ class Flatten extends MiniPhaseTransform with SymTransformer { thisTransform => import ast.tpd._ override def phaseName = "flatten" -- cgit v1.2.3