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





                   
                                                                            
                                                                                                  
                                  
                                 
                   
                       
                                                
                         
                         
                       
                              
                    
                                                     
                    
                    
                               
                         
                                   
                                      
 
                                        
                          
 




                                                                                    


                                             
                                                      

       
   
 
                                                              

                                          

                                                                                              
                                    


                                                                     
                                   
       



                                                                                                               
 



                                                                            
                                                                   
              



                                                                                       









                                                            



            






                                                                             



                                                                      
                                                                               


                                                                                            







                                                                                             










                                                                                                                                                        
                                                                           
       
                                                                                                    


                                                    
 


                                                                

                                                                
                        
                                                                                              
        










                                                                                                

 
                                                                          


















                                                                                         
                             


                


                                             
 
                                                                                    

                                                       
                                                                
     

                                                                                       
 
                                                                             


                                                                               
     
                                                            
 
                                                        
                                                                                       
     
                                                               






                                                                                       
                                                             
 

                                                                                

                                                                               
     
                      
 
                                               

                                                                 

                                           
                                              
     
   
 


                                                                                           
          
                                                   
                                                                                     



         










                                                                           


                                                                      
                                                                 
 

                                                       
 











                                                                                         

                                                                                       
                                                                                     
                    
 
                                                             
 




                                             
                                                       
                                    
                                              
                                                                                                  




                                                                          

     
                                                                                   
 
                
                                              
                                                               
                                                           
                                               
                                               
                                                                          
                                                                              

                                                         
                             
                                                    
                                               

                                                               
                                                                          

                                                                                        
                                       
                                                                             

                              






                                                                                    



                                                                                                      
 




                                                                
                                
                                                                                   
                                          
                                                             
                          

                                                                                           


                

   




                                                               
                                                                              




                    
                                                 





                                                                                             
 
                                                                       
          
                                                                                        



                                                                                           
       
                                                                              
     

   



                                                                    
                                                            
                                                                       
             
   
 

                                                                          
                                                                   


                  
                                                          




                                                                        
                                                                                           
   

                                                  
                                                                                                         
                                                 
                    
                                                                   
                                                  

               


            



                                                                             





                                                                                                  
       
                    

                                              



               








                                                                                                

                                                                       






                                                                        
                                             

                                                 
                                   







                                   
                             
   
 

















                                                                                                 









                                                                                              
                                                                                 
                                                  
                                                           


                

                                                                                 
 
                                                   

























                                                                                              
 












                                                                                                
 


                                                                                
                                
                                                                                  





                                                                               
                                                            




                                                                          
                 

                                                              











                                                                                        
                                                     
                 
 

                       
                   
         

     
                                                                    
                                                                                       

                                                                  

                                                                                    


                                                             




















                                                                  
                                                        
                                                                    




                                
 




                                                                               

                                                                 
                                                                      

                                                                        
                                                                      





                                                                                                       










                                                                                                                           
       
     
 
                         
                        


                                                                               

   


































                                                                                    
                                                                                         

                                                                                      
                                                                                                



































                                                                                      
                                                                                          
                                                                               
 
                                                                                           
 


                                                            
                                                               
                              
                                            
                                                                                             
                              
                                          
                                 
                                                                           
                         

                                                                 
                           




                                                               
     
 









                                                                                                                    
                                      
     
 

                                                                      

                                   

                                                                                 


               



                                                                            
                            
                      
                                                                 

                 
                          


                                                  
     

   









                                                                                                                       
                                      
                                            
                                                      



                                             








                                                                          
                                                                                                              
                       
 
                                                                                                  
 
                                                                           
 
                                         
                                          
                                                 




                              
                                                             
                                                                          
 

                                                                      
         

                                                                       
                                                             
                
                                                        





                                                                   
                                             
                                                                                       
         
 


                                                                                               

                                                                                                    
         
                                                         
                                                            
                                        
              

                                                                        
                                    





                                                                                        
                           
           







                                                                                                
         

       
                                           
 

                                






                                                                                         
                               
 
                                                                    

                                                                                






                                                                           
                                
                                            
 
                                                      
 
                                                                             
                                                                        
                                                                                                                  
 
                                          
 
                                   
                                                      
                                                

     
 

                                                                                                    
                              
                                           

                               
                               
                                              

             
   

                                                                                            
                                                                                                  

                                                                                            
                                                                                
 






                                                                                    

                                                                        
                            
                                               
   
 










                                                                             





                                                                       
                                                                                                                                                                   
 













                                                                            



                                                                                                                        
                           






                                                                                                   
                       
                                                                      
                           
             


                                                                                                   
                                
                                                                                                          
                         
           
         
 





                                                                              

                                                


                                                                         
                


                                                                                     
                                                                               

                                                            
                          
           

                                                             
                                                                    

                        
                              
 

                                                                               
                                                                     
 
                                                                     

                                                                                    
                                                                

                                                             
                                              
       




                                                                                       
                                                        
                                                                                   
                                                                           
                                                                                     
                                                                                         



                                                                                                                
            

                                                                                                     

                                 





                                                                 
                                   
       
     
 
                                   
                                      
                    
                        

                                                                                      



                                                              




                                                                                          

                   
                    
               
                    
     
                                                   
   
 
                                                         
                                                                     
                                                    
                                               























                                                                                                    
                             



                                                                        
                                             
                                                                                                
                                            
                                                                                                          
                                                                   
                   
                                                                                                      

                        
                                                                                              
                                             
                                                                    
     
                                                                        
   
 
                                                                                                           
                                                                            

                                                









                                                                                          

                                                                
                              
                                          


                                             
                                                                         
                                    

                                                                           
     




                                                                     











                                                                                      
            
   
 
package dotty.tools
package dotc
package typer

import core._
import ast._
import Trees._, Constants._, StdNames._, Scopes._, Denotations._, Comments._
import Contexts._, Symbols._, Types._, SymDenotations._, Names._, NameOps._, Flags._, Decorators._
import NameKinds.DefaultGetterName
import ast.desugar, ast.desugar._
import ProtoTypes._
import util.Positions._
import util.{Property, SourcePosition, DotClass}
import collection.mutable
import annotation.tailrec
import ErrorReporting._
import tpd.ListOfTreeDecorator
import config.Config
import config.Printers.{typr, completions, noPrinter}
import Annotations._
import Inferencing._
import transform.ValueClasses._
import TypeApplications._
import language.implicitConversions
import reporting.diagnostic.messages._

trait NamerContextOps { this: Context =>
  import NamerContextOps._

  /** Enter symbol into current class, if current class is owner of current context,
   *  or into current scope, if not. Should always be called instead of scope.enter
   *  in order to make sure that updates to class members are reflected in
   *  finger prints.
   */
  def enter(sym: Symbol): Symbol = {
    ctx.owner match {
      case cls: ClassSymbol => cls.enter(sym)
      case _ => this.scope.openForMutations.enter(sym)
    }
    sym
  }

