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





                   
                                                                                            
                                                                                                  
                                   
                       
                           
                  
                
                         
 

                    
 



                                                                                                          




                                                                    
                                                           









                                                                                           

                                                                                                       
    
                                                                                     
                                                        
                                                                                                     
                                                       

                                                                                                


                                                                                    
                                
                                            



                                                                                    


                                                            
         
                                            



                                                                                             
                                  
                                          
                         

                                  
                                                   





                                                    
                                                                                              
                                                               



                                                                              




                                                                                                            






                                                                                

                                                      

                         
           

                                                           

                                                               

                                                     
                                                     
                                     
                                                                     
                                        
                                         

                                                         

                                                                                       
                  
                                                              
           

                                                                      
                                          
                                    






                     


                                                                                   























                                                                                                        

                                                                   
                                                      

                                                                           







                                                                                                       
                                                                                   

                                                                              
                                           
                                                   


                                                        






                                                                              
                                                                   




                                                                                          
                                                                                            

                     
         




                                                                                                                   
            
                                                           









                                                                                           

                                                                                     

                        
                              



                                                                                                              
                  
                                                                            

                                                                 

















                                                                                                

                                                                      
 
                                                                                   
                                 
                         
                                          






                                                                                           






                                                                                          



                                                   
 


                                                                     

                                                              

                            

                                     
                                                                         

       





                                                                 
                                                                                                                                
                      

                                      




                                                                                      
                                                                          
                         
                                                               

                 

                                                     
                                                                    
            
                                              

                                                                                    





                                                                                          
                                                                                                  
                                                                   
               
                                                                           






                                                                                              

                                      

                                                                                         
                                           
                                           



                                                                                                       


                                                                     
                                                  

                                        
                         






                                                                                       
           
 










                                                        
                                   





                                                                     
                                                                                                        
                                                                                 
         
               
                                                                                
     
 


                          









                                                                                           



                                                                                                     




                                                                                        
                  

                                                                        









                                                                                  
                                                                                            

                                                                    
 





                                                                                                     
   













                                                                                                       
                                                 
                                                         
                                              
                                                                                                   
                                                              
                                     
                                                                        
         
                                                                                     
                                                                                                        


                                                                                   
                 
                                                             
                                                                        
                                                                          


                          
                                                                                                            
                                                                             
 



                                                                                         
                                                                                  
 

                                                                        







                                                                                     
                                                                                                     

                                                                          
                                                                   

                                                                           




                                                                      
                                                          











                                                                                               

                                                                          
                                       
 
                                                                                        
                                                                  


                                                                            



                                        
package dotty.tools
package dotc
package typer

import core._
import ast._
import Scopes._, Contexts._, Constants._, Types._, Symbols._, Names._, Flags._, Decorators._
import ErrorReporting._, Annotations._, Denotations._, SymDenotations._, StdNames._, TypeErasure._
import TypeApplications.AppliedType
import util.Positions._
import config.Printers.typr
import ast.Trees._
import NameOps._
import collection.mutable

trait TypeAssigner {
  import tpd._

