aboutsummaryrefslogblamecommitdiff
path: root/src/dotty/tools/dotc/typer/Namer.scala
blob: e9195a072eafc766fa055ee34cdb5dea45429d98 (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._
import Contexts._, Symbols._, Types._, SymDenotations._, Names._, NameOps._, Flags._, Decorators._
import ast.desugar, ast.desugar._
import ProtoTypes._
import util.Positions._
import util.{Attachment, SourcePosition, DotClass}
import collection.mutable
import annotation.tailrec
import ErrorReporting._
import tpd.ListOfTreeDecorator
import config.Printers._
import language.implicitConversions

trait NamerContextOps { this: Context =>

  /** 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.asInstanceOf[MutableScope].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.asInstanceOf[MutableScope].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.decls
    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
}

/** 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 Attachment.Key[tpd.Tree]
  val ExpandedTree = new Attachment.Key[Tree]
  val SymOfTree = new Attachment.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
    }
  }

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

  /** 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 record(sym: Symbol): Symbol = {
      val refs = tree.attachmentOrElse(References, Nil)
      if (refs.nonEmpty) {
        tree.removeAttachment(References)
        refs foreach (_.pushAttachment(OriginalSymbol, sym))
      }
      tree.pushAttachment(SymOfTree, sym)
      sym
    }

    /** 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) {
        val name = tree.name.encode
        if (name.isTermName)
          completer withModuleClass (_ => findModuleBuddy(name.moduleClassName))
        else
          completer withSourceModule (_ => findModuleBuddy(name.sourceModuleName))
      }
      else completer

    typr.println(i"creating symbol for $tree")

    def checkNoConflict(name: Name): Unit = {
      def preExisting = ctx.effectiveScope.lookup(name)
      if (ctx.owner is PackageClass) {
        if (preExisting.isDefinedInCurrentRun)
          ctx.error(s"${preExisting.showLocated} is compiled twice, runid = ${ctx.runId}", tree.pos)
        }
      else if ((!ctx.owner.isClass || name.isTypeName) && preExisting.exists) {
        ctx.error(i"$name is already defined as $preExisting", tree.pos)
      }
    }

    tree match {
      case tree: TypeDef if tree.isClassDef =>
        val name = tree.name.encode.asTypeName
        checkNoConflict(name)
        val cls = record(ctx.newClassSymbol(
          ctx.owner, name, tree.mods.flags,
          cls => adjustIfModule(new ClassCompleter(cls, tree)(ctx), tree),
          privateWithinClass(tree.mods), tree.pos, ctx.source.file))
        cls.completer.asInstanceOf[ClassCompleter].init()
        cls
      case tree: MemberDef =>
        val name = tree.name.encode
        checkNoConflict(name)
        val deferred = if (lacksDefinition(tree)) Deferred else EmptyFlags
        val method = if (tree.isInstanceOf[DefDef]) Method else 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).
        val cctx = if (tree.name == nme.CONSTRUCTOR) ctx.outer else ctx

        record(ctx.newSymbol(
          ctx.owner, name, tree.mods.flags | deferred | method,
          adjustIfModule(new Completer(tree)(cctx), tree),
          privateWithinClass(tree.mods), tree.pos))
      case tree: Import =>
        record(ctx.newSymbol(
          ctx.owner, nme.IMPORT, Synthetic, new Completer(tree), NoSymbol, tree.pos))
      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 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(sym: Symbol, selectors: List[Tree])(implicit ctx: Context) =
    ctx.fresh.setImportInfo(new ImportInfo(sym, selectors))

  /** 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.asInstanceOf[MutableScope].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(stat: Tree)(implicit ctx: Context): Context = expanded(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))
      ctx
    case imp: Import =>
      importContext(createSymbol(imp), imp.selectors)
    case mdef: DefTree =>
      enterSymbol(createSymbol(mdef))
      ctx
    case stats: Thicket =>
      for (tree <- stats.toList) enterSymbol(createSymbol(tree))
      ctx
    case _ =>
      ctx
  }

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

    /** Merge the definitions of a synthetic companion generated by a case class
     *  and the real companion, if both exist.
     */
    def mergeCompanionDefs() = {
      val classDef = mutable.Map[TypeName, TypeDef]()
      for (cdef @ TypeDef(mods, name, _) <- stats)
        if (cdef.isClassDef) classDef(name) = cdef
      for (mdef @ ModuleDef(_, name, _) <- stats)
        classDef get name.toTypeName match {
          case Some(cdef) =>
            val Thicket(vdef :: (mcls @ TypeDef(_, _, impl: Template)) :: Nil) = mdef.attachment(ExpandedTree)
            cdef.attachmentOrElse(ExpandedTree, cdef) match {
              case Thicket(cls :: mval :: TypeDef(_, _, compimpl: Template) :: crest) =>
                val mcls1 = cpy.TypeDef(mcls, mcls.mods, mcls.name,
                    cpy.Template(impl, impl.constr, impl.parents, impl.self,
                        compimpl.body ++ impl.body))
                mdef.putAttachment(ExpandedTree, Thicket(vdef :: mcls1 :: Nil))
                cdef.putAttachment(ExpandedTree, Thicket(cls :: crest))
              case _ =>
            }
          case none =>
        }
    }

    stats foreach expand
    mergeCompanionDefs()
    (ctx /: stats) ((ctx, stat) => indexExpanded(stat)(ctx))
  }

  /** 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)

    private def typeSig(sym: Symbol): Type = original match {
      case original: ValDef =>
        if (sym is Module) moduleValSig(sym)
        else valOrDefDefSig(original, sym, Nil, identity)(localContext(sym).setNewScope)
      case original: DefDef =>
        val typer1 = new Typer
        nestedTyper(sym) = typer1
        typer1.defDefSig(original, sym)(localContext(sym).setTyper(typer1))
      case original: TypeDef =>
        assert(!original.isClassDef)
        typeDefSig(original, sym)(localContext(sym).setNewScope)
      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)
    }

    def completeInCreationContext(denot: SymDenotation): Unit =
      denot.info = typeSig(denot.symbol)
  }

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

    protected implicit val ctx: Context = localContext(cls)

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

    val (params, rest) = body span {
      case td: TypeDef => td.mods is Param
      case td: ValDef => td.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).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.uninstantiatedTypeParams.isEmpty) ptype
          else typedAheadExpr(parent).tpe
        }

      def checkedParentType(parent: untpd.Tree): Type = {
        val ptype = parentType(parent)(ctx.fresh addMode Mode.InSuperCall)
        checkClassTypeWithStablePrefix(ptype, parent.pos, traitReq = parent ne parents.head)
      }

      val selfInfo =
        if (self.isEmpty) NoType
        else if (cls is Module) cls.owner.thisType select sourceModule
        else createSymbol(self)

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

      // 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)
      symbolOfTree(constr).ensureCompleted()

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

      index(rest)(inClassContext(selfInfo))
      denot.info = ClassInfo(cls.owner.thisType, cls, parentRefs, decls, selfInfo)
    }
  }

  /** Typecheck tree during completion, and remember result in typedtree map */
  private def typedAheadImpl(tree: Tree, pt: Type)(implicit ctx: Context): tpd.Tree = {
    val xtree = expanded(tree)
    xtree.getAttachment(TypedAhead) match {
      case Some(ttree) => ttree
      case none =>
        val ttree = typer.typed(tree, pt)
        xtree.pushAttachment(TypedAhead, ttree)
        ttree
    }
  }

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

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

  /** Enter and typecheck parameter list */
  def completeParams(params: List[MemberDef])(implicit ctx: Context) = {
    index(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], 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) =>
            val iRawInfo =
              cls.info.nonPrivateDecl(sym.name).matchingDenotation(site, schema).info
            val iInstInfo = iRawInfo match {
              case iRawInfo: PolyType =>
                if (iRawInfo.paramNames.length == typeParams.length)
                  iRawInfo.instantiate(typeParams map (_.typeRef))
                else NoType
              case _ =>
                if (typeParams.isEmpty) iRawInfo
                else NoType
            }
            val iResType = iInstInfo.finalResultType.asSeenFrom(site, cls)
            if (iResType.exists)
              typr.println(s"using inherited type; raw: $iRawInfo, inst: $iInstInfo, 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 = {
        val name = sym.asTerm.name
        val idx = name.defaultGetterIndex
        if (idx < 0) WildcardType
        else {
          val original = name.defaultGetterToMethod
          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))
              else paramProto(paramss1, idx - params.length)
            case nil =>
              WildcardType
          }
          val defaultAlts = meth.altsWith(_.hasDefaultParams)
          if (defaultAlts.length == 1)
            paramProto(defaultAlts.head.info.widen.paramTypess, idx)
          else
            WildcardType
        }
      }

      // println(s"final inherited for $sym: ${inherited.toString}") !!!
      // println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}")
      val rhsCtx = ctx.fresh addMode Mode.InferringReturnType
      def rhsType = typedAheadExpr(mdef.rhs, rhsProto)(rhsCtx).tpe.widen.approximateUnion
      def lhsType = fullyDefinedType(rhsType, "right-hand side", mdef.pos)
      if (inherited.exists) inherited
      else {
        if (sym is Implicit) {
          val resStr = if (mdef.isInstanceOf[DefDef]) "result " else ""
          ctx.error(d"${resStr}type of implicit definition needs to be given explicitly", mdef.pos)
          sym.resetFlag(Implicit)
        }
        lhsType orElse WildcardType
      }
    }

    val pt = mdef.tpt match {
      case _: untpd.DerivedTypeTree => WildcardType
      case TypeTree(untpd.EmptyTree) => inferredType
      case _ => WildcardType
    }
    paramFn(typedAheadType(mdef.tpt, pt).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
    completeParams(tparams)
    vparamss foreach completeParams
    val isConstructor = name == nme.CONSTRUCTOR
    val isSecondaryConstructor = isConstructor && sym != sym.owner.primaryConstructor
    def typeParams =
      if (isSecondaryConstructor) sym.owner.primaryConstructor.typeParams
      else tparams map symbolOfTree
    def wrapMethType(restpe: Type): Type = {
      var paramSymss = vparamss.nestedMap(symbolOfTree)
      // Make sure constructor has one non-implicit parameter list
      if (isConstructor &&
          (paramSymss.isEmpty || paramSymss.head.nonEmpty && (paramSymss.head.head is Implicit)))
        paramSymss = Nil :: paramSymss
      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
      val monotpe =
        (paramSymss :\ restpe1) { (params, restpe) =>
          val make =
            if (params.nonEmpty && (params.head is Implicit)) ImplicitMethodType
            else MethodType
          make.fromSymbols(params, restpe)
        }
      if (typeParams.nonEmpty) PolyType.fromSymbols(typeParams, monotpe)
      else if (vparamss.isEmpty) ExprType(monotpe)
      else monotpe
    }
    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(sym.owner.typeRef.appliedTo(typeParams map (_.typeRef)))
    }
    else valOrDefDefSig(ddef, sym, typeParams, wrapMethType)
  }

  def typeDefSig(tdef: TypeDef, sym: Symbol)(implicit ctx: Context): Type = {
    completeParams(tdef.tparams)
    sym.info = TypeBounds.empty // avoid cyclic reference errors for F-bounds
    val tparamSyms = tdef.tparams map symbolOfTree
    val rhsType = typedAheadType(tdef.rhs).tpe

    rhsType match {
      case bounds: TypeBounds =>
        if (tparamSyms.nonEmpty) bounds.higherKinded(tparamSyms)
        else rhsType
      case _ =>
        val abstractedRhsType =
          if (tparamSyms.nonEmpty) rhsType.LambdaAbstract(tparamSyms)(ctx.error(_, _))
          else rhsType
        TypeAlias(abstractedRhsType, if (sym is Local) sym.variance else 0)
    }
  }
}