aboutsummaryrefslogblamecommitdiff
path: root/src/dotty/tools/dotc/typer/Typer.scala
blob: bb3e1052a7d5b605919cc312f7ff52fff20d90b5 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11





                   




                    
                    



                       
                    



                   
                       
                                                                  
                             


                          
                         
                  
                       



                                         

              
                          
 







                                                                           
 
                                            
                                                                     



                                                           






                                                       
 
 
                                                            
 
                

                          
 


                                                           

                                                                             


                                                   
                                                                                           


                                                  

                                                        
                            
                  

                                                                           



               





                                                                                             
                                                                                      
                                              
                              
                                                                                         

     













                                                                                                                
                                                              



                                                                     
                                                                
                 




                                                                                        


             
 














                                                                                                          






                                                                                
                                                                                                  

                        




                                                                        











                                                                              








                                                                     








                                                                                                   
                                                                
       
 















                                                                                                 
                                                                                                        
                                                        







                                                                      
                  
                                                  












                                                                                          


                                                                              

               
                                  
                         
                                                        
                                                                 
                                     
                                                                 







                                                                                   
                                
         
                                                  

                                                                             



                                                                          
         

              









                                                                                           
                                     

                             

                                                                       
                                 
                                    
                                       


                                                                                                            





                                                                                                                    
                                                                                         




                                                                                              
                                                  








                                                                                             

                                                                   





                                                                                       
 

                                
 








                                                               
                                            


                                               

   
                                                                                                     
                                                                        


                                                        

   
                                                                                     



                                                                 
                                                                                        







                                                                                      
                                                                         

                                                                
     




                                                                           
                                                                          

   
                                                                                        






                                          
   
 












                                                                                      

   
                                                                                         
                                                     
                                                             



                                              
                                                                                                   

   









                                                                                                    

   
                                                                                                     
                                  
                                                          

   




























                                                                                                 

   
                                                                                            
                                   




                                                                                      
                                     

                                                                                  


                                                                                                  

   
                                                                                   

                                                  
                                                                               


                                                                         
                                                                                                     






                                                                                
                                                               











                                                              
                                                   
                                                                 


                                                                                           
     

   
                                                                                                  
                                              
                                         



                                               
                                                                                                  
                
                                                                           
     
                                                               

   





                                                                                            
                                                                              

                                                                            
                                                           














                                                                                                          
 






                                                                               
                       
             


                                                                    
           


                                                                                   
         
 

                                                                                 
     

   
                                                                                             

                                                                      
                                                     




                                 




                                                                  
                                                                                          


                          







                                                                                         
                                                                                           









                                                                                        
                                                                                         



                                                    
                                                                                                                       
                                                
                                                          
                                                                           

   
                                                                                                               

                                                    

                                  
                              
                                         
                                 
                              






                                                  
                                                                                                                                         




                                                       
                                                                                                                                                       
                                                                        


                                                                                              
                                                                                                                 




                                                                        
                                                                                                             

                                  


                                                                       
                                                                                                                                 

                                                       
                                                      





                                                                                                   
                                                                          




                                                                                       
                                                           




                                                          
                                                                                                                                 
                              
                                                

                                       
                                                                                               



                                                                                  
                                                                                                                             


                               
                                                                                               


                                                                            
                                                                                               




                                                                                              
                                                                                                                           
                                                      
                                                                            

   
                                                                                                         

                                                                      
                                                                

   
                                                                                                  
                                                      
   
 
                                                                                                  
                                           


                                       

                                                               

   
                                                                                                  
                                                              

                                                                       
                                                                                       

                                       
                                                                                       
                                                                                         

   
                                                                                                              
                                       
                                    
                             
                                                             

   
                                                                                                            
                                                                                
                                    
                                                    
                                                 
                                                
                                                     
                                                                          

                                                                   
 
                                                              







                                                          

   
                                                                                                         
                                                      
                                                              

   
                                                                                                              








                                                                        
                                                                                                       
                                                     
                         
                        

                                                             
                                                    

           
                                                                 


                                                                                
















                                                                                                    
                                                                  







                                                                               
 








                                                               
                                                                       

























                                                                                   
 



                                                                                    
     
   
 
                                                                                                                                               

                                                         

                                                               

   

                                                                              
 






                                                                                                       
                                           






                                        

                                    
                          

                                                                                           






                      
                                                                                         
                                                       
                                                                                         



                                                                                            
                                                                                           


                                               
                                                      





                                   
                                                                                                           
               
                                                                                       


              
 




                                                                          


                                                                                                   
 

































                                                                                                      
                                                                                                                                                                
 

                     

                                                  
                                         

                                            
                                                                                 
                                               



                                         
                         
                           
                                                                 
                                                    



                                                                                      
                    






                                                                    

                    
                         
                                                                                  
                                                       


       
                                                          
                                
                                          



                                     
                                                                         
       

     



                                                



                                                      
                                                                                   








                                                                                                             
         
                                                    
                                                                

                                                                    

                                        


                                         
                                                

                                                                                                                   
                                 
                                                                               
                                

     
                                           



                                                     
                                  



                                                          
                                                                  

                              
                                                                        



                                                                          
       
                                   
                                 




                                                  
       

     





                                                                               
                                              
                



                                                             

                                                                       
                   
                    
                                                     




                                               

           
     
    
 
package dotty.tools
package dotc
package typer

import core._
import ast._
import Trees._
import Constants._
import StdNames._
import Scopes._
import Denotations._
import Inferencing._
import Contexts._
import Symbols._
import Types._
import SymDenotations._
import Annotations._
import Names._
import NameOps._
import Flags._
import Decorators._
import ErrorReporting._
import Inferencing.{FunProto, PolyProto, Compatibility, normalize}
import EtaExpansion.etaExpand
import util.Positions._
import util.SourcePosition
import collection.mutable
import annotation.tailrec
import Implicits._
import util.Stats.track
import language.implicitConversions

trait TyperContextOps { ctx: Context => }

object Typer {

  import tpd.{cpy => _, _}

  object BindingPrec {
    val definition = 4
    val namedImport = 3
    val wildImport = 2
    val packageClause = 1
    val nothingBound = 0
    def isImportPrec(prec: Int) = prec == namedImport || prec == wildImport
  }

  implicit class TreeDecorator(tree: Tree) {
    def qualifierType(implicit ctx: Context): Type = tree.tpe match {
      case tpe: TermRef if !tpe.symbol.isStable => tpe.info
      case tpe => tpe
    }
  }

  case class StateFul[T](value: T, state: TyperState) {
    def commit()(implicit ctx: Context): T = {
      state.commit()
      value
    }
  }
}

class Typer extends Namer with Applications with Implicits {

  import Typer._
  import tpd.{cpy => _, _}
  import untpd.cpy

