📄 infer.scala
字号:
} } if (sym1.isTerm) { if (sym1 hasFlag JAVA) cook(sym1) else if (sym1 hasFlag OVERLOADED) for (sym2 <- sym1.alternatives) if (sym2 hasFlag JAVA) cook(sym2) } //Console.println("check acc " + sym1 + ":" + sym1.tpe + " from " + pre);//DEBUG var owntype = try{ pre.memberType(sym1) } catch { case ex: MalformedType => if (settings.debug.value) ex.printStackTrace val sym2 = underlying(sym1) val itype = withoutMalformedChecks(pre.memberType(sym2)) accessError("\n because its instance type "+itype+ (if ("malformed type: "+itype.toString==ex.msg) " is malformed" else " contains a "+ex.msg)) ErrorType } if (pre.isInstanceOf[SuperType]) owntype = owntype.substSuper(pre, site.symbol.thisType) tree setSymbol sym1 setType owntype } } def isPlausiblyCompatible(tp: Type, pt: Type): Boolean = tp match { case PolyType(_, restpe) => isPlausiblyCompatible(restpe, pt) case mt: ImplicitMethodType => isPlausiblyCompatible(mt.resultType, pt) case ExistentialType(tparams, qtpe) => isPlausiblyCompatible(qtpe, pt) case MethodType(formals, _) => pt.normalize match { case TypeRef(pre, sym, args) => !sym.isClass || { val l = args.length - 1 l == formals.length && sym == FunctionClass(l) && List.forall2(args, formals) (isPlausiblySubType) && isPlausiblySubType(tp.resultApprox, args.last) } case _ => true } case _ => true } private def isPlausiblySubType(tp1: Type, tp2: Type): Boolean = tp1.normalize match { case TypeRef(_, sym1, _) => !sym1.isClass || { tp2.normalize match { case TypeRef(_, sym2, _) => !sym2.isClass || (sym1 isSubClass sym2) case _ => true } } case _ => true } def isCompatible(tp: Type, pt: Type): Boolean = { val tp1 = normalize(tp) (tp1 <:< pt) || isCoercible(tp, pt) } def isWeaklyCompatible(tp: Type, pt: Type): Boolean = pt.typeSymbol == UnitClass || isCompatible(tp, pt) def isCoercible(tp: Type, pt: Type): Boolean = false def isCompatible(tps: List[Type], pts: List[Type]): Boolean = List.map2(tps, pts)((tp, pt) => isCompatible(tp, pt)) forall (x => x) /* -- Type instantiation------------------------------------------------ */ /** Return inferred type arguments of polymorphic expression, given * its type parameters and result type and a prototype <code>pt</code>. * If no minimal type variables exist that make the * instantiated type a subtype of <code>pt</code>, return null. * * @param tparams ... * @param restpe ... * @param pt ... * @return ... */ private def exprTypeArgs(tparams: List[Symbol], restpe: Type, pt: Type): List[Type] = { val tvars = tparams map freshVar if (isCompatible(restpe.instantiateTypeParams(tparams, tvars), pt)) { try { solvedTypes(tvars, tparams, tparams map varianceInType(restpe), false) } catch { case ex: NoInstance => null } } else null } /** Return inferred proto-type arguments of function, given * its type and value parameters and result type, and a * prototype <code>pt</code> for the function result. * Type arguments need to be either determined precisely by * the prototype, or they are maximized, if they occur only covariantly * in the value parameter list. * If instantiation of a type parameter fails, * take WildcardType for the proto-type argument. * * @param tparams ... * @param formals ... * @param restype ... * @param pt ... * @return ... */ def protoTypeArgs(tparams: List[Symbol], formals: List[Type], restpe: Type, pt: Type): List[Type] = { /** Map type variable to its instance, or, if `variance' is covariant/contravariant, * to its upper/lower bound */ def instantiateToBound(tvar: TypeVar, variance: Int): Type = try { //Console.println("instantiate "+tvar+tvar.constr+" variance = "+variance);//DEBUG if (tvar.constr.inst != NoType) { instantiate(tvar.constr.inst) } else if ((variance & COVARIANT) != 0 && !tvar.constr.hibounds.isEmpty) { tvar.constr.inst = glb(tvar.constr.hibounds) assertNonCyclic(tvar)//debug instantiate(tvar.constr.inst) } else if ((variance & CONTRAVARIANT) != 0 && !tvar.constr.lobounds.isEmpty) { tvar.constr.inst = lub(tvar.constr.lobounds) assertNonCyclic(tvar)//debug instantiate(tvar.constr.inst) } else if (!tvar.constr.hibounds.isEmpty && !tvar.constr.lobounds.isEmpty && glb(tvar.constr.hibounds) <:< lub(tvar.constr.lobounds)) { tvar.constr.inst = glb(tvar.constr.hibounds) assertNonCyclic(tvar)//debug instantiate(tvar.constr.inst) } else { WildcardType } } catch { case ex: NoInstance => WildcardType } val tvars = tparams map freshVar if (isWeaklyCompatible(restpe.instantiateTypeParams(tparams, tvars), pt)) List.map2(tparams, tvars) ((tparam, tvar) => instantiateToBound(tvar, varianceInTypes(formals)(tparam))) else tvars map (tvar => WildcardType) } /** Return inferred type arguments, given type parameters, formal parameters, * argument types, result type and expected result type. * If this is not possible, throw a <code>NoInstance</code> exception. * Undetermined type arguments are represented by `definitions.AllClass.tpe'. * No check that inferred parameters conform to their bounds is made here. * * @param tparams the type parameters of the method * @param formals the value parameter types of the method * @param restp the result type of the method * @param argtpes the argument types of the application * @param pt the expected return type of the application * @param uninstantiated a listbuffer receiving all uninstantiated type parameters * (type parameters mapped by the constraint solver to `scala.All' * and not covariant in <code>restpe</code> are taken to be * uninstantiated. Maps all those type arguments to their * corresponding type parameters). * @return ... * @throws NoInstance */ // bq: was private, but need it for unapply checking def methTypeArgs(tparams: List[Symbol], formals: List[Type], restpe: Type, argtpes: List[Type], pt: Type, uninstantiated: ListBuffer[Symbol]): List[Type] = { val tvars = tparams map freshVar if (formals.length != argtpes.length) { throw new NoInstance("parameter lists differ in length") } // check first whether type variables can be fully defined from // expected result type. if (!isWeaklyCompatible(restpe.instantiateTypeParams(tparams, tvars), pt)) {// just wait and instantiate form the arguments.// that way, we can try to apply an implicit conversion afterwards. // This case could happen if restpe is not fully defined, so that// search for an implicit from it to pt fails because of an ambiguity.// See #0347. Therefore, the following two lines are commented out.// throw new DeferredNoInstance(() =>// "result type " + normalize(restpe) + " is incompatible with expected type " + pt) } for (tvar <- tvars) if (!isFullyDefined(tvar)) tvar.constr.inst = NoType // Then define remaining type variables from argument types. List.map2(argtpes, formals) {(argtpe, formal) => if (!isCompatible(argtpe.deconst.instantiateTypeParams(tparams, tvars), formal.instantiateTypeParams(tparams, tvars))) { if (settings.explaintypes.value) explainTypes(argtpe.deconst.instantiateTypeParams(tparams, tvars), formal.instantiateTypeParams(tparams, tvars)) throw new DeferredNoInstance(() => "argument expression's type is not compatible with formal parameter type" + foundReqMsg(argtpe.deconst.instantiateTypeParams(tparams, tvars), formal.instantiateTypeParams(tparams, tvars))) } () } val targs = solvedTypes(tvars, tparams, tparams map varianceInTypes(formals), false)// val res = List.map2(tparams, targs) {(tparam, targ) => if (targ.typeSymbol == AllClass && (varianceInType(restpe)(tparam) & COVARIANT) == 0) { uninstantiated += tparam tparam.tpe //@M TODO: might be affected by change to tpe in Symbol } else if (targ.typeSymbol == RepeatedParamClass) { targ.baseType(SeqClass) } else { targ.widen } }// println("meth type args "+", tparams = "+tparams+", formals = "+formals+", restpe = "+restpe+", argtpes = "+argtpes+", underlying = "+(argtpes map (_.widen))+", pt = "+pt+", uninstantiated = "+uninstantiated.toList+", result = "+res) //DEBUG// res } private[typechecker] def followApply(tp: Type): Type = tp match { case PolyType(List(), restp) => val restp1 = followApply(restp) if (restp1 eq restp) tp else restp1 case _ => val appmeth = tp.nonPrivateMember(nme.apply) filter (_.isPublic) if (appmeth == NoSymbol) tp else OverloadedType(tp, appmeth.alternatives) } def hasExactlyNumParams(tp: Type, n: Int): Boolean = tp match { case OverloadedType(pre, alts) => alts exists (alt => hasExactlyNumParams(pre.memberType(alt), n)) case _ => formalTypes(tp.paramTypes, n).length == n } /** Is there an instantiation of free type variables <code>undetparams</code> * such that function type <code>ftpe</code> is applicable to * <code>argtpes</code> and its result conform to <code>pt</code>? * * @param undetparams ... * @param ftpe ... * @param argtpes ... * @param pt ... * @return ... */ private def isApplicable(undetparams: List[Symbol], ftpe: Type, argtpes0: List[Type], pt: Type): Boolean = ftpe match { case OverloadedType(pre, alts) => alts exists (alt => isApplicable(undetparams, pre.memberType(alt), argtpes0, pt)) case ExistentialType(tparams, qtpe) => isApplicable(undetparams, qtpe, argtpes0, pt) case MethodType(formals0, _) => val formals = formalTypes(formals0, argtpes0.length) val argtpes = actualTypes(argtpes0, formals.length) val restpe = ftpe.resultType(argtpes) if (undetparams.isEmpty) { (formals.length == argtpes.length && isCompatible(argtpes, formals) && isWeaklyCompatible(restpe, pt)) } else { try { val uninstantiated = new ListBuffer[Symbol] val targs = methTypeArgs(undetparams, formals, restpe, argtpes, pt, uninstantiated) (exprTypeArgs(uninstantiated.toList, restpe.instantiateTypeParams(undetparams, targs), pt) ne null) && isWithinBounds(NoPrefix, NoSymbol, undetparams, targs) } catch { case ex: NoInstance => false } } case PolyType(tparams, restpe) => val tparams1 = cloneSymbols(tparams) isApplicable(tparams1 ::: undetparams, restpe.substSym(tparams, tparams1), argtpes0, pt) case ErrorType => true case _ => false } private[typechecker] def isApplicableSafe(undetparams: List[Symbol], ftpe: Type, argtpes0: List[Type], pt: Type): Boolean = { val reportAmbiguousErrors = context.reportAmbiguousErrors context.reportAmbiguousErrors = false try { isApplicable(undetparams, ftpe, argtpes0, pt) } catch { case ex: TypeError => false } finally { context.reportAmbiguousErrors = reportAmbiguousErrors } } /** Is type <code>ftpe1</code> strictly more specific than type <code>ftpe2</code> * when both are alternatives in an overloaded function? * @see SLS (sec:overloading-resolution) * * @param ftpe1 ... * @param ftpe2 ... * @return ... */ def isMoreSpecific(ftpe1: Type, ftpe2: Type): Boolean = ftpe1 match { case OverloadedType(pre, alts) => alts exists (alt => isMoreSpecific(pre.memberType(alt), ftpe2)) case et: ExistentialType => et.withTypeVars(isStrictlyMoreSpecific(_, ftpe2)) case MethodType(formals @ (x :: xs), _) => isApplicable(List(), ftpe2, formals, WildcardType) case PolyType(_, MethodType(formals @ (x :: xs), _)) => isApplicable(List(), ftpe2, formals, WildcardType) case ErrorType => true case _ => ftpe2 match { case OverloadedType(pre, alts) => alts forall (alt => isMoreSpecific(ftpe1, pre.memberType(alt))) case et: ExistentialType => et.withTypeVars(isStrictlyMoreSpecific(ftpe1, _)) case MethodType(_, _) | PolyType(_, MethodType(_, _)) => true case _ => isMoreSpecificValueType(ftpe1, ftpe2, List(), List()) } } def isStrictlyMoreSpecific(ftpe1: Type, ftpe2: Type): Boolean = ftpe1.isError || isMoreSpecific(ftpe1, ftpe2) && (!isMoreSpecific(ftpe2, ftpe1) || !ftpe1.isInstanceOf[OverloadedType] && ftpe2.isInstanceOf[OverloadedType] || phase.erasedTypes && covariantReturnOverride(ftpe1, ftpe2)) private def covariantReturnOverride(ftpe1: Type, ftpe2: Type): Boolean = (ftpe1, ftpe2) match { case (MethodType(_, rtpe1), MethodType(_, rtpe2)) => rtpe1 <:< rtpe2 || rtpe2.typeSymbol == ObjectClass case _ => false } private def isMoreSpecificValueType(tpe1: Type, tpe2: Type, undef1: List[Symbol], undef2: List[Symbol]): Boolean = (tpe1, tpe2) match { case (PolyType(tparams1, rtpe1), _) => isMoreSpecificValueType(rtpe1, tpe2, undef1 ::: tparams1, undef2) case (_, PolyType(tparams2, rtpe2)) => isMoreSpecificValueType(tpe1, rtpe2, undef1, undef2 ::: tparams2) case _ => existentialAbstraction(undef1, tpe1) <:< existentialAbstraction(undef2, tpe2) }/* /** Is type `tpe1' a strictly better expression alternative than type `tpe2'? */ def isStrictlyBetterExpr(tpe1: Type, tpe2: Type) = { isMethod(tpe2) && !isMethod(tpe1) ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -