<commit_before>/* NSC -- new scala compiler
 * Copyright 2005 LAMP/EPFL
 * @author  <NAME>
 */
// $Id$
//todo: rewrite or disallow new T where T is a trait (currently: <init> not a member of T)
package scala.tools.nsc.typechecker;

import nsc.util.ListBuffer;
import symtab.Flags._;
import scala.tools.util.Position;
import collection.mutable.HashMap;

/** Methods to create symbols and to enter them into scopes. */
[_trait_] abstract class Typers: Analyzer {
  import global._;
  import definitions._;
  import posAssigner.atPos;

  var appcnt = 0;
  var idcnt = 0;
  var selcnt = 0;
  var implcnt = 0;
  var impltime = 0l;

  private val transformed = new HashMap[Tree, Tree];

  private val superDefs = new HashMap[Symbol, ListBuffer[Tree]];

  def resetTyper: unit = {
    resetContexts;
    transformed.clear;
    superDefs.clear;
  }

  def newTyper(context: Context): Typer = new Typer(context);

  class Typer(context0: Context) {
    import context0.unit;

    val infer = new Inferencer(context0) {
      override def isCoercible(tp: Type, pt: Type): boolean =
        tp.isError || pt.isError ||
	context0.reportGeneralErrors && // this condition prevents chains of views
	inferView(Position.NOPOS, tp, pt, false) != EmptyTree
    }

    private def inferView(pos: int, from: Type, to: Type, reportAmbiguous: boolean): Tree = {
      if (settings.debug.value) log("infer view from " + from + " to " + to);//debug
      if (phase.erasedTypes) EmptyTree
      else inferImplicit(pos, functionType(List(from), to), true, reportAmbiguous);
    }

    private def inferView(pos: int, from: Type, name: Name, reportAmbiguous: boolean): Tree = {
      val to = refinedType(List(WildcardType), NoSymbol);
      val psym = (if (name.isTypeName) to.symbol.newAbstractType(pos, name)
		  else to.symbol.newValue(pos, name)) setInfo WildcardType;
      to.decls.enter(psym);
      inferView(pos, from, to, reportAmbiguous)
    }

    import infer._;

    private var namerCache: Namer = null;
    def namer = {
      if (namerCache == null || namerCache.context != context) namerCache = new Namer(context);
      namerCache
    }

    private var context = context0;

    /** Mode constants
     */
    val NOmode        = 0x000;
    val EXPRmode      = 0x001;   // these 3 modes are mutually exclusive.
    val PATTERNmode   = 0x002;
    val TYPEmode      = 0x004;

    val INCONSTRmode  = 0x008;   // orthogonal to above. When set we are
                                 // in the body of a constructor

    val FUNmode       = 0x10;    // orthogonal to above. When set
                                 // we are looking for a method or constructor

    val POLYmode      = 0x020;   // orthogonal to above. When set
                                 // expression types can be polymorphic.

    val QUALmode      = 0x040;   // orthogonal to above. When set
                                 // expressions may be packages and
                                 // Java statics modules.

    val TAPPmode      = 0x080;   // Set for the function/type constructor part
	                         // of a type application. When set we do not
	                         // decompose PolyTypes.

    val SUPERCONSTRmode = 0x100; // Set for the `super' in a superclass constructor call
                                 // super.<init>

    private val stickyModes: int  = EXPRmode | PATTERNmode | TYPEmode;

    /** Report a type error.
     *  @param pos    The position where to report the error
     *  @param ex     The exception that caused the error */
    def reportTypeError(pos: int, ex: TypeError): unit = {
      val msg = ex match {
	case CyclicReference(sym, info: TypeCompleter) =>
	  info.tree match {
	    case ValDef(_, _, tpt, _) if (tpt.tpe == null) =>
	      "recursive " + sym + " needs type"
	    case DefDef(_, _, _, _, tpt, _) if (tpt.tpe == null) =>
	      "recursive " + sym + " needs result type"
	    case _ =>
	      ex.getMessage()
	  }
	case _ =>
	  ex.getMessage()
      }
      if (settings.debug.value) ex.printStackTrace();
      if (context.reportGeneralErrors) error(pos, msg)
      else throw new Error(msg)
    }

    /** Check that tree is a stable expression.
     */
    def checkStable(tree: Tree): Tree =
      if (treeInfo.isPureExpr(tree) || tree.tpe.isError) tree;
      else errorTree(tree, "stable identifier required, but " + tree + " found.");

    /** Check that type `tp' is not a subtype of itself.
     */
    def checkNonCyclic(pos: int, tp: Type): unit = {
      def checkNotLocked(sym: Symbol): boolean = {
	sym.initialize;
	if (sym hasFlag LOCKED) {
	  error(pos, "cyclic aliasing or subtyping involving " + sym); false
	} else true
      }
      tp match {
	case TypeRef(pre, sym, args) =>
	  if (checkNotLocked(sym) && (sym.isAliasType || sym.isAbstractType)) {
	    //System.out.println("checking " + sym);//DEBUG
	    checkNonCyclic(pos, pre.memberInfo(sym).subst(sym.typeParams, args), sym);
	  }
	case SingleType(pre, sym) =>
	  checkNotLocked(sym)
	case st: SubType =>
	  checkNonCyclic(pos, st.supertype)
	case ct: CompoundType =>
	  for (val p <- ct.parents) checkNonCyclic(pos, p)
	case _ =>
      }
    }

    def checkNonCyclic(pos: int, tp: Type, lockedSym: Symbol): unit = {
      lockedSym.setFlag(LOCKED);
      checkNonCyclic(pos, tp);
      lockedSym.resetFlag(LOCKED)
    }

    /** Check that type of given tree does not contain local or private components
     */
    object checkNoEscaping extends TypeMap {
      private var owner: Symbol = _;
      private var scope: Scope = _;
      private var badSymbol: Symbol = _;

      /** Check that type `tree' does not refer to private components unless itself is wrapped
       *  in something private (`owner' tells where the type occurs). */
      def privates[T <: Tree](owner: Symbol, tree: T): T = {
	check(owner, EmptyScope, tree);
      }

      /**  Check that type `tree' does not refer to entities defined in scope `scope'. */
      def locals[T <: Tree](scope: Scope, pt: Type, tree: T): T =
        if (isFullyDefined(pt)) tree setType pt else check(NoSymbol, scope, tree);

      def check[T <: Tree](owner: Symbol, scope: Scope, tree: T): T = {
        this.owner = owner;
        this.scope = scope;
        badSymbol = NoSymbol;
	assert(tree.tpe != null, tree);//debug
        apply(tree.tpe);
        if (badSymbol == NoSymbol) tree
        else {
          error(tree.pos,
                (if (badSymbol.hasFlag(PRIVATE)) "private " else "") + badSymbol +
                " escapes its defining scope as part of type " + tree.tpe);
          setError(tree)
        }
      }

      override def apply(t: Type): Type = {
        def checkNoEscape(sym: Symbol): unit = {
          if (sym.hasFlag(PRIVATE)) {
            var o = owner;
            while (o != NoSymbol && o != sym.owner && !o.isLocal && !o.hasFlag(PRIVATE))
              o = o.owner;
            if (o == sym.owner) badSymbol = sym
          } else if (sym.owner.isTerm) {
            val e = scope.lookupEntry(sym.name);
            if (e != null && e.sym == sym && e.owner == scope && !e.sym.isTypeParameter) badSymbol = e.sym
          }
        }
        if (badSymbol == NoSymbol)
          t match {
            case TypeRef(_, sym, _) => checkNoEscape(sym)
            case SingleType(_, sym) => checkNoEscape(sym)
            case _ =>
          }
        mapOver(t)
      }
    }

    def reenterValueParams(vparamss: List[List[ValDef]]): unit =
      for (val vparams <- vparamss; val vparam <- vparams) context.scope enter vparam.symbol;

    def reenterTypeParams(tparams: List[AbsTypeDef]): List[Symbol] =
      for (val tparam <- tparams) yield {
	context.scope enter tparam.symbol;
	tparam.symbol.deSkolemize
      }

    def attrInfo(attr: Tree): AttrInfo = attr match {
      case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) =>
        Pair(tpt.tpe, args map {
          case Literal(value) =>
            value
          case arg =>
            error(arg.pos, "attribute argument needs to be a constant; found: " + arg);
            null
        })
    }

    /** Post-process an identifier or selection node, performing the following:
     *  (1) Check that non-function pattern expressions are stable
     *  (2) Check that packages and static modules are not used as values
     *  (3) Turn tree type into stable type if possible and required by context. */
    private def stabilize(tree: Tree, pre: Type, mode: int, pt: Type): Tree = {
      if (tree.symbol.hasFlag(OVERLOADED) && (mode & FUNmode) == 0)
	inferExprAlternative(tree, pt);
      val sym = tree.symbol;
      if ((mode & (PATTERNmode | FUNmode)) == PATTERNmode && tree.isTerm) { // (1)
        checkStable(tree)
      } else if ((mode & (EXPRmode | QUALmode)) == EXPRmode && !sym.isValue) { // (2)
        errorTree(tree, sym.toString() + " is not a value");
      } else if (sym.isStable && pre.isStable && tree.tpe.symbol != ByNameParamClass &&
	         (pt.isStable || (mode & QUALmode) != 0 && !sym.isConstant ||
		  sym.isModule && !sym.isMethod)) {
	tree.setType(singleType(pre, sym))
      } else tree
    }

    def stabilizeFun(tree: Tree, mode: int, pt: Type): Tree = {
      val sym = tree.symbol;
      val pre = tree match {
	case Select(qual, _) => qual.tpe
	case _ => NoPrefix
      }
      if (tree.tpe.isInstanceOf[MethodType] && pre.isStable &&
	  (pt.isStable || (mode & QUALmode) != 0 && !sym.isConstant || sym.isModule)) {
	assert(sym.tpe.paramTypes.isEmpty);
	tree.setType(MethodType(List(), singleType(pre, sym)))
      } else tree
    }

    /** Perform the following adaptations of expression, pattern or type `tree' wrt to
     *  given mode `mode' and given prototype `pt':
     *  (0) Convert expressions with constant types to literals
     *  (1) Resolve overloading, unless mode contains FUNmode
     *  (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, convert to function by eta-expansion,
     *        except if the method is a constructor, in which case we issue an error.
     *  (5) Convert a class type that serves as a constructor in a pattern as follows:
     *  (5.1) If this type refers to a case class, set tree's type to the unique
     *        instance of its primary constructor that is a subtype of the expected type.
     *  (5.2) Otherwise, if this type is a subtype of scala.Seq[A], set trees' type
     *        to a method type from a repeated parameter sequence type A* to the expected type.
     *  (6) Convert all other types to TypeTree nodes.
     *  (7) When in TYPEmode nut not FUNmode, check that types are fully parameterized
     *  (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 a view
     *  If all this fails, error
     */
//    def adapt(tree: Tree, mode: int, pt: Type): Tree = {
    protected def adapt(tree: Tree, mode: int, pt: Type): Tree = tree.tpe match {
      case ct @ ConstantType(value) if ((mode & TYPEmode) == 0 && (ct <:< pt)) => // (0)
	copy.Literal(tree, value)
      case OverloadedType(pre, alts) if ((mode & FUNmode) == 0) => // (1)
	inferExprAlternative(tree, pt);
	adapt(tree, mode, pt)
      case PolyType(List(), restpe) => // (2)
	adapt(tree setType restpe, mode, pt);
      case TypeRef(_, sym, List(arg))
      if ((mode & EXPRmode) != 0 && sym == ByNameParamClass) => // (2)
	adapt(tree setType arg, mode, pt);
      case PolyType(tparams, restpe) if ((mode & TAPPmode) == 0) => // (3)
	val tparams1 = cloneSymbols(tparams);
        val tree1 = if (tree.isType) tree
                    else TypeApply(tree, tparams1 map (tparam =>
                      TypeTree() setPos tree.pos setType tparam.tpe)) setPos tree.pos;
	context.undetparams = context.undetparams ::: tparams1;
	adapt(tree1 setType restpe.substSym(tparams, tparams1), mode, pt)
      case mt: ImplicitMethodType if ((mode & (EXPRmode | FUNmode)) == EXPRmode) => // (4.1)
	val tree1 =
	  if (!context.undetparams.isEmpty & (mode & POLYmode) == 0) { // (9)
	    val tparams = context.undetparams;
	    context.undetparams = List();
	    inferExprInstance(tree, tparams, pt);
	    adapt(tree, mode, pt)
	  } else tree;
	typed(applyImplicitArgs(tree1), mode, pt)
      case mt: MethodType if ((mode & (EXPRmode | FUNmode)) == EXPRmode &&
	                      isCompatible(tree.tpe, pt)) => // (4.2)
	if (tree.symbol.isConstructor) errorTree(tree, "missing arguments for " + tree.symbol)
	else {
	  typed(etaExpand(tree), mode, pt)
	}
      case _ =>
	if (tree.isType) {
	  val clazz = tree.tpe.symbol;
	  if ((mode & PATTERNmode) != 0) { // (5)
	    if (tree.tpe.isInstanceOf[MethodType]) {
	      tree // everything done already
	    } else {
	      clazz.initialize;
	      if (clazz.hasFlag(CASE)) {   // (5.1)
		val tree1 = TypeTree() setPos tree.pos
		    setType
		      clazz.primaryConstructor.tpe.asSeenFrom(tree.tpe.prefix, clazz.owner);
		// tree.tpe.prefix.memberType(clazz.primaryConstructor); //!!!
		inferConstructorInstance(tree1, clazz.unsafeTypeParams, pt);
		tree1
	      } else if (clazz.isSubClass(SeqClass)) { // (5.2)
		pt.baseType(clazz).baseType(SeqClass) match {
		  case TypeRef(pre, seqClass, args) =>
		    tree.setType(MethodType(List(typeRef(pre, RepeatedParamClass, args)), pt))
		  case NoType =>
		    errorTree(tree, "expected pattern type " + pt +
			      " does not conform to sequence " + clazz)
		}
	      } else {
		if (!tree.tpe.isError)
		  error(tree.pos, clazz.toString() + " is neither a case class nor a sequence class");
		setError(tree)
	      }
	    }
	  } else if ((mode & FUNmode) != 0) {
	    tree
	  } else if (tree.hasSymbol && !tree.symbol.unsafeTypeParams.isEmpty) { // (7)
            errorTree(tree, "" + clazz + " takes type parameters");
          } else tree match { // (6)
            case TypeTree() => tree
            case _ => TypeTree() setPos tree.pos setType tree.tpe
          }
	} else if ((mode & (EXPRmode | FUNmode)) == (EXPRmode | FUNmode) &&
                   ((mode & TAPPmode) == 0 || tree.tpe.typeParams.isEmpty) &&
		   tree.tpe.member(nme.apply).filter(m => m.tpe.paramSectionCount > 0) != NoSymbol) { // (8)
	  typed(Select(tree, nme.apply) setPos tree.pos, mode, pt)
	} else if (!context.undetparams.isEmpty & (mode & POLYmode) == 0) { // (9)
	    val tparams = context.undetparams;
	    context.undetparams = List();
	    inferExprInstance(tree, tparams, pt);
	    adapt(tree, mode, pt)
	} else if (tree.tpe <:< pt) {
	  tree
	} else {
	  val tree1 = constfold(tree, pt); // (10) (11)
	  if (tree1.tpe <:< pt) adapt(tree1, mode, pt)
	  else {
            if ((mode & (EXPRmode | FUNmode)) == EXPRmode) {
              pt match {
                case TypeRef(_, sym, _) =>
                  // note: was if (pt.symbol == UnitClass) but this leads to a potentially
                  // infinite expansion if pt is constant type ()
                  if (sym == UnitClass && tree.tpe <:< AnyClass.tpe) // (12)
                    return typed(atPos(tree.pos)(Block(List(tree), Literal(()))), mode, pt)
                case _ =>
              }
	      if (context.reportGeneralErrors && !tree.tpe.isError && !pt.isError) {
		// (13); the condition prevents chains of views
	        val coercion = inferView(tree.pos, tree.tpe, pt, true);
	        if (coercion != EmptyTree) {
		  if (settings.debug.value) log("inferred view from " + tree.tpe + " to " + pt + " = " + coercion + ":" + coercion.tpe);
		  return typed(Apply(coercion, List(tree)) setPos tree.pos, mode, pt);
		}
	      }
            }
            if (settings.debug.value) log("error tree = " + tree);
	    typeErrorTree(tree, tree.tpe, pt)
          }
	}
    }
//      System.out.println("adapt " + tree + ":" + tree.tpe + ", mode = " + mode + ", pt = " + pt);
//      adapt(tree, mode, pt)
//    }

    private def completeSuperType(supertpt: Tree, tparams: List[Symbol], enclTparams: List[Symbol], vparamss: List[List[ValDef]], superargs: List[Tree]): Type = {
      enclTparams foreach context.scope.enter;
      namer.enterValueParams(context.owner, vparamss);
      val newTree = New(supertpt) setType
	PolyType(tparams, appliedType(supertpt.tpe, tparams map (.tpe)));
      val tree = typed(atPos(supertpt.pos)(Apply(Select(newTree, nme.CONSTRUCTOR), superargs)));
      if (settings.debug.value) log("superconstr " + tree + " co = " + context.owner);//debug
      tree.tpe
    }

    def parentTypes(templ: Template): List[Tree] = try {
      if (templ.parents.isEmpty) List()
      else {
	var supertpt = typedTypeConstructor(templ.parents.head);
	var mixins = templ.parents.tail map typedType;
	// If first parent is trait, make it first mixin and add its superclass as first parent
	while (supertpt.tpe.symbol != null && supertpt.tpe.symbol.initialize.isTrait) {
	  mixins = typedType(supertpt) :: mixins;
	  supertpt = TypeTree(supertpt.tpe.parents.head) setPos supertpt.pos;
	}
	if (supertpt.hasSymbol) {
	  val tparams = supertpt.symbol.typeParams;
	  if (!tparams.isEmpty) {
	    val constr @ DefDef(_, _, _, vparamss, _, Apply(_, superargs)) =
	      treeInfo.firstConstructor(templ.body);
	    val outercontext = context.outer;
	    supertpt = TypeTree(
	      newTyper(outercontext.makeNewScope(constr, outercontext.owner/*.newValue(templ.pos, newTermName("<dummy>"))*/))
		.completeSuperType(
		  supertpt,
                  tparams,
		  context.owner.unsafeTypeParams,
		  vparamss map (.map(.duplicate.asInstanceOf[ValDef])),
		  superargs map (.duplicate))) setPos supertpt.pos;
	  }
	}
	//System.out.println("parents(" + context.owner + ") = " + supertpt :: mixins);//DEBUG
	List.mapConserve(supertpt :: mixins)(tpt => checkNoEscaping.privates(context.owner, tpt))
      }
    } catch {
      case ex: TypeError =>
	reportTypeError(templ.pos, ex);
	List(TypeTree(AnyRefClass.tpe))
    }

    /** Check that
     *  - all parents are class types,
     *  - first parent cluss is not a trait; following classes are traits,
     *  - final classes are not inherited,
     *  - sealed classes are only inherited by classes which are
     *    nested within definition of base class, or that occur within same
     *    statement sequence,
     *  - self-type of current class is a subtype of self-type of each parent class.
     *  - no two parents define same symbol.
     */
    def validateParentClasses(parents: List[Tree], selfType: Type): unit = {
      var c = context;
      do { c = c.outer } while (c.owner == context.owner);
      val defscope = c.scope;

      def validateParentClass(parent: Tree, isFirst: boolean): unit =
	if (!parent.tpe.isError) {
	  val psym = parent.tpe.symbol.initialize;
	  if (!psym.isClass)
	    error(parent.pos, "class type expected");
	  else if (!isFirst && !psym.isTrait)
	    error(parent.pos, "" + psym + " is not a trait; cannot be used as mixin");
	  else if (psym.hasFlag(FINAL))
	    error(parent.pos, "illegal inheritance from final class");
	  else if (psym.isSealed && !phase.erasedTypes) {
	    // are we in same scope as base type definition?
	    val e = defscope.lookupEntry(psym.name);
	    if (!(e != null && e.sym == psym && e.owner == defscope)) {
	      // we are not within same statement sequence
	      var c = context;
	      while (c != NoContext && c.owner !=  psym) c = c.outer.enclClass;
	      if (c == NoContext) error(parent.pos, "illegal inheritance from sealed " + psym)
	    }
	  }
	  if (!(selfType <:< parent.tpe.typeOfThis) && !phase.erasedTypes) {
	    System.out.println(context.owner);//debug
	    System.out.println(context.owner.thisSym);//debug
	    error(parent.pos, "illegal inheritance;\n self-type " +
		  selfType + " does not conform to " + parent +
		  "'s selftype " + parent.tpe.typeOfThis);
	    if (settings.explaintypes.value) explainTypes(selfType, parent.tpe.typeOfThis);
	  }
	  if (parents exists (p => p != parent && p.tpe.symbol == psym && !psym.isError))
	    error(parent.pos, "" + psym + " is inherited twice")
	}

      if (!parents.isEmpty) {
        validateParentClass(parents.head, true);
        for (val p <- parents.tail) validateParentClass(p, false);
      }
    }

    def typedClassDef(cdef: ClassDef): Tree = {
      val clazz = cdef.symbol;
      reenterTypeParams(cdef.tparams);
      val tparams1 = List.mapConserve(cdef.tparams)(typedAbsTypeDef);
      val tpt1 = checkNoEscaping.privates(clazz.thisSym, typedType(cdef.tpt));
      val impl1 = newTyper(context.make(cdef.impl, clazz, new Scope()))
        .typedTemplate(cdef.impl, parentTypes(cdef.impl));
      val impl2 = addSyntheticMethods(impl1, clazz);
      copy.ClassDef(cdef, cdef.mods, cdef.name, tparams1, tpt1, impl2)
	setType NoType
    }

    def typedModuleDef(mdef: ModuleDef): Tree = {
      val clazz = mdef.symbol.moduleClass;
      val impl1 = newTyper(context.make(mdef.impl, clazz, new Scope()))
        .typedTemplate(mdef.impl, parentTypes(mdef.impl));
      copy.ModuleDef(mdef, mdef.mods, mdef.name, impl1) setType NoType
    }

    def addGetterSetter(stat: Tree): List[Tree] = stat match {
      case ValDef(mods, name, tpe, rhs) if (mods & LOCAL) == 0 && !stat.symbol.isModuleVar =>
	val vdef = copy.ValDef(stat, mods | PRIVATE | LOCAL, nme.getterToLocal(name), tpe, rhs);
        val value = vdef.symbol;
        val getter = if ((mods & DEFERRED) != 0) value else value.getter(value.owner);
	if (getter hasFlag OVERLOADED) System.out.println("overloaded getter: " + getter.alternatives + getter.alternatives.map(.tpe));//debug
        assert(getter != NoSymbol, value);//debug
	val getterDef: DefDef = {
	  val result = atPos(vdef.pos)(
	    DefDef(getter, vparamss =>
	      if ((mods & DEFERRED) != 0) EmptyTree
	      else typed(Select(This(value.owner), value), EXPRmode, value.tpe)));
          checkNoEscaping.privates(getter, result.tpt);
          result
	}
	def setterDef: DefDef = {
	  val setter = value.owner.info.decl(nme.getterToSetter(getter.name));
          assert(setter != NoSymbol, getter);//debug
          atPos(vdef.pos)(
	    DefDef(setter, vparamss =>
	      if ((mods & DEFERRED) != 0) EmptyTree
	      else typed(Assign(Select(This(value.owner), value),
				Ident(vparamss.head.head)))))
	}
	val gs = if ((mods & MUTABLE) != 0) List(getterDef, setterDef)
                 else List(getterDef);
	if ((mods & DEFERRED) != 0) gs else vdef :: gs
      case DocDef(comment, defn) =>
	addGetterSetter(defn) map (stat => DocDef(comment, stat))
      case Attributed(attr, defn) =>
	addGetterSetter(defn) map (stat => Attributed(attr.duplicate, stat))
      case _ =>
	List(stat)
    }

    def typedTemplate(templ: Template, parents1: List[Tree]): Template = {
      val clazz = context.owner;
      if (templ.symbol == NoSymbol) templ setSymbol clazz.newLocalDummy(templ.pos);
      val selfType =
        if (clazz.isAnonymousClass && !phase.erasedTypes)
          intersectionType(clazz.info.parents, clazz.owner)
        else clazz.typeOfThis;
      // the following is necessary for templates generated later
      new Namer(context.outer.make(templ, clazz, clazz.info.decls)).enterSyms(templ.body);
      validateParentClasses(parents1, selfType);
      val body1 = typedStats(templ.body flatMap addGetterSetter, templ.symbol);
      copy.Template(templ, parents1, body1) setType clazz.tpe
    }

    def typedValDef(vdef: ValDef): ValDef = {
      val sym = vdef.symbol;
      var tpt1 = checkNoEscaping.privates(sym, typedType(vdef.tpt));
      checkNonCyclic(vdef.pos, tpt1.tpe, sym);
      val rhs1 =
        if (vdef.rhs.isEmpty) {
          if (sym.isVariable && sym.owner.isTerm && phase.id <= currentRun.typerPhase.id)
            error(vdef.pos, "local variables must be initialized");
          vdef.rhs
        } else {
          newTyper(context.make(vdef, sym)).transformedOrTyped(vdef.rhs, tpt1.tpe)
        }
      copy.ValDef(vdef, vdef.mods, vdef.name, tpt1, rhs1) setType NoType
    }

    /** Enter all aliases of local parameter accessors. */
    def computeParamAliases(clazz: Symbol, vparamss: List[List[ValDef]], rhs: Tree): unit = {
      if (settings.debug.value) log("computing param aliases for " + clazz + ":" + clazz.primaryConstructor.tpe + ":" + rhs);//debug
      def decompose(call: Tree): Pair[Tree, List[Tree]] = call match {
	case Apply(fn, args) =>
	  val Pair(superConstr, args1) = decompose(fn);
	  val formals = fn.tpe.paramTypes;
	  val args2 = if (formals.isEmpty || formals.last.symbol != RepeatedParamClass) args
		      else args.take(formals.length - 1) ::: List(EmptyTree);
	  if (args2.length != formals.length) assert(false, "mismatch " + clazz + " " + formals + " " + args2);//debug
	  Pair(superConstr, args1 ::: args2)
	case Block(stats, expr) =>
	  decompose(stats.head)
	case _ =>
	  Pair(call, List())
      }
      val Pair(superConstr, superArgs) = decompose(rhs);
      assert(superConstr.symbol != null, superConstr);//debug
      if (superConstr.symbol.isPrimaryConstructor) {
	val superClazz = superConstr.symbol.owner;
        if (!superClazz.hasFlag(JAVA)) {
	  val superParamAccessors = superClazz.constrParamAccessors;
	  if (superParamAccessors.length != superArgs.length) {
	    System.out.println("" + superClazz + ":" + superClazz.info.decls.toList.filter(.hasFlag(PARAMACCESSOR)));
	    assert(false, "mismatch: " + superParamAccessors + ";" + rhs + ";" + superClazz.info.decls); //debug
	  }
	  List.map2(superParamAccessors, superArgs) { (superAcc, superArg) =>
	    superArg match {
	      case Ident(name) =>
	        if (vparamss.exists(.exists(vp => vp.symbol == superArg.symbol))) {
		  var alias = superAcc.initialize.alias;
		  if (alias == NoSymbol)
                    alias = superAcc.getter(superAcc.owner);
		  if (alias != NoSymbol &&
		      superClazz.info.nonPrivateMember(alias.name) != alias)
		    alias = NoSymbol;
		  if (alias != NoSymbol) {
		    var ownAcc = clazz.info.decl(name);
		    if (ownAcc hasFlag ACCESSOR) ownAcc = ownAcc.accessed;
		    if (settings.debug.value) log("" + ownAcc + " has alias " + alias + alias.locationString);//debug
		    ownAcc.asInstanceOf[TermSymbol].setAlias(alias)
		  }
	        }
	      case _ =>
	    }
          }
	  ()
        }
      }
    }

    def typedDefDef(ddef: DefDef): DefDef = {
      val meth = ddef.symbol;
      reenterTypeParams(ddef.tparams);
      reenterValueParams(ddef.vparamss);
      val tparams1 = List.mapConserve(ddef.tparams)(typedAbsTypeDef);
      val vparamss1 = List.mapConserve(ddef.vparamss)(vparams1 =>
	List.mapConserve(vparams1)(typedValDef));
      for (val vparams <- vparamss1; val vparam <- vparams) {
	checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); ()
      }
      var tpt1 =
	checkNoEscaping.locals(context.scope, WildcardType,
	  checkNoEscaping.privates(meth,
	      typedType(ddef.tpt)));
      checkNonCyclic(ddef.pos, tpt1.tpe, meth);
      val rhs1 =
	if (ddef.name == nme.CONSTRUCTOR) {
	  if (!meth.hasFlag(SYNTHETIC) &&
	      !(meth.owner.isClass ||
		meth.owner.isModuleClass ||
		meth.owner.isAnonymousClass ||
		meth.owner.isRefinementClass))
	    error(ddef.pos, "constructor definition not allowed here " + meth.owner);//debug
	  context.enclClass.owner.setFlag(INCONSTRUCTOR);
	  val result = typed(ddef.rhs, EXPRmode | INCONSTRmode, UnitClass.tpe);
	  context.enclClass.owner.resetFlag(INCONSTRUCTOR);
	  if (meth.isPrimaryConstructor && !phase.erasedTypes && reporter.errors() == 0)
	    computeParamAliases(meth.owner, vparamss1, result);
	  result
	} else transformedOrTyped(ddef.rhs, tpt1.tpe);
      copy.DefDef(ddef, ddef.mods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType
    }

    def typedAbsTypeDef(tdef: AbsTypeDef): AbsTypeDef = {
      val lo1 = checkNoEscaping.privates(tdef.symbol, typedType(tdef.lo));
      val hi1 = checkNoEscaping.privates(tdef.symbol, typedType(tdef.hi));
      checkNonCyclic(tdef.pos, tdef.symbol.tpe);
      copy.AbsTypeDef(tdef, tdef.mods, tdef.name, lo1, hi1) setType NoType
    }

    def typedAliasTypeDef(tdef: AliasTypeDef): AliasTypeDef = {
      reenterTypeParams(tdef.tparams);
      val tparams1 = List.mapConserve(tdef.tparams)(typedAbsTypeDef);
      val rhs1 = checkNoEscaping.privates(tdef.symbol, typedType(tdef.rhs));
      checkNonCyclic(tdef.pos, tdef.symbol.tpe);
      copy.AliasTypeDef(tdef, tdef.mods, tdef.name, tparams1, rhs1) setType NoType
    }

    private def enterLabelDef(stat: Tree): unit = stat match {
      case ldef @ LabelDef(_, _, _) =>
        if (ldef.symbol == NoSymbol)
          ldef.symbol = namer.enterInScope(
            context.owner.newLabel(ldef.pos, ldef.name) setInfo MethodType(List(), UnitClass.tpe));
      case _ =>
    }

    def typedLabelDef(ldef: LabelDef): LabelDef = {
      val restpe = ldef.symbol.tpe.resultType;
      val rhs1 = typed(ldef.rhs, restpe);
      ldef.params foreach (param => param.tpe = param.symbol.tpe);
      copy.LabelDef(ldef, ldef.name, ldef.params, rhs1) setType restpe
    }

    def typedBlock(block: Block, mode: int, pt: Type): Block = {
      namer.enterSyms(block.stats);
      block.stats foreach enterLabelDef;
      val stats1 =
        if ((mode & INCONSTRmode) != 0) {
          val constrCall = typed(block.stats.head, mode, WildcardType);
          context.enclClass.owner.resetFlag(INCONSTRUCTOR);
          constrCall :: typedStats(block.stats.tail, context.owner);
        } else {
	  typedStats(block.stats, context.owner)
        }
      val expr1 = typed(block.expr, mode & ~(FUNmode | QUALmode), pt);
      val block1 = copy.Block(block, stats1, expr1)
        setType (if (treeInfo.isPureExpr(block)) expr1.tpe else expr1.tpe.deconst);
      if (isFullyDefined(pt)) block1
      else {
	if (block1.tpe.symbol.isAnonymousClass)
	  block1 setType intersectionType(block1.tpe.parents, block1.tpe.symbol.owner);
	checkNoEscaping.locals(context.scope, pt, block1)
      }
    }

    def typedCase(cdef: CaseDef, pattpe: Type, pt: Type): CaseDef = {
      val pat1: Tree = typedPattern(cdef.pat, pattpe);
      val guard1: Tree = if (cdef.guard == EmptyTree) EmptyTree
	                 else typed(cdef.guard, BooleanClass.tpe);
      val body1: Tree = typed(cdef.body, pt);
      context.restoreTypeBounds;
      copy.CaseDef(cdef, pat1, guard1, body1) setType body1.tpe
    }

    def typedCases(tree: Tree, cases: List[CaseDef], pattp: Type, pt: Type): List[CaseDef] = {
      List.mapConserve(cases)(cdef =>
	newTyper(context.makeNewScope(cdef, context.owner)).typedCase(cdef, pattp, pt))
    }

    def typedFunction(fun: Function, mode: int, pt: Type): Tree = {
      def decompose(pt: Type): Triple[Symbol, List[Type], Type] =<commit_msg>*** empty log message ***<commit_after>/* NSC -- new scala compiler
 * Copyright 2005 LAMP/EPFL
 * @author  <NAME>
 */
// $Id$
//todo: rewrite or disallow new T where T is a trait (currently: <init> not a member of T)
package scala.tools.nsc.typechecker;

import nsc.util.ListBuffer;
import symtab.Flags._;
import scala.tools.util.Position;
import collection.mutable.HashMap;

/** Methods to create symbols and to enter them into scopes. */
[_trait_] abstract class Typers: Analyzer {
  import global._;
  import definitions._;
  import posAssigner.atPos;

  var appcnt = 0;
  var idcnt = 0;
  var selcnt = 0;
  var implcnt = 0;
  var impltime = 0l;

  private val transformed = new HashMap[Tree, Tree];

  private val superDefs = new HashMap[Symbol, ListBuffer[Tree]];

  def resetTyper: unit = {
    resetContexts;
    transformed.clear;
    superDefs.clear;
  }

  def newTyper(context: Context): Typer = new Typer(context);

  class Typer(context0: Context) {
    import context0.unit;

    val infer = new Inferencer(context0) {
      override def isCoercible(tp: Type, pt: Type): boolean =
        tp.isError || pt.isError ||
	context0.reportGeneralErrors && // this condition prevents chains of views
	inferView(Position.NOPOS, tp, pt, false) != EmptyTree
    }

    private def inferView(pos: int, from: Type, to: Type, reportAmbiguous: boolean): Tree = {
      if (settings.debug.value) log("infer view from " + from + " to " + to);//debug
      if (phase.erasedTypes) EmptyTree
      else inferImplicit(pos, functionType(List(from), to), true, reportAmbiguous);
    }

    private def inferView(pos: int, from: Type, name: Name, reportAmbiguous: boolean): Tree = {
      val to = refinedType(List(WildcardType), NoSymbol);
      val psym = (if (name.isTypeName) to.symbol.newAbstractType(pos, name)
		  else to.symbol.newValue(pos, name)) setInfo WildcardType;
      to.decls.enter(psym);
      inferView(pos, from, to, reportAmbiguous)
    }

    import infer._;

    private var namerCache: Namer = null;
    def namer = {
      if (namerCache == null || namerCache.context != context) namerCache = new Namer(context);
      namerCache
    }

    private var context = context0;

    /** Mode constants
     */
    val NOmode        = 0x000;
    val EXPRmode      = 0x001;   // these 3 modes are mutually exclusive.
    val PATTERNmode   = 0x002;
    val TYPEmode      = 0x004;

    val INCONSTRmode  = 0x008;   // orthogonal to above. When set we are
                                 // in the body of a constructor

    val FUNmode       = 0x10;    // orthogonal to above. When set
                                 // we are looking for a method or constructor

    val POLYmode      = 0x020;   // orthogonal to above. When set
                                 // expression types can be polymorphic.

    val QUALmode      = 0x040;   // orthogonal to above. When set
                                 // expressions may be packages and
                                 // Java statics modules.

    val TAPPmode      = 0x080;   // Set for the function/type constructor part
	                         // of a type application. When set we do not
	                         // decompose PolyTypes.

    val SUPERCONSTRmode = 0x100; // Set for the `super' in a superclass constructor call
                                 // super.<init>

    private val stickyModes: int  = EXPRmode | PATTERNmode | TYPEmode;

    /** Report a type error.
     *  @param pos    The position where to report the error
     *  @param ex     The exception that caused the error */
    def reportTypeError(pos: int, ex: TypeError): unit = {
      val msg = ex match {
	case CyclicReference(sym, info: TypeCompleter) =>
	  info.tree match {
	    case ValDef(_, _, tpt, _) if (tpt.tpe == null) =>
	      "recursive " + sym + " needs type"
	    case DefDef(_, _, _, _, tpt, _) if (tpt.tpe == null) =>
	      "recursive " + sym + " needs result type"
	    case _ =>
	      ex.getMessage()
	  }
	case _ =>
	  ex.getMessage()
      }
      if (settings.debug.value) ex.printStackTrace();
      if (context.reportGeneralErrors) error(pos, msg)
      else throw new Error(msg)
    }

    /** Check that tree is a stable expression.
     */
    def checkStable(tree: Tree): Tree =
      if (treeInfo.isPureExpr(tree) || tree.tpe.isError) tree;
      else errorTree(tree, "stable identifier required, but " + tree + " found.");

    /** Check that type `tp' is not a subtype of itself.
     */
    def checkNonCyclic(pos: int, tp: Type): unit = {
      def checkNotLocked(sym: Symbol): boolean = {
	sym.initialize;
	if (sym hasFlag LOCKED) {
	  error(pos, "cyclic aliasing or subtyping involving " + sym); false
	} else true
      }
      tp match {
	case TypeRef(pre, sym, args) =>
	  if (checkNotLocked(sym) && (sym.isAliasType || sym.isAbstractType)) {
	    //System.out.println("checking " + sym);//DEBUG
	    checkNonCyclic(pos, pre.memberInfo(sym).subst(sym.typeParams, args), sym);
	  }
	case SingleType(pre, sym) =>
	  checkNotLocked(sym)
	case st: SubType =>
	  checkNonCyclic(pos, st.supertype)
	case ct: CompoundType =>
	  for (val p <- ct.parents) checkNonCyclic(pos, p)
	case _ =>
      }
    }

    def checkNonCyclic(pos: int, tp: Type, lockedSym: Symbol): unit = {
      lockedSym.setFlag(LOCKED);
      checkNonCyclic(pos, tp);
      lockedSym.resetFlag(LOCKED)
    }

    /** Check that type of given tree does not contain local or private components
     */
    object checkNoEscaping extends TypeMap {
      private var owner: Symbol = _;
      private var scope: Scope = _;
      private var badSymbol: Symbol = _;

      /** Check that type `tree' does not refer to private components unless itself is wrapped
       *  in something private (`owner' tells where the type occurs). */
      def privates[T <: Tree](owner: Symbol, tree: T): T = {
	check(owner, EmptyScope, tree);
      }

      /**  Check that type `tree' does not refer to entities defined in scope `scope'. */
      def locals[T <: Tree](scope: Scope, pt: Type, tree: T): T =
        if (isFullyDefined(pt)) tree setType pt else check(NoSymbol, scope, tree);

      def check[T <: Tree](owner: Symbol, scope: Scope, tree: T): T = {
        this.owner = owner;
        this.scope = scope;
        badSymbol = NoSymbol;
	assert(tree.tpe != null, tree);//debug
        apply(tree.tpe);
        if (badSymbol == NoSymbol) tree
        else {
          error(tree.pos,
                (if (badSymbol.hasFlag(PRIVATE)) "private " else "") + badSymbol +
                " escapes its defining scope as part of type " + tree.tpe);
          setError(tree)
        }
      }

      override def apply(t: Type): Type = {
        def checkNoEscape(sym: Symbol): unit = {
          if (sym.hasFlag(PRIVATE)) {
            var o = owner;
            while (o != NoSymbol && o != sym.owner && !o.isLocal && !o.hasFlag(PRIVATE))
              o = o.owner;
            if (o == sym.owner) badSymbol = sym
          } else if (sym.owner.isTerm) {
            val e = scope.lookupEntry(sym.name);
            if (e != null && e.sym == sym && e.owner == scope && !e.sym.isTypeParameter) badSymbol = e.sym
          }
        }
        if (badSymbol == NoSymbol)
          t match {
            case TypeRef(_, sym, _) => checkNoEscape(sym)
            case SingleType(_, sym) => checkNoEscape(sym)
            case _ =>
          }
        mapOver(t)
      }
    }

    def reenterValueParams(vparamss: List[List[ValDef]]): unit =
      for (val vparams <- vparamss; val vparam <- vparams) context.scope enter vparam.symbol;

    def reenterTypeParams(tparams: List[AbsTypeDef]): List[Symbol] =
      for (val tparam <- tparams) yield {
	context.scope enter tparam.symbol;
	tparam.symbol.deSkolemize
      }

    def attrInfo(attr: Tree): AttrInfo = attr match {
      case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) =>
        Pair(tpt.tpe, args map {
          case Literal(value) =>
            value
          case arg =>
            error(arg.pos, "attribute argument needs to be a constant; found: " + arg);
            null
        })
    }

    /** Post-process an identifier or selection node, performing the following:
     *  (1) Check that non-function pattern expressions are stable
     *  (2) Check that packages and static modules are not used as values
     *  (3) Turn tree type into stable type if possible and required by context. */
    private def stabilize(tree: Tree, pre: Type, mode: int, pt: Type): Tree = {
      if (tree.symbol.hasFlag(OVERLOADED) && (mode & FUNmode) == 0)
	inferExprAlternative(tree, pt);
      val sym = tree.symbol;
      if ((mode & (PATTERNmode | FUNmode)) == PATTERNmode && tree.isTerm) { // (1)
        checkStable(tree)
      } else if ((mode & (EXPRmode | QUALmode)) == EXPRmode && !sym.isValue) { // (2)
        errorTree(tree, sym.toString() + " is not a value");
      } else if (sym.isStable && pre.isStable && tree.tpe.symbol != ByNameParamClass &&
	         (pt.isStable || (mode & QUALmode) != 0 && !sym.isConstant ||
		  sym.isModule && !sym.isMethod)) {
	tree.setType(singleType(pre, sym))
      } else tree
    }

    def stabilizeFun(tree: Tree, mode: int, pt: Type): Tree = {
      val sym = tree.symbol;
      val pre = tree match {
	case Select(qual, _) => qual.tpe
	case _ => NoPrefix
      }
      if (tree.tpe.isInstanceOf[MethodType] && pre.isStable &&
	  (pt.isStable || (mode & QUALmode) != 0 && !sym.isConstant || sym.isModule)) {
	assert(sym.tpe.paramTypes.isEmpty);
	tree.setType(MethodType(List(), singleType(pre, sym)))
      } else tree
    }

    /** Perform the following adaptations of expression, pattern or type `tree' wrt to
     *  given mode `mode' and given prototype `pt':
     *  (0) Convert expressions with constant types to literals
     *  (1) Resolve overloading, unless mode contains FUNmode
     *  (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, convert to function by eta-expansion,
     *        except if the method is a constructor, in which case we issue an error.
     *  (5) Convert a class type that serves as a constructor in a pattern as follows:
     *  (5.1) If this type refers to a case class, set tree's type to the unique
     *        instance of its primary constructor that is a subtype of the expected type.
     *  (5.2) Otherwise, if this type is a subtype of scala.Seq[A], set trees' type
     *        to a method type from a repeated parameter sequence type A* to the expected type.
     *  (6) Convert all other types to TypeTree nodes.
     *  (7) When in TYPEmode nut not FUNmode, check that types are fully parameterized
     *  (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 a view
     *  If all this fails, error
     */
//    def adapt(tree: Tree, mode: int, pt: Type): Tree = {
    protected def adapt(tree: Tree, mode: int, pt: Type): Tree = tree.tpe match {
      case ct @ ConstantType(value) if ((mode & TYPEmode) == 0 && (ct <:< pt)) => // (0)
	copy.Literal(tree, value)
      case OverloadedType(pre, alts) if ((mode & FUNmode) == 0) => // (1)
	inferExprAlternative(tree, pt);
	adapt(tree, mode, pt)
      case PolyType(List(), restpe) => // (2)
	adapt(tree setType restpe, mode, pt);
      case TypeRef(_, sym, List(arg))
      if ((mode & EXPRmode) != 0 && sym == ByNameParamClass) => // (2)
	adapt(tree setType arg, mode, pt);
      case PolyType(tparams, restpe) if ((mode & TAPPmode) == 0) => // (3)
	val tparams1 = cloneSymbols(tparams);
        val tree1 = if (tree.isType) tree
                    else TypeApply(tree, tparams1 map (tparam =>
                      TypeTree() setPos tree.pos setType tparam.tpe)) setPos tree.pos;
	context.undetparams = context.undetparams ::: tparams1;
	adapt(tree1 setType restpe.substSym(tparams, tparams1), mode, pt)
      case mt: ImplicitMethodType if ((mode & (EXPRmode | FUNmode)) == EXPRmode) => // (4.1)
	val tree1 =
	  if (!context.undetparams.isEmpty & (mode & POLYmode) == 0) { // (9)
	    val tparams = context.undetparams;
	    context.undetparams = List();
	    inferExprInstance(tree, tparams, pt);
	    adapt(tree, mode, pt)
	  } else tree;
	typed(applyImplicitArgs(tree1), mode, pt)
      case mt: MethodType if ((mode & (EXPRmode | FUNmode)) == EXPRmode &&
	                      isCompatible(tree.tpe, pt)) => // (4.2)
	if (tree.symbol.isConstructor) errorTree(tree, "missing arguments for " + tree.symbol)
	else {
	  typed(etaExpand(tree), mode, pt)
	}
      case _ =>
	if (tree.isType) {
	  val clazz = tree.tpe.symbol;
	  if ((mode & PATTERNmode) != 0) { // (5)
	    if (tree.tpe.isInstanceOf[MethodType]) {
	      tree // everything done already
	    } else {
	      clazz.initialize;
	      if (clazz.hasFlag(CASE)) {   // (5.1)
		val tree1 = TypeTree() setPos tree.pos
		    setType
		      clazz.primaryConstructor.tpe.asSeenFrom(tree.tpe.prefix, clazz.owner);
		// tree.tpe.prefix.memberType(clazz.primaryConstructor); //!!!
		inferConstructorInstance(tree1, clazz.unsafeTypeParams, pt);
		tree1
	      } else if (clazz.isSubClass(SeqClass)) { // (5.2)
		pt.baseType(clazz).baseType(SeqClass) match {
		  case TypeRef(pre, seqClass, args) =>
		    tree.setType(MethodType(List(typeRef(pre, RepeatedParamClass, args)), pt))
		  case NoType =>
		    errorTree(tree, "expected pattern type " + pt +
			      " does not conform to sequence " + clazz)
		}
	      } else {
		if (!tree.tpe.isError)
		  error(tree.pos, clazz.toString() + " is neither a case class nor a sequence class");
		setError(tree)
	      }
	    }
	  } else if ((mode & FUNmode) != 0) {
	    tree
	  } else if (tree.hasSymbol && !tree.symbol.unsafeTypeParams.isEmpty) { // (7)
            errorTree(tree, "" + clazz + " takes type parameters");
          } else tree match { // (6)
            case TypeTree() => tree
            case _ => TypeTree() setPos tree.pos setType tree.tpe
          }
	} else if ((mode & (EXPRmode | FUNmode)) == (EXPRmode | FUNmode) &&
                   ((mode & TAPPmode) == 0 || tree.tpe.typeParams.isEmpty) &&
		   tree.tpe.member(nme.apply).filter(m => m.tpe.paramSectionCount > 0) != NoSymbol) { // (8)
	  typed(Select(tree, nme.apply) setPos tree.pos, mode, pt)
	} else if (!context.undetparams.isEmpty & (mode & POLYmode) == 0) { // (9)
	    val tparams = context.undetparams;
	    context.undetparams = List();
	    inferExprInstance(tree, tparams, pt);
	    adapt(tree, mode, pt)
	} else if (tree.tpe <:< pt) {
	  tree
	} else {
	  val tree1 = constfold(tree, pt); // (10) (11)
	  if (tree1.tpe <:< pt) adapt(tree1, mode, pt)
	  else {
            if ((mode & (EXPRmode | FUNmode)) == EXPRmode) {
              pt match {
                case TypeRef(_, sym, _) =>
                  // note: was if (pt.symbol == UnitClass) but this leads to a potentially
                  // infinite expansion if pt is constant type ()
                  if (sym == UnitClass && tree.tpe <:< AnyClass.tpe) // (12)
                    return typed(atPos(tree.pos)(Block(List(tree), Literal(()))), mode, pt)
                case _ =>
              }
	      if (context.reportGeneralErrors && !tree.tpe.isError && !pt.isError) {
		// (13); the condition prevents chains of views
	        val coercion = inferView(tree.pos, tree.tpe, pt, true);
	        if (coercion != EmptyTree) {
		  if (settings.debug.value) log("inferred view from " + tree.tpe + " to " + pt + " = " + coercion + ":" + coercion.tpe);
		  return typed(Apply(coercion, List(tree)) setPos tree.pos, mode, pt);
		}
	      }
            }
            if (settings.debug.value) log("error tree = " + tree);
	    typeErrorTree(tree, tree.tpe, pt)
          }
	}
    }
//      System.out.println("adapt " + tree + ":" + tree.tpe + ", mode = " + mode + ", pt = " + pt);
//      adapt(tree, mode, pt)
//    }

    private def completeSuperType(supertpt: Tree, tparams: List[Symbol], enclTparams: List[Symbol], vparamss: List[List[ValDef]], superargs: List[Tree]): Type = {
      enclTparams foreach context.scope.enter;
      namer.enterValueParams(context.owner, vparamss);
      val newTree = New(supertpt) setType
	PolyType(tparams, appliedType(supertpt.tpe, tparams map (.tpe)));
      val tree = typed(atPos(supertpt.pos)(Apply(Select(newTree, nme.CONSTRUCTOR), superargs)));
      if (settings.debug.value) log("superconstr " + tree + " co = " + context.owner);//debug
      tree.tpe
    }

    def parentTypes(templ: Template): List[Tree] = try {
      if (templ.parents.isEmpty) List()
      else {
	var supertpt = typedTypeConstructor(templ.parents.head);
	var mixins = templ.parents.tail map typedType;
	// If first parent is trait, make it first mixin and add its superclass as first parent
	while (supertpt.tpe.symbol != null && supertpt.tpe.symbol.initialize.isTrait) {
	  mixins = typedType(supertpt) :: mixins;
	  supertpt = TypeTree(supertpt.tpe.parents.head) setPos supertpt.pos;
	}
	if (supertpt.hasSymbol) {
	  val tparams = supertpt.symbol.typeParams;
	  if (!tparams.isEmpty) {
	    val constr @ DefDef(_, _, _, vparamss, _, Apply(_, superargs)) =
	      treeInfo.firstConstructor(templ.body);
	    val outercontext = context.outer;
	    supertpt = TypeTree(
	      newTyper(outercontext.makeNewScope(constr, outercontext.owner/*.newValue(templ.pos, newTermName("<dummy>"))*/))
		.completeSuperType(
		  supertpt,
                  tparams,
		  context.owner.unsafeTypeParams,
		  vparamss map (.map(.duplicate.asInstanceOf[ValDef])),
		  superargs map (.duplicate))) setPos supertpt.pos;
	  }
	}
	//System.out.println("parents(" + context.owner + ") = " + supertpt :: mixins);//DEBUG
	List.mapConserve(supertpt :: mixins)(tpt => checkNoEscaping.privates(context.owner, tpt))
      }
    } catch {
      case ex: TypeError =>
	reportTypeError(templ.pos, ex);
	List(TypeTree(AnyRefClass.tpe))
    }

    /** Check that
     *  - all parents are class types,
     *  - first parent cluss is not a trait; following classes are traits,
     *  - final classes are not inherited,
     *  - sealed classes are only inherited by classes which are
     *    nested within definition of base class, or that occur within same
     *    statement sequence,
     *  - self-type of current class is a subtype of self-type of each parent class.
     *  - no two parents define same symbol.
     */
    def validateParentClasses(parents: List[Tree], selfType: Type): unit = {
      var c = context;
      do { c = c.outer } while (c.owner == context.owner);
      val defscope = c.scope;

      def validateParentClass(parent: Tree, isFirst: boolean): unit =
	if (!parent.tpe.isError) {
	  val psym = parent.tpe.symbol.initialize;
	  if (!psym.isClass)
	    error(parent.pos, "class type expected");
	  else if (!isFirst && !psym.isTrait)
	    error(parent.pos, "" + psym + " is not a trait; cannot be used as mixin");
	  else if (psym.hasFlag(FINAL))
	    error(parent.pos, "illegal inheritance from final class");
	  else if (psym.isSealed && !phase.erasedTypes) {
	    // are we in same scope as base type definition?
	    val e = defscope.lookupEntry(psym.name);
	    if (!(e != null && e.sym == psym && e.owner == defscope)) {
	      // we are not within same statement sequence
	      var c = context;
	      while (c != NoContext && c.owner !=  psym) c = c.outer.enclClass;
	      if (c == NoContext) error(parent.pos, "illegal inheritance from sealed " + psym)
	    }
	  }
	  if (!(selfType <:< parent.tpe.typeOfThis) && !phase.erasedTypes) {
	    System.out.println(context.owner);//debug
	    System.out.println(context.owner.thisSym);//debug
	    error(parent.pos, "illegal inheritance;\n self-type " +
		  selfType + " does not conform to " + parent +
		  "'s selftype " + parent.tpe.typeOfThis);
	    if (settings.explaintypes.value) explainTypes(selfType, parent.tpe.typeOfThis);
	  }
	  if (parents exists (p => p != parent && p.tpe.symbol == psym && !psym.isError))
	    error(parent.pos, "" + psym + " is inherited twice")
	}

      if (!parents.isEmpty) {
        validateParentClass(parents.head, true);
        for (val p <- parents.tail) validateParentClass(p, false);
      }
    }

    def typedClassDef(cdef: ClassDef): Tree = {
      val clazz = cdef.symbol;
      reenterTypeParams(cdef.tparams);
      val tparams1 = List.mapConserve(cdef.tparams)(typedAbsTypeDef);
      val tpt1 = checkNoEscaping.privates(clazz.thisSym, typedType(cdef.tpt));
      val impl1 = newTyper(context.make(cdef.impl, clazz, new Scope()))
        .typedTemplate(cdef.impl, parentTypes(cdef.impl));
      val impl2 = addSyntheticMethods(impl1, clazz);
      copy.ClassDef(cdef, cdef.mods, cdef.name, tparams1, tpt1, impl2)
	setType NoType
    }

    def typedModuleDef(mdef: ModuleDef): Tree = {
      val clazz = mdef.symbol.moduleClass;
      val impl1 = newTyper(context.make(mdef.impl, clazz, new Scope()))
        .typedTemplate(mdef.impl, parentTypes(mdef.impl));
      copy.ModuleDef(mdef, mdef.mods, mdef.name, impl1) setType NoType
    }

    def addGetterSetter(stat: Tree): List[Tree] = stat match {
      case ValDef(mods, name, tpe, rhs) if (mods & LOCAL) == 0 && !stat.symbol.isModuleVar =>
	val vdef = copy.ValDef(stat, mods | PRIVATE | LOCAL, nme.getterToLocal(name), tpe, rhs);
        val value = vdef.symbol;
        val getter = if ((mods & DEFERRED) != 0) value else value.getter(value.owner);
	if (getter hasFlag OVERLOADED) System.out.println("overloaded getter: " + getter.alternatives + getter.alternatives.map(.tpe));//debug
        assert(getter != NoSymbol, value);//debug
	val getterDef: DefDef = {
	  val result = atPos(vdef.pos)(
	    DefDef(getter, vparamss =>
	      if ((mods & DEFERRED) != 0) EmptyTree
	      else typed(Select(This(value.owner), value), EXPRmode, value.tpe)));
          checkNoEscaping.privates(getter, result.tpt);
          result
	}
	def setterDef: DefDef = {
	  val setter = value.owner.info.decl(nme.getterToSetter(getter.name));
          assert(setter != NoSymbol, getter);//debug
          atPos(vdef.pos)(
	    DefDef(setter, vparamss =>
	      if ((mods & DEFERRED) != 0) EmptyTree
	      else typed(Assign(Select(This(value.owner), value),
				Ident(vparamss.head.head)))))
	}
	val gs = if ((mods & MUTABLE) != 0) List(getterDef, setterDef)
                 else List(getterDef);
	if ((mods & DEFERRED) != 0) gs else vdef :: gs
      case DocDef(comment, defn) =>
	addGetterSetter(defn) map (stat => DocDef(comment, stat))
      case Attributed(attr, defn) =>
	addGetterSetter(defn) map (stat => Attributed(attr.duplicate, stat))
      case _ =>
	List(stat)
    }

    def typedTemplate(templ: Template, parents1: List[Tree]): Template = {
      val clazz = context.owner;
      if (templ.symbol == NoSymbol) templ setSymbol clazz.newLocalDummy(templ.pos);
      val selfType =
        if (clazz.isAnonymousClass && !phase.erasedTypes)
          intersectionType(clazz.info.parents, clazz.owner)
        else clazz.typeOfThis;
      // the following is necessary for templates generated later
      new Namer(context.outer.make(templ, clazz, clazz.info.decls)).enterSyms(templ.body);
      validateParentClasses(parents1, selfType);
      val body1 = typedStats(templ.body flatMap addGetterSetter, templ.symbol);
      copy.Template(templ, parents1, body1) setType clazz.tpe
    }

    def typedValDef(vdef: ValDef): ValDef = {
      val sym = vdef.symbol;
      var tpt1 = checkNoEscaping.privates(sym, typedType(vdef.tpt));
      checkNonCyclic(vdef.pos, tpt1.tpe, sym);
      val rhs1 =
        if (vdef.rhs.isEmpty) {
          if (sym.isVariable && sym.owner.isTerm && phase.id <= currentRun.typerPhase.id)
            error(vdef.pos, "local variables must be initialized");
          vdef.rhs
        } else {
          newTyper(context.make(vdef, sym)).transformedOrTyped(vdef.rhs, tpt1.tpe)
        }
      copy.ValDef(vdef, vdef.mods, vdef.name, tpt1, rhs1) setType NoType
    }

    /** Enter all aliases of local parameter accessors. */
    def computeParamAliases(clazz: Symbol, vparamss: List[List[ValDef]], rhs: Tree): unit = {
      if (settings.debug.value) log("computing param aliases for " + clazz + ":" + clazz.primaryConstructor.tpe + ":" + rhs);//debug
      def decompose(call: Tree): Pair[Tree, List[Tree]] = call match {
	case Apply(fn, args) =>
	  val Pair(superConstr, args1) = decompose(fn);
	  val formals = fn.tpe.paramTypes;
	  val args2 = if (formals.isEmpty || formals.last.symbol != RepeatedParamClass) args
		      else args.take(formals.length - 1) ::: List(EmptyTree);
	  if (args2.length != formals.length) assert(false, "mismatch " + clazz + " " + formals + " " + args2);//debug
	  Pair(superConstr, args1 ::: args2)
	case Block(stats, expr) =>
	  decompose(stats.head)
	case _ =>
	  Pair(call, List())
      }
      val Pair(superConstr, superArgs) = decompose(rhs);
      assert(superConstr.symbol != null, superConstr);//debug
      if (superConstr.symbol.isPrimaryConstructor) {
	val superClazz = superConstr.symbol.owner;
        if (!superClazz.hasFlag(JAVA)) {
	  val superParamAccessors = superClazz.constrParamAccessors;
	  if (superParamAccessors.length != superArgs.length) {
	    System.out.println("" + superClazz + ":" + superClazz.info.decls.toList.filter(.hasFlag(PARAMACCESSOR)));
	    assert(false, "mismatch: " + superParamAccessors + ";" + rhs + ";" + superClazz.info.decls); //debug
	  }
	  List.map2(superParamAccessors, superArgs) { (superAcc, superArg) =>
	    superArg match {
	      case Ident(name) =>
	        if (vparamss.exists(.exists(vp => vp.symbol == superArg.symbol))) {
		  var alias = superAcc.initialize.alias;
		  if (alias == NoSymbol)
                    alias = superAcc.getter(superAcc.owner);
		  if (alias != NoSymbol &&
		      superClazz.info.nonPrivateMember(alias.name) != alias)
		    alias = NoSymbol;
		  if (alias != NoSymbol) {
		    var ownAcc = clazz.info.decl(name);
		    if (ownAcc hasFlag ACCESSOR) ownAcc = ownAcc.accessed;
		    if (settings.debug.value) log("" + ownAcc + " has alias " + alias + alias.locationString);//debug
		    ownAcc.asInstanceOf[TermSymbol].setAlias(alias)
		  }
	        }
	      case _ =>
	    }
          }
	  ()
        }
      }
    }

    def typedDefDef(ddef: DefDef): DefDef = {
      val meth = ddef.symbol;
      reenterTypeParams(ddef.tparams);
      reenterValueParams(ddef.vparamss);
      val tparams1 = List.mapConserve(ddef.tparams)(typedAbsTypeDef);
      val vparamss1 = List.mapConserve(ddef.vparamss)(vparams1 =>
	List.mapConserve(vparams1)(typedValDef));
      for (val vparams <- vparamss1; val vparam <- vparams) {
	checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); ()
      }
      var tpt1 =
	checkNoEscaping.locals(context.scope, WildcardType,
	  checkNoEscaping.privates(meth,
	      typedType(ddef.tpt)));
      checkNonCyclic(ddef.pos, tpt1.tpe, meth);
      val rhs1 =
	if (ddef.name == nme.CONSTRUCTOR) {
	  if (!meth.hasFlag(SYNTHETIC) &&
	      !(meth.owner.isClass ||
		meth.owner.isModuleClass ||
		meth.owner.isAnonymousClass ||
		meth.owner.isRefinementClass))
	    error(ddef.pos, "constructor definition not allowed here " + meth.owner);//debug
	  context.enclClass.owner.setFlag(INCONSTRUCTOR);
	  val result = typed(ddef.rhs, EXPRmode | INCONSTRmode, UnitClass.tpe);
	  context.enclClass.owner.resetFlag(INCONSTRUCTOR);
	  if (meth.isPrimaryConstructor && !phase.erasedTypes && reporter.errors() == 0)
	    computeParamAliases(meth.owner, vparamss1, result);
	  result
	} else transformedOrTyped(ddef.rhs, tpt1.tpe);
      copy.DefDef(ddef, ddef.mods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType
    }

    def typedAbsTypeDef(tdef: AbsTypeDef): AbsTypeDef = {
      val lo1 = checkNoEscaping.privates(tdef.symbol, typedType(tdef.lo));
      val hi1 = checkNoEscaping.privates(tdef.symbol, typedType(tdef.hi));
      checkNonCyclic(tdef.pos, tdef.symbol.tpe);
      copy.AbsTypeDef(tdef, tdef.mods, tdef.name, lo1, hi1) setType NoType
    }

    def typedAliasTypeDef(tdef: AliasTypeDef): AliasTypeDef = {
      reenterTypeParams(tdef.tparams);
      val tparams1 = List.mapConserve(tdef.tparams)(typedAbsTypeDef);
      val rhs1 = checkNoEscaping.privates(tdef.symbol, typedType(tdef.rhs));
      checkNonCyclic(tdef.pos, tdef.symbol.tpe);
      copy.AliasTypeDef(tdef, tdef.mods, tdef.name, tparams1, rhs1) setType NoType
    }

    private def enterLabelDef(stat: Tree): unit = stat match {
      case ldef @ LabelDef(_, _, _) =>
        if (ldef.symbol == NoSymbol)
          ldef.symbol = namer.enterInScope(
            context.owner.newLabel(ldef.pos, ldef.name) setInfo MethodType(List(), UnitClass.tpe));
      case _ =>
    }

    def typedLabelDef(ldef: LabelDef): LabelDef = {
      val restpe = ldef.symbol.tpe.resultType;
      val rhs1 = typed(ldef.rhs, restpe);
      ldef.params foreach (param => param.tpe = param.symbol.tpe);
      copy.LabelDef(ldef, ldef.name, ldef.params, rhs1) setType restpe
    }

    def typedBlock(block: Block, mode: int, pt: Type): Block = {
      namer.enterSyms(block.stats);
      block.stats foreach enterLabelDef;
      val stats1 =
        if ((mode & INCONSTRmode) != 0) {
          val constrCall = typed(block.stats.head, mode, WildcardType);
          context.enclClass.owner.resetFlag(INCONSTRUCTOR);
          constrCall :: typedStats(block.stats.tail, context.owner);
        } else {
	  typedStats(block.stats, context.owner)
        }
      val expr1 = typed(block.expr, mode & ~(FUNmode | QUALmode), pt);
      val block1 = copy.Block(block, stats1, expr1)
        setType (if (treeInfo.isPureExpr(block)) expr1.tpe else expr1.tpe.deconst);
      if (isFullyDefined(pt)) block1
      else {
	if (block1.tpe.symbol.isAnonymousClass)
	  block1 setType intersectionType(block1.tpe.parents, block1.tpe.symbol.owner);
	checkNoEscaping.locals(context.scope, pt, block1)
      }
    }

    def typedCase(cdef: CaseDef, pattpe: Type, pt: Type): CaseDef = {
      val pat1: Tree = typedPattern(cdef.pat, pattpe);
      val guard1: Tree = if (cdef.guard == EmptyTree) EmptyTree
	                 else typed(cdef.guard, BooleanClass.tpe);
      var body1: Tree = typed(cdef.body, pt);
      if (!context.savedTypeBounds.isEmpty) {
        context.restoreTypeBounds;
        // the following is a hack to make the pattern matcher work
        body1 =
          typed {
            atPos(body1.pos) {
              TypeApply(Select(body1, Any_asInstanceOf), List(TypeTree(pt)))
            }
          }
      }
      copy.CaseDef(cdef, pat1, guard1, body1) setType body1.tpe
    }

    def typedCases(tree: Tree, cases: List[CaseDef], pattp: Type, pt: Type): List[CaseDef] = {
      List.mapConserve(cases)(cdef =>
	newTyper(context.makeNewScope(cdef, context.owner)).typedCase(cdef, pattp, pt))
    }

    def typedFunction(fun: Function, mode: int, pt: Type): Tree = {
      def decompose(pt: Type): Triple[Symbol, List[Type], Type] =
{'fraction_non_alphanumeric': 0.12783847980997626, 'fraction_numerical': 0.0070150435471100555, 'mean_word_length': 2.721989744798727, 'pattern_counts': {'":': 10, '<': 53, '<?xml version=': 0, '>': 127, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2883556', 'n_tokens_mistral': 21315, 'n_tokens_neox': 20309, 'n_words': 5389}