  /** The denotation with the given name in current context */
  def denotNamed(name: Name): Denotation =
    if (owner.isClass)
      if (outer.owner == owner) { // inner class scope; check whether we are referring to self
        if (scope.size == 1) {
          val elem = scope.lastEntry
          if (elem.name == name) return elem.sym.denot // return self
        }
        assert(scope.size <= 1, scope)
        owner.thisType.member(name)
      }
      else // we are in the outermost context belonging to a class; self is invisible here. See inClassContext.
        owner.findMember(name, owner.thisType, EmptyFlags)
    else
      scope.denotsNamed(name).toDenot(NoPrefix)

  /** Either the current scope, or, if the current context owner is a class,
   *  the declarations of the current class.
   */
  def effectiveScope: Scope =
    if (owner != null && owner.isClass) owner.asClass.unforcedDecls
    else scope

  /** The symbol (stored in some typer's symTree) of an enclosing context definition */
  def symOfContextTree(tree: untpd.Tree) = {
    def go(ctx: Context): Symbol = {
      ctx.typeAssigner match {
        case typer: Typer =>
          tree.getAttachment(typer.SymOfTree) match {
            case Some(sym) => sym
            case None =>
              var cx = ctx.outer
              while (cx.typeAssigner eq typer) cx = cx.outer
              go(cx)
          }
        case _ => NoSymbol
      }
    }
    go(this)
  }

  /** Context where `sym` is defined, assuming we are in a nested context. */
  def defContext(sym: Symbol) =
    outersIterator
      .dropWhile(_.owner != sym)
      .dropWhile(_.owner == sym)
      .next

  /** The given type, unless `sym` is a constructor, in which case the
   *  type of the constructed instance is returned
   */
  def effectiveResultType(sym: Symbol, typeParams: List[Symbol], given: Type) =
    if (sym.name == nme.CONSTRUCTOR) sym.owner.typeRef.appliedTo(typeParams map (_.typeRef))
    else given

  /** if isConstructor, make sure it has one non-implicit parameter list */
  def normalizeIfConstructor(paramSymss: List[List[Symbol]], isConstructor: Boolean) =
    if (isConstructor &&
      (paramSymss.isEmpty || paramSymss.head.nonEmpty && (paramSymss.head.head is Implicit)))
      Nil :: paramSymss
    else
      paramSymss

  /** The method type corresponding to given parameters and result type */
  def methodType(typeParams: List[Symbol], valueParamss: List[List[Symbol]], resultType: Type, isJava: Boolean = false)(implicit ctx: Context): Type = {
    val monotpe =
      (valueParamss :\ resultType) { (params, resultType) =>
        val make =
          if (params.nonEmpty && (params.head is Implicit)) ImplicitMethodType
          else if (isJava) JavaMethodType
          else MethodType
        if (isJava)
          for (param <- params)
            if (param.info.isDirectRef(defn.ObjectClass)) param.info = defn.AnyType
        make.fromSymbols(params.asInstanceOf[List[TermSymbol]], resultType)
      }
    if (typeParams.nonEmpty) PolyType.fromParams(typeParams.asInstanceOf[List[TypeSymbol]], monotpe)
    else if (valueParamss.isEmpty) ExprType(monotpe)
    else monotpe
  }

  /** Add moduleClass or sourceModule functionality to completer
   *  for a module or module class
   */
  def adjustModuleCompleter(completer: LazyType, name: Name) = {
    val scope = this.effectiveScope
    if (name.isTermName)
      completer withModuleClass (implicit ctx => findModuleBuddy(name.moduleClassName, scope))
    else
      completer withSourceModule (implicit ctx => findModuleBuddy(name.sourceModuleName, scope))
  }
}

object NamerContextOps {
  /** Find moduleClass/sourceModule in effective scope */
  private def findModuleBuddy(name: Name, scope: Scope)(implicit ctx: Context) = {
    val it = scope.lookupAll(name).filter(_ is Module)
    assert(it.hasNext, s"no companion $name in $scope")
    it.next
  }
}

/** This class creates symbols from definitions and imports and gives them
 *  lazy types.
 *
 *  Timeline:
 *
 *  During enter, trees are expanded as necessary, populating the expandedTree map.
 *  Symbols are created, and the symOfTree map is set up.
 *
 *  Symbol completion causes some trees to be already typechecked and typedTree
 *  entries are created to associate the typed trees with the untyped expanded originals.
 *
 *  During typer, original trees are first expanded using expandedTree. For each
 *  expanded member definition or import we extract and remove the corresponding symbol
 *  from the symOfTree map and complete it. We then consult the typedTree map to see
 *  whether a typed tree exists already. If yes, the typed tree is returned as result.
 *  Otherwise, we proceed with regular type checking.
 *
 *  The scheme is designed to allow sharing of nodes, as long as each duplicate appears
 *  in a different method.
 */
class Namer { typer: Typer =>

  import untpd._

  val TypedAhead = new Property.Key[tpd.Tree]
  val ExpandedTree = new Property.Key[Tree]
  val SymOfTree = new Property.Key[Symbol]

  /** A partial map from unexpanded member and pattern defs and to their expansions.
   *  Populated during enterSyms, emptied during typer.
   */
  //lazy val expandedTree = new mutable.AnyRefMap[DefTree, Tree]
  /*{
    override def default(tree: DefTree) = tree // can't have defaults on AnyRefMaps :-(
  }*/

  /** A map from expanded MemberDef, PatDef or Import trees to their symbols.
   *  Populated during enterSyms, emptied at the point a typed tree
   *  with the same symbol is created (this can be when the symbol is completed
   *  or at the latest when the tree is typechecked.
   */
  //lazy val symOfTree = new mutable.AnyRefMap[Tree, Symbol]

  /** A map from expanded trees to their typed versions.
   *  Populated when trees are typechecked during completion (using method typedAhead).
   */
  // lazy val typedTree = new mutable.AnyRefMap[Tree, tpd.Tree]

  /** A map from method symbols to nested typers.
   *  Populated when methods are completed. Emptied when they are typechecked.
   *  The nested typer contains new versions of the four maps above including this
   *  one, so that trees that are shared between different DefDefs can be independently
   *  used as indices. It also contains a scope that contains nested parameters.
   */
  lazy val nestedTyper = new mutable.AnyRefMap[Symbol, Typer]

  /** The scope of the typer.
   *  For nested typers this is a place parameters are entered during completion
   *  and where they survive until typechecking. A context with this typer also
   *  has this scope.
   */
  val scope = newScope

  /** The symbol of the given expanded tree. */
  def symbolOfTree(tree: Tree)(implicit ctx: Context): Symbol = {
    val xtree = expanded(tree)
    xtree.getAttachment(TypedAhead) match {
      case Some(ttree) => ttree.symbol
      case none => xtree.attachment(SymOfTree)
    }
  }

  /** The enclosing class with given name; error if none exists */
  def enclosingClassNamed(name: TypeName, pos: Position)(implicit ctx: Context): Symbol = {
    if (name.isEmpty) NoSymbol
    else {
      val cls = ctx.owner.enclosingClassNamed(name)
      if (!cls.exists) ctx.error(s"no enclosing class or object is named $name", pos)
      cls
    }
  }

