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



                                                                                                  
                                               



                                              
                             
                     



                                                                                               
                           


                                                                                                  
  
                                                                         
  



                                                                                    
  
                                                     
  
                                                                                  
  
                                                          
  
                                            
  
                                                                  
  
                                                    
  

                                                                        

                                                     


                                                                                

















                                                                                            
 

                                                     
                                                      
 



                                                                       
 


                                                                                    
 





                                                                                           
                                                                                                                            



                                                                                               
                                                  
 
                                            
 
                                            
 






                                                                            
 

                                                                                      
 




                                                                               
                                                                                    
                           
                                                                                 
                                              
     
 
                                                                                                 


                                                                                  
                                                                                                
                 




                                                            

       
 

























                                                                                                                          
                              
                                                                   
                                                                                                     





                                                                        
                                                                     
                      
                                           

                                                                 
                                                           
           




                                                              
              
                                                                       



                                                                             

                                                                   




                                                                         
                                                                                                 
                     
                                    
           

                                                         












                                                                                                 
                              
                                
                                                      

                                                             
                                         


                                                             
                                    
                            
                                  
                                                                               
                             
                                  
                               





                                                                                                
 

                                                                                       



                                                                        
 


                               
                               
                                  

                                                                       
                                                        
                               

                                                                          




                                                          
                               


                              
                                                                                         


                             

                                       
                                                      




                                                                                                                


                                                                        

                               
                    








                                                    
package dotty.tools.dotc
package transform

import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, TreeTransform, TreeTransformer}
import dotty.tools.dotc.ast.{Trees, tpd, untpd}
import scala.collection.{ mutable, immutable }
import ValueClasses._
import scala.annotation.tailrec
import core._
import typer.ErrorReporting._
import typer.Checking
import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTransformers._
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._
import util.Positions._
import Decorators._
import config.Printers.typr
import Symbols._, TypeUtils._

/** A macro transform that runs immediately after typer and that performs the following functions:
 *
 *  (1) Add super accessors and protected accessors (@see SuperAccessors)
 *
 *  (2) Convert parameter fields that have the same name as a corresponding
 *      public parameter field in a superclass to a forwarder to the superclass
 *      field (corresponding = super class field is initialized with subclass field)
 *      (@see ForwardParamAccessors)
 *
 *  (3) Add synthetic methods (@see SyntheticMethods)
 *
 *  (4) Check that `New` nodes can be instantiated, and that annotations are valid
 *
 *  (5) Convert all trees representing types to TypeTrees.
 *
 *  (6) Check the bounds of AppliedTypeTrees
 *
 *  (7) Insert `.package` for selections of package object members
 *
 *  (8) Replaces self references by name with `this`
 *
 *  (9) Adds SourceFile annotations to all top-level classes and objects
 *
 *  (10) Adds Child annotations to all sealed classes
 *
 *  (11) Minimizes `call` fields of `Inline` nodes to just point to the toplevel
 *       class from which code was inlined.
 *
 *  The reason for making this a macro transform is that some functions (in particular
 *  super and protected accessors and instantiation checks) are naturally top-down and
 *  don't lend themselves to the bottom-up approach of a mini phase. The other two functions
 *  (forwarding param accessors and synthetic methods) only apply to templates and fit
 *  mini-phase or subfunction of a macro phase equally well. But taken by themselves
 *  they do not warrant their own group of miniphases before pickling.
 */
class PostTyper extends MacroTransform with IdentityDenotTransformer  { thisTransformer =>

  import tpd._

  /** the following two members override abstract members in Transform */
  override def phaseName: String = "posttyper"

  override def transformPhase(implicit ctx: Context) = thisTransformer.next

  protected def newTransformer(implicit ctx: Context): Transformer =
    new PostTyperTransformer

  val superAcc = new SuperAccessors(thisTransformer)
  val paramFwd = new ParamForwarding(thisTransformer)
  val synthMth = new SyntheticMethods(thisTransformer)

  private def newPart(tree: Tree): Option[New] = methPart(tree) match {
    case Select(nu: New, _) => Some(nu)
    case _ => None
  }

  private def checkValidJavaAnnotation(annot: Tree)(implicit ctx: Context): Unit = {
    // TODO fill in
  }

