aboutsummaryrefslogblamecommitdiff
path: root/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala
blob: a3cf71ef220335db7482cfae323829dae5e2244f (plain) (tree)
1
2
3
4
5
6
7
8
9




                        


                                                   
                  
              

                         

                       

                       

                                                           

                               
                     
                
                                                  
                 

 

                                                                                
                                                         
                               
                                                                    
                                                          
                                                          


                                            
   
                                                                                                                    

                  
                                           
 



                                                               

                                                                                       
                                                                                          


        
                                           

                                                                                             



                                               
 
    




                                                                                              








                                                                                   

    

                                                                              
                                                                                   
                                                                                                                                       




                                                  

   

























                                                                                                                           

                                                                             
                                                                


                                                  


                                                                         
                                                                                                          

                                          
                                  



                                                                      
                                                                            
                                                                                         

                       
 
                                        

   

                                                                                       
                                                                                      






                                                                                            



                                                                                                        
 
                                                                                              


                                                      
                                                   

                                                              
   
 

                                                                                                            


                                                                                                      
                                              
                                                                                
   
 
                                                                                          
                                                         
                             

                                                                                            
                                                         
                             
 







                                                                                                  
 

                                                                                          
 





                                                                                    


                                                   
 
package dotty.tools.dotc
package transform

import core._
import Names._
import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Phases.NeedsCompanions
import dotty.tools.dotc.transform.TreeTransforms._
import ast.Trees._
import Flags._
import Types._
import Constants.Constant
import Contexts.Context
import Symbols._
import SymDenotations._
import Decorators._
import dotty.tools.dotc.core.Annotations.ConcreteAnnotation
import dotty.tools.dotc.core.Denotations.SingleDenotation
import scala.collection.mutable
import DenotTransformers._
import typer.Checking
import NameOps._
import NameKinds.{AvoidClashName, OuterSelectName}
import StdNames._


/** The first tree transform
 *   - ensures there are companion objects for all classes except module classes
 *   - eliminates some kinds of trees: Imports, NamedArgs
 *   - stubs out native methods
 *   - eliminates self tree in Template and self symbol in ClassInfo
 *   - collapses all type trees to trees of class TypeTree
 *   - converts idempotent expressions with constant types
 *   - drops branches of ifs using the rules
 *          if (true) A else B  --> A
 *          if (false) A else B --> B
 */
class FirstTransform extends MiniPhaseTransform with InfoTransformer with AnnotationTransformer { thisTransformer =>
  import ast.tpd._

  override def phaseName = "firstTransform"

  private var addCompanionPhases: List[NeedsCompanions] = _

  def needsCompanion(cls: ClassSymbol)(implicit ctx: Context) =
    addCompanionPhases.exists(_.isCompanionNeeded(cls))

  override def prepareForUnit(tree: tpd.Tree)(implicit ctx: Context): TreeTransform = {
    addCompanionPhases = ctx.phasePlan.flatMap(_ collect { case p: NeedsCompanions => p })
    this
  }

  /** eliminate self symbol in ClassInfo */
  override def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = tp match {
    case tp @ ClassInfo(_, _, _, _, self: Symbol) =>
      tp.derivedClassInfo(selfInfo = self.info)
    case _ =>
      tp
  }

  /*
      tp match {
        //create companions for value classes that are not from currently compiled source file
        case tp@ClassInfo(_, cls, _, decls, _)
          if (ValueClasses.isDerivedValueClass(cls)) &&
            !sym.isDefinedInCurrentRun && sym.scalacLinkedClass == NoSymbol =>
          val newDecls = decls.cloneScope
          val (modul, mcMethod, symMethod) = newCompanion(sym.name.toTermName, sym)
          modul.entered
          mcMethod.entered
          newDecls.enter(symMethod)
          tp.derivedClassInfo(decls = newDecls)
        case _ => tp
      }
  }
  */

  override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = {
    tree match {
      case Select(qual, name) if !name.is(OuterSelectName) && tree.symbol.exists =>
        assert(qual.tpe derivesFrom tree.symbol.owner, i"non member selection of ${tree.symbol.showLocated} from ${qual.tpe} in $tree")
      case _: TypeTree =>
      case _: Import | _: NamedArg | _: TypTree =>
        assert(false, i"illegal tree: $tree")
      case _ =>
    }
  }

