summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Typers.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Typers.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala1567
1 files changed, 1567 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
new file mode 100644
index 0000000000..f4098b615a
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -0,0 +1,1567 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $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.nsc.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 from match {
+ case MethodType(_, _) => EmptyTree
+ case OverloadedType(_, _) => EmptyTree
+ case PolyType(_, _) => EmptyTree
+ case _ => 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.isTypeParameterOrSkolem)
+ 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(tparam.tpe) setPos tree.pos)) 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 || pt == WildcardType ||
+ !(pt <:< functionType(mt.paramTypes map (t => WildcardType), WildcardType))) {
+ errorTree(tree, "missing arguments for " + tree.symbol) //debug
+ } else {
+ if (settings.debug.value) log("eta-expanding " + tree + ":" + tree.tpe + " to " + pt);//debug
+ 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(clazz.primaryConstructor.tpe.asSeenFrom(tree.tpe.prefix, clazz.owner)) setOriginal(tree);
+
+
+ // 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(tree.tpe) setOriginal(tree)
+ }
+ } else if ((mode & (EXPRmode | FUNmode)) == (EXPRmode | FUNmode) &&
+ !tree.tpe.isInstanceOf[MethodType] && !tree.tpe.isInstanceOf[OverloadedType] &&
+ ((mode & TAPPmode) == 0 || tree.tpe.typeParams.isEmpty) &&
+ adaptToName(tree, nme.apply).tpe.nonLocalMember(nme.apply)
+ .filter(m => m.tpe.paramSectionCount > 0) != NoSymbol) { // (8)
+ typed(atPos(tree.pos)(Select(adaptToName(tree, nme.apply), nme.apply)), 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
+ if (settings.debug.value) log("inferring view from " + tree.tpe + " to " + pt);
+ 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)
+// }
+
+ def adaptToName(qual: Tree, name: Name): Tree =
+ if (qual.isTerm && (qual.symbol == null || qual.symbol.isValue) &&
+ !phase.erasedTypes && !qual.tpe.widen.isError &&
+ qual.tpe.nonLocalMember(name) == NoSymbol) {
+ val coercion = inferView(qual.pos, qual.tpe, name, true);
+ if (coercion != EmptyTree) typedQualifier(atPos(qual.pos)(Apply(coercion, List(qual))))
+ else qual
+ } else qual;
+
+ 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.unsafeTypeParams);//debug
+ System.out.println(List.fromArray(context.owner.info.closure));//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);
+ val ret = copy.ClassDef(cdef, cdef.mods, cdef.name, tparams1, tpt1, impl2)
+ .setType(NoType);
+ ret;
+ }
+
+ 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));
+ val impl2 = addSyntheticMethods(impl1, clazz);
+
+ copy.ModuleDef(mdef, mdef.mods, mdef.name, impl2) setType NoType
+ }
+
+ def addGetterSetter(stat: Tree): List[Tree] = stat match {
+ case ValDef(mods, name, tpe, rhs) if !(mods hasFlag LOCAL) && !stat.symbol.isModuleVar =>
+ val vdef = copy.ValDef(stat, mods | PRIVATE | LOCAL, nme.getterToLocal(name), tpe, rhs);
+ val value = vdef.symbol;
+ val getter = if (mods hasFlag DEFERRED) value else value.getter(value.owner);
+ assert(getter != NoSymbol, getter);//debug
+ val getterDef: DefDef = {
+ val result = atPos(vdef.pos)(
+ DefDef(getter, vparamss =>
+ if (mods hasFlag DEFERRED) EmptyTree
+ else typed(atPos(vdef.pos)(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 hasFlag DEFERRED) EmptyTree
+ else typed(Assign(Select(This(value.owner), value),
+ Ident(vparamss.head.head)))))
+ }
+ val gs = if (mods hasFlag MUTABLE) List(getterDef, setterDef)
+ else List(getterDef);
+ if (mods hasFlag DEFERRED) 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 if (settings.Xgadt.value) clazz.typeOfThis.asSeenFrom(context.prefix, clazz)
+ 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;
+ val typer1 = if (sym.hasFlag(PARAM) && sym.owner.isConstructor)
+ newTyper(context.makeConstructorContext)
+ else this;
+ var tpt1 = checkNoEscaping.privates(sym, typer1.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);//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 typedSuperCall(tree: Tree): Tree =
+ typed(tree, EXPRmode | INCONSTRmode, UnitClass.tpe);
+
+ 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
+ val result = ddef.rhs match {
+ case Block(stat :: stats, expr) =>
+ val stat1 = typedSuperCall(stat);
+ newTyper(context.makeConstructorSuffixContext).typed(
+ copy.Block(ddef.rhs, stats, expr), UnitClass.tpe) match {
+ case block1 @ Block(stats1, expr1) =>
+ copy.Block(block1, stat1 :: stats1, expr1)
+ }
+ case _ =>
+ typedSuperCall(ddef.rhs)
+ }
+ 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 = 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] =
+ if (isFunctionType(pt)
+ ||
+ pt.symbol == PartialFunctionClass &&
+ fun.vparams.length == 1 && fun.body.isInstanceOf[Match])
+ Triple(pt.symbol, pt.typeArgs.init, pt.typeArgs.last)
+ else
+ Triple(FunctionClass(fun.vparams.length), fun.vparams map (x => NoType), WildcardType);
+
+ val Triple(clazz, argpts, respt) =
+ decompose(if (pt.symbol == TypedCodeClass) pt.typeArgs.head else pt);
+
+ val vparamSyms = List.map2(fun.vparams, argpts) { (vparam, argpt) =>
+ if (vparam.tpt.isEmpty)
+ vparam.tpt.tpe =
+ if (argpt == NoType) { error(vparam.pos, "missing parameter type"); ErrorType }
+ else argpt;
+ namer.enterSym(vparam);
+ vparam.symbol
+ }
+ val vparams = List.mapConserve(fun.vparams)(typedValDef);
+ for (val vparam <- vparams) {
+ checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); ()
+ }
+ val body = checkNoEscaping.locals(context.scope, respt, typed(fun.body, respt));
+ val formals = vparamSyms map (.tpe);
+ val restpe = body.tpe.deconst;
+ val funtpe = typeRef(clazz.tpe.prefix, clazz, formals ::: List(restpe));
+ val fun1 = copy.Function(fun, vparams, checkNoEscaping.locals(context.scope, restpe, body))
+ .setType(funtpe);
+ if (pt.symbol == TypedCodeClass) typed(atPos(fun.pos)(codify(fun1)))
+ else fun1
+ }
+
+ def typedRefinement(stats: List[Tree]): List[Tree] = {
+ namer.enterSyms(stats);
+ for (val stat <- stats) stat.symbol setFlag OVERRIDE;
+ typedStats(stats, NoSymbol);
+ }
+
+ def typedStats(stats: List[Tree], exprOwner: Symbol): List[Tree] =
+ List.mapConserve(stats) { stat =>
+ if (context.owner.isRefinementClass && !treeInfo.isDeclaration(stat))
+ errorTree(stat, "only declarations allowed here");
+ stat match {
+ case imp @ Import(_, _) =>
+ context = context.makeNewImport(imp);
+ stat.symbol.initialize;
+ EmptyTree
+ case _ =>
+ (if (exprOwner != context.owner && (!stat.isDef || stat.isInstanceOf[LabelDef]))
+ newTyper(context.make(stat, exprOwner)) else this).typed(stat)
+ }
+ }
+
+ protected def typed1(tree: Tree, mode: int, pt: Type): Tree = {
+
+ def funmode = mode & stickyModes | FUNmode | POLYmode;
+
+ def ptOrLub(tps: List[Type]) = if (isFullyDefined(pt)) pt else lub(tps);
+
+ def typedTypeApply(fun: Tree, args: List[Tree]): Tree = fun.tpe match {
+ case OverloadedType(pre, alts) =>
+ inferPolyAlternatives(fun, args.length);
+ typedTypeApply(fun, args)
+ case PolyType(tparams, restpe) if (tparams.length != 0) =>
+ if (tparams.length == args.length) {
+ val targs = args map (.tpe);
+ checkBounds(tree.pos, tparams, targs, "");
+ copy.TypeApply(tree, fun, args) setType restpe.subst(tparams, targs);
+ } else {
+ errorTree(tree, "wrong number of type parameters for " + treeSymTypeMsg(fun))
+ }
+ case ErrorType =>
+ setError(tree)
+ case _ =>
+ System.out.println(fun.toString() + " " + args);//debug
+ errorTree(tree, treeSymTypeMsg(fun) + " does not take type parameters.");
+ }
+
+ def typedArg(arg: Tree, pt: Type): Tree = {
+ val argTyper = if ((mode & INCONSTRmode) != 0) newTyper(context.makeConstructorContext)
+ else this;
+ argTyper.typed(arg, mode & stickyModes, pt)
+ }
+
+ def typedApply(fun: Tree, args: List[Tree]): Tree = fun.tpe match {
+ case OverloadedType(pre, alts) =>
+ val args1 = List.mapConserve(args)(arg =>
+ typedArg(arg, WildcardType));
+ inferMethodAlternative(fun, context.undetparams, args1 map (.tpe.deconst), pt);
+ typedApply(adapt(fun, funmode, WildcardType), args1);
+ case MethodType(formals0, restpe) =>
+ val formals = formalTypes(formals0, args.length);
+ if (formals.length != args.length) {
+ //System.out.println("" + formals.length + " " + args.length);//DEBUG
+ errorTree(tree, "wrong number of arguments for " + treeSymTypeMsg(fun))
+ } else {
+ val tparams = context.undetparams;
+ context.undetparams = List();
+ if (tparams.isEmpty) {
+ val args1 = List.map2(args, formals)(typedArg);
+ def ifPatternSkipFormals(tp: Type) = tp match {
+ case MethodType(_, rtp) if ((mode & PATTERNmode) != 0) => rtp
+ case _ => tp
+ }
+ constfold(copy.Apply(tree, fun, args1).setType(ifPatternSkipFormals(restpe)));
+ } else {
+ assert((mode & PATTERNmode) == 0); // this case cannot arise for patterns
+ val lenientTargs = protoTypeArgs(tparams, formals, restpe, pt);
+ val strictTargs = List.map2(lenientTargs, tparams)((targ, tparam) =>
+ if (targ == WildcardType) tparam.tpe else targ);
+ def typedArgToPoly(arg: Tree, formal: Type): Tree = {
+ val lenientPt = formal.subst(tparams, lenientTargs);
+ val arg1 = typedArg(arg, lenientPt);
+ val argtparams = context.undetparams;
+ context.undetparams = List();
+ if (!argtparams.isEmpty) {
+ val strictPt = formal.subst(tparams, strictTargs);
+ inferArgumentInstance(arg1, argtparams, strictPt, lenientPt);
+ }
+ arg1
+ }
+ val args1 = List.map2(args, formals)(typedArgToPoly);
+ if (args1 exists (.tpe.isError)) setError(tree)
+ else {
+ if (settings.debug.value) log("infer method inst " + fun + ", tparams = " + tparams + ", args = " + args1.map(.tpe) + ", pt = " + pt + ", lobounds = " + tparams.map(.tpe.bounds.lo));//debug
+ val undetparams = inferMethodInstance(fun, tparams, args1, pt);
+ val result = typedApply(fun, args1);
+ context.undetparams = undetparams;
+ result
+ }
+ }
+ }
+ case ErrorType =>
+ setError(tree)
+ case _ =>
+ errorTree(tree, "" + fun + " does not take parameters");
+ }
+
+ /** The qualifying class of a this or super with prefix `qual' */
+ def qualifyingClassContext(qual: Name): Context = {
+ if (qual == nme.EMPTY.toTypeName) {
+ if (context.enclClass.owner.isPackageClass)
+ error(tree.pos, "" + tree + " can be used only in a class, object, or template");
+ context.enclClass
+ } else {
+ var c = context.enclClass;
+ while (c != NoContext && c.owner.name != qual) c = c.outer.enclClass;
+ if (c == NoContext) error(tree.pos, "" + qual + " is not an enclosing class");
+ c
+ }
+ }
+
+ /** Attribute a selection where `tree' is `qual.name'.
+ * `qual' is already attributed.
+ */
+ def typedSelect(qual: Tree, name: Name): Tree = {
+ val sym =
+ if (tree.symbol != NoSymbol) {
+ if (phase.erasedTypes && qual.isInstanceOf[Super]) qual.tpe = tree.symbol.owner.tpe;
+ if (false && settings.debug.value) { // todo: replace by settings.check.value?
+ val alts = qual.tpe.member(tree.symbol.name).alternatives;
+ if (!(alts exists (alt =>
+ alt == tree.symbol || alt.isTerm && (alt.tpe matches tree.symbol.tpe))))
+ assert(false, "symbol " + tree.symbol + tree.symbol.locationString + " not in " + alts + " of " + qual.tpe +
+ "\n members = " + qual.tpe.members +
+ "\n type history = " + qual.tpe.symbol.infosString +
+ "\n phase = " + phase);
+ }
+ tree.symbol
+ } else qual.tpe match {
+ case ThisType(clazz) if (clazz == context.enclClass.owner) =>
+ qual.tpe.member(name)
+ case _ =>
+ qual.tpe.nonLocalMember(name)
+ }
+ if (sym == NoSymbol) {
+ val qual1 = adaptToName(qual, name);
+ if (qual1 ne qual) return typed(copy.Select(tree, qual1, name), mode, pt)
+ }
+ if (sym.info == NoType) {
+ if (settings.debug.value) log("qual = " + qual + ":" + qual.tpe + "\nSymbol=" + qual.tpe.symbol + "\nsymbol-info = " + qual.tpe.symbol.info + "\nscope-id = " + qual.tpe.symbol.info.decls.hashCode() + "\nmembers = " + qual.tpe.members + "\nfound = " + sym);
+ if (!qual.tpe.widen.isError)
+ error(tree.pos,
+ decode(name) + " is not a member of " + qual.tpe.widen +
+ (if (Position.line(context.unit.source, qual.pos) <
+ Position.line(context.unit.source, tree.pos))
+ "\npossible cause: maybe a semicolon is missing before `" + name + "'?" else ""));
+ setError(tree)
+ } else {
+ val tree1 = tree match {
+ case Select(_, _) => copy.Select(tree, qual, name)
+ case SelectFromTypeTree(_, _) => copy.SelectFromTypeTree(tree, qual, name);
+ }
+ stabilize(checkAccessible(tree1, sym, qual.tpe, qual), qual.tpe, mode, pt);
+ }
+ }
+
+ /** Attribute an identifier consisting of a simple name or an outer reference.
+ * @param tree The tree representing the identifier.
+ * @param name The name of the identifier.
+ * Transformations: (1) Prefix class members with this.
+ * (2) Change imported symbols to selections
+ */
+ def typedIdent(name: Name): Tree = {
+ def ambiguousError(msg: String) =
+ error(tree.pos, "reference to " + name + " is ambiguous;\n" + msg);
+
+ var defSym: Symbol = tree.symbol; // the directly found symbol
+ var pre: Type = NoPrefix; // the prefix type of defSym, if a class member
+ var qual: Tree = EmptyTree; // the qualififier tree if transformed tree is a select
+
+ if (defSym == NoSymbol) {
+ var defEntry: ScopeEntry = null; // the scope entry of defSym, if defined in a local scope
+
+ var cx = context;
+ while (defSym == NoSymbol && cx != NoContext) {
+ pre = cx.enclClass.prefix;
+ defEntry = cx.scope.lookupEntry(name);
+ if (defEntry != null) {
+ defSym = defEntry.sym;
+ } else {
+ cx = cx.enclClass;
+ defSym = pre.member(name) filter (sym => context.isAccessible(sym, pre, false));
+ if (defSym == NoSymbol) cx = cx.outer;
+ }
+ }
+ val symDepth = if (defEntry == null) cx.depth
+ else cx.depth - (cx.scope.nestingLevel - defEntry.owner.nestingLevel);
+ var impSym: Symbol = NoSymbol; // the imported symbol
+ var imports = context.imports; // impSym != NoSymbol => it is imported from imports.head
+ while (impSym == NoSymbol && !imports.isEmpty && imports.head.depth > symDepth) {
+ impSym = imports.head.importedSymbol(name);
+ if (impSym == NoSymbol) imports = imports.tail;
+ }
+
+ // detect ambiguous definition/import,
+ // update `defSym' to be the final resolved symbol,
+ // update `pre' to be `sym's prefix type in case it is an imported member,
+ // and compute value of:
+
+ // imported symbols take precedence over external package-owned symbols (hack?)
+ if (defSym.tpe != NoType && impSym.tpe != NoType && defSym.isExternal && defSym.owner.isPackageClass)
+ defSym = NoSymbol;
+
+ if (defSym.tpe != NoType) {
+ if (impSym.tpe != NoType)
+ ambiguousError(
+ "it is both defined in " + defSym.owner +
+ " and imported subsequently by \n" + imports.head);
+ else if (!defSym.owner.isClass || defSym.owner.isPackageClass || defSym.isTypeParameterOrSkolem)
+ pre = NoPrefix
+ else
+ qual = atPos(tree.pos)(gen.mkQualifier(pre));
+ } else {
+ if (impSym.tpe != NoType) {
+ var impSym1 = NoSymbol;
+ var imports1 = imports.tail;
+ def ambiguousImportError = ambiguousError(
+ "it is imported twice in the same scope by\n" + imports.head + "\nand " + imports1.head);
+ while (!imports1.isEmpty && imports1.head.depth == imports.head.depth) {
+ var impSym1 = imports1.head.importedSymbol(name);
+ if (impSym1 != NoSymbol) {
+ if (imports1.head.isExplicitImport(name)) {
+ if (imports.head.isExplicitImport(name)) ambiguousImportError;
+ impSym = impSym1;
+ imports = imports1;
+ } else if (!imports.head.isExplicitImport(name)) ambiguousImportError
+ }
+ imports1 = imports1.tail;
+ }
+ defSym = impSym;
+ qual = imports.head.qual;
+ pre = qual.tpe;
+ } else {
+ if (settings.debug.value) {
+ log(context.imports);//debug
+ }
+ error(tree.pos, "not found: " + decode(name));
+ defSym = context.owner.newErrorSymbol(name);
+ }
+ }
+ }
+ if (defSym.owner.isPackageClass) pre = defSym.owner.thisType;
+ val tree1 = if (qual == EmptyTree) tree
+ else atPos(tree.pos)(Select(qual, name));
+ // atPos necessary because qualifier might come from startContext
+ //System.out.println("check acc: " + defSym + " " + pre);//DEBUG
+ stabilize(checkAccessible(tree1, defSym, pre, qual), pre, mode, pt)
+ }
+
+ // begin typed1
+ val sym: Symbol = tree.symbol;
+ if (sym != null) sym.initialize;
+ //if (settings.debug.value && tree.isDef) log("typing definition of " + sym);//DEBUG
+ tree match {
+ case PackageDef(name, stats) =>
+ val stats1 = newTyper(context.make(tree, sym.moduleClass, sym.info.decls))
+ .typedStats(stats, NoSymbol);
+ copy.PackageDef(tree, name, stats1) setType NoType
+
+ case cdef @ ClassDef(_, _, _, _, _) =>
+ newTyper(context.makeNewScope(tree, sym)).typedClassDef(cdef)
+
+ case mdef @ ModuleDef(_, _, _) =>
+ newTyper(context.make(tree, sym.moduleClass)).typedModuleDef(mdef)
+
+ case vdef @ ValDef(_, _, _, _) =>
+ typedValDef(vdef)
+
+ case ddef @ DefDef(_, _, _, _, _, _) =>
+ newTyper(context.makeNewScope(tree, sym)).typedDefDef(ddef)
+
+ case tdef @ AbsTypeDef(_, _, _, _) =>
+ newTyper(context.makeNewScope(tree, sym)).typedAbsTypeDef(tdef)
+
+ case tdef @ AliasTypeDef(_, _, _, _) =>
+ newTyper(context.makeNewScope(tree, sym)).typedAliasTypeDef(tdef)
+
+ case ldef @ LabelDef(_, _, _) =>
+ var lsym = ldef.symbol;
+ var typer1 = this;
+ if (lsym == NoSymbol) { // labeldef is part of template
+ typer1 = newTyper(context.makeNewScope(tree, context.owner));
+ typer1.enterLabelDef(ldef);
+ }
+ typer1.typedLabelDef(ldef)
+
+ case Attributed(attr, defn) =>
+ val attr1 = typed(attr, AttributeClass.tpe);
+ val defn1 = typed(defn, mode, pt);
+ val ai = attrInfo(attr1);
+ if (ai != null) defn1.symbol.attributes = defn1.symbol.attributes ::: List(ai);
+ defn1
+
+ case DocDef(comment, defn) =>
+ typed(defn, mode, pt);
+
+ case block @ Block(_, _) =>
+ newTyper(context.makeNewScope(tree, context.owner))
+ .typedBlock(block, mode, pt)
+
+ case Sequence(elems) =>
+ val elems1 = List.mapConserve(elems)(elem => typed(elem, mode, pt));
+ copy.Sequence(tree, elems1) setType pt
+
+ case Alternative(alts) =>
+ val alts1 = List.mapConserve(alts)(alt => typed(alt, mode, pt));
+ copy.Alternative(tree, alts1) setType pt
+
+ case Star(elem) =>
+ val elem1 = typed(elem, mode, pt);
+ copy.Star(tree, elem1) setType pt
+
+ case Bind(name, body) =>
+ var vble = tree.symbol;
+ if (vble == NoSymbol) vble = context.owner.newValue(tree.pos, name);
+ if (vble.name != nme.WILDCARD) namer.enterInScope(vble);
+ val body1 = typed(body, mode, pt);
+ vble.setInfo(if (treeInfo.isSequenceValued(body)) seqType(body1.tpe) else body1.tpe);
+ copy.Bind(tree, name, body1) setSymbol vble setType body1.tpe; // buraq, was: pt
+
+ case ArrayValue(elemtpt, elems) =>
+ val elemtpt1 = typedType(elemtpt);
+ val elems1 = List.mapConserve(elems)(elem => typed(elem, mode, elemtpt1.tpe));
+ copy.ArrayValue(tree, elemtpt1, elems1)
+ .setType(if (isFullyDefined(pt) && !phase.erasedTypes) pt
+ else appliedType(ArrayClass.typeConstructor, List(elemtpt1.tpe)))
+
+ case fun @ Function(_, _) =>
+/*
+ newTyper(context.makeNewScope(tree, context.owner)).typedFunction(fun, mode, pt)
+*/
+ tree.symbol = context.owner.newValue(tree.pos, nme.ANON_FUN_NAME)
+ .setFlag(SYNTHETIC).setInfo(NoType);
+ newTyper(context.makeNewScope(tree, tree.symbol)).typedFunction(fun, mode, pt)
+
+ case Assign(lhs, rhs) =>
+ def isGetter(sym: Symbol) = sym.info match {
+ case PolyType(List(), _) => sym.owner.isClass && !sym.isStable
+ case _ => false
+ }
+ val lhs1 = typed(lhs);
+ val varsym = lhs1.symbol;
+ if (varsym != null && isGetter(varsym)) {
+ lhs1 match {
+ case Select(qual, name) =>
+ typed(
+ Apply(
+ Select(qual, nme.getterToSetter(name)) setPos lhs.pos,
+ List(rhs)) setPos tree.pos, mode, pt)
+ }
+ } else if (varsym != null && (varsym.isVariable || varsym.isValue && phase.erasedTypes)) {
+ val rhs1 = typed(rhs, lhs1.tpe);
+ copy.Assign(tree, lhs1, rhs1) setType UnitClass.tpe;
+ } else {
+ System.out.println("" + lhs1 + " " + varsym + " " + varsym.isValue + " " + flagsToString(varsym.flags));//debug
+ if (!lhs1.tpe.isError) error(tree.pos, "assignment to non-variable ");
+ setError(tree)
+ }
+
+ case If(cond, thenp, elsep) =>
+ val cond1 = typed(cond, BooleanClass.tpe);
+ if (elsep.isEmpty) {
+ val thenp1 = typed(thenp, UnitClass.tpe);
+ copy.If(tree, cond1, thenp1, elsep) setType UnitClass.tpe
+ } else {
+ val thenp1 = typed(thenp, pt);
+ val elsep1 = typed(elsep, pt);
+ copy.If(tree, cond1, thenp1, elsep1) setType ptOrLub(List(thenp1.tpe, elsep1.tpe));
+ }
+
+ case Match(selector, cases) =>
+ val selector1 = typed(selector);
+ val cases1 = typedCases(tree, cases, selector1.tpe.widen, pt);
+ copy.Match(tree, selector1, cases1) setType ptOrLub(cases1 map (.tpe))
+
+ case Return(expr) =>
+ val enclFun = if (tree.symbol != NoSymbol) tree.symbol else context.owner.enclMethod;
+ if (!enclFun.isMethod || enclFun.isConstructor)
+ errorTree(tree, "return outside method definition")
+ else if (!context.owner.isInitialized)
+ errorTree(tree, "method " + context.owner + " has return statement; needs result type")
+ else {
+ val expr1: Tree = typed(expr, enclFun.tpe.finalResultType);
+ copy.Return(tree, expr1) setSymbol enclFun setType AllClass.tpe;
+ }
+
+ case Try(block, catches, finalizer) =>
+ val block1 = typed(block, pt);
+ val catches1 = typedCases(tree, catches, ThrowableClass.tpe, pt);
+ val finalizer1 = if (finalizer.isEmpty) finalizer
+ else typed(finalizer, UnitClass.tpe);
+ copy.Try(tree, block1, catches1, finalizer1)
+ .setType(ptOrLub(block1.tpe :: (catches1 map (.tpe))))
+
+ case Throw(expr) =>
+ val expr1 = typed(expr, ThrowableClass.tpe);
+ copy.Throw(tree, expr1) setType AllClass.tpe
+
+ case New(tpt: Tree) =>
+ var tpt1 = typedTypeConstructor(tpt);
+ if (tpt1.hasSymbol && !tpt1.symbol.typeParams.isEmpty) {
+ context.undetparams = cloneSymbols(tpt1.symbol.unsafeTypeParams);
+ tpt1 = TypeTree()
+ .setPos(tpt1.pos)
+ .setType(appliedType(tpt1.tpe, context.undetparams map (.tpe)));
+ }
+ if (tpt1.tpe.symbol.isTrait) error(tree.pos, "traits cannot be instantiated");
+ copy.New(tree, tpt1).setType(tpt1.tpe)
+
+ case Typed(expr, tpt @ Ident(name)) if (name == nme.WILDCARD_STAR.toTypeName) =>
+ val expr1 = typed(expr, mode & stickyModes, seqType(pt));
+ expr1.tpe.baseType(SeqClass) match {
+ case TypeRef(_, _, List(elemtp)) =>
+ copy.Typed(tree, expr1, tpt setType elemtp) setType elemtp
+ case _ =>
+ setError(tree)
+ }
+ case Typed(expr, tpt) =>
+ val tpt1 = typedType(tpt);
+ val expr1 = typed(expr, mode & stickyModes, tpt1.tpe);
+ copy.Typed(tree, expr1, tpt1) setType tpt1.tpe
+
+ case TypeApply(fun, args) =>
+ val args1 = List.mapConserve(args)(typedType);
+ // do args first in order to maintain conext.undetparams on the function side.
+ typedTypeApply(typed(fun, funmode | TAPPmode, WildcardType), args1)
+
+ case Apply(Block(stats, expr), args) =>
+ typed1(Block(stats, Apply(expr, args)), mode, pt)
+
+ case Apply(fun, args) =>
+ val stableApplication = fun.symbol != null && fun.symbol.isMethod && fun.symbol.isStable;
+ if (stableApplication && (mode & PATTERNmode) != 0) {
+ // treat stable function applications f() as expressions.
+ typed1(tree, mode & ~PATTERNmode | EXPRmode, pt)
+ } else {
+ val funpt = if ((mode & PATTERNmode) != 0) pt else WildcardType;
+ var fun1 = typed(fun, funmode, funpt);
+ if (stableApplication) fun1 = stabilizeFun(fun1, mode, pt);
+ // if function is overloaded, filter all alternatives that match
+ // number of arguments and expected result type.
+ // if (settings.debug.value) log("trans app " + fun1 + ":" + fun1.symbol + ":" + fun1.tpe + " " + args);//DEBUG
+ if (fun1.hasSymbol && fun1.symbol.hasFlag(OVERLOADED)) {
+ val argtypes = args map (arg => AllClass.tpe);
+ val pre = fun1.symbol.tpe.prefix;
+ val sym = fun1.symbol filter (alt =>
+ isApplicable(context.undetparams, pre.memberType(alt), argtypes, pt));
+ if (sym != NoSymbol)
+ fun1 = adapt(fun1 setSymbol sym setType pre.memberType(sym), funmode, WildcardType)
+ }
+ if (util.Statistics.enabled) appcnt = appcnt + 1;
+ typedApply(fun1, args)
+ }
+
+ case Super(qual, mix) =>
+ val Pair(clazz, selftype) =
+ if (tree.symbol != NoSymbol) {
+ Pair(tree.symbol, tree.symbol.thisType)
+ } else {
+ val clazzContext = qualifyingClassContext(qual);
+ Pair(clazzContext.owner, clazzContext.prefix)
+ }
+ if (clazz == NoSymbol) setError(tree)
+ else {
+ val owntype =
+ if (mix == nme.EMPTY.toTypeName)
+ if ((mode & SUPERCONSTRmode) != 0) clazz.info.parents.head
+ else intersectionType(clazz.info.parents)
+ else {
+ val ps = clazz.info.parents dropWhile (p => p.symbol.name != mix);
+ if (ps.isEmpty) {
+ System.out.println(clazz.info.parents map (.symbol.name));//debug
+ error(tree.pos, "" + mix + " does not name a base class of " + clazz);
+ ErrorType
+ } else ps.head
+ }
+ tree setSymbol clazz setType SuperType(selftype, owntype)
+ }
+
+ case This(qual) =>
+ val Pair(clazz, selftype) =
+ if (tree.symbol != NoSymbol) {
+ Pair(tree.symbol, tree.symbol.thisType)
+ } else {
+ val clazzContext = qualifyingClassContext(qual);
+ Pair(clazzContext.owner, clazzContext.prefix)
+ }
+ if (clazz == NoSymbol) setError(tree)
+ else {
+ val owntype = if (pt.isStable || (mode & QUALmode) != 0) selftype
+ else selftype.singleDeref;
+ tree setSymbol clazz setType owntype
+ }
+
+ case Select(qual @ Super(_, _), nme.CONSTRUCTOR) =>
+ val qual1 = typed(qual, EXPRmode | QUALmode | POLYmode | SUPERCONSTRmode, WildcardType);
+ // the qualifier type of a supercall constructor is its first parent class
+ typedSelect(qual1, nme.CONSTRUCTOR);
+
+ case Select(qual, name) =>
+ if (util.Statistics.enabled) selcnt = selcnt + 1;
+ var qual1 = typedQualifier(qual);
+ if (name.isTypeName) qual1 = checkStable(qual1);
+ typedSelect(qual1, name);
+
+ case Ident(name) =>
+ idcnt = idcnt + 1;
+ if (name == nme.WILDCARD && (mode & (PATTERNmode | FUNmode)) == PATTERNmode)
+ tree setType pt
+ else
+ typedIdent(name)
+
+ // todo: try with case Literal(Constant(()))
+ case Literal(value) =>
+ tree setType (
+ if (value.tag == UnitTag) UnitClass.tpe
+ else ConstantType(value))
+
+ case SingletonTypeTree(ref) =>
+ val ref1 = checkStable(typed(ref, EXPRmode | QUALmode, AnyRefClass.tpe));
+ tree setType ref1.tpe.resultType;
+
+ case SelectFromTypeTree(qual, selector) =>
+ tree setType typedSelect(typedType(qual), selector).tpe
+
+ case CompoundTypeTree(templ: Template) =>
+ tree setType {
+ val parents1 = List.mapConserve(templ.parents)(typedType);
+ if (parents1 exists (.tpe.isError)) ErrorType
+ else {
+ val decls = new Scope();
+ val self = refinedType(parents1 map (.tpe), context.enclClass.owner, decls);
+ newTyper(context.make(templ, self.symbol, decls)).typedRefinement(templ.body);
+ self
+ }
+ }
+
+ case AppliedTypeTree(tpt, args) =>
+ val tpt1 = typed1(tpt, mode | FUNmode | TAPPmode, WildcardType);
+ val tparams = tpt1.symbol.typeParams;
+ val args1 = List.mapConserve(args)(typedType);
+ if (tpt1.tpe.isError) {
+ setError(tree)
+ } else if (tparams.length == args1.length) {
+ val argtypes = args1 map (.tpe);
+ val owntype = if (tpt1.symbol.isClass) appliedType(tpt1.tpe, argtypes)
+ else tpt1.tpe.subst(tparams, argtypes);
+ TypeTree(owntype) setOriginal(tree) // setPos tree.pos
+ } else if (tparams.length == 0) {
+ errorTree(tree, "" + tpt1.tpe + " does not take type parameters")
+ } else {
+ //System.out.println("\{tpt1}:\{tpt1.symbol}:\{tpt1.symbol.info}");
+ System.out.println("" + tpt1 + ":" + tpt1.symbol + ":" + tpt1.symbol.info);//debug
+ errorTree(tree, "wrong number of type arguments for " + tpt1.tpe + ", should be " + tparams.length)
+ }
+ case _ =>
+ throw new Error("unexpected tree: " + tree);//debug
+ }
+ }
+
+ def typed(tree: Tree, mode: int, pt: Type): Tree =
+ try {
+ if (settings.debug.value) {
+ assert(pt != null, tree);//debug
+ //System.out.println("typing " + tree);//DEBUG
+ }
+ val tree1 = if (tree.tpe != null) tree else typed1(tree, mode, pt);
+ //System.out.println("typed " + tree1 + ":" + tree1.tpe);//debug
+ val result = if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt);
+ //System.out.println("adapted " + tree1 + ":" + tree1.tpe + " to " + pt);//debug
+ result
+ } catch {
+ case ex: TypeError =>
+ //System.out.println("caught " + ex + " in typed");//DEBUG
+ reportTypeError(tree.pos, ex);
+ setError(tree)
+ case ex: Throwable =>
+ if (settings.debug.value)
+ System.out.println("exception when typing " + tree + ", pt = " + pt);
+ throw(ex)
+ }
+
+ def atOwner(owner: Symbol): Typer =
+ new Typer(context.make(context.tree, owner));
+
+ def atOwner(tree: Tree, owner: Symbol): Typer =
+ new Typer(context.make(tree, owner));
+
+ /** Types expression or definition `tree' */
+ def typed(tree: Tree): Tree =
+ typed(tree, EXPRmode, WildcardType);
+
+ /** Types expression `tree' with given prototype `pt' */
+ def typed(tree: Tree, pt: Type): Tree =
+ typed(tree, EXPRmode, pt);
+
+ /** Types qualifier `tree' of a select node. E.g. is tree occurs in acontext like `tree.m'. */
+ def typedQualifier(tree: Tree): Tree =
+ typed(tree, EXPRmode | QUALmode | POLYmode, WildcardType);
+
+ /** Types function part of an application */
+ def typedOperator(tree: Tree): Tree =
+ typed(tree, EXPRmode | FUNmode | POLYmode | TAPPmode, WildcardType);
+
+ /** Types a pattern with prototype `pt' */
+ def typedPattern(tree: Tree, pt: Type): Tree =
+ typed(tree, PATTERNmode, pt);
+
+ /** Types a (fully parameterized) type tree */
+ def typedType(tree: Tree): Tree =
+ typed(tree, TYPEmode, WildcardType);
+
+ /** Types a type constructor tree used in a new or supertype */
+ def typedTypeConstructor(tree: Tree): Tree = {
+ val result = typed(tree, TYPEmode | FUNmode, WildcardType);
+ if (!phase.erasedTypes && result.tpe.isInstanceOf[TypeRef] && !result.tpe.prefix.isStable)
+ error(tree.pos, result.tpe.prefix.toString() + " is not a legal prefix for a constructor");
+ result
+ }
+
+ def computeType(tree: Tree): Type = {
+ val tree1 = typed(tree);
+ transformed(tree) = tree1;
+ tree1.tpe
+ }
+
+ def transformedOrTyped(tree: Tree, pt: Type): Tree = transformed.get(tree) match {
+ case Some(tree1) => transformed -= tree; tree1
+ case None => typed(tree, pt)
+ }
+
+/*
+ def convertToTypeTree(tree: Tree): Tree = tree match {
+ case TypeTree() => tree
+ case _ => TypeTree(tree.tpe)
+ }
+*/
+ /* -- Views --------------------------------------------------------------- */
+
+ private def depoly(tp: Type): Type = tp match {
+ case PolyType(tparams, restpe) => restpe.subst(tparams, tparams map (t => WildcardType))
+ case _ => tp
+ }
+
+ private def typedImplicit(pos: int, info: ImplicitInfo, pt: Type, local: boolean): Tree =
+ if (isCompatible(depoly(info.tpe), pt)) {
+ var tree: Tree = EmptyTree;
+ def fail(reason: String): Tree = {
+ if (settings.debug.value)
+ log(tree.toString() + " is not a valid implicit value because:\n" + reason);
+ EmptyTree
+ }
+ try {
+ tree = Ident(info.name) setPos pos;
+ if (!local) tree setSymbol info.sym;
+ tree = typed1(tree, EXPRmode, pt);
+ if (settings.debug.value)
+ log("typed implicit " + tree + ":" + tree.tpe + ", pt = " + pt);//debug
+ val tree1 = adapt(tree, EXPRmode, pt);
+ if (settings.debug.value)
+ log("adapted implicit " + tree.symbol + ":" + tree1.tpe + " to " + pt);//debug
+ if (info.sym == tree.symbol) tree1
+ else fail("syms differ: " + tree.symbol + " " + info.sym)
+ } catch {
+ case ex: TypeError => fail(ex.getMessage())
+ }
+ } else EmptyTree;
+
+ private def inferImplicit(pos: int, pt: Type, isView: boolean, reportAmbiguous: boolean): Tree = {
+
+ if (util.Statistics.enabled) implcnt = implcnt + 1;
+ val startTime = if (util.Statistics.enabled) System.currentTimeMillis() else 0l;
+
+ def isBetter(sym1: Symbol, tpe1: Type, sym2: Symbol, tpe2: Type): boolean = (
+ sym2.isError ||
+ (sym1.owner != sym2.owner) && (sym1.owner isSubClass sym2.owner) && (tpe1 matches tpe2)
+ );
+ val tc = newTyper(context.makeImplicit(reportAmbiguous));
+
+ def searchImplicit(implicitInfoss: List[List[ImplicitInfo]], local: boolean): Tree = {
+ var iss = implicitInfoss;
+ var tree: Tree = EmptyTree;
+ while (tree == EmptyTree && !iss.isEmpty) {
+ var is = iss.head;
+ iss = iss.tail;
+ while (!is.isEmpty) {
+ tree = tc.typedImplicit(pos, is.head, pt, local);
+ if (settings.debug.value) log("tested " + is.head.sym + is.head.sym.locationString + ":" + is.head.tpe + "=" + tree);//debug
+ val is0 = is;
+ is = is.tail;
+ if (tree != EmptyTree) {
+ while (!is.isEmpty) {
+ val tree1 = tc.typedImplicit(pos, is.head, pt, local);
+ if (tree1 != EmptyTree) {
+ if (isBetter(is.head.sym, tree1.tpe, is0.head.sym, tree.tpe))
+ tree = tree1
+ else if (!isBetter(is0.head.sym, tree.tpe, is.head.sym, tree1.tpe))
+ error(
+ pos,
+ "ambiguous implicit value:\n" +
+ " both " + is0.head.sym + is0.head.sym.locationString + " of type " + tree.tpe +
+ "\n and " + is.head.sym + is.head.sym.locationString + " of type " + tree1.tpe +
+ (if (isView)
+ "\n are possible conversion functions from " +
+ pt.typeArgs(0) + " to " + pt.typeArgs(1)
+ else
+ "\n match expected type " + pt));
+ }
+ is = is.tail
+ }
+ }
+ }
+ }
+ tree
+ }
+
+ def implicitsOfType(tp: Type): List[List[ImplicitInfo]] = {
+ val tp1 = if (isFunctionType(tp)) intersectionType(tp.typeArgs.reverse) else tp;
+ tp1.baseClasses map implicitsOfClass;
+ }
+
+ def implicitsOfClass(clazz: Symbol): List[ImplicitInfo] = (
+ clazz.initialize.linkedModule.moduleClass.info.decls.toList.filter(.hasFlag(IMPLICIT)) map
+ (sym => ImplicitInfo(sym.name, clazz.linkedModule.tpe.memberType(sym), sym))
+ );
+
+ var tree = searchImplicit(context.implicitss, true);
+ if (tree == EmptyTree) tree = searchImplicit(implicitsOfType(pt.widen), false);
+ if (util.Statistics.enabled) impltime = impltime + System.currentTimeMillis() - startTime;
+ tree
+ }
+
+ def applyImplicitArgs(tree: Tree): Tree = tree.tpe match {
+ case MethodType(formals, _) =>
+ def implicitArg(pt: Type) = {
+ val arg = inferImplicit(tree.pos, pt, false, true);
+ if (arg != EmptyTree) arg
+ else errorTree(tree, "no implicit argument matching parameter type " + pt + " was found.")
+ }
+ Apply(tree, formals map implicitArg) setPos tree.pos
+ }
+ }
+}
+