  /** If the type of `tree` is a TermRefWithSignature with an underdefined
   *  signature, narrow the type by re-computing the signature (which should
   *  be fully-defined by now).
   */
  private def fixSignature[T <: Tree](tree: T)(implicit ctx: Context): T = tree.tpe match {
    case tpe: TermRefWithSignature if tpe.signature.isUnderDefined =>
      typr.println(i"fixing $tree with type ${tree.tpe.widen.toString} with sig ${tpe.signature} to ${tpe.widen.signature}")
      tree.withType(TermRef.withSig(tpe.prefix, tpe.name, tpe.widen.signature)).asInstanceOf[T]
    case _ => tree
  }

  class PostTyperTransformer extends Transformer {

    private var inJavaAnnot: Boolean = false

    private var parentNews: Set[New] = Set()

    private def transformAnnot(annot: Tree)(implicit ctx: Context): Tree = {
      val saved = inJavaAnnot
      inJavaAnnot = annot.symbol is JavaDefined
      if (inJavaAnnot) checkValidJavaAnnotation(annot)
      try transform(annot)
      finally inJavaAnnot = saved
    }

    private def transformAnnot(annot: Annotation)(implicit ctx: Context): Annotation =
      annot.derivedAnnotation(transformAnnot(annot.tree))

    private def registerChild(sym: Symbol, tp: Type)(implicit ctx: Context) = {
      val cls = tp.classSymbol
      if (cls.is(Sealed)) cls.addAnnotation(Annotation.makeChild(sym))
    }

    private def transformMemberDef(tree: MemberDef)(implicit ctx: Context): Unit = {
      val sym = tree.symbol
      if (sym.is(CaseVal, butNot = Method | Module)) registerChild(sym, sym.info)
      sym.transformAnnotations(transformAnnot)
    }

    private def transformSelect(tree: Select, targs: List[Tree])(implicit ctx: Context): Tree = {
      val qual = tree.qualifier
      qual.symbol.moduleClass.denot match {
        case pkg: PackageClassDenotation if !tree.symbol.maybeOwner.is(Package) =>
          transformSelect(cpy.Select(tree)(qual select pkg.packageObj.symbol, tree.name), targs)
        case _ =>
          val tree1 = super.transform(tree)
          constToLiteral(tree1) match {
            case _: Literal => tree1
            case _ => superAcc.transformSelect(tree1, targs)
          }
      }
    }

    private def normalizeTypeArgs(tree: TypeApply)(implicit ctx: Context): TypeApply = tree.tpe match {
      case pt: PolyType => // wait for more arguments coming
        tree
      case _ =>
        def decompose(tree: TypeApply): (Tree, List[Tree]) = tree.fun match {
          case fun: TypeApply =>
            val (tycon, args) = decompose(fun)
            (tycon, args ++ tree.args)
          case _ =>
            (tree.fun, tree.args)
        }
        def reorderArgs(pnames: List[Name], namedArgs: List[NamedArg], otherArgs: List[Tree]): List[Tree] = pnames match {
          case pname :: pnames1 =>
            namedArgs.partition(_.name == pname) match {
              case (NamedArg(_, arg) :: _, namedArgs1) =>
                arg :: reorderArgs(pnames1, namedArgs1, otherArgs)
              case _ =>
                val otherArg :: otherArgs1 = otherArgs
                otherArg :: reorderArgs(pnames1, namedArgs, otherArgs1)
            }
          case nil =>
            assert(namedArgs.isEmpty && otherArgs.isEmpty)
            Nil
        }
        val (tycon, args) = decompose(tree)
        tycon.tpe.widen match {
          case tp: PolyType =>
            val (namedArgs, otherArgs) = args.partition(isNamedArg)
            val args1 = reorderArgs(tp.paramNames, namedArgs.asInstanceOf[List[NamedArg]], otherArgs)
            TypeApply(tycon, args1).withPos(tree.pos).withType(tree.tpe)
          case _ =>
            tree
        }
    }