  /** The qualifying class of a this or super with prefix `qual` (which might be empty).
   *  @param packageOk   The qualifier may refer to a package.
   */
  def qualifyingClass(tree: untpd.Tree, qual: Name, packageOK: Boolean)(implicit ctx: Context): Symbol = {
    def qualifies(sym: Symbol) =
      sym.isClass && (
          qual.isEmpty ||
          sym.name == qual ||
          sym.is(Module) && sym.name.stripModuleClassSuffix == qual)
    ctx.outersIterator.map(_.owner).find(qualifies) 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
    }
  }

  /** An upper approximation of the given type `tp` that does not refer to any symbol in `symsToAvoid`.
   *  Approximation steps are:
   *
   *   - follow aliases and upper bounds if the original refers to a forbidden symbol
   *   - widen termrefs that refer to a forbidden symbol
   *   - replace ClassInfos of forbidden classes by the intersection of their parents, refined by all
   *     non-private fields, methods, and type members.
   *   - if the prefix of a class refers to a forbidden symbol, first try to replace the prefix,
   *     if this is not possible, replace the ClassInfo as above.
   *   - drop refinements referring to a forbidden symbol.
   */
  def avoid(tp: Type, symsToAvoid: => List[Symbol])(implicit ctx: Context): Type = {
    val widenMap = new TypeMap {
      lazy val forbidden = symsToAvoid.toSet
      def toAvoid(tp: Type): Boolean =
        // TODO: measure the cost of using `existsPart`, and if necessary replace it
        // by a `TypeAccumulator` where we have set `stopAtStatic = true`.
        tp existsPart {
          case tp: NamedType => forbidden contains tp.symbol
          case tp: ThisType => forbidden contains tp.cls
          case _ => false
        }
      def apply(tp: Type): Type = tp match {
        case tp: TermRef
        if toAvoid(tp) && (variance > 0 || tp.info.widenExpr <:< tp) =>
          // Can happen if `x: y.type`, then `x.type =:= y.type`, hence we can widen `x.type`
          // to y.type in all contexts, not just covariant ones.
          apply(tp.info.widenExpr)
        case tp: TypeRef if toAvoid(tp) =>
          tp.info match {
            case TypeAlias(ref) =>
              apply(ref)
            case info: ClassInfo if variance > 0 =>
              if (!(forbidden contains tp.symbol)) {
                val prefix = apply(tp.prefix)
                val tp1 = tp.derivedSelect(prefix)
                if (tp1.typeSymbol.exists)
                  return tp1
              }
              val parentType = info.parentsWithArgs.reduceLeft(ctx.typeComparer.andType(_, _))
              def addRefinement(parent: Type, decl: Symbol) = {
                val inherited =
                  parentType.findMember(decl.name, info.cls.thisType, Private)
                    .suchThat(decl.matches(_))
                val inheritedInfo = inherited.info
                if (inheritedInfo.exists && decl.info <:< inheritedInfo && !(inheritedInfo <:< decl.info)) {
                  val r = RefinedType(parent, decl.name, decl.info)
                  typr.println(i"add ref $parent $decl --> " + r)
                  r
                }
                else
                  parent
              }
              val refinableDecls = info.decls.filterNot(
                sym => sym.is(TypeParamAccessor | Private) || sym.isConstructor)
              val fullType = (parentType /: refinableDecls)(addRefinement)
              mapOver(fullType)
            case TypeBounds(lo, hi) if variance > 0 =>
              apply(hi)
            case _ =>
              mapOver(tp)
          }
        case tp @ HKApply(tycon, args) if toAvoid(tycon) =>
          apply(tp.superType)
        case tp @ AppliedType(tycon, args) if toAvoid(tycon) =>
          val base = apply(tycon)
          var args = tp.baseArgInfos(base.typeSymbol)
          if (base.typeParams.length != args.length)
            args = base.typeParams.map(_.paramBounds)
          apply(base.appliedTo(args))
        case tp @ RefinedType(parent, name, rinfo) if variance > 0 =>
          val parent1 = apply(tp.parent)
          val refinedInfo1 = apply(rinfo)
          if (toAvoid(refinedInfo1)) {
            typr.println(s"dropping refinement from $tp")
            if (name.isTypeName) tp.derivedRefinedType(parent1, name, TypeBounds.empty)
            else parent1
          } else {
            tp.derivedRefinedType(parent1, name, refinedInfo1)
          }
        case tp: TypeVar if ctx.typerState.constraint.contains(tp) =>
          val lo = ctx.typerState.constraint.fullLowerBound(tp.origin)
          val lo1 = avoid(lo, symsToAvoid)
          if (lo1 ne lo) lo1 else tp
        case _ =>
          mapOver(tp)
      }
    }
    widenMap(tp)
  }

  def avoidingType(expr: Tree, bindings: List[Tree])(implicit ctx: Context): Type =
    avoid(expr.tpe, localSyms(bindings).filter(_.isTerm))

  def seqToRepeated(tree: Tree)(implicit ctx: Context): Tree =
    Typed(tree, TypeTree(tree.tpe.widen.translateParameterized(defn.SeqClass, defn.RepeatedParamClass)))

  /** A denotation exists really if it exists and does not point to a stale symbol. */
  final def reallyExists(denot: Denotation)(implicit ctx: Context): Boolean = try
    denot match {
      case denot: SymDenotation =>
        denot.exists && {
          denot.ensureCompleted
          !denot.isAbsent
        }
      case denot: SingleDenotation =>
        val sym = denot.symbol
        (sym eq NoSymbol) || reallyExists(sym.denot)
      case _ =>
        true
    }
  catch {
    case ex: StaleSymbol => false
  }

  /** If `tpe` is a named type, check that its denotation is accessible in the
   *  current context. Return the type with those alternatives as denotations
   *  which are accessible.
   *
   *  Also performs the following normalizations on the type `tpe`.
   *  (1) parameter accessors are always dereferenced.
   *  (2) if the owner of the denotation is a package object, it is assured
   *      that the package object shows up as the prefix.
   */
  def ensureAccessible(tpe: Type, superAccess: Boolean, pos: Position)(implicit ctx: Context): Type = {
    def test(tpe: Type, firstTry: Boolean): Type = tpe match {
      case tpe: NamedType =>
        val pre = tpe.prefix
        val name = tpe.name
        val d = tpe.denot.accessibleFrom(pre, superAccess)
        if (!d.exists) {
          // it could be that we found an inaccessible private member, but there is
          // an inherited non-private member with the same name and signature.
          val d2 = pre.nonPrivateMember(name)
          if (reallyExists(d2) && firstTry)
            test(tpe.shadowed.withDenot(d2), false)
          else if (pre.derivesFrom(defn.DynamicClass)) {
            TryDynamicCallType
          } else {
            val alts = tpe.denot.alternatives.map(_.symbol).filter(_.exists)
            val what = alts match {
              case Nil =>
                name.toString
              case sym :: Nil =>
                if (sym.owner == pre.typeSymbol) sym.show else sym.showLocated
              case _ =>
                em"none of the overloaded alternatives named $name"
            }
            val where = if (ctx.owner.exists) s" from ${ctx.owner.enclosingClass}" else ""
            val whyNot = new StringBuffer
            alts foreach (_.isAccessibleFrom(pre, superAccess, whyNot))
            if (!tpe.isError)
              ctx.error(ex"$what cannot be accessed as a member of $pre$where.$whyNot", pos)
            ErrorType
          }
        }
        else if (d.symbol is TypeParamAccessor)
          if (d.info.isAlias)
            ensureAccessible(d.info.bounds.hi, superAccess, pos)
          else // It's a named parameter, use the non-symbolic representation to pick up inherited versions as well
            d.symbol.owner.thisType.select(d.symbol.name)
        else
          ctx.makePackageObjPrefixExplicit(tpe withDenot d)
      case _ =>
        tpe
    }
    test(tpe, true)
  }

  /** The type of a selection with `name` of a tree with type `site`.
   */
  def selectionType(site: Type, name: Name, pos: Position)(implicit ctx: Context): Type = {
    val mbr = site.member(name)
    if (reallyExists(mbr)) site.select(name, mbr)
    else if (site.derivesFrom(defn.DynamicClass) && !Dynamic.isDynamicMethod(name)) {
      TryDynamicCallType
    } else {
      if (!site.isErroneous) {
        def kind = if (name.isTypeName) "type" else "value"
        def addendum =
          if (site.derivesFrom(defn.DynamicClass)) "\npossible cause: maybe a wrong Dynamic method signature?"
          else ""
        ctx.error(
          if (name == nme.CONSTRUCTOR) ex"$site does not have a constructor"
          else ex"$kind $name is not a member of $site$addendum",
          pos)
      }
      ErrorType
    }
  }

  /** The selection type, which is additionally checked for accessibility.
   */
  def accessibleSelectionType(tree: untpd.RefTree, qual1: Tree)(implicit ctx: Context): Type = {
    val ownType = selectionType(qual1.tpe.widenIfUnstable, tree.name, tree.pos)
    ensureAccessible(ownType, qual1.isInstanceOf[Super], tree.pos)
  }

  /** Type assignment method. Each method takes as parameters
   *   - an untpd.Tree to which it assigns a type,
   *   - typed child trees it needs to access to cpmpute that type,
   *   - any further information it needs to access to compute that type.
   */

  def assignType(tree: untpd.Ident, tp: Type)(implicit ctx: Context) =
    tree.withType(tp)

  def assignType(tree: untpd.Select, qual: Tree)(implicit ctx: Context): Select = {
    def qualType = qual.tpe.widen
    def arrayElemType = {
      val JavaArrayType(elemtp) = qualType
      elemtp
    }
    val p = nme.primitive
    val tp = tree.name match {
      case p.arrayApply => MethodType(defn.IntType :: Nil, arrayElemType)
      case p.arrayUpdate => MethodType(defn.IntType :: arrayElemType :: Nil, defn.UnitType)
      case p.arrayLength => MethodType(Nil, defn.IntType)

      // Note that we do not need to handle calls to Array[T]#clone() specially:
      // The JLS section 10.7 says "The return type of the clone method of an array type
      // T[] is T[]", but the actual return type at the bytecode level is Object which
      // is casted to T[] by javac. Since the return type of Array[T]#clone() is Array[T],
      // this is exactly what Erasure will do.

      case _ => accessibleSelectionType(tree, qual)
    }
    tree.withType(tp)
  }

  def assignType(tree: untpd.New, tpt: Tree)(implicit ctx: Context) =
    tree.withType(tpt.tpe)

  def assignType(tree: untpd.Literal)(implicit ctx: Context) =
    tree.withType {
      val value = tree.const
      value.tag match {
        case UnitTag => defn.UnitType
        case NullTag => defn.NullType
        case _ => if (ctx.erasedTypes) value.tpe else ConstantType(value)
      }
    }

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

  def assignType(tree: untpd.Super, qual: Tree, inConstrCall: Boolean, mixinClass: Symbol = NoSymbol)(implicit ctx: Context) = {
    val mix = tree.mix
    val qtype @ ThisType(_) = qual.tpe
    val cls = qtype.cls

    def findMixinSuper(site: Type): Type = site.parents filter (_.name == mix) match {
      case p :: Nil =>
        p
      case Nil =>
        errorType(em"$mix does not name a parent class of $cls", tree.pos)
      case p :: q :: _ =>
        errorType("ambiguous parent class qualifier", tree.pos)
    }
    val owntype =
      if (mixinClass.exists) mixinClass.typeRef
      else if (!mix.isEmpty) findMixinSuper(cls.info)
      else if (inConstrCall || ctx.erasedTypes) cls.info.firstParent
      else {
        val ps = cls.classInfo.parentsWithArgs
        if (ps.isEmpty) defn.AnyType else ps.reduceLeft((x: Type, y: Type) => x & y)
      }
    tree.withType(SuperType(cls.thisType, owntype))
  }

  def assignType(tree: untpd.Apply, fn: Tree, args: List[Tree])(implicit ctx: Context) = {
    val ownType = fn.tpe.widen match {
      case fntpe @ MethodType(_, ptypes) =>
        if (sameLength(ptypes, args) || ctx.phase.prev.relaxedTyping) fntpe.instantiate(args.tpes)
        else wrongNumberOfArgs(fn.tpe, "", ptypes.length, tree.pos)
      case t =>
        errorType(i"${err.exprStr(fn)} does not take parameters", tree.pos)
    }
    tree.withType(ownType)
  }

  def assignType(tree: untpd.TypeApply, fn: Tree, args: List[Tree])(implicit ctx: Context) = {
    val ownType = fn.tpe.widen match {
      case pt: PolyType =>
        val paramNames = pt.paramNames
        if (hasNamedArg(args)) {
          // Type arguments which are specified by name (immutable after this first loop)
          val namedArgMap = new mutable.HashMap[Name, Type]
          for (NamedArg(name, arg) <- args)
            if (namedArgMap.contains(name))
              ctx.error("duplicate name", arg.pos)
            else if (!paramNames.contains(name))
              ctx.error(s"undefined parameter name, required: ${paramNames.mkString(" or ")}", arg.pos)
            else
              namedArgMap(name) = arg.tpe

          // Holds indexes of non-named typed arguments in paramNames
          val gapBuf = new mutable.ListBuffer[Int]
          def nextPoly(idx: Int) = {
            val newIndex = gapBuf.length
            gapBuf += idx
            // Re-index unassigned type arguments that remain after transformation
            PolyParam(pt, newIndex)
          }

          // Type parameters after naming assignment, conserving paramNames order
          val normArgs: List[Type] = paramNames.zipWithIndex.map { case (pname, idx) =>
            namedArgMap.getOrElse(pname, nextPoly(idx))
          }

          val transform = new TypeMap {
            def apply(t: Type) = t match {
              case PolyParam(`pt`, idx) => normArgs(idx)
              case _ => mapOver(t)
            }
          }
          val resultType1 = transform(pt.resultType)
          if (gapBuf.isEmpty) resultType1
          else {
            val gaps = gapBuf.toList
            pt.derivedPolyType(
              gaps.map(paramNames),
              gaps.map(idx => transform(pt.paramBounds(idx)).bounds),
              resultType1)
          }
        }
        else {
          val argTypes = args.tpes
          if (sameLength(argTypes, paramNames) || ctx.phase.prev.relaxedTyping) pt.instantiate(argTypes)
          else wrongNumberOfArgs(fn.tpe, "type ", pt.paramNames.length, tree.pos)
        }
      case _ =>
        errorType(i"${err.exprStr(fn)} does not take type parameters", tree.pos)
    }

    tree.withType(ownType)
  }

  def assignType(tree: untpd.Typed, tpt: Tree)(implicit ctx: Context) =
    tree.withType(tpt.tpe)

  def assignType(tree: untpd.NamedArg, arg: Tree)(implicit ctx: Context) =
    tree.withType(arg.tpe)

  def assignType(tree: untpd.Assign)(implicit ctx: Context) =
    tree.withType(defn.UnitType)

  def assignType(tree: untpd.Block, stats: List[Tree], expr: Tree)(implicit ctx: Context) =
    tree.withType(avoidingType(expr, stats))

  def assignType(tree: untpd.Inlined, bindings: List[Tree], expansion: Tree)(implicit ctx: Context) =
    tree.withType(avoidingType(expansion, bindings))

  def assignType(tree: untpd.If, thenp: Tree, elsep: Tree)(implicit ctx: Context) =
    tree.withType(thenp.tpe | elsep.tpe)

  def assignType(tree: untpd.Closure, meth: Tree, target: Tree)(implicit ctx: Context) =
    tree.withType(
      if (target.isEmpty) meth.tpe.widen.toFunctionType(tree.env.length)
      else target.tpe)

  def assignType(tree: untpd.CaseDef, body: Tree)(implicit ctx: Context) =
    tree.withType(body.tpe)

  def assignType(tree: untpd.Match, cases: List[CaseDef])(implicit ctx: Context) =
    tree.withType(ctx.typeComparer.lub(cases.tpes))

  def assignType(tree: untpd.Return)(implicit ctx: Context) =
    tree.withType(defn.NothingType)

  def assignType(tree: untpd.Try, expr: Tree, cases: List[CaseDef])(implicit ctx: Context) =
    if (cases.isEmpty) tree.withType(expr.tpe)
    else tree.withType(ctx.typeComparer.lub(expr.tpe :: cases.tpes))

  def assignType(tree: untpd.SeqLiteral, elems: List[Tree], elemtpt: Tree)(implicit ctx: Context) = {
    val ownType = tree match {
      case tree: JavaSeqLiteral => defn.ArrayOf(elemtpt.tpe)
      case _ => if (ctx.erasedTypes) defn.SeqType else defn.SeqType.appliedTo(elemtpt.tpe)
    }
    tree.withType(ownType)
  }

  def assignType(tree: untpd.SingletonTypeTree, ref: Tree)(implicit ctx: Context) =
    tree.withType(ref.tpe)

  def assignType(tree: untpd.AndTypeTree, left: Tree, right: Tree)(implicit ctx: Context) =
    tree.withType(left.tpe & right.tpe)

  def assignType(tree: untpd.OrTypeTree, left: Tree, right: Tree)(implicit ctx: Context) =
    tree.withType(left.tpe | right.tpe)

  // RefinedTypeTree is missing, handled specially in Typer and Unpickler.

  def assignType(tree: untpd.AppliedTypeTree, tycon: Tree, args: List[Tree])(implicit ctx: Context) = {
    val tparams = tycon.tpe.typeParams
    lazy val ntparams = tycon.tpe.namedTypeParams
    def refineNamed(tycon: Type, arg: Tree) = arg match {
      case ast.Trees.NamedArg(name, argtpt) =>
        // Dotty deviation: importing ast.Trees._ and matching on NamedArg gives a cyclic ref error
        val tparam = tparams.find(_.paramName == name) match {
          case Some(tparam) => tparam
          case none => ntparams.find(_.name == name).getOrElse(NoSymbol)
        }
        if (tparam.isTypeParam) RefinedType(tycon, name, argtpt.tpe.toBounds(tparam))
        else errorType(i"$tycon does not have a parameter or abstract type member named $name", arg.pos)
      case _ =>
        errorType(s"named and positional type arguments may not be mixed", arg.pos)
    }
    val ownType =
      if (hasNamedArg(args)) (tycon.tpe /: args)(refineNamed)
      else if (sameLength(tparams, args)) tycon.tpe.appliedTo(args.tpes)
      else wrongNumberOfArgs(tycon.tpe, "type ", tparams.length, tree.pos)
    tree.withType(ownType)
  }

  def assignType(tree: untpd.TypeLambdaTree, tparamDefs: List[TypeDef], body: Tree)(implicit ctx: Context) =
    tree.withType(TypeLambda.fromSymbols(tparamDefs.map(_.symbol), body.tpe))

  def assignType(tree: untpd.ByNameTypeTree, result: Tree)(implicit ctx: Context) =
    tree.withType(ExprType(result.tpe))

  def assignType(tree: untpd.TypeBoundsTree, lo: Tree, hi: Tree)(implicit ctx: Context) =
    tree.withType(if (lo eq hi) TypeAlias(lo.tpe) else TypeBounds(lo.tpe, hi.tpe))

  def assignType(tree: untpd.Bind, sym: Symbol)(implicit ctx: Context) =
    tree.withType(NamedType.withFixedSym(NoPrefix, sym))

  def assignType(tree: untpd.Alternative, trees: List[Tree])(implicit ctx: Context) =
    tree.withType(ctx.typeComparer.lub(trees.tpes))

  def assignType(tree: untpd.UnApply, proto: Type)(implicit ctx: Context) =
    tree.withType(proto)

  def assignType(tree: untpd.ValDef, sym: Symbol)(implicit ctx: Context) =
    tree.withType(if (sym.exists) assertExists(symbolicIfNeeded(sym).orElse(sym.valRef)) else NoType)

  def assignType(tree: untpd.DefDef, sym: Symbol)(implicit ctx: Context) =
    tree.withType(symbolicIfNeeded(sym).orElse(sym.termRefWithSig))

  def assignType(tree: untpd.TypeDef, sym: Symbol)(implicit ctx: Context) =
    tree.withType(symbolicIfNeeded(sym).orElse(sym.typeRef))

  private def symbolicIfNeeded(sym: Symbol)(implicit ctx: Context) = {
    val owner = sym.owner
    owner.infoOrCompleter match {
      case info: ClassInfo if info.givenSelfType.exists =>
        // In that case a simple typeRef/termWithWithSig could return a member of
        // the self type, not the symbol itself. To avoid this, we make the reference
        // symbolic. In general it seems to be faster to keep the non-symblic
        // reference, since there is less pressure on the uniqueness tables that way
        // and less work to update all the different references. That's why symbolic references
        // are only used if necessary.
        NamedType.withFixedSym(owner.thisType, sym)
      case _ => NoType
    }
  }

  def assertExists(tp: Type) = { assert(tp != NoType); tp }

  def assignType(tree: untpd.Import, sym: Symbol)(implicit ctx: Context) =
    tree.withType(sym.nonMemberTermRef)

  def assignType(tree: untpd.Annotated, arg: Tree, annot: Tree)(implicit ctx: Context) =
    tree.withType(AnnotatedType(arg.tpe.widen, Annotation(annot)))

  def assignType(tree: untpd.PackageDef, pid: Tree)(implicit ctx: Context) =
    tree.withType(pid.symbol.valRef)
}

object TypeAssigner extends TypeAssigner