  /** A temporary data item valid for a single typed ident:
   *  The set of all root import symbols that have been
   *  encountered as a qualifier of an import so far.
   *  Note: It would be more proper to move importedFromRoot into typedIdent.
   *  We should check that this has no performance degradation, however.
   */
  private var importedFromRoot: Set[Symbol] = Set()

  def selectionType(site: Type, name: Name, pos: Position)(implicit ctx: Context): Type = {
    val ref =
      if (name == nme.CONSTRUCTOR) site.decl(name)
      else site.member(name)
    if (ref.exists) NamedType(site, name).withDenot(ref)
    else {
      if (!site.isErroneous)
        ctx.error(
          if (name == nme.CONSTRUCTOR) i"$site does not have a constructor"
          else i"$name is not a member of $site", pos)
      ErrorType
    }
  }

  def checkedSelectionType(qual1: Tree, tree: untpd.RefTree)(implicit ctx: Context): Type = {
    val ownType = selectionType(qual1.qualifierType, tree.name, tree.pos)
    if (!ownType.isError) checkAccessible(ownType, qual1.isInstanceOf[Super], tree.pos)
    ownType
  }

  def checkValue(tpe: Type, proto: Type, pos: Position)(implicit ctx: Context): Unit =
    if (!proto.isInstanceOf[SelectionProto]) {
      val sym = tpe.termSymbol
      if ((sym is Package) || (sym is JavaModule)) ctx.error(i"$sym is not a value", pos)
    }

  def checkAccessible(tpe: Type, superAccess: Boolean, pos: Position)(implicit ctx: Context): Type = tpe match {
    case tpe: NamedType =>
      val pre = tpe.prefix
      val name = tpe.name
      val d = tpe.denot.accessibleFrom(pre, superAccess)
      if (!d.exists) {
        val alts = tpe.denot.alternatives.map(_.symbol).filter(_.exists)
        val where = pre.typeSymbol
        val what = alts match {
          case Nil =>
            name.toString
          case sym :: Nil =>
            if (sym.owner == where) sym.show else sym.showLocated
          case _ =>
            i"none of the overloaded alternatives named $name"
        }
        val whyNot = new StringBuffer
        val addendum =
          alts foreach (_.isAccessibleFrom(pre, superAccess, whyNot))
        ctx.error(i"$what cannot be accessed in $where.$whyNot")
        ErrorType
      }
      else if (d.symbol is TypeParamAccessor) // always dereference type param accessors
        checkAccessible(d.info.bounds.hi, superAccess, pos)
      else
        tpe withDenot d
    case _ =>
      tpe
  }

  /** The qualifying class
   *  of a this or super with prefix `qual`.
   *  packageOk is equal false when qualifying class symbol
   */
  def qualifyingClass(tree: untpd.Tree, qual: Name, packageOK: Boolean)(implicit ctx: Context): Symbol =
    ctx.owner.enclosingClass.ownersIterator.find(o => qual.isEmpty || o.isClass && o.name == qual) match {
      case Some(c) if packageOK || !(c is Package) =>
        c
      case _ =>
        ctx.error(
          if (qual.isEmpty) tree.show + " can be used only in a class, object, or template"
          else qual.show + " is not an enclosing class", tree.pos)
        NoSymbol
    }