    override def transform(tree: Tree)(implicit ctx: Context): Tree =
      try tree match {
        case tree: Ident if !tree.isType =>
          tree.tpe match {
            case tpe: ThisType => This(tpe.cls).withPos(tree.pos)
            case _ => paramFwd.adaptRef(fixSignature(tree))
          }
        case tree @ Select(qual, name) =>
          if (name.isTypeName) {
            Checking.checkRealizable(qual.tpe, qual.pos.focus)
            super.transform(tree)
          }
          else
            transformSelect(paramFwd.adaptRef(fixSignature(tree)), Nil)
        case tree: Super =>
          if (ctx.owner.enclosingMethod.isInlineMethod)
            ctx.error(em"super not allowed in inline ${ctx.owner}", tree.pos)
          super.transform(tree)
        case tree: TypeApply =>
          val tree1 @ TypeApply(fn, args) = normalizeTypeArgs(tree)
          Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType])
          fn match {
            case sel: Select =>
              val args1 = transform(args)
              val sel1 = transformSelect(sel, args1)
              if (superAcc.isProtectedAccessor(sel1)) sel1 else cpy.TypeApply(tree1)(sel1, args1)
            case _ =>
              super.transform(tree1)
          }
        case tree @ Assign(sel: Select, _) =>
          superAcc.transformAssign(super.transform(tree))
        case Inlined(call, bindings, expansion) =>
          // Leave only a call trace consisting of
          //  - a reference to the top-level class from which the call was inlined,
          //  - the call's position
          // in the call field of an Inlined node.
          // The trace has enough info to completely reconstruct positions.
          // The minimization is done for two reasons:
          //  1. To save space (calls might contain large inline arguments, which would otherwise
          //     be duplicated
          //  2. To enable correct pickling (calls can share symbols with the inlined code, which
          //     would trigger an assertion when pickling).
          val callTrace = Ident(call.symbol.topLevelClass.typeRef).withPos(call.pos)
          cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion))
        case tree: Template =>
          val saved = parentNews
          parentNews ++= tree.parents.flatMap(newPart)
          try {
            val templ1 = paramFwd.forwardParamAccessors(tree)
            synthMth.addSyntheticMethods(
                superAcc.wrapTemplate(templ1)(
                  super.transform(_).asInstanceOf[Template]))
          }
          finally parentNews = saved
        case tree: DefDef =>
          transformMemberDef(tree)
          superAcc.wrapDefDef(tree)(super.transform(tree).asInstanceOf[DefDef])
        case tree: TypeDef =>
          transformMemberDef(tree)
          val sym = tree.symbol
          if (sym.isClass) {
            // Add SourceFile annotation to top-level classes
            if (sym.owner.is(Package) &&
              ctx.compilationUnit.source.exists &&
              sym != defn.SourceFileAnnot)
              sym.addAnnotation(Annotation.makeSourceFile(ctx.compilationUnit.source.file.path))

            // Add Child annotation to sealed parents unless current class is anonymous
            if (!sym.isAnonymousClass) // ignore anonymous class
              sym.asClass.classInfo.classParents.foreach { parent =>
                val sym2 = if (sym.is(Module)) sym.sourceModule else sym
                registerChild(sym2, parent)
              }

            tree
          }
          super.transform(tree)
        case tree: MemberDef =>
          transformMemberDef(tree)
          super.transform(tree)
        case tree: New if !inJavaAnnot && !parentNews.contains(tree) =>
          Checking.checkInstantiable(tree.tpe, tree.pos)
          super.transform(tree)
        case tree @ Annotated(annotated, annot) =>
          cpy.Annotated(tree)(transform(annotated), transformAnnot(annot))
        case tree: AppliedTypeTree =>
          Checking.checkAppliedType(tree)
          super.transform(tree)
        case SingletonTypeTree(ref) =>
          Checking.checkRealizable(ref.tpe, ref.pos.focus)
          super.transform(tree)
        case tree: TypeTree =>
          tree.withType(
            tree.tpe match {
              case AnnotatedType(tpe, annot) => AnnotatedType(tpe, transformAnnot(annot))
              case tpe => tpe
            }
          )
        case Import(expr, selectors) =>
          val exprTpe = expr.tpe
          def checkIdent(ident: untpd.Ident): Unit = {
            val name = ident.name.asTermName.encode
            if (name != nme.WILDCARD && !exprTpe.member(name).exists && !exprTpe.member(name.toTypeName).exists)
              ctx.error(s"${ident.name} is not a member of ${expr.show}", ident.pos)
          }
          selectors.foreach {
            case ident: untpd.Ident                 => checkIdent(ident)
            case Thicket((ident: untpd.Ident) :: _) => checkIdent(ident)
            case _                                  =>
          }
          super.transform(tree)
        case tree =>
          super.transform(tree)
      }
      catch {
        case ex : AssertionError =>
          println(i"error while transforming $tree")
          throw ex
      }
  }
}