  /** Record `sym` as the symbol defined by `tree` */
  def recordSym(sym: Symbol, tree: Tree)(implicit ctx: Context): Symbol = {
    val refs = tree.attachmentOrElse(References, Nil)
    if (refs.nonEmpty) {
      tree.removeAttachment(References)
      refs foreach (_.pushAttachment(OriginalSymbol, sym))
    }
    tree.pushAttachment(SymOfTree, sym)
    sym
  }

  /** If this tree is a member def or an import, create a symbol of it
   *  and store in symOfTree map.
   */
  def createSymbol(tree: Tree)(implicit ctx: Context): Symbol = {

    def privateWithinClass(mods: Modifiers) =
      enclosingClassNamed(mods.privateWithin, mods.pos)

    def checkFlags(flags: FlagSet) =
      if (flags.isEmpty) flags
      else {
        val (ok, adapted, kind) = tree match {
          case tree: TypeDef => (flags.isTypeFlags, flags.toTypeFlags, "type")
          case _ => (flags.isTermFlags, flags.toTermFlags, "value")
        }
        if (!ok)
          ctx.error(i"modifier(s) `$flags' incompatible with $kind definition", tree.pos)
        adapted
      }

    /** Add moduleClass/sourceModule to completer if it is for a module val or class */
    def adjustIfModule(completer: LazyType, tree: MemberDef) =
      if (tree.mods is Module) ctx.adjustModuleCompleter(completer, tree.name.encode)
      else completer

    typr.println(i"creating symbol for $tree in ${ctx.mode}")

    def checkNoConflict(name: Name): Name = {
      def errorName(msg: => String) = {
        ctx.error(msg, tree.pos)
        name.freshened
      }
      def preExisting = ctx.effectiveScope.lookup(name)
      if (ctx.owner is PackageClass)
        if (preExisting.isDefinedInCurrentRun)
          errorName(s"${preExisting.showLocated} has already been compiled\nonce during this run")
        else name
      else
        if ((!ctx.owner.isClass || name.isTypeName) && preExisting.exists)
          errorName(i"$name is already defined as $preExisting")
        else name
    }

    val inSuperCall = if (ctx.mode is Mode.InSuperCall) InSuperCall else EmptyFlags

    tree match {
      case tree: TypeDef if tree.isClassDef =>
        val name = checkNoConflict(tree.name.encode).toTypeName
        val flags = checkFlags(tree.mods.flags &~ Implicit)
        val cls = recordSym(ctx.newClassSymbol(
          ctx.owner, name, flags | inSuperCall,
          cls => adjustIfModule(new ClassCompleter(cls, tree)(ctx), tree),
          privateWithinClass(tree.mods), tree.namePos, ctx.source.file), tree)
        cls.completer.asInstanceOf[ClassCompleter].init()
        cls
      case tree: MemberDef =>
        val name = checkNoConflict(tree.name.encode)
        val flags = checkFlags(tree.mods.flags)
        val isDeferred = lacksDefinition(tree)
        val deferred = if (isDeferred) Deferred else EmptyFlags
        val method = if (tree.isInstanceOf[DefDef]) Method else EmptyFlags
        val inSuperCall1 = if (tree.mods is ParamOrAccessor) EmptyFlags else inSuperCall
          // suppress inSuperCall for constructor parameters
        val higherKinded = tree match {
          case TypeDef(_, LambdaTypeTree(_, _)) if isDeferred => HigherKinded
          case _ => EmptyFlags
        }

        // to complete a constructor, move one context further out -- this
        // is the context enclosing the class. Note that the context in which a
        // constructor is recorded and the context in which it is completed are
        // different: The former must have the class as owner (because the
        // constructor is owned by the class), the latter must not (because
        // constructor parameters are interpreted as if they are outside the class).
        // Don't do this for Java constructors because they need to see the import
        // of the companion object, and it is not necessary for them because they
        // have no implementation.
        val cctx = if (tree.name == nme.CONSTRUCTOR && !(tree.mods is JavaDefined)) ctx.outer else ctx

        val completer = tree match {
          case tree: TypeDef => new TypeDefCompleter(tree)(cctx)
          case _ => new Completer(tree)(cctx)
        }

        recordSym(ctx.newSymbol(
          ctx.owner, name, flags | deferred | method | higherKinded | inSuperCall1,
          adjustIfModule(completer, tree),
          privateWithinClass(tree.mods), tree.namePos), tree)
      case tree: Import =>
        recordSym(ctx.newSymbol(
          ctx.owner, nme.IMPORT, Synthetic, new Completer(tree), NoSymbol, tree.pos), tree)
      case _ =>
        NoSymbol
    }
  }

   /** If `sym` exists, enter it in effective scope. Check that
    *  package members are not entered twice in the same run.
    */
  def enterSymbol(sym: Symbol)(implicit ctx: Context) = {
    if (sym.exists) {
      typr.println(s"entered: $sym in ${ctx.owner} and ${ctx.effectiveScope}")
      ctx.enter(sym)
    }
    sym
  }

  /** Create package if it does not yet exist. */
  private def createPackageSymbol(pid: RefTree)(implicit ctx: Context): Symbol = {
    val pkgOwner = pid match {
      case Ident(_) => if (ctx.owner eq defn.EmptyPackageClass) defn.RootClass else ctx.owner
      case Select(qual: RefTree, _) => createPackageSymbol(qual).moduleClass
    }
    val existing = pkgOwner.info.decls.lookup(pid.name)

    if ((existing is Package) && (pkgOwner eq existing.owner)) existing
    else {
      /** If there's already an existing type, then the package is a dup of this type */
      val existingType = pkgOwner.info.decls.lookup(pid.name.toTypeName)
      if (existingType.exists) {
        ctx.error(PkgDuplicateSymbol(existingType), pid.pos)
        ctx.newCompletePackageSymbol(pkgOwner, (pid.name ++ "$_error_").toTermName).entered
      }
      else ctx.newCompletePackageSymbol(pkgOwner, pid.name.asTermName).entered
    }
  }

  /** Expand tree and store in `expandedTree` */
  def expand(tree: Tree)(implicit ctx: Context): Unit = tree match {
    case mdef: DefTree =>
      val expanded = desugar.defTree(mdef)
      typr.println(i"Expansion: $mdef expands to $expanded")
      if (expanded ne mdef) mdef.pushAttachment(ExpandedTree, expanded)
    case _ =>
  }

  /** The expanded version of this tree, or tree itself if not expanded */
  def expanded(tree: Tree)(implicit ctx: Context): Tree = tree match {
    case ddef: DefTree => ddef.attachmentOrElse(ExpandedTree, ddef)
    case _ => tree
  }

  /** A new context that summarizes an import statement */
  def importContext(imp: Import, sym: Symbol)(implicit ctx: Context) = {
    val impNameOpt = imp.expr match {
      case ref: RefTree => Some(ref.name.asTermName)
      case _            => None
    }
    ctx.fresh.setImportInfo(new ImportInfo(implicit ctx => sym, imp.selectors, impNameOpt))
  }

