📄 infer.scala
字号:
if (!(lo <:< hi)) { if (settings.debug.value) log("inconsistent: "+tparam+" "+lo+" "+hi) } else if (!((lo <:< tparam.info.bounds.lo) && (tparam.info.bounds.hi <:< hi))) { context.nextEnclosing(_.tree.isInstanceOf[CaseDef]).pushTypeBounds(tparam) tparam setInfo mkTypeBounds(lo, hi) if (settings.debug.value) log("new bounds of " + tparam + " = " + tparam.info) } else { if (settings.debug.value) log("redundant: "+tparam+" "+tparam.info+"/"+lo+" "+hi) } } } def checkCheckable(pos: Position, tp: Type, kind: String) { def patternWarning(tp: Type, prefix: String) = { context.unit.uncheckedWarning(pos, prefix+tp+" in type"+kind+" is unchecked since it is eliminated by erasure") } def check(tp: Type, bound: List[Symbol]) { def isLocalBinding(sym: Symbol) = sym.isAbstractType && ((bound contains sym) || sym.name == nme.WILDCARD.toTypeName || { val e = context.scope.lookupEntry(sym.name) (e ne null) && e.sym == sym && e.owner == context.scope }) tp match { case SingleType(pre, _) => check(pre, bound) case TypeRef(pre, sym, args) => if (sym.isAbstractType) patternWarning(tp, "abstract type ") else if (sym.isAliasType) check(tp.normalize, bound) else if (sym == AllClass || sym == AllRefClass) error(pos, "this type cannot be used in a type pattern") else for (arg <- args) { if (sym == ArrayClass) check(arg, bound) else arg match { case TypeRef(_, sym, _) if isLocalBinding(sym) => ; case _ => patternWarning(arg, "non variable type-argument ") } } check(pre, bound) case RefinedType(parents, decls) => if (decls.isEmpty) for (p <- parents) check(p, bound) else patternWarning(tp, "refinement ") case ExistentialType(quantified, tp1) => check(tp1, bound ::: quantified) case ThisType(_) => ; case NoPrefix => ; case _ => patternWarning(tp, "type ") } } check(tp, List()) } /** Type intersection of simple type <code>tp1</code> with general * type <code>tp2</code>. The result eliminates some redundancies. */ def intersect(tp1: Type, tp2: Type): Type = { if (tp1 <:< tp2) tp1 else if (tp2 <:< tp1) tp2 else { val reduced2 = tp2 match { case rtp @ RefinedType(parents2, decls2) => copyRefinedType(rtp, parents2 filter (p2 => !(tp1 <:< p2)), decls2) case _ => tp2 } intersectionType(List(tp1, reduced2)) } } def inferTypedPattern(pos: Position, pattp: Type, pt0: Type): Type = { val pt = widen(pt0) checkCheckable(pos, pattp, " pattern") if (!(pattp <:< pt)) { val tpparams = freeTypeParamsOfTerms.collect(pattp) if (settings.debug.value) log("free type params (1) = " + tpparams) var tvars = tpparams map freshVar var tp = pattp.instantiateTypeParams(tpparams, tvars) if (!(tp <:< pt)) { tvars = tpparams map freshVar tp = pattp.instantiateTypeParams(tpparams, tvars) val ptparams = freeTypeParamsOfTerms.collect(pt) if (settings.debug.value) log("free type params (2) = " + ptparams) val ptvars = ptparams map freshVar val pt1 = pt.instantiateTypeParams(ptparams, ptvars) if (!isPopulated(tp, pt1)) { error(pos, "pattern type is incompatible with expected type"+foundReqMsg(pattp, pt)) return pattp } ptvars foreach instantiateTypeVar } tvars foreach instantiateTypeVar } intersect(pt, pattp) } def inferModulePattern(pat: Tree, pt: Type) = if (!(pat.tpe <:< pt)) { val ptparams = freeTypeParamsOfTerms.collect(pt) if (settings.debug.value) log("free type params (2) = " + ptparams) val ptvars = ptparams map freshVar val pt1 = pt.instantiateTypeParams(ptparams, ptvars) if (pat.tpe <:< pt1) ptvars foreach instantiateTypeVar else error(pat.pos, "pattern type is incompatible with expected type"+foundReqMsg(pat.tpe, pt)) } object toOrigin extends TypeMap { def apply(tp: Type): Type = tp match { case TypeVar(origin, _) => origin case _ => mapOver(tp) } } abstract class SymCollector extends TypeTraverser { private var result: List[Symbol] = _ protected def includeCondition(sym: Symbol): Boolean override def traverse(tp: Type): TypeTraverser = { tp.normalize match { case TypeRef(_, sym, _) => if (includeCondition(sym) && !result.contains(sym)) result = sym :: result case _ => } mapOver(tp) this } /** Collect all abstract type symbols referred to by type <code>tp</code>. * * @param tp ... * @return ... */ def collect(tp: Type): List[Symbol] = { result = List() traverse(tp) result } } object approximateAbstracts extends TypeMap { def apply(tp: Type): Type = tp.normalize match { case TypeRef(pre, sym, _) if sym.isAbstractType => WildcardType case _ => mapOver(tp) } } /** A traverser to collect type parameters referred to in a type */ object freeTypeParamsOfTerms extends SymCollector { protected def includeCondition(sym: Symbol): Boolean = sym.isAbstractType && sym.owner.isTerm } object typeRefs extends SymCollector { protected def includeCondition(sym: Symbol): Boolean = true } def checkDead(tree: Tree): Tree = { if (settings.Xwarndeadcode.value && tree.tpe.typeSymbol == AllClass) context.warning (tree.pos, "dead code following this construct") tree } /* -- Overload Resolution ---------------------------------------------- */ def checkNotShadowed(pos: Position, pre: Type, best: Symbol, eligible: List[Symbol]) = if (!phase.erasedTypes) for (alt <- eligible) { if (alt.owner != best.owner && alt.owner.isSubClass(best.owner)) error(pos, "erroneous reference to overloaded definition,\n"+ "most specific definition is: "+best+best.locationString+" of type "+pre.memberType(best)+ ",\nyet alternative definition "+alt+alt.locationString+" of type "+pre.memberType(alt)+ "\nis defined in a subclass") } /** Assign <code>tree</code> the symbol and type of the alternative which * matches prototype <code>pt</code>, if it exists. * If several alternatives match `pt', take parameterless one. * If no alternative matches `pt', take the parameterless one anyway. */ def inferExprAlternative(tree: Tree, pt: Type): Unit = tree.tpe match { case OverloadedType(pre, alts) => tryTwice { var alts1 = alts filter (alt => isWeaklyCompatible(pre.memberType(alt), pt)) var secondTry = false if (alts1.isEmpty) { alts1 = alts secondTry = true } def improves(sym1: Symbol, sym2: Symbol): Boolean = sym2 == NoSymbol || { val tp1 = pre.memberType(sym1) val tp2 = pre.memberType(sym2) (tp2 == ErrorType || !global.typer.infer.isWeaklyCompatible(tp2, pt) && global.typer.infer.isWeaklyCompatible(tp1, pt) || isStrictlyMoreSpecific(tp1, tp2)) } val best = ((NoSymbol: Symbol) /: alts1) ((best, alt) => if (improves(alt, best)) alt else best) val competing = alts1 dropWhile (alt => best == alt || improves(best, alt)) if (best == NoSymbol) { if (settings.debug.value) { tree match { case Select(qual, _) => Console.println("qual: " + qual + ":" + qual.tpe + " with decls " + qual.tpe.decls + " with members " + qual.tpe.members + " with members " + qual.tpe.member(newTermName("$minus"))) case _ => } } typeErrorTree(tree, tree.symbol.tpe, pt) } else if (!competing.isEmpty) { if (secondTry) { typeErrorTree(tree, tree.symbol.tpe, pt) } else { if (!pt.isErroneous) context.ambiguousError(tree.pos, pre, best, competing.head, "expected type " + pt) setError(tree) } } else { val applicable = alts1 filter (alt => global.typer.infer.isWeaklyCompatible(pre.memberType(alt), pt)) checkNotShadowed(tree.pos, pre, best, applicable) tree.setSymbol(best).setType(pre.memberType(best)) } } } /** Assign <code>tree</code> the type of an alternative which is applicable * to <code>argtpes</code>, and whose result type is compatible with `pt'. * If several applicable alternatives exist, take the * most specialized one. * If no applicable alternative exists, and pt != WildcardType, try again * with pt = WildcardType. * Otherwise, if there is no best alternative, error. */ def inferMethodAlternative(tree: Tree, undetparams: List[Symbol], argtpes: List[Type], pt: Type): Unit = tree.tpe match { case OverloadedType(pre, alts) => tryTwice { if (settings.debug.value) log("infer method alt " + tree.symbol + " with alternatives " + (alts map pre.memberType) + ", argtpes = " + argtpes + ", pt = " + pt) val applicable = alts filter (alt => isApplicable(undetparams, followApply(pre.memberType(alt)), argtpes, pt)) def improves(sym1: Symbol, sym2: Symbol) = sym2 == NoSymbol || sym2.isError || isStrictlyMoreSpecific(followApply(pre.memberType(sym1)), followApply(pre.memberType(sym2))) val best = ((NoSymbol: Symbol) /: applicable) ((best, alt) => if (improves(alt, best)) alt else best) val competing = applicable dropWhile (alt => best == alt || improves(best, alt)) if (best == NoSymbol) { if (pt == WildcardType) { errorTree(tree, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt)) } else { inferMethodAlternative(tree, undetparams, argtpes, WildcardType) } } else if (!competing.isEmpty) { if (!(argtpes exists (_.isErroneous)) && !pt.isErroneous) context.ambiguousError(tree.pos, pre, best, competing.head, "argument types " + argtpes.mkString("(", ",", ")") + (if (pt == WildcardType) "" else " and expected result type " + pt)) setError(tree) () } else { checkNotShadowed(tree.pos, pre, best, applicable) tree.setSymbol(best).setType(pre.memberType(best)) } } case _ => } /** Try inference twice, once without views and once with views, * unless views are already disabled. * * @param infer ... */ def tryTwice(infer: => Unit) { if (context.implicitsEnabled) { val reportGeneralErrors = context.reportGeneralErrors context.reportGeneralErrors = false context.implicitsEnabled = false try { infer } catch { case ex: CyclicReference => throw ex case ex: TypeError => context.reportGeneralErrors = reportGeneralErrors context.implicitsEnabled = true infer } context.reportGeneralErrors = reportGeneralErrors context.implicitsEnabled = true } else infer } /** Assign <code>tree</code> the type of unique polymorphic alternative * with <code>nparams</code> as the number of type parameters, if it exists. * If several or none such polymorphic alternatives exist, error. * * @param tree ... * @param nparams ... */ def inferPolyAlternatives(tree: Tree, argtypes: List[Type]): Unit = tree.tpe match { case OverloadedType(pre, alts) => val sym0 = tree.symbol filter { alt => alt.typeParams.length == argtypes.length } if (sym0 == NoSymbol) { error( tree.pos, if (alts exists (alt => alt.typeParams.length > 0)) "wrong number of type parameters for " + treeSymTypeMsg(tree) else treeSymTypeMsg(tree) + " does not take type parameters") return } if (sym0.hasFlag(OVERLOADED)) { val sym = sym0 filter { alt => isWithinBounds(pre, alt.owner, alt.typeParams, argtypes) } if (sym == NoSymbol) { if (!(argtypes exists (_.isErroneous))) { error( tree.pos, "type arguments " + argtypes.mkString("[", ",", "]") + " conform to the bounds of none of the overloaded alternatives of\n "+sym0+ ": "+sym0.info) return } } if (sym.hasFlag(OVERLOADED)) { val tparams = new AsSeenFromMap(pre, sym.alternatives.head.owner).mapOver( sym.alternatives.head.typeParams) val bounds = tparams map (_.tpe) //@M TODO: might be affected by change to tpe in Symbol val tpe = PolyType(tparams, OverloadedType(AntiPolyType(pre, bounds), sym.alternatives)) sym.setInfo(tpe) tree.setSymbol(sym).setType(tpe) } else { tree.setSymbol(sym).setType(pre.memberType(sym)) } } else { tree.setSymbol(sym0).setType(pre.memberType(sym0)) } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -