⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 infer.scala

📁 JAVA 语言的函数式编程扩展
💻 SCALA
📖 第 1 页 / 共 4 页
字号:
            }          }          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 + -