  /** A new context for the interior of a class */
  def inClassContext(selfInfo: DotClass /* Should be Type | Symbol*/)(implicit ctx: Context): Context = {
    val localCtx: Context = ctx.fresh.setNewScope
    selfInfo match {
      case sym: Symbol if sym.exists && sym.name != nme.WILDCARD =>
        localCtx.scope.openForMutations.enter(sym)
      case _ =>
    }
    localCtx
  }

  /** For all class definitions `stat` in `xstats`: If the companion class if
    * not also defined in `xstats`, invalidate it by setting its info to
    * NoType.
    */
  def invalidateCompanions(pkg: Symbol, xstats: List[untpd.Tree])(implicit ctx: Context): Unit = {
    val definedNames = xstats collect { case stat: NameTree => stat.name }
    def invalidate(name: TypeName) =
      if (!(definedNames contains name)) {
        val member = pkg.info.decl(name).asSymDenotation
        if (member.isClass && !(member is Package)) member.info = NoType
      }
    xstats foreach {
      case stat: TypeDef if stat.isClassDef =>
        invalidate(stat.name.moduleClassName)
      case _ =>
    }
  }

  /** Expand tree and create top-level symbols for statement and enter them into symbol table */
  def index(stat: Tree)(implicit ctx: Context): Context = {
    expand(stat)
    indexExpanded(stat)
  }

  /** Create top-level symbols for all statements in the expansion of this statement and
   *  enter them into symbol table
   */
  def indexExpanded(origStat: Tree)(implicit ctx: Context): Context = {
    def recur(stat: Tree): Context = stat match {
      case pcl: PackageDef =>
        val pkg = createPackageSymbol(pcl.pid)
        index(pcl.stats)(ctx.fresh.setOwner(pkg.moduleClass))
        invalidateCompanions(pkg, Trees.flatten(pcl.stats map expanded))
        setDocstring(pkg, stat)
        ctx
      case imp: Import =>
        importContext(imp, createSymbol(imp))
      case mdef: DefTree =>
        val sym = enterSymbol(createSymbol(mdef))
        setDocstring(sym, origStat)
        addEnumConstants(mdef, sym)
        ctx
      case stats: Thicket =>
        stats.toList.foreach(recur)
        ctx
      case _ =>
        ctx
    }
    recur(expanded(origStat))
  }

  /** Determines whether this field holds an enum constant.
    * To qualify, the following conditions must be met:
    *  - The field's class has the ENUM flag set
    *  - The field's class extends java.lang.Enum
    *  - The field has the ENUM flag set
    *  - The field is static
    *  - The field is stable
    */
  def isEnumConstant(vd: ValDef)(implicit ctx: Context) = {
    // val ownerHasEnumFlag =
    // Necessary to check because scalac puts Java's static members into the companion object
    // while Scala's enum constants live directly in the class.
    // We don't check for clazz.superClass == JavaEnumClass, because this causes a illegal
    // cyclic reference error. See the commit message for details.
    //  if (ctx.compilationUnit.isJava) ctx.owner.companionClass.is(Enum) else ctx.owner.is(Enum)
    vd.mods.is(allOf(Enum,  Stable, JavaStatic, JavaDefined)) // && ownerHasEnumFlag
  }

  /** Add java enum constants */
  def addEnumConstants(mdef: DefTree, sym: Symbol)(implicit ctx: Context): Unit = mdef match {
    case vdef: ValDef if (isEnumConstant(vdef)) =>
      val enumClass = sym.owner.linkedClass
      if (!(enumClass is Flags.Sealed)) enumClass.setFlag(Flags.AbstractSealed)
      enumClass.addAnnotation(Annotation.makeChild(sym))
    case _ =>
  }


  def setDocstring(sym: Symbol, tree: Tree)(implicit ctx: Context) = tree match {
    case t: MemberDef if t.rawComment.isDefined =>
      ctx.docCtx.foreach(_.addDocstring(sym, t.rawComment))
    case _ => ()
  }

  /** Create top-level symbols for statements and enter them into symbol table */
  def index(stats: List[Tree])(implicit ctx: Context): Context = {

    // module name -> (stat, moduleCls | moduleVal)
    val moduleClsDef = mutable.Map[TypeName, (Tree, TypeDef)]()
    val moduleValDef = mutable.Map[TermName, (Tree, ValDef)]()

    /** Remove the subtree `tree` from the expanded tree of `mdef` */
    def removeInExpanded(mdef: Tree, tree: Tree): Unit = {
      val Thicket(trees) = expanded(mdef)
      mdef.putAttachment(ExpandedTree, Thicket(trees.filter(_ != tree)))
    }

    /** Merge the module class `modCls` in the expanded tree of `mdef` with the given stats */
    def mergeModuleClass(mdef: Tree, modCls: TypeDef, stats: List[Tree]): TypeDef = {
      var res: TypeDef = null
      val Thicket(trees) = expanded(mdef)
      val merged = trees.map { tree =>
        if (tree == modCls) {
          val impl = modCls.rhs.asInstanceOf[Template]
          res = cpy.TypeDef(modCls)(rhs = cpy.Template(impl)(body = stats ++ impl.body))
          res
        }
        else tree
      }

      mdef.putAttachment(ExpandedTree, Thicket(merged))

      res
    }

    /** Merge `fromCls` of `fromStat` into `toCls` of `toStat`
     *  if the former is synthetic and the latter not.
     *
     *  Note:
     *    1. `fromStat` and `toStat` could be the same stat
     *    2. `fromCls` and `toCls` are necessarily different
     */
    def mergeIfSynthetic(fromStat: Tree, fromCls: TypeDef, toStat: Tree, toCls: TypeDef): Unit =
      if (fromCls.mods.is(Synthetic) && !toCls.mods.is(Synthetic)) {
        removeInExpanded(fromStat, fromCls)
        val mcls = mergeModuleClass(toStat, toCls, fromCls.rhs.asInstanceOf[Template].body)
        moduleClsDef(fromCls.name) = (toStat, mcls)
      }

    /** Merge the definitions of a synthetic companion generated by a case class
     *  and the real companion, if both exist.
     */
    def mergeCompanionDefs() = {
      def valid(mdef: MemberDef): Boolean = mdef.mods.is(Module, butNot = Package)

      for (stat <- stats)
        expanded(stat) match {
          case Thicket(trees) => // companion object always expands to thickets
            trees.map {
              case mcls @ TypeDef(name, impl: Template) if valid(mcls) =>
                (moduleClsDef.get(name): @unchecked) match {
                  case Some((stat1, mcls1@TypeDef(_, impl1: Template))) =>
                    mergeIfSynthetic(stat, mcls, stat1, mcls1)
                    mergeIfSynthetic(stat1, mcls1, stat, mcls)
                  case None =>
                    moduleClsDef(name) = (stat, mcls)
                }

              case vdef @ ValDef(name, _, _) if valid(vdef) =>
                moduleValDef.get(name) match {
                  case Some((stat1, vdef1)) =>
                    if (vdef.mods.is(Synthetic) && !vdef1.mods.is(Synthetic))
                      removeInExpanded(stat, vdef)
                    else if (!vdef.mods.is(Synthetic) && vdef1.mods.is(Synthetic)) {
                      removeInExpanded(stat1, vdef1)
                      moduleValDef(name) = (stat, vdef)
                    }
                    else {
                      // double definition of objects or case classes, handled elsewhere
                    }
                  case None =>
                    moduleValDef(name) = (stat, vdef)
                }

              case _ =>
            }
          case _ =>
        }
    }

    /** Create links between companion object and companion class */
    def createLinks(classTree: TypeDef, moduleTree: TypeDef)(implicit ctx: Context) = {
      val claz = ctx.effectiveScope.lookup(classTree.name.encode)
      val modl = ctx.effectiveScope.lookup(moduleTree.name.encode)
      ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, claz, modl).entered
      ctx.synthesizeCompanionMethod(nme.COMPANION_MODULE_METHOD, modl, claz).entered
    }

