typers.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 1,553 行 · 第 1/5 页

SCALA
1,553
字号
      if sym.isAliasType && tr.normalize.isInstanceOf[ExistentialType] &&        ((mode & (EXPRmode | LHSmode)) == EXPRmode) =>        adapt(tree setType tr.normalize.skolemizeExistential(context.owner, tree), mode, pt)      case et @ ExistentialType(_, _) if ((mode & (EXPRmode | LHSmode)) == EXPRmode) =>        adapt(tree setType et.skolemizeExistential(context.owner, tree), mode, pt)      case PolyType(tparams, restpe) if ((mode & (TAPPmode | PATTERNmode)) == 0) => // (3)        assert((mode & HKmode) == 0) //@M        val tparams1 = cloneSymbols(tparams)        val tree1 = if (tree.isType) tree                     else TypeApply(tree, tparams1 map (tparam =>                       TypeTree(tparam.tpe) setOriginal tree)) setPos tree.pos        context.undetparams = context.undetparams ::: tparams1        adapt(tree1 setType restpe.substSym(tparams, tparams1), mode, pt)      case mt: ImplicitMethodType if ((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) => // (4.1)        if (!context.undetparams.isEmpty & (mode & POLYmode) == 0) { // (9)          val tparams = context.undetparams          context.undetparams = List()          inferExprInstance(tree, tparams, pt)          adapt(tree, mode, pt)        } else {          val typer1 = constrTyperIf(treeInfo.isSelfOrSuperConstrCall(tree))          typer1.typed(typer1.applyImplicitArgs(tree), mode, pt)        }      case mt: MethodType      if (((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) &&           (context.undetparams.isEmpty || (mode & POLYmode) != 0)) =>        val meth = tree.symbol        if (!meth.isConstructor &&             //isCompatible(tparamsToWildcards(mt, context.undetparams), pt) &&            isFunctionType(pt))/* &&            (pt <:< functionType(mt.paramTypes map (t => WildcardType), WildcardType)))*/ { // (4.2)          if (settings.debug.value) log("eta-expanding "+tree+":"+tree.tpe+" to "+pt)          checkParamsConvertible(tree.pos, tree.tpe)          typed(etaExpand(context.unit, tree), mode, pt)        } else if (!meth.isConstructor && mt.paramTypes.isEmpty) { // (4.3)          adapt(typed(Apply(tree, List()) setPos tree.pos), mode, pt)        } else if (context.implicitsEnabled) {          errorTree(tree, "missing arguments for "+meth+meth.locationString+                    (if (meth.isConstructor) ""                     else ";\nfollow this method with `_' if you want to treat it as a partially applied function"))        } else {          setError(tree)        }      case _ =>        def applyPossible = {          def applyMeth = member(adaptToName(tree, nme.apply), nme.apply)          if ((mode & TAPPmode) != 0)            tree.tpe.typeParams.isEmpty && applyMeth.filter(! _.tpe.typeParams.isEmpty) != NoSymbol          else             applyMeth.filter(_.tpe.paramSectionCount > 0) != NoSymbol        }        if (tree.isType) {          if ((mode & FUNmode) != 0) {            tree          } else if (tree.hasSymbol && !tree.symbol.typeParams.isEmpty && (mode & HKmode) == 0) { // (7)             // @M When not typing a higher-kinded type ((mode & HKmode) == 0), types must be of kind *,             // and thus parameterised types must be applied to their type arguments            // @M TODO: why do kind-* tree's have symbols, while higher-kinded ones don't?            errorTree(tree, tree.symbol+" takes type parameters")            tree setType tree.tpe          } else if ( // (7.1) @M: check kind-arity                     // @M: removed check for tree.hasSymbol and replace tree.symbol by tree.tpe.symbol (TypeTree's must also be checked here, and they don't directly have a symbol)                     ((mode & HKmode) != 0) &&                     // @M: don't check tree.tpe.symbol.typeParams. check tree.tpe.typeParams!!!                     // (e.g., m[Int] --> tree.tpe.symbol.typeParams.length == 1, tree.tpe.typeParams.length == 0!)                     tree.tpe.typeParams.length != pt.typeParams.length &&                      !(tree.tpe.typeSymbol==AnyClass ||                        tree.tpe.typeSymbol==AllClass ||                        pt == WildcardType )) {              // Check that the actual kind arity (tree.symbol.typeParams.length) conforms to the expected              // kind-arity (pt.typeParams.length). Full checks are done in checkKindBounds in Infer.              // Note that we treat Any and Nothing as kind-polymorphic.               // We can't perform this check when typing type arguments to an overloaded method before the overload is resolved               // (or in the case of an error type) -- this is indicated by pt == WildcardType (see case TypeApply in typed1).              errorTree(tree, tree.tpe+" takes "+reporter.countElementsAsString(tree.tpe.typeParams.length, "type parameter")+                              ", expected: "+reporter.countAsString(pt.typeParams.length))              tree setType tree.tpe          } else tree match { // (6)            case TypeTree() => tree            case _ => TypeTree(tree.tpe) setOriginal(tree)          }        } else if ((mode & (PATTERNmode | FUNmode)) == (PATTERNmode | FUNmode)) { // (5)          val extractor = tree.symbol.filter(sym => unapplyMember(sym.tpe).exists)          if (extractor != NoSymbol) {            tree setSymbol extractor            val unapply = unapplyMember(extractor.tpe)            val clazz = if (unapply.tpe.paramTypes.length == 1) unapply.tpe.paramTypes.head.typeSymbol                         else NoSymbol            if ((unapply hasFlag CASE) && (clazz hasFlag CASE) &&                 !(clazz.info.baseClasses.tail exists (_ hasFlag CASE))) {              if (!phase.erasedTypes) checkStable(tree) //todo: do we need to demand this?              // convert synthetic unapply of case class to case class constructor              val prefix = tree.tpe.prefix              val tree1 = TypeTree(clazz.primaryConstructor.tpe.asSeenFrom(prefix, clazz.owner))                  .setOriginal(tree)              try {                inferConstructorInstance(tree1, clazz.typeParams, pt)              } catch {                case tpe : TypeError => throw tpe                case t : Exception =>                  logError("CONTEXT: " + (tree.pos).dbgString, t)                  throw t              }              tree1            } else {              tree            }          } else {            errorTree(tree, tree.symbol + " is not a case class constructor, nor does it have an unapply/unapplySeq method")          }        } else if ((mode & (EXPRmode | FUNmode)) == (EXPRmode | FUNmode) &&                    !tree.tpe.isInstanceOf[MethodType] &&                    !tree.tpe.isInstanceOf[OverloadedType] &&                    applyPossible) {          assert((mode & HKmode) == 0) //@M          val qual = adaptToName(tree, nme.apply) match {            case id @ Ident(_) =>              val pre = if (id.symbol.owner.isPackageClass) id.symbol.owner.thisType                        else if (id.symbol.owner.isClass)                           context.enclosingSubClassContext(id.symbol.owner).prefix                        else NoPrefix              stabilize(id, pre, EXPRmode | QUALmode, WildcardType)            case sel @ Select(qualqual, _) =>               stabilize(sel, qualqual.tpe, EXPRmode | QUALmode, WildcardType)            case other =>               other          }          typed(atPos(tree.pos)(Select(qual, nme.apply)), mode, pt)        } else if (!context.undetparams.isEmpty && (mode & POLYmode) == 0) { // (9)          assert((mode & HKmode) == 0) //@M          instantiate(tree, mode, pt)        } else if (tree.tpe <:< pt) {          def isStructuralType(tpe: Type): Boolean = tpe match {            case RefinedType(ps, decls) =>              decls.toList exists (x => x.isTerm && x.allOverriddenSymbols.isEmpty)            case _ =>              false          }          if (isStructuralType(pt) && tree.tpe.typeSymbol == ArrayClass) {            // all Arrays used as structural refinement typed values must be boxed            // this does not solve the case where the type to be adapted to comes            // from a type variable that was bound by a strctural but is instantiated            typed(Apply(Select(gen.mkAttributedRef(ScalaRunTimeModule), nme.forceBoxedArray), List(tree)))          }          else            tree        } else {          if ((mode & PATTERNmode) != 0) {            if ((tree.symbol ne null) && tree.symbol.isModule)              inferModulePattern(tree, pt)            if (isPopulated(tree.tpe, approximateAbstracts(pt)))              return tree          }          val tree1 = constfold(tree, pt) // (10) (11)          if (tree1.tpe <:< pt) adapt(tree1, mode, pt)          else {            if ((mode & (EXPRmode | FUNmode)) == EXPRmode) {              pt.normalize match {                case TypeRef(_, sym, _) =>                  // note: was if (pt.typeSymbol == 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.undetparams.isEmpty) {                return instantiate(tree, mode, pt)              }              if (context.implicitsEnabled && !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)                // convert forward views of delegate types into closures wrapped around                // the delegate's apply method (the "Invoke" method, which was translated into apply)                if (forMSIL && coercion != null && isCorrespondingDelegate(tree.tpe, pt)) {                  val meth: Symbol = tree.tpe.member(nme.apply)                  if(settings.debug.value)                    log("replacing forward delegate view with: " + meth + ":" + meth.tpe)                  return typed(Select(tree, meth), mode, pt)                }                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)              if (settings.explaintypes.value) explainTypes(tree.tpe, pt)            }            typeErrorTree(tree, tree.tpe, pt)          }        }    }    /**     *  @param tree ...     *  @param mode ...     *  @param pt   ...     *  @return     ...     */    def instantiate(tree: Tree, mode: Int, pt: Type): Tree = {      val tparams = context.undetparams      context.undetparams = List()      inferExprInstance(tree, tparams, pt)      adapt(tree, mode, pt)    }    /**     *  @param qual ...     *  @param name ...     *  @param tp   ...     *  @return     ...     */    def adaptToMember(qual: Tree, name: Name, tp: Type): Tree = {      val qtpe = qual.tpe.widen      if (qual.isTerm &&           ((qual.symbol eq null) || !qual.symbol.isTerm || qual.symbol.isValue) &&          phase.id <= currentRun.typerPhase.id && !qtpe.isError && !tp.isError &&          qtpe.typeSymbol != AllRefClass && qtpe.typeSymbol != AllClass && qtpe != WildcardType) {        val coercion = inferView(qual.pos, qtpe, name, tp, true)        if (coercion != EmptyTree)           typedQualifier(atPos(qual.pos)(Apply(coercion, List(qual))))        else qual      } else qual    }    def adaptToName(qual: Tree, name: Name) =      if (member(qual, name) != NoSymbol) qual      else adaptToMember(qual, name, WildcardType)    private def typePrimaryConstrBody(clazz : Symbol, cbody: Tree, tparams: List[Symbol], enclTparams: List[Symbol], vparamss: List[List[ValDef]]): Tree = {      // XXX: see about using the class's symbol....      enclTparams foreach (sym => context.scope.enter(sym))      namer.enterValueParams(context.owner, vparamss)      typed(cbody)    }    def parentTypes(templ: Template): List[Tree] =       if (templ.parents.isEmpty) List()      else try {        val clazz = context.owner        // Normalize supertype and mixins so that supertype is always a class, not a trait.        var supertpt = typedTypeConstructor(templ.parents.head)        val firstParent = supertpt.tpe.typeSymbol        var mixins = templ.parents.tail map typedType        // If first parent is a trait, make it first mixin and add its superclass as first parent         while ((supertpt.tpe.typeSymbol ne null) && supertpt.tpe.typeSymbol.initialize.isTrait) {          val supertpt1 = typedType(supertpt)          if (!supertpt1.tpe.isError) {            mixins = supertpt1 :: mixins            supertpt = TypeTree(supertpt1.tpe.parents.head) setOriginal supertpt /* setPos supertpt.pos */          }        }        // Determine         //  - supertparams: Missing type parameters from supertype        //  - supertpe: Given supertype, polymorphic in supertparams        val supertparams = if (supertpt.hasSymbol) supertpt.symbol.typeParams else List()        var supertpe = supertpt.tpe        if (!supertparams.isEmpty)          supertpe = PolyType(supertparams, appliedType(supertpe, supertparams map (_.tpe)))        // A method to replace a super reference by a New in a supercall        def transformSuperCall(scall: Tree): Tree = (scall: @unchecked) match {          case Apply(fn, args) =>            copy.Apply(scall, transformSuperCall(fn), args map (_.duplicate))          case Select(Super(_, _), nme.CONSTRUCTOR) =>            copy.Select(              scall,               New(TypeTree(supertpe) setOriginal supertpt) setType supertpe setPos supertpt.pos,              nme.CONSTRUCTOR)        }        treeInfo.firstConstructor(templ.body) match {          case constr @ DefDef(_, _, _, vparamss, _, cbody @ Block(cstats, cunit)) =>            // Convert constructor body to block in environment and typecheck it            val cstats1: List[Tree] = cstats map (_.duplicate)            val scall = if (cstats.isEmpty) EmptyTree else cstats.last            val cbody1 = scall match {              case Apply(_, _) =>                copy.Block(cbody, cstats1.init,                            if (supertparams.isEmpty) cunit.duplicate                            else transformSuperCall(scall))              case _ =>                copy.Block(cbody, cstats1, cunit.duplicate)            }            val outercontext = context.outer             assert(clazz != NoSymbol)            val cscope = outercontext.makeNewScope(constr, outercontext.owner)(ParentTypesScopeKind(clazz))            val cbody2 = newTyper(cscope) // called both during completion AND typing.                .typePrimaryConstrBody(clazz,                    cbody1, supertparams, clazz.unsafeTypeParams, vparamss map (_.map(_.duplicate)))            scall match {              case Apply(_, _) =>                val sarg = treeInfo.firstArgument(scall)                if (sarg != EmptyTree && supertpe.typeSymbol != firstParent)                   error(sarg.pos, firstParent+" is a trait; does not take constructor arguments")                if (!supertparams.isEmpty) supertpt = TypeTree(cbody2.tpe) setPos supertpt.pos              case _ =>                if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments")            }            List.map2(cstats1, treeInfo.preSuperFields(templ.body)) {              (ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe            }          case _ =>            if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments")

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?