  /** Attribute an identifier consisting of a simple name or an outer reference.
   *
   *  @param tree      The tree representing the identifier.
   *  Transformations: (1) Prefix class members with this.
   *                   (2) Change imported symbols to selections
   *
   */
  def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context): Tree = track("typedIdent") {
    val name = tree.name

    /** Method is necessary because error messages need to bind to
     *  to typedIdent's context which is lost in nested calls to findRef
     */
    def error(msg: => String, pos: Position) = ctx.error(msg, pos)

    /** Is this import a root import that has been shadowed by an explicit
     *  import in the same program?
     */
    def isDisabled(imp: ImportInfo, site: Type): Boolean = {
      val qualSym = site.termSymbol
      if (defn.RootImports contains qualSym) {
        if (imp.rootImport && (importedFromRoot contains qualSym)) return true
        importedFromRoot += qualSym
      }
      false
    }

    /** Does this identifier appear as a constructor of a pattern? */
    def isPatternConstr =
      if (ctx.mode.isExpr && (ctx.outer.mode is Mode.Pattern))
        ctx.outer.tree match {
          case Apply(`tree`, _) => true
          case _ => false
        }
      else false

    /** A symbol qualifies if it exists and is not stale. Stale symbols
     *  are made to disappear here. In addition,
     *  if we are in a constructor of a pattern, we ignore all definitions
     *  which are methods (note: if we don't do that
     *  case x :: xs in class List would return the :: method)
     *  unless they are stable or are accessors (the latter exception is for better error messages)
     */
    def qualifies(sym: Symbol): Boolean = !(
         sym.isAbsent
      || isPatternConstr && (sym is (Method, butNot = Accessor))
      )

    /** Find the denotation of enclosing `name` in given context `ctx`.
     *  @param previous    A denotation that was found in a more deeply nested scope,
     *                     or else `NoDenotation` if nothing was found yet.
     *  @param prevPrec    The binding precedence of the previous denotation,
     *                     or else `nothingBound` if nothing was found yet.
     *  @param prevCtx     The context of the previous denotation,
     *                     or else `NoContext` if nothing was found yet.
     */
    def findRef(previous: Type, prevPrec: Int, prevCtx: Context)(implicit ctx: Context): Type = {
      import BindingPrec._

      /** A string which explains how something was bound; Depending on `prec` this is either
       *      imported by <tree>
       *  or  defined in <symbol>
       */
      def bindingString(prec: Int, whereFound: Context, qualifier: String = "") =
        if (prec == wildImport || prec == namedImport) i"imported$qualifier by ${whereFound.importInfo}"
        else i"defined$qualifier in ${whereFound.owner}"

      /** Check that any previously found result from an inner context
       *  does properly shadow the new one from an outer context.
       */
      def checkNewOrShadowed(found: Type, newPrec: Int): Type =
        if (!previous.exists || (previous == found)) found
        else {
          if (!previous.isError && !found.isError)
            error(
              i"""reference to $name is ambiguous;
                 |it is both ${bindingString(newPrec, ctx, "")}
                 |and ${bindingString(prevPrec, prevCtx, " subsequently")}""".stripMargin,
              tree.pos)
          previous
        }

      /** The type representing a named import with enclosing name when imported
       *  from given `site` and `selectors`.
       */
      def namedImportRef(site: Type, selectors: List[untpd.Tree]): Type = {
        def checkUnambiguous(found: Type) = {
          val other = namedImportRef(site, selectors.tail)
          if (other.exists && (found != other))
            error(i"""reference to $name is ambiguous; it is imported twice in
                     |${ctx.tree}""".stripMargin,
                  tree.pos)
          found
        }
        val Name = name.toTermName
        selectors match {
          case Pair(Ident(from), Ident(Name)) :: rest =>
            checkUnambiguous(selectionType(site, name, tree.pos))
          case Ident(Name) :: rest =>
            checkUnambiguous(selectionType(site, name, tree.pos))
          case _ :: rest =>
            namedImportRef(site, rest)
          case nil =>
            NoType
        }
      }

      /** The type representing a wildcard import with enclosing name when imported
       *  from given import info
       */
      def wildImportRef(imp: ImportInfo): Type = {
        if (imp.wildcardImport && !(imp.excluded contains name.toTermName)) {
          val pre = imp.site
          if (!isDisabled(imp, pre)) {
            val denot = pre.member(name)
            if (denot.exists) return NamedType(pre, name).withDenot(denot)
          }
        }
        NoType
      }

      /** Is (some alternative of) the given predenotation `denot`
       *  defined in current compilation unit?
       */
      def isDefinedInCurrentUnit(denot: PreDenotation): Boolean = denot match {
        case DenotUnion(d1, d2) => isDefinedInCurrentUnit(d1) || isDefinedInCurrentUnit(d2)
        case denot: SingleDenotation => denot.symbol.sourceFile == ctx.source
      }

      // begin findRef
      if (ctx.scope == null) previous
      else {
        val outer = ctx.outer
        if ((ctx.scope ne outer.scope) || (ctx.owner ne outer.owner)) {
          val defDenots = ctx.denotsNamed(name)
          if (defDenots.exists) {
            val curOwner = ctx.owner
            val pre = curOwner.thisType
            val defDenot = defDenots toDenot pre
            val found = NamedType(pre, name) withDenot defDenot
            if (!(curOwner is Package) || (defDenot.symbol is Package) || isDefinedInCurrentUnit(defDenots))
              return checkNewOrShadowed(found, definition) // no need to go further out, we found highest prec entry
            else if (prevPrec < packageClause)
              return findRef(found, packageClause, ctx)(outer)
          }
        }
        val curImport = ctx.importInfo
        if (curImport != null && curImport.rootImport && previous.exists) return previous
        if (prevPrec < namedImport && (curImport ne outer.importInfo)) {
          val namedImp = namedImportRef(curImport.site, curImport.selectors)
          if (namedImp.exists)
            return findRef(checkNewOrShadowed(namedImp, namedImport), namedImport, ctx)(outer)
          if (prevPrec < wildImport) {
            val wildImp = wildImportRef(curImport)
            if (wildImp.exists)
              return findRef(checkNewOrShadowed(wildImp, wildImport), wildImport, ctx)(outer)
          }
        }
        findRef(previous, prevPrec, prevCtx)(outer)
      }
    }

    // begin typedIdent
    def kind = if (name.isTermName) "term" else "type" // !!! DEBUG
    println(s"typed ident $kind $name in ${ctx.owner}")
    if (ctx.mode is Mode.Pattern) {
      if (name == nme.WILDCARD)
        return tree.withType(pt)
      if (isVarPattern(tree))
        return typed(untpd.Bind(name, untpd.Ident(nme.WILDCARD)).withPos(tree.pos), pt)
    }

    val saved = importedFromRoot
    importedFromRoot = Set()

    val rawType =
      try findRef(NoType, BindingPrec.nothingBound, NoContext)
      finally importedFromRoot = saved
    checkValue(rawType, pt, tree.pos)

    val ownType =
      if (rawType.exists)
        checkAccessible(rawType, superAccess = false, tree.pos)
      else {
        error(i"not found: $name", tree.pos)
        ErrorType
      }
    tree.withType(ownType.underlyingIfRepeated)
  }

  def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = track("typedSelect") {
    val qual1 = typedExpr(tree.qualifier, selectionProto(tree.name, pt))
    val ownType = checkedSelectionType(qual1, tree)
    checkValue(ownType, pt, tree.pos)
    cpy.Select(tree, qual1, tree.name).withType(ownType)
  }

  def typedThis(tree: untpd.This)(implicit ctx: Context): Tree = track("typedThis") {
    val cls = qualifyingClass(tree, tree.qual, packageOK = false)
    tree.withType(cls.thisType)
  }

  def typedSuper(tree: untpd.Super)(implicit ctx: Context): Tree = track("typedSuper") {
    val mix = tree.mix
    val qual1 = typed(tree.qual)
    val cls = qual1.tpe.typeSymbol

    def findMixinSuper(site: Type): Type = site.parents filter (_.name == mix) match {
      case p :: Nil =>
        p
      case Nil =>
        errorType(i"$mix does not name a parent class of $cls", tree.pos)
      case p :: q :: _ =>
        errorType(s"ambiguous parent class qualifier", tree.pos)
    }
    val owntype =
      if (!mix.isEmpty) findMixinSuper(cls.info)
      else if (ctx.mode is Mode.InSuperInit) cls.info.firstParent
      else cls.info.parents.reduceLeft((x: Type, y: Type) => AndType(x, y))

    cpy.Super(tree, qual1, mix).withType(SuperType(cls.thisType, owntype))
  }

  def typedLiteral(tree: untpd.Literal)(implicit ctx: Context) = track("typedLiteral") {
    tree.withType {
      tree.const.tag match {
        case UnitTag => defn.UnitType
        case NullTag => defn.NullType
        case _ => ConstantType(tree.const)
      }
    }
  }

  def typedNew(tree: untpd.New, pt: Type)(implicit ctx: Context) = track("typedNew") {
    tree.tpt match {
      case templ: Template =>
        import untpd._
        val x = tpnme.ANON_CLASS
        val clsDef = TypeDef(Modifiers(Final), x, templ)
        typed(cpy.Block(tree, clsDef :: Nil, New(Ident(x), Nil)), pt)
      case _ =>
        val tpt1 = typedType(tree.tpt)
        val cls = checkClassTypeWithStablePrefix(tpt1.tpe, tpt1.pos)
        // todo in a later phase: checkInstantiatable(cls, tpt1.pos)
        cpy.New(tree, tpt1).withType(tpt1.tpe)
    }
  }

  def typedPair(tree: untpd.Pair, pt: Type)(implicit ctx: Context) = track("typedPair") {
    val (leftProto, rightProto) = pt.typeArgs match {
      case l :: r :: Nil if pt isRef defn.PairClass => (l, r)
      case _ => (WildcardType, WildcardType)
    }
    val left1 = typed(tree.left, leftProto)
    val right1 = typed(tree.right, rightProto)
    cpy.Pair(tree, left1, right1).withType(defn.PairType.appliedTo(left1.tpe :: right1.tpe :: Nil))
  }

  def typedTyped(tree: untpd.Typed, pt: Type)(implicit ctx: Context): Tree = track("typedTyped") {
    tree.expr match {
      case id: Ident if (ctx.mode is Mode.Pattern) && isVarPattern(id) && id.name != nme.WILDCARD =>
        import untpd._
        typed(Bind(id.name, Typed(Ident(nme.WILDCARD), tree.tpt)).withPos(id.pos))
      case _ =>
        val tpt1 = typedType(tree.tpt)
        val expr1 = typedExpr(tree.expr, tpt1.tpe)
        cpy.Typed(tree, expr1, tpt1).withType(tpt1.tpe)
    }
  }

  def typedNamedArg(tree: untpd.NamedArg, pt: Type)(implicit ctx: Context) = track("typedNamedArg") {
    val arg1 = typed(tree.arg, pt)
    cpy.NamedArg(tree, tree.name, arg1).withType(arg1.tpe)
  }

  def typedAssign(tree: untpd.Assign, pt: Type)(implicit ctx: Context) = track("typedAssign") {
    tree.lhs match {
      case lhs @ Apply(fn, args) =>
        typed(cpy.Apply(lhs, untpd.Select(fn, nme.update), args :+ tree.rhs), pt)
      case lhs =>
        val lhs1 = typed(lhs)
        def reassignmentToVal =
          errorTree(cpy.Assign(tree, lhs1, typed(tree.rhs, lhs1.tpe.widen)),
            "reassignment to val")
        lhs1.tpe match {
          case ref: TermRef if ref.symbol is Mutable =>
            cpy.Assign(tree, lhs1, typed(tree.rhs, ref.info)).withType(defn.UnitType)
          case ref: TermRef if ref.info.isParameterless =>
            val pre = ref.prefix
            val setterName = ref.name.setterName
            val setter = pre.member(setterName)
            lhs1 match {
              case lhs1: RefTree if setter.exists =>
                val setterTypeRaw = TermRef(pre, setterName).withDenot(setter)
                val setterType = checkAccessible(setterTypeRaw, isSuperSelection(tree), tree.pos)
                val lhs2 = lhs1.withName(setterName).withType(setterType)
                typed(cpy.Apply(tree, untpd.TypedSplice(lhs2), tree.rhs :: Nil))
              case _ =>
                reassignmentToVal
            }
          case _ =>
            reassignmentToVal
        }
    }
  }

  def typedBlock(tree: untpd.Block, pt: Type)(implicit ctx: Context) = track("typedBlock") {
    val exprCtx = index(tree.stats)
    val stats1 = typedStats(tree.stats, ctx.owner)
    val expr1 = typedExpr(tree.expr, pt)(exprCtx)
    val result = cpy.Block(tree, stats1, expr1).withType(blockType(stats1, expr1.tpe))
    val leaks = CheckTrees.escapingRefs(result)
    if (leaks.isEmpty) result
    else if (forceFullyDefined(pt)) {
      val expr2 = typed(untpd.Typed(untpd.TypedSplice(expr1), untpd.TypeTree(pt)))
      untpd.Block(stats1, expr2) withType expr2.tpe
    } else
      errorTree(result,
          i"local definition of ${leaks.head.name} escapes as part of block's type ${result.tpe}")
  }

  def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context) = track("typedIf") {
    val cond1 = typed(tree.cond, defn.BooleanType)
    val thenp1 = typed(tree.thenp, pt)
    val elsep1 = typed(if (tree.elsep.isEmpty) unitLiteral else tree.elsep, pt)
    cpy.If(tree, cond1, thenp1, elsep1).withType(thenp1.tpe | elsep1.tpe)
  }

  def typedFunction(tree: untpd.Function, pt: Type)(implicit ctx: Context) = track("typedFunction") {
    val untpd.Function(args, body) = tree
    if (ctx.mode is Mode.Type)
      typed(cpy.AppliedTypeTree(tree,
        ref(defn.FunctionClass(args.length).typeConstructor), args :+ body), pt)
    else {
      val params = args.asInstanceOf[List[ValDef]]
      val protoFormals: List[Type] = pt match {
        case _ if pt isRef defn.FunctionClass(params.length) =>
          pt.typeArgs take params.length
        case SAMType(meth) =>
          val MethodType(_, paramTypes) = meth.info
          paramTypes
        case _ =>
          params map Function.const(WildcardType)
      }
      val inferredParams: List[untpd.ValDef] =
        for ((param, formal) <- params zip protoFormals) yield
          if (!param.tpt.isEmpty) param
          else {
            val paramType =
              if (forceFullyDefined(formal)) formal
              else errorType("missing parameter type", param.pos)
            cpy.ValDef(param, param.mods, param.name, untpd.TypeTree(paramType), param.rhs)
          }
      typed(desugar.makeClosure(inferredParams, body), pt)
    }
  }

  def typedClosure(tree: untpd.Closure, pt: Type)(implicit ctx: Context) = track("typedClosure") {
    val env1 = tree.env mapconserve (typed(_))
    val meth1 = typedUnadapted(tree.meth)
    val ownType = meth1.tpe.widen match {
      case mt: MethodType if !mt.isDependent =>
        mt.toFunctionType
      case mt: MethodType =>
        errorType(i"internal error: cannot turn dependent method type $mt into closure", tree.pos)
      case tp =>
        errorType(i"internal error: closing over non-method $tp", tree.pos)
    }
    cpy.Closure(tree, env1, meth1, EmptyTree).withType(ownType)
  }

  def typedMatch(tree: untpd.Match, pt: Type)(implicit ctx: Context) = track("typedMatch") {
    tree.selector match {
      case EmptyTree =>
        typed(desugar.makeCaseLambda(tree.cases) withPos tree.pos, pt)
      case _ =>
        val sel1 = typedExpr(tree.selector)
        val selType = fullyDefinedType(sel1.tpe, "pattern selector", tree.pos)

        /** gadtSyms = "all type parameters of enclosing methods that appear
         *              non-variantly in the selector type"
         */
        val gadtSyms: Set[Symbol] = {
          val accu = new TypeAccumulator[Set[Symbol]] {
            def apply(tsyms: Set[Symbol], t: Type): Set[Symbol] = {
              val tsyms1 = t match {
                case tr: TypeRef if (tr.symbol is TypeParam) && tr.symbol.owner.isTerm && variance == 0 =>
                  tsyms + tr.symbol
                case _ =>
                  tsyms
              }
              foldOver(tsyms1, t)
            }
          }
          accu(Set.empty, selType)
        }

        def typedCase(tree: untpd.CaseDef): CaseDef = track("typedCase") {
          def caseRest(pat: Tree)(implicit ctx: Context) = {
            gadtSyms foreach (_.resetGADTFlexType)
            foreachSubTreeOf(pat) {
              case b: Bind =>
                if (ctx.scope.lookup(b.name) == NoSymbol) ctx.enter(b.symbol)
                else ctx.error(i"duplicate pattern variable: ${b.name}", b.pos)
              case _ =>
            }
            val guard1 = typedExpr(tree.guard, defn.BooleanType)
            val body1 = typedExpr(tree.body, pt)
            cpy.CaseDef(tree, pat, guard1, body1) withType body1.tpe
          }
          val doCase: () => CaseDef =
            () => caseRest(typedPattern(tree.pat, selType))(ctx.fresh.withNewScope)
          (doCase /: gadtSyms)((op, tsym) => tsym.withGADTFlexType(op))()
        }

        val cases1 = tree.cases mapconserve typedCase
        cpy.Match(tree, sel1, cases1).withType(ctx.typeComparer.lub(cases1.tpes))
    }
  }

  def typedReturn(tree: untpd.Return)(implicit ctx: Context): Return = track("typedReturn") {
    def enclMethInfo(cx: Context): (Tree, Type) =
      if (cx == NoContext || cx.tree.isInstanceOf[Trees.TypeDef[_]]) {
        ctx.error("return outside method definition")
        (EmptyTree, WildcardType)
      }
      else cx.tree match {
        case ddef: DefDef =>
          val meth = ddef.symbol
          val from = Ident(TermRef.withSym(NoPrefix, meth.asTerm))
          val proto =
            if (meth.isConstructor)
              defn.UnitType
            else if (ddef.tpt.isEmpty)
              errorType(i"method $meth has return statement; needs result type", tree.pos)
            else
              ddef.tpt.tpe
          (from, proto)
        case _ =>
          enclMethInfo(cx.outer)
      }
    val (from, proto) = enclMethInfo(ctx)
    val expr1 = typedExpr(if (tree.expr.isEmpty) untpd.unitLiteral else tree.expr, proto)
    cpy.Return(tree, expr1, from) withType defn.NothingType
  }

  def typedTry(tree: untpd.Try, pt: Type)(implicit ctx: Context): Try = track("typedTry") {
    val expr1 = typed(tree.expr, pt)
    val handler1 = typed(tree.handler, defn.FunctionType(defn.ThrowableType :: Nil, pt))
    val finalizer1 = typed(tree.finalizer, defn.UnitType)
    val handlerResultType = handler1.tpe match {
      case defn.FunctionType(_, resultType) => resultType
      case _ => defn.NothingType
    }
    cpy.Try(tree, expr1, handler1, finalizer1).withType(expr1.tpe | handlerResultType)
  }

  def typedThrow(tree: untpd.Throw)(implicit ctx: Context): Throw = track("typedThrow") {
    val expr1 = typed(tree.expr, defn.ThrowableType)
    cpy.Throw(tree, expr1) withType defn.NothingType
  }

  def typedSeqLiteral(tree: untpd.SeqLiteral, pt: Type)(implicit ctx: Context): SeqLiteral = track("typedSeqLiteral") {
    val proto1 = pt.elemType orElse WildcardType
    val elems1 = tree.elems mapconserve (typed(_, proto1))
    cpy.SeqLiteral(tree, elems1) withType ctx.typeComparer.lub(elems1.tpes)
  }

  def typedTypeTree(tree: untpd.TypeTree, pt: Type)(implicit ctx: Context): TypeTree = track("typedTypeTree") {
    val (original1, ownType) = tree.original match {
      case untpd.EmptyTree =>
        assert(isFullyDefined(pt))
        (EmptyTree, pt)
      case original: ValDef =>
        val meth = symbolOfTree(original)
        assert(meth.exists, meth)
        (EmptyTree, meth.info)
      case original =>
        val original1 = typed(original)
        (original1, original1.tpe)
    }
    cpy.TypeTree(tree, original1) withType ownType
  }

  def typedSingletonTypeTree(tree: untpd.SingletonTypeTree)(implicit ctx: Context): SingletonTypeTree = track("typedSingletonTypeTree") {
    val ref1 = typedExpr(tree.ref)
    checkStable(ref1.qualifierType, tree.pos)
    cpy.SingletonTypeTree(tree, ref1) withType ref1.tpe
  }

  def typedSelectFromTypeTree(tree: untpd.SelectFromTypeTree, pt: Type)(implicit ctx: Context): SelectFromTypeTree = track("typedSelectFromTypeTree") {
    val qual1 = typedType(tree.qualifier, selectionProto(tree.name, pt))
    cpy.SelectFromTypeTree(tree, qual1, tree.name).withType(checkedSelectionType(qual1, tree))
  }

  def typedAndTypeTree(tree: untpd.AndTypeTree)(implicit ctx: Context): AndTypeTree = track("typedAndTypeTree") {
    val left1 = typed(tree.left)
    val right1 = typed(tree.right)
    cpy.AndTypeTree(tree, left1, right1) withType left1.tpe & right1.tpe
  }

  def typedOrTypeTree(tree: untpd.OrTypeTree)(implicit ctx: Context): OrTypeTree = track("typedOrTypeTree") {
    val left1 = typed(tree.left)
    val right1 = typed(tree.right)
    cpy.OrTypeTree(tree, left1, right1) withType left1.tpe | right1.tpe
  }

  def typedRefinedTypeTree(tree: untpd.RefinedTypeTree)(implicit ctx: Context): RefinedTypeTree = track("typedRefinedTypeTree") {
    val tpt1 = typedAheadType(tree.tpt)
    val refineClsDef = desugar.refinedTypeToClass(tree)
    val refineCls = createSymbol(refineClsDef).asClass
    val TypeDef(_, _, Template(_, _, _, refinements1)) = typed(refineClsDef)
    assert(tree.refinements.length == refinements1.length, s"${tree.refinements} != $refinements1")
    def addRefinement(parent: Type, refinement: Tree): Type = {
      foreachSubTreeOf(refinement) {
        case tree: RefTree =>
          if (tree.symbol.owner == refineCls && tree.pos.start <= tree.symbol.pos.end)
            ctx.error("illegal forward reference in refinement", tree.pos)
        case _ =>
      }
      val rsym = refinement.symbol
      val rinfo = if (rsym is Accessor) rsym.info.resultType else rsym.info
      RefinedType(parent, rsym.name, rt => rinfo.substThis(refineCls, RefinedThis(rt)))
      // todo later: check that refinement is within bounds
    }
    cpy.RefinedTypeTree(tree, tpt1, refinements1) withType
      (tpt1.tpe /: refinements1)(addRefinement)
  }

  def typedAppliedTypeTree(tree: untpd.AppliedTypeTree)(implicit ctx: Context): AppliedTypeTree = track("typedAppliedTypeTree") {
    val tpt1 = typed(tree.tpt)
    val args1 = tree.args mapconserve (typed(_))
    val tparams = tpt1.tpe.typeParams
    if (args1.length != tparams.length)
      ctx.error(i"wrong number of type arguments for ${tpt1.tpe}, should be ${tparams.length}")
    // todo in later phase: check arguments conform to parameter bounds
    cpy.AppliedTypeTree(tree, tpt1, args1) withType tpt1.tpe.appliedTo(args1.tpes)
  }

  def typedTypeBoundsTree(tree: untpd.TypeBoundsTree)(implicit ctx: Context): TypeBoundsTree = track("typedTypeBoundsTree") {
    val lo1 = typed(tree.lo)
    val hi1 = typed(tree.hi)
    if (!(lo1.tpe <:< hi1.tpe))
      ctx.error(i"lower bound ${lo1.tpe} does not conform to upper bound ${hi1.tpe}", tree.pos)
    cpy.TypeBoundsTree(tree, lo1, hi1) withType TypeBounds(lo1.tpe, hi1.tpe)
  }

  def typedBind(tree: untpd.Bind, pt: Type)(implicit ctx: Context): Bind = track("typedBind") {
    val body1 = typed(tree.body, pt)
    val sym = ctx.newSymbol(ctx.owner, tree.name.asTermName, EmptyFlags, pt, coord = tree.pos)
    cpy.Bind(tree, tree.name, body1) withType TermRef.withSym(NoPrefix, sym)
  }

  def typedAlternative(tree: untpd.Alternative, pt: Type)(implicit ctx: Context): Alternative = track("typedAlternative") {
    val trees1 = tree.trees mapconserve (typed(_, pt))
    cpy.Alternative(tree, trees1) withType ctx.typeComparer.lub(trees1.tpes)
  }

  def typedModifiers(mods: untpd.Modifiers)(implicit ctx: Context): Modifiers = track("typedModifiers") {
    val annotations1 = mods.annotations mapconserve typedAnnotation
    if (annotations1 eq mods.annotations) mods.asInstanceOf[Modifiers]
    else Modifiers(mods.flags, mods.privateWithin, annotations1)
  }

  def typedAnnotation(annot: untpd.Tree)(implicit ctx: Context): Tree = track("typedAnnotation") {
    typed(annot, defn.AnnotationClass.typeConstructor)
  }

  def typedValDef(vdef: untpd.ValDef, sym: Symbol)(implicit ctx: Context) = track("typedValDef") {
    val ValDef(mods, name, tpt, rhs) = vdef
    val mods1 = typedModifiers(mods)
    val tpt1 = typedType(tpt)
    val rhs1 = typedExpr(rhs, tpt1.tpe)
    val refType = if (sym.exists) sym.symRef else NoType
    cpy.ValDef(vdef, mods1, name, tpt1, rhs1).withType(refType)
  }

  def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = track("typedDefDef") {
    val DefDef(mods, name, tparams, vparamss, tpt, rhs) = ddef
    val mods1 = typedModifiers(mods)
    val tparams1 = tparams mapconserve (typed(_).asInstanceOf[TypeDef])
    val vparamss1 = vparamss mapconserve(_ mapconserve (typed(_).asInstanceOf[ValDef]))
    val tpt1 = typedType(tpt)
    val rhs1 = typedExpr(rhs, tpt1.tpe)
    cpy.DefDef(ddef, mods1, name, tparams1, vparamss1, tpt1, rhs1).withType(sym.symRef)
    //todo: make sure dependent method types do not depend on implicits or by-name params
  }

  def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(implicit ctx: Context): TypeDef = track("typedTypeDef") {
    val TypeDef(mods, name, rhs) = tdef
    val mods1 = typedModifiers(mods)
    val rhs1 = typedType(rhs)
    cpy.TypeDef(tdef, mods1, name, rhs1).withType(sym.symRef)
  }

  def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(implicit ctx: Context) = track("typedClassDef") {
    val TypeDef(mods, name, impl @ Template(constr, parents, self, body)) = cdef
    val mods1 = typedModifiers(mods)
    val constr1 = typed(constr).asInstanceOf[DefDef]
    val parents1 = parents mapconserve (typed(_))
    val self1 = typed(self).asInstanceOf[ValDef]
    val localDummy = ctx.newLocalDummy(cls, impl.pos)
    val body1 = typedStats(body, localDummy)(inClassContext(self1.symbol))
    val impl1 = cpy.Template(impl, constr1, parents1, self1, body1)
      .withType(localDummy.symRef)

    cpy.TypeDef(cdef, mods1, name, impl1).withType(cls.symRef)

    // todo later: check that
    //  1. If class is non-abstract, it is instantiatable:
    //  - self type is s supertype of own type
    //  - all type members have consistent bounds
    // 2. all private type members have consistent bounds
    // 3. Types do not override classes.
    // 4. Polymorphic type defs override nothing.
  }

  def typedImport(imp: untpd.Import, sym: Symbol)(implicit ctx: Context): Import = track("typedImport") {
    val expr1 = typedExpr(imp.expr, AnySelectionProto)
    cpy.Import(imp, expr1, imp.selectors).withType(sym.symRef)
  }

  def typedAnnotated(tree: untpd.Annotated, pt: Type)(implicit ctx: Context): Tree = track("typedAnnotated") {
    val annot1 = typed(tree.annot, defn.AnnotationClass.typeConstructor)
    val arg1 = typed(tree.arg, pt)
    val ownType = AnnotatedType(Annotation(annot1), arg1.tpe)
    if (ctx.mode is Mode.Type)
      cpy.Annotated(tree, annot1, arg1) withType ownType
    else
      cpy.Typed(tree, arg1, TypeTree(ownType)) withType ownType
  }

  def typedPackageDef(tree: untpd.PackageDef)(implicit ctx: Context): Tree = track("typedPackageDef") {
    val pid1 = typedExpr(tree.pid, AnySelectionProto)
    val pkg = pid1.symbol
    val packageContext =
      if (pkg is Package) ctx.fresh withOwner pkg.moduleClass
      else {
        ctx.error(i"$pkg is not a packge", tree.pos)
        ctx
      }
    val stats1 = typedStats(tree.stats, NoSymbol)(packageContext)
    cpy.PackageDef(tree, pid1.asInstanceOf[RefTree], stats1) withType pkg.symRef
  }

  def typedUnadapted(initTree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = {

    val xtree = expanded(initTree)
    typedTree remove xtree match {
      case Some(ttree) => ttree
      case none =>
        val sym = symOfTree.remove(xtree).getOrElse(NoSymbol)
        sym.ensureCompleted()
        def localContext = ctx.fresh.withOwner(sym)

        def typedNamed(tree: untpd.NameTree): Tree = tree match {
          case tree: untpd.Ident => typedIdent(tree, pt)
          case tree: untpd.Select => typedSelect(tree, pt)
          case tree: untpd.SelectFromTypeTree => typedSelectFromTypeTree(tree, pt)
          case tree: untpd.Bind => typedBind(tree, pt)
          case tree: untpd.ValDef =>
            if (tree.isEmpty) tpd.EmptyValDef
            else typedValDef(tree, sym)(localContext.withNewScope)
          case tree: untpd.DefDef =>
            val typer1 = nestedTyper.remove(sym).get
            typer1.typedDefDef(tree, sym)(localContext.withTyper(typer1))
          case tree: untpd.TypeDef =>
            if (tree.isClassDef) typedClassDef(tree, sym.asClass)(localContext)
            else typedTypeDef(tree, sym)(localContext.withNewScope)
          case _ => typedUnadapted(desugar(tree), pt)
        }

        def typedUnnamed(tree: untpd.Tree): Tree = tree match {
          case tree: untpd.Apply => typedApply(tree, pt)
          case tree: untpd.This => typedThis(tree)
          case tree: untpd.Literal => typedLiteral(tree)
          case tree: untpd.New => typedNew(tree, pt)
          case tree: untpd.Pair => typedPair(tree, pt)
          case tree: untpd.Typed => typedTyped(tree, pt)
          case tree: untpd.NamedArg => typedNamedArg(tree, pt)
          case tree: untpd.Assign => typedAssign(tree, pt)
          case tree: untpd.Block => typedBlock(desugar.block(tree), pt)
          case tree: untpd.If => typedIf(tree, pt)
          case tree: untpd.Function => typedFunction(tree, pt)
          case tree: untpd.Closure => typedClosure(tree, pt)
          case tree: untpd.Match => typedMatch(tree, pt)
          case tree: untpd.Return => typedReturn(tree)
          case tree: untpd.Try => typedTry(tree, pt)
          case tree: untpd.Throw => typedThrow(tree)
          case tree: untpd.TypeApply => typedTypeApply(tree, pt)
          case tree: untpd.Super => typedSuper(tree)
          case tree: untpd.SeqLiteral => typedSeqLiteral(tree, pt)
          case tree: untpd.TypeTree => typedTypeTree(tree, pt)
          case tree: untpd.SingletonTypeTree => typedSingletonTypeTree(tree)
          case tree: untpd.AndTypeTree => typedAndTypeTree(tree)
          case tree: untpd.OrTypeTree => typedOrTypeTree(tree)
          case tree: untpd.RefinedTypeTree => typedRefinedTypeTree(tree)
          case tree: untpd.AppliedTypeTree => typedAppliedTypeTree(tree)
          case tree: untpd.TypeBoundsTree => typedTypeBoundsTree(tree)
          case tree: untpd.Alternative => typedAlternative(tree, pt)
          case tree: untpd.Import => typedImport(tree, sym)
          case tree: untpd.PackageDef => typedPackageDef(tree)
          case tree: untpd.Annotated => typedAnnotated(tree, pt)
          case tree: untpd.TypedSplice => tree.tree
          case untpd.PostfixOp(tree, nme.WILDCARD) => typed(tree, AnyFunctionProto)
          case untpd.EmptyTree => tpd.EmptyTree
          case _ => typedUnadapted(desugar(tree), pt)
        }

        xtree match {
          case xtree: untpd.NameTree => typedNamed(xtree withName xtree.name.encode)
          case xtree => typedUnnamed(xtree)
        }
    }
  }

  def typed(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = ctx.traceIndented (s"typing ${tree.show}", show = true) {
    try interpolateAndAdapt(typedUnadapted(tree, pt), pt)
    catch {
      case ex: FatalTypeError => errorTree(tree, ex.getMessage)
    }
  }

  def typedTrees(trees: List[untpd.Tree])(implicit ctx: Context): List[Tree] =
    trees mapconserve (typed(_))

  def typedStats(stats: List[untpd.Tree], exprOwner: Symbol)(implicit ctx: Context): List[tpd.Tree] = {
    val buf = new mutable.ListBuffer[Tree]
    @tailrec def traverse(stats: List[untpd.Tree])(implicit ctx: Context): List[Tree] = stats match {
      case (imp: untpd.Import) :: rest =>
        val imp1 = typed(imp)
        buf += imp1
        traverse(rest)(importContext(imp1.symbol, imp.selectors))
      case (mdef: untpd.DefTree) :: rest =>
        expandedTree remove mdef match {
          case Some(xtree) =>
            traverse(xtree :: rest)
          case none =>
            buf += typed(mdef)
            traverse(rest)
        }
      case Thicket(stats) :: rest =>
        traverse(stats ++ rest)
      case stat :: rest =>
        val nestedCtx = if (exprOwner == ctx.owner) ctx else ctx.fresh.withOwner(exprOwner)
        buf += typed(stat)(nestedCtx)
        traverse(rest)
      case _ =>
        buf.toList
    }
    traverse(stats)
  }

  def typedExpr(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree =
    typed(tree, pt)(ctx retractMode Mode.PatternOrType)
  def typedType(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree =
    typed(tree, pt)(ctx addMode Mode.Type)
  def typedPattern(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree =
    typed(tree, pt)(ctx addMode Mode.Pattern)

  def tryEither[T](op: Context => T)(fallBack: StateFul[T] => T)(implicit ctx: Context) = {
    val nestedCtx = ctx.fresh.withNewTyperState
    val result = op(nestedCtx)
    if (nestedCtx.reporter.hasErrors)
      fallBack(StateFul(result, nestedCtx.typerState))
    else {
      nestedCtx.typerState.commit()
      result
    }
  }

  def tryInsertApply(tree: Tree, pt: Type)(fallBack: StateFul[Tree] => Tree)(implicit ctx: Context): Tree =
    tryEither {
      implicit ctx => typedSelect(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt)
    } {
      fallBack
    }

  def interpolateAndAdapt(tree: Tree, pt: Type)(implicit ctx: Context) = {
    ctx.interpolateUndetVars(tree.tpe.widen, tree.pos)
    adapt(tree, pt)
  }

  /** (-1) For expressions with annotated types, let AnnotationCheckers decide what to do
   *  (0) Convert expressions with constant types to literals (unless in interactive/scaladoc mode)
   */

  /** Perform the following adaptations of expression, pattern or type `tree` wrt to
   *  given prototype `pt`:
   *  (1) Resolve overloading
   *  (2) Apply parameterless functions
   *  (3) Apply polymorphic types to fresh instances of their type parameters and
   *      store these instances in context.undetparams,
   *      unless followed by explicit type application.
   *  (4) Do the following to unapplied methods used as values:
   *  (4.1) If the method has only implicit parameters pass implicit arguments
   *  (4.2) otherwise, if `pt` is a function type and method is not a constructor,
   *        convert to function by eta-expansion,
   *  (4.3) otherwise, if the method is nullary with a result type compatible to `pt`
   *        and it is not a constructor, apply it to ()
   *  otherwise issue an error
   *  (5) Convert constructors in a pattern as follows:
   *  (5.1) If constructor refers to a case class factory, set tree's type to the unique
   *        instance of its primary constructor that is a subtype of the expected type.
   *  (5.2) If constructor refers to an extractor, convert to application of
   *        unapply or unapplySeq method.
   *
   *  (6) Convert all other types to TypeTree nodes.
   *  (7) When in TYPEmode but not FUNmode or HKmode, check that types are fully parameterized
   *      (7.1) In HKmode, higher-kinded types are allowed, but they must have the expected kind-arity
   *  (8) When in both EXPRmode and FUNmode, add apply method calls to values of object type.
   *  (9) If there are undetermined type variables and not POLYmode, infer expression instance
   *  Then, if tree's type is not a subtype of expected type, try the following adaptations:
   *  (10) If the expected type is Byte, Short or Char, and the expression
   *      is an integer fitting in the range of that type, convert it to that type.
   *  (11) Widen numeric literals to their expected type, if necessary
   *  (12) When in mode EXPRmode, convert E to { E; () } if expected type is scala.Unit.
   *  (13) When in mode EXPRmode, apply AnnotationChecker conversion if expected type is annotated.
   *  (14) When in mode EXPRmode, apply a view
   *  If all this fails, error
   */
  def adapt(tree: Tree, pt: Type)(implicit ctx: Context): Tree = track("adapt") { ctx.traceIndented(i"adapting $tree of type ${tree.tpe} to $pt", show = true) {

    assert(pt.exists)

    def methodStr = err.refStr(methPart(tree).tpe)

    def adaptOverloaded(ref: TermRef) = {
      val altDenots = ref.denot.alternatives
      val alts = altDenots map (alt =>
        TermRef.withSig(ref.prefix, ref.name, alt.info.signature).withDenot(alt))
      def expectedStr = err.expectedTypeStr(pt)
      resolveOverloaded(alts, pt) match {
        case alt :: Nil =>
          adapt(tree.withType(alt), pt)
        case Nil =>
          def noMatches =
            errorTree(tree,
              i"""none of the ${err.overloadedAltsStr(altDenots)}
                 |match $expectedStr""".stripMargin)
          def hasEmptyParams(denot: SingleDenotation) = denot.info.paramTypess match {
            case Nil :: _ => true
            case _ => false
          }
          pt match {
            case pt: FunProto =>
              tryInsertApply(tree, pt)(_ => noMatches)
            case _ =>
              if (altDenots exists hasEmptyParams)
                typed(untpd.Apply(untpd.TypedSplice(tree), Nil), pt)
              else
                noMatches
          }
        case alts =>
          errorTree(tree,
            i"""Ambiguous overload. The ${err.overloadedAltsStr(altDenots take 2)}
               |both match $expectedStr""".stripMargin)
      }
    }

    def adaptToArgs(wtp: Type, pt: FunProto) = wtp match {
      case _: MethodType => tree
      case _ => tryInsertApply(tree, pt) {
        val more = tree match {
          case Apply(_, _) => " more"
          case _ => ""
        }
        _ => errorTree(tree, i"$methodStr does not take$more parameters")
      }
    }

    def adaptNoArgs(wtp: Type) = wtp match {
      case wtp: ExprType =>
        adapt(tree.withType(wtp.resultType), pt)
      case wtp: ImplicitMethodType =>
        def implicitArgError(msg: => String): Tree = {
          ctx.error(msg, tree.pos.endPos)
          EmptyTree
        }
        val args = (wtp.paramNames, wtp.paramTypes).zipped map { (pname, formal) =>
          def where = i"parameter $pname of $methodStr"
          inferImplicit(formal, EmptyTree, tree.pos.endPos) match {
            case SearchSuccess(arg) =>
              arg
            case ambi: AmbiguousImplicits =>
              implicitArgError(s"ambiguous implicits: ${ambi.explanation} of $where")
            case failure: SearchFailure =>
              implicitArgError(i"no implicit argument of type $formal found for $where" + failure.postscript)
          }
        }
        adapt(tpd.Apply(tree, args), wtp.resultType)
      case wtp: MethodType if !pt.isInstanceOf[SingletonType] =>
        if ((defn.isFunctionType(pt) || (pt eq AnyFunctionProto)) &&
            !tree.symbol.isConstructor)
          etaExpand(tree, wtp)
        else if (wtp.paramTypes.isEmpty)
          adapt(tpd.Apply(tree, Nil), pt)
        else
          errorTree(tree,
            i"""missing arguments for $methodStr
               |follow this method with `_' if you want to treat it as a partially applied function""".stripMargin)
      case _ =>
        if (tree.tpe <:< pt) tree
        else if (ctx.mode is Mode.Pattern) tree // no subtype check for pattern
        else adaptToSubType(wtp)
    }

    def adaptToSubType(wtp: Type): Tree = {
      // try converting a constant to the target type
      val folded = ConstFold(tree, pt)
      if (folded ne EmptyTree) return folded
      // drop type if prototype is Unit
      if (pt isRef defn.UnitClass)
        return tpd.Block(tree :: Nil, Literal(Constant()))
      // convert function literal to SAM closure
      tree match {
        case Closure(Nil, id @ Ident(nme.ANON_FUN), _)
        if defn.isFunctionType(wtp) && !defn.isFunctionType(pt) =>
          pt match {
            case SAMType(meth)
            if wtp <:< meth.info.toFunctionType && isFullyDefined(pt) =>
              return cpy.Closure(tree, Nil, id, TypeTree(pt)).withType(pt)
            case _ =>
          }
        case _ =>
      }
      // try an implicit conversion
      inferView(tree, pt) match {
        case SearchSuccess(adapted) =>
          adapted
        case failure: SearchFailure =>
          if (pt.isInstanceOf[ProtoType]) tree
          else err.typeMismatch(tree, pt, failure)
      }
    }

    tree match {
      case _: MemberDef | _: PackageDef | _: Import | _: WithoutType[_] => tree
      case _ => tree.tpe.widen match {
        case ref: TermRef =>
          adaptOverloaded(ref)
        case poly: PolyType =>
          if (pt.isInstanceOf[PolyProto]) tree
          else {
            val tvars = ctx.typerState.withCheckingDisabled {
              val tracked = ctx.track(poly)
              ctx.newTypeVars(tracked, tree.pos)
            }
            adapt(tpd.TypeApply(tree, tvars map (tpd.TypeTree(_))), pt)
          }
        case wtp =>
          pt match {
            case pt: FunProto => adaptToArgs(wtp, pt)
            case _ =>
              if (ctx.mode is Mode.Type)
                if (tree.tpe <:< pt) tree
                else err.typeMismatch(tree, pt)
              else adaptNoArgs(wtp)
          }
      }
    }
  }}
}