    def createCompanionLinks(implicit ctx: Context): Unit = {
      val classDef  = mutable.Map[TypeName, TypeDef]()
      val moduleDef = mutable.Map[TypeName, TypeDef]()

      def updateCache(cdef: TypeDef): Unit = {
        if (!cdef.isClassDef || cdef.mods.is(Package)) return

        if (cdef.mods.is(ModuleClass)) moduleDef(cdef.name) = cdef
        else classDef(cdef.name) = cdef
      }

      for (stat <- stats)
        expanded(stat) match {
          case cdef : TypeDef => updateCache(cdef)
          case Thicket(trees) =>
            trees.map {
              case cdef: TypeDef => updateCache(cdef)
              case _ =>
            }
          case _ =>
        }

      for (cdef @ TypeDef(name, _) <- classDef.values) {
        moduleDef.getOrElse(name.moduleClassName, EmptyTree) match {
          case t: TypeDef =>
            createLinks(cdef, t)
          case EmptyTree =>
        }
      }

      // If a top-level object or class has no companion in the current run, we
      // enter a dummy companion (`denot.isAbsent` returns true) in scope. This
      // ensures that we never use a companion from a previous run or from the
      // classpath. See tests/pos/false-companion for an example where this
      // matters.
      if (ctx.owner.is(PackageClass)) {
        for (cdef @ TypeDef(moduleName, _) <- moduleDef.values) {
          val moduleSym = ctx.effectiveScope.lookup(moduleName.encode)
          if (moduleSym.isDefinedInCurrentRun) {
            val className = moduleName.stripModuleClassSuffix.toTypeName
            val classSym = ctx.effectiveScope.lookup(className.encode)
            if (!classSym.isDefinedInCurrentRun) {
              val absentClassSymbol = ctx.newClassSymbol(ctx.owner, className, EmptyFlags, _ => NoType)
              enterSymbol(absentClassSymbol)
            }
          }
        }
        for (cdef @ TypeDef(className, _) <- classDef.values) {
          val classSym = ctx.effectiveScope.lookup(className.encode)
          if (classSym.isDefinedInCurrentRun) {
            val moduleName = className.toTermName
            val moduleSym = ctx.effectiveScope.lookup(moduleName.encode)
            if (!moduleSym.isDefinedInCurrentRun) {
              val absentModuleSymbol = ctx.newModuleSymbol(ctx.owner, moduleName, EmptyFlags, EmptyFlags, (_, _) => NoType)
              enterSymbol(absentModuleSymbol)
            }
          }
        }
      }
    }