  /** Reorder statements so that module classes always come after their companion classes, add missing companion classes */
  private def reorderAndComplete(stats: List[Tree])(implicit ctx: Context): List[Tree] = {
    val moduleClassDefs, singleClassDefs = mutable.Map[Name, Tree]()

    def reorder(stats: List[Tree]): List[Tree] = stats match {
      case (stat: TypeDef) :: stats1 if stat.symbol.isClass =>
        if (stat.symbol is Flags.Module) {
          moduleClassDefs += (stat.name -> stat)
          singleClassDefs -= stat.name.stripModuleClassSuffix
          val stats1r = reorder(stats1)
          if (moduleClassDefs contains stat.name) stat :: stats1r else stats1r
        } else {
          def stats1r = reorder(stats1)
          val normalized = moduleClassDefs remove stat.name.moduleClassName match {
            case Some(mcdef) =>
              mcdef :: stats1r
            case None =>
              singleClassDefs += (stat.name -> stat)
              stats1r
          }
          stat :: normalized
        }
      case stat :: stats1 => stat :: reorder(stats1)
      case Nil => Nil
    }

    def registerCompanion(name: TermName, forClass: Symbol): TermSymbol = {
      val (modul, mcCompanion, classCompanion) = newCompanion(name, forClass)
      if (ctx.owner.isClass) modul.enteredAfter(thisTransformer)
      mcCompanion.enteredAfter(thisTransformer)
      classCompanion.enteredAfter(thisTransformer)
      modul
    }

    def addMissingCompanions(stats: List[Tree]): List[Tree] = stats map {
      case stat: TypeDef if (singleClassDefs contains stat.name) && needsCompanion(stat.symbol.asClass) =>
        val objName = stat.name.toTermName
        val nameClash = stats.exists {
          case other: MemberDef =>
            other.name == objName && other.symbol.info.isParameterless
          case _ =>
            false
        }
        val uniqueName = if (nameClash) AvoidClashName(objName) else objName
        Thicket(stat :: ModuleDef(registerCompanion(uniqueName, stat.symbol), Nil).trees)
      case stat => stat
    }

    addMissingCompanions(reorder(stats))
  }

  private def newCompanion(name: TermName, forClass: Symbol)(implicit ctx: Context) = {
    val modul = ctx.newCompleteModuleSymbol(forClass.owner, name, Synthetic, Synthetic,
      defn.ObjectType :: Nil, Scopes.newScope, assocFile = forClass.asClass.assocFile)
    val mc = modul.moduleClass

    val mcComp = ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, forClass, mc)
    val classComp = ctx.synthesizeCompanionMethod(nme.COMPANION_MODULE_METHOD, mc, forClass)
    (modul, mcComp, classComp)
  }

  /** elimiate self in Template */
  override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo): Tree = {
    cpy.Template(impl)(self = EmptyValDef)
  }

  override def transformDefDef(ddef: DefDef)(implicit ctx: Context, info: TransformerInfo) = {
    if (ddef.symbol.hasAnnotation(defn.NativeAnnot)) {
      ddef.symbol.resetFlag(Deferred)
      DefDef(ddef.symbol.asTerm,
        _ => ref(defn.Sys_errorR).withPos(ddef.pos)
          .appliedTo(Literal(Constant("native method stub"))))
    } else ddef
  }

  override def transformStats(trees: List[Tree])(implicit ctx: Context, info: TransformerInfo): List[Tree] =
    ast.Trees.flatten(reorderAndComplete(trees)(ctx.withPhase(thisTransformer.next)))

  override def transformOther(tree: Tree)(implicit ctx: Context, info: TransformerInfo) = tree match {
    case tree: Import => EmptyTree
    case tree: NamedArg => transform(tree.arg)
    case tree => if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos) else tree
  }

  override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo) =
    if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos)
    else constToLiteral(tree)

  override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo) =
    if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos)
    else constToLiteral(tree)

  override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo) =
    constToLiteral(tree)

  override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo) =
    constToLiteral(tree)

  override def transformTyped(tree: Typed)(implicit ctx: Context, info: TransformerInfo) =
    constToLiteral(tree)

  override def transformBlock(tree: Block)(implicit ctx: Context, info: TransformerInfo) =
    constToLiteral(tree)

  override def transformIf(tree: If)(implicit ctx: Context, info: TransformerInfo) =
    tree.cond match {
      case Literal(Constant(c: Boolean)) => if (c) tree.thenp else tree.elsep
      case _ => tree
    }

  // invariants: all modules have companion objects
  // all types are TypeTrees
  // all this types are explicit
}