aboutsummaryrefslogblamecommitdiff
path: root/compiler/src/dotty/tools/dotc/transform/DropEmptyCompanions.scala.disabled
blob: 7b37c5881dc916fb5277a8264b4ff047c3e36e34 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14













                                       
                                        

                                                                













                                                                                       
                  
                                                
                                                                        
 
                                                                                                      

                                               

                                                                           
                                            
                                                          
                                           
            



               
                                                                         

                                                       
                                      
                             
                                                                              





                                                                          
                                            
                                                 
                                                        






                                                                       
                                                  
                                                         

                                                         


                     


















                                                                         

   
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.MiniPhaseTransform
import dotty.tools.dotc.transform.TreeTransforms.TransformerInfo

/** Remove companion objects that are empty
 *  Lots of constraints here:
 *  1. It's impractical to place DropEmptyCompanions before lambda lift because dropped
 *     modules can be anywhere and have hard to trace references.
 *  2. DropEmptyCompanions cannot be interleaved with LambdaLift or Flatten because
 *     they put things in liftedDefs sets which cause them to surface later. So
 *     removed modules resurface.
 *  3. DropEmptyCompanions has to be before RestoreScopes.
 *  The solution to the constraints is to put DropEmptyCompanions between Flatten
 *  and RestoreScopes and to only start working once we are back on PackageDef
 *  level, so we know that all objects moved by LambdaLift and Flatten have arrived
 *  at their destination.
 */
class DropEmptyCompanions extends MiniPhaseTransform { thisTransform =>
  import ast.tpd._
  override def phaseName = "dropEmptyCompanions"
  override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Flatten])

  override def transformPackageDef(pdef: PackageDef)(implicit ctx: Context, info: TransformerInfo) = {

    /** Is `tree` an empty companion object? */
    def isEmptyCompanion(tree: Tree) = tree match {
      case TypeDef(_, impl: Template) if tree.symbol.is(SyntheticModule) &&
        tree.symbol.companionClass.exists &&
        impl.body.forall(_.symbol.isPrimaryConstructor) =>
        ctx.log(i"removing ${tree.symbol}")
        true
      case _ =>
        false
    }

    val dropped = pdef.stats.filter(isEmptyCompanion).map(_.symbol).toSet

    /** Symbol is a $lzy field representing a module */
    def isLazyModuleVar(sym: Symbol) =
      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.
     */
    def symIsDropped(sym: Symbol): 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
     */
    def toDrop(stat: Tree): Boolean = stat match {
      case stat: TypeDef => dropped.contains(stat.symbol)
      case stat: ValOrDefDef => symIsDropped(stat.symbol)
      case stat: Assign => symIsDropped(stat.lhs.symbol)
      case _ => false
    }

    def prune(tree: Tree): Tree = tree match {
      case tree @ TypeDef(name, impl @ Template(constr, _, _, _)) =>
        cpy.TypeDef(tree)(
          rhs = cpy.Template(impl)(
            constr = cpy.DefDef(constr)(rhs = pruneLocals(constr.rhs)),
            body = pruneStats(impl.body)))
      case _ =>
        tree
    }

    def pruneStats(stats: List[Tree]) =
      stats.filterConserve(!toDrop(_)).mapConserve(prune)

    def pruneLocals(expr: Tree) = expr match {
      case Block(stats, expr) => cpy.Block(expr)(pruneStats(stats), expr)
      case _ => expr
    }

    cpy.PackageDef(pdef)(pdef.pid, pruneStats(pdef.stats))
  }
}