    stats.foreach(expand)
    mergeCompanionDefs()
    val ctxWithStats = (ctx /: stats) ((ctx, stat) => indexExpanded(stat)(ctx))
    createCompanionLinks(ctxWithStats)
    ctxWithStats
  }

  /** Add all annotations of definitions in `stats` to the defined symbols */
  def annotate(stats: List[Tree])(implicit ctx: Context): Unit = {
    def recur(stat: Tree): Unit = stat match {
      case pcl: PackageDef =>
        annotate(pcl.stats)
      case stat: untpd.MemberDef =>
        stat.getAttachment(SymOfTree) match {
          case Some(sym) =>
            sym.infoOrCompleter match {
              case info: Completer if !defn.isPredefClass(sym.owner) =>
                // Annotate Predef methods only when they are completed;
                // This is necessary to break a cyclic dependence between `Predef`
                // and `deprecated` in test `compileStdLib`.
                addAnnotations(sym, stat)(info.creationContext)
              case _ =>
                // Annotations were already added as part of the symbol's completion
            }
          case none =>
            assert(stat.typeOpt.exists, i"no symbol for $stat")
        }
      case stat: untpd.Thicket =>
        stat.trees.foreach(recur)
      case _ =>
    }

    for (stat <- stats) recur(expanded(stat))
  }

  /** Add annotations of `stat` to `sym`.
   *  This method can be called twice on a symbol (e.g. once
   *  during the `annotate` phase and then again during completion).
   *  Therefore, care needs to be taken not to add annotations again
   *  that are already added to the symbol.
   */
  def addAnnotations(sym: Symbol, stat: MemberDef)(implicit ctx: Context) = {
    // (1) The context in which an annotation of a top-level class or module is evaluated
    // is the closest enclosing context which has the enclosing package as owner.
    // (2) The context in which an annotation for any other symbol is evaluated is the
    // closest enclosing context which has the owner of the class enclosing the symbol as owner.
    // E.g in
    //
    //     package p
    //     import a.b
    //     class C {
    //       import d.e
    //       @ann m() ...
    //     }
    //
    // `@ann` is evaluated in the context just outside `C`, where the `a.b`
    // import is visible but the `d.e` import is forgotten. This measure is necessary
    // in order to avoid cycles.
    lazy val annotCtx = {
      var target = sym.owner.lexicallyEnclosingClass
      if (!target.is(PackageClass)) target = target.owner
      var c = ctx
      while (c.owner != target) c = c.outer
      c
    }
    for (annotTree <- untpd.modsDeco(stat).mods.annotations) {
      val cls = typedAheadAnnotation(annotTree)(annotCtx)
      if (sym.unforcedAnnotation(cls).isEmpty) {
        val ann = Annotation.deferred(cls, implicit ctx => typedAnnotation(annotTree))
        sym.addAnnotation(ann)
        if (cls == defn.InlineAnnot && sym.is(Method, butNot = Accessor))
          sym.setFlag(Inline)
      }
    }
  }

  def indexAndAnnotate(stats: List[Tree])(implicit ctx: Context): Context = {
    val localCtx = index(stats)
    annotate(stats)
    localCtx
  }

  /** The completer of a symbol defined by a member def or import (except ClassSymbols) */
  class Completer(val original: Tree)(implicit ctx: Context) extends LazyType {

    protected def localContext(owner: Symbol) = ctx.fresh.setOwner(owner).setTree(original)

    /** The context with which this completer was created */
    def creationContext = ctx

    protected def typeSig(sym: Symbol): Type = original match {
      case original: ValDef =>
        if (sym is Module) moduleValSig(sym)
        else valOrDefDefSig(original, sym, Nil, Nil, identity)(localContext(sym).setNewScope)
      case original: DefDef =>
        val typer1 = ctx.typer.newLikeThis
        nestedTyper(sym) = typer1
        typer1.defDefSig(original, sym)(localContext(sym).setTyper(typer1))
      case imp: Import =>
        try {
          val expr1 = typedAheadExpr(imp.expr, AnySelectionProto)
          ImportType(expr1)
        } catch {
          case ex: CyclicReference =>
            typr.println(s"error while completing ${imp.expr}")
            throw ex
        }
    }

    final override def complete(denot: SymDenotation)(implicit ctx: Context) = {
      if (completions != noPrinter && ctx.typerState != this.ctx.typerState) {
        completions.println(completions.getClass.toString)
        def levels(c: Context): Int =
          if (c.typerState eq this.ctx.typerState) 0
          else if (c.typerState == null) -1
          else if (c.outer.typerState == c.typerState) levels(c.outer)
          else levels(c.outer) + 1
        completions.println(s"!!!completing ${denot.symbol.showLocated} in buried typerState, gap = ${levels(ctx)}")
      }
      completeInCreationContext(denot)
    }

    private def addInlineInfo(denot: SymDenotation) = original match {
      case original: untpd.DefDef if denot.isInlineMethod =>
        Inliner.registerInlineInfo(
            denot,
            implicit ctx => typedAheadExpr(original).asInstanceOf[tpd.DefDef].rhs
          )(localContext(denot.symbol))
      case _ =>
    }

    /** Intentionally left without `implicit ctx` parameter. We need
     *  to pick up the context at the point where the completer was created.
     */
    def completeInCreationContext(denot: SymDenotation): Unit = {
      val sym = denot.symbol
      original match {
        case original: MemberDef => addAnnotations(sym, original)
        case _ =>
      }
      addInlineInfo(denot)
      denot.info = typeSig(sym)
      Checking.checkWellFormed(sym)
      denot.info = avoidPrivateLeaks(sym, sym.pos)
    }
  }

  class TypeDefCompleter(original: TypeDef)(ictx: Context) extends Completer(original)(ictx) with TypeParamsCompleter {
    private var myTypeParams: List[TypeSymbol] = null
    private var nestedCtx: Context = null
    assert(!original.isClassDef)

    def completerTypeParams(sym: Symbol)(implicit ctx: Context): List[TypeSymbol] = {
      if (myTypeParams == null) {
        //println(i"completing type params of $sym in ${sym.owner}")
        nestedCtx = localContext(sym).setNewScope
        myTypeParams = {
          implicit val ctx = nestedCtx
          val tparams = original.rhs match {
            case LambdaTypeTree(tparams, _) => tparams
            case _ => Nil
          }
          completeParams(tparams)
          tparams.map(symbolOfTree(_).asType)
        }
      }
      myTypeParams
    }

    override protected def typeSig(sym: Symbol): Type =
      typeDefSig(original, sym, completerTypeParams(sym)(ictx))(nestedCtx)
  }

  class ClassCompleter(cls: ClassSymbol, original: TypeDef)(ictx: Context) extends Completer(original)(ictx) {
    withDecls(newScope)

    protected implicit val ctx: Context = localContext(cls).setMode(ictx.mode &~ Mode.InSuperCall)

    val TypeDef(name, impl @ Template(constr, parents, self, _)) = original

    val (params, rest) = impl.body span {
      case td: TypeDef => td.mods is Param
      case vd: ValDef => vd.mods is ParamAccessor
      case _ => false
    }

    def init() = index(params)

    /** The type signature of a ClassDef with given symbol */
    override def completeInCreationContext(denot: SymDenotation): Unit = {

      /* The type of a parent constructor. Types constructor arguments
       * only if parent type contains uninstantiated type parameters.
       */
      def parentType(parent: untpd.Tree)(implicit ctx: Context): Type =
        if (parent.isType) {
          typedAheadType(parent, AnyTypeConstructorProto).tpe
        } else {
          val (core, targs) = stripApply(parent) match {
            case TypeApply(core, targs) => (core, targs)
            case core => (core, Nil)
          }
          val Select(New(tpt), nme.CONSTRUCTOR) = core
          val targs1 = targs map (typedAheadType(_))
          val ptype = typedAheadType(tpt).tpe appliedTo targs1.tpes
          if (ptype.typeParams.isEmpty) ptype
          else fullyDefinedType(typedAheadExpr(parent).tpe, "class parent", parent.pos)
        }

      /* Check parent type tree `parent` for the following well-formedness conditions:
       * (1) It must be a class type with a stable prefix (@see checkClassTypeWithStablePrefix)
       * (2) If may not derive from itself
       * (3) The class is not final
       * (4) If the class is sealed, it is defined in the same compilation unit as the current class
       */
      def checkedParentType(parent: untpd.Tree): Type = {
        val ptype = parentType(parent)(ctx.superCallContext)
        if (cls.isRefinementClass) ptype
        else {
          val pt = checkClassType(ptype, parent.pos,
              traitReq = parent ne parents.head, stablePrefixReq = true)
          if (pt.derivesFrom(cls)) {
            val addendum = parent match {
              case Select(qual: Super, _) if ctx.scala2Mode =>
                "\n(Note that inheriting a class of the same name is no longer allowed)"
              case _ => ""
            }
            ctx.error(i"cyclic inheritance: $cls extends itself$addendum", parent.pos)
            defn.ObjectType
          }
          else {
            val pclazz = pt.typeSymbol
            if (pclazz.is(Final))
              ctx.error(em"cannot extend final $pclazz", cls.pos)
            if (pclazz.is(Sealed) && pclazz.associatedFile != cls.associatedFile)
              ctx.error(em"cannot extend sealed $pclazz in different compilation unit", cls.pos)
            pt
          }
        }
      }

     addAnnotations(denot.symbol, original)

      val selfInfo =
        if (self.isEmpty) NoType
        else if (cls.is(Module)) {
          val moduleType = cls.owner.thisType select sourceModule
          if (self.name == nme.WILDCARD) moduleType
          else recordSym(
            ctx.newSymbol(cls, self.name, self.mods.flags, moduleType, coord = self.pos),
            self)
        }
        else createSymbol(self)

      // pre-set info, so that parent types can refer to type params
      val tempInfo = new TempClassInfo(cls.owner.thisType, cls, decls, selfInfo)
      denot.info = tempInfo

      // Ensure constructor is completed so that any parameter accessors
      // which have type trees deriving from its parameters can be
      // completed in turn. Note that parent types access such parameter
      // accessors, that's why the constructor needs to be completed before
      // the parent types are elaborated.
      index(constr)
      annotate(constr :: params)
      symbolOfTree(constr).ensureCompleted()

      indexAndAnnotate(rest)(inClassContext(selfInfo))

      val parentTypes = ensureFirstIsClass(parents.map(checkedParentType(_)))
      val parentRefs = ctx.normalizeToClassRefs(parentTypes, cls, decls)
      typr.println(s"completing $denot, parents = $parents, parentTypes = $parentTypes, parentRefs = $parentRefs")

      tempInfo.finalize(denot, parentRefs)

      Checking.checkWellFormed(cls)
      if (isDerivedValueClass(cls)) cls.setFlag(Final)
      cls.info = avoidPrivateLeaks(cls, cls.pos)
    }
  }

  /** Typecheck `tree` during completion using `typed`, and remember result in TypedAhead map */
  def typedAheadImpl(tree: Tree, typed: untpd.Tree => tpd.Tree)(implicit ctx: Context): tpd.Tree = {
    val xtree = expanded(tree)
    xtree.getAttachment(TypedAhead) match {
      case Some(ttree) => ttree
      case none =>
        val ttree = typed(tree)
        xtree.putAttachment(TypedAhead, ttree)
        ttree
    }
  }

  def typedAheadType(tree: Tree, pt: Type = WildcardType)(implicit ctx: Context): tpd.Tree =
    typedAheadImpl(tree, typer.typed(_, pt)(ctx retractMode Mode.PatternOrType addMode Mode.Type))

  def typedAheadExpr(tree: Tree, pt: Type = WildcardType)(implicit ctx: Context): tpd.Tree =
    typedAheadImpl(tree, typer.typed(_, pt)(ctx retractMode Mode.PatternOrType))

  def typedAheadAnnotation(tree: Tree)(implicit ctx: Context): Symbol = tree match {
    case Apply(fn, _) => typedAheadAnnotation(fn)
    case TypeApply(fn, _) => typedAheadAnnotation(fn)
    case Select(qual, nme.CONSTRUCTOR) => typedAheadAnnotation(qual)
    case New(tpt) => typedAheadType(tpt).tpe.classSymbol
  }

  /** Enter and typecheck parameter list */
  def completeParams(params: List[MemberDef])(implicit ctx: Context) = {
    indexAndAnnotate(params)
    for (param <- params) typedAheadExpr(param)
  }

  /** The signature of a module valdef.
   *  This will compute the corresponding module class TypeRef immediately
   *  without going through the defined type of the ValDef. This is necessary
   *  to avoid cyclic references involving imports and module val defs.
   */
  def moduleValSig(sym: Symbol)(implicit ctx: Context): Type = {
    val clsName = sym.name.moduleClassName
    val cls = ctx.denotNamed(clsName) suchThat (_ is ModuleClass)
    ctx.owner.thisType select (clsName, cls)
  }

  /** The type signature of a ValDef or DefDef
   *  @param mdef     The definition
   *  @param sym      Its symbol
   *  @param paramFn  A wrapping function that produces the type of the
   *                  defined symbol, given its final return type
   */
  def valOrDefDefSig(mdef: ValOrDefDef, sym: Symbol, typeParams: List[Symbol], paramss: List[List[Symbol]], paramFn: Type => Type)(implicit ctx: Context): Type = {

    def inferredType = {
      /** A type for this definition that might be inherited from elsewhere:
       *  If this is a setter parameter, the corresponding getter type.
       *  If this is a class member, the conjunction of all result types
       *  of overridden methods.
       *  NoType if neither case holds.
       */
      val inherited =
        if (sym.owner.isTerm) NoType
        else {
          // TODO: Look only at member of supertype instead?
          lazy val schema = paramFn(WildcardType)
          val site = sym.owner.thisType
          ((NoType: Type) /: sym.owner.info.baseClasses.tail) { (tp, cls) =>
            def instantiatedResType(info: Type, tparams: List[Symbol], paramss: List[List[Symbol]]): Type = info match {
              case info: PolyType =>
                if (info.paramNames.length == typeParams.length)
                  instantiatedResType(info.instantiate(tparams.map(_.typeRef)), Nil, paramss)
                else NoType
              case info: MethodType =>
                paramss match {
                  case params :: paramss1 if info.paramNames.length == params.length =>
                    instantiatedResType(info.instantiate(params.map(_.termRef)), tparams, paramss1)
                  case _ =>
                    NoType
                }
              case _ =>
                if (tparams.isEmpty && paramss.isEmpty) info.widenExpr
                else NoType
            }
            val iRawInfo =
              cls.info.nonPrivateDecl(sym.name).matchingDenotation(site, schema).info
            val iResType = instantiatedResType(iRawInfo, typeParams, paramss).asSeenFrom(site, cls)
            if (iResType.exists)
              typr.println(i"using inherited type for ${mdef.name}; raw: $iRawInfo, inherited: $iResType")
            tp & iResType
          }
        }

      /** The proto-type to be used when inferring the result type from
       *  the right hand side. This is `WildcardType` except if the definition
       *  is a default getter. In that case, the proto-type is the type of
       *  the corresponding parameter where bound parameters are replaced by
       *  Wildcards.
       */
      def rhsProto = sym.asTerm.name collect {
        case DefaultGetterName(original, idx) =>
          val meth: Denotation =
            if (original.isConstructorName && (sym.owner is ModuleClass))
              sym.owner.companionClass.info.decl(nme.CONSTRUCTOR)
            else
              ctx.defContext(sym).denotNamed(original)
          def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match {
            case params :: paramss1 =>
              if (idx < params.length) wildApprox(params(idx), null, Set.empty)
              else paramProto(paramss1, idx - params.length)
            case nil =>
              WildcardType
          }
          val defaultAlts = meth.altsWith(_.hasDefaultParams)
          if (defaultAlts.length == 1)
            paramProto(defaultAlts.head.info.widen.paramInfoss, idx)
          else
            WildcardType
      } getOrElse WildcardType

      // println(s"final inherited for $sym: ${inherited.toString}") !!!
      // println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}")
      def isInline = sym.is(FinalOrInline, butNot = Method | Mutable)

      // Widen rhs type and approximate `|' but keep ConstantTypes if
      // definition is inline (i.e. final in Scala2) and keep module singleton types
      // instead of widening to the underlying module class types.
      def widenRhs(tp: Type): Type = tp.widenTermRefExpr match {
        case ctp: ConstantType if isInline => ctp
        case ref: TypeRef if ref.symbol.is(ModuleClass) => tp
        case _ => ctx.harmonizeUnion(tp.widen)
      }

      // Replace aliases to Unit by Unit itself. If we leave the alias in
      // it would be erased to BoxedUnit.
      def dealiasIfUnit(tp: Type) = if (tp.isRef(defn.UnitClass)) defn.UnitType else tp

      val rhsCtx = ctx.addMode(Mode.InferringReturnType)
      def rhsType = typedAheadExpr(mdef.rhs, inherited orElse rhsProto)(rhsCtx).tpe
      def cookedRhsType = ctx.deskolemize(dealiasIfUnit(widenRhs(rhsType)))
      lazy val lhsType = fullyDefinedType(cookedRhsType, "right-hand side", mdef.pos)
      //if (sym.name.toString == "y") println(i"rhs = $rhsType, cooked = $cookedRhsType")
      if (inherited.exists)
        if (sym.is(Final, butNot = Method) && lhsType.isInstanceOf[ConstantType])
          lhsType // keep constant types that fill in for a non-constant (to be revised when inline has landed).
        else inherited
      else {
        def missingType(modifier: String) = {
          ctx.error(s"${modifier}type of implicit definition needs to be given explicitly", mdef.pos)
          sym.resetFlag(Implicit)
        }
        if (sym is Implicit)
          mdef match {
            case _: DefDef => missingType("result")
            case _: ValDef if sym.owner.isType => missingType("")
            case _ =>
          }
        lhsType orElse WildcardType
      }
    }

    val tptProto = mdef.tpt match {
      case _: untpd.DerivedTypeTree =>
        WildcardType
      case TypeTree() =>
        inferredType
      case TypedSplice(tpt: TypeTree) if !isFullyDefined(tpt.tpe, ForceDegree.none) =>
        val rhsType = typedAheadExpr(mdef.rhs, tpt.tpe).tpe
        mdef match {
          case mdef: DefDef if mdef.name == nme.ANON_FUN =>
            val hygienicType = avoid(rhsType, paramss.flatten)
            if (!(hygienicType <:< tpt.tpe))
              ctx.error(i"return type ${tpt.tpe} of lambda cannot be made hygienic;\n" +
                i"it is not a supertype of the hygienic type $hygienicType", mdef.pos)
            //println(i"lifting $rhsType over $paramss -> $hygienicType = ${tpt.tpe}")
            //println(TypeComparer.explained { implicit ctx => hygienicType <:< tpt.tpe })
          case _ =>
        }
        WildcardType
      case _ =>
        WildcardType
    }
    paramFn(typedAheadType(mdef.tpt, tptProto).tpe)
  }

  /** The type signature of a DefDef with given symbol */
  def defDefSig(ddef: DefDef, sym: Symbol)(implicit ctx: Context) = {
    val DefDef(name, tparams, vparamss, _, _) = ddef
    val isConstructor = name == nme.CONSTRUCTOR

    // The following 3 lines replace what was previously just completeParams(tparams).
    // But that can cause bad bounds being computed, as witnessed by
    // tests/pos/paramcycle.scala. The problematic sequence is this:
    //   0. Class constructor gets completed.
    //   1. Type parameter CP of constructor gets completed
    //   2. As a first step CP's bounds are set to Nothing..Any.
    //   3. CP's real type bound demands the completion of corresponding type parameter DP
    //      of enclosing class.
    //   4. Type parameter DP has a rhs a DerivedFromParam tree, as installed by
    //      desugar.classDef
    //   5. The completion of DP then copies the current bounds of CP, which are still Nothing..Any.
    //   6. The completion of CP finishes installing the real type bounds.
    // Consequence: CP ends up with the wrong bounds!
    // To avoid this we always complete type parameters of a class before the type parameters
    // of the class constructor, but after having indexed the constructor parameters (because
    // indexing is needed to provide a symbol to copy for DP's completion.
    // With the patch, we get instead the following sequence:
    //   0. Class constructor gets completed.
    //   1. Class constructor parameter CP is indexed.
    //   2. Class parameter DP starts completion.
    //   3. Info of CP is computed (to be copied to DP).
    //   4. CP is completed.
    //   5. Info of CP is copied to DP and DP is completed.
    indexAndAnnotate(tparams)
    if (isConstructor) sym.owner.typeParams.foreach(_.ensureCompleted())
    for (tparam <- tparams) typedAheadExpr(tparam)

    vparamss foreach completeParams
    def typeParams = tparams map symbolOfTree
    val paramSymss = ctx.normalizeIfConstructor(vparamss.nestedMap(symbolOfTree), isConstructor)
    def wrapMethType(restpe: Type): Type = {
      val restpe1 = // try to make anonymous functions non-dependent, so that they can be used in closures
        if (name == nme.ANON_FUN) avoid(restpe, paramSymss.flatten)
        else restpe
      ctx.methodType(tparams map symbolOfTree, paramSymss, restpe1, isJava = ddef.mods is JavaDefined)
    }
    if (isConstructor) {
      // set result type tree to unit, but take the current class as result type of the symbol
      typedAheadType(ddef.tpt, defn.UnitType)
      wrapMethType(ctx.effectiveResultType(sym, typeParams, NoType))
    }
    else valOrDefDefSig(ddef, sym, typeParams, paramSymss, wrapMethType)
  }

  def typeDefSig(tdef: TypeDef, sym: Symbol, tparamSyms: List[TypeSymbol])(implicit ctx: Context): Type = {
    def abstracted(tp: Type): Type = HKTypeLambda.fromParams(tparamSyms, tp)
    val dummyInfo = abstracted(TypeBounds.empty)
    sym.info = dummyInfo
      // Temporarily set info of defined type T to ` >: Nothing <: Any.
      // This is done to avoid cyclic reference errors for F-bounds.
      // This is subtle: `sym` has now an empty TypeBounds, but is not automatically
      // made an abstract type. If it had been made an abstract type, it would count as an
      // abstract type of its enclosing class, which might make that class an invalid
      // prefix. I verified this would lead to an error when compiling io.ClassPath.
      // A distilled version is in pos/prefix.scala.
      //
      // The scheme critically relies on an implementation detail of isRef, which
      // inspects a TypeRef's info, instead of simply dealiasing alias types.

    val isDerived = tdef.rhs.isInstanceOf[untpd.DerivedTypeTree]
    val rhs = tdef.rhs match {
      case LambdaTypeTree(_, body) => body
      case rhs => rhs
    }
    val rhsBodyType = typedAheadType(rhs).tpe
    val rhsType = if (isDerived) rhsBodyType else abstracted(rhsBodyType)
    val unsafeInfo = rhsType match {
      case bounds: TypeBounds => bounds
      case alias => TypeAlias(alias, if (sym is Local) sym.variance else 0)
    }
    if (isDerived) sym.info = unsafeInfo
    else {
      sym.info = NoCompleter
      sym.info = checkNonCyclic(sym, unsafeInfo, reportErrors = true)
    }

    // Here we pay the price for the cavalier setting info to TypeBounds.empty above.
    // We need to compensate by invalidating caches in references that might
    // still contain the TypeBounds.empty. If we do not do this, stdlib factories
    // fail with a bounds error in PostTyper.
    def ensureUpToDate(tp: Type, outdated: Type) = tp match {
      case tref: TypeRef if tref.info == outdated && sym.info != outdated =>
        tref.uncheckedSetSym(null)
      case _ =>
    }
    ensureUpToDate(sym.typeRef, dummyInfo)
    ensureUpToDate(sym.typeRef.appliedTo(tparamSyms.map(_.typeRef)), TypeBounds.empty)
    sym.info
  }
}