typers.scala

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

SCALA
1,553
字号
        case MethodType(formals, restpe) =>          /*          if (formals.exists(_.typeSymbol == ByNameParamClass) && formals.length != 1)            error(pos, "methods with `=>'-parameter can be converted to function values only if they take no other parameters")          if (formals exists (_.typeSymbol == RepeatedParamClass))            error(pos, "methods with `*'-parameters cannot be converted to function values");          */          if (restpe.isDependent)            error(pos, "method with dependent type "+tpe+" cannot be converted to function value");          checkParamsConvertible(pos, restpe)        case _ =>      }    }    def checkRegPatOK(pos: Position, mode: Int) =       if ((mode & REGPATmode) == 0)        error(pos, "no regular expression pattern allowed here\n"+              "(regular expression patterns are only allowed in arguments to *-parameters)")    /** 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 hiddenSymbols: List[Symbol] = _      /** Check that type <code>tree</code> does not refer to private       *  components unless itself is wrapped in something private       *  (<code>owner</code> tells where the type occurs).       *       *  @param owner ...       *  @param tree  ...       *  @return      ...       */      def privates[T <: Tree](owner: Symbol, tree: T): T =        check(owner, EmptyScope, WildcardType, tree)      /** Check that type <code>tree</code> does not refer to entities       *  defined in scope <code>scope</code>.       *       *  @param scope ...       *  @param pt    ...       *  @param tree  ...       *  @return      ...       */      def locals[T <: Tree](scope: Scope, pt: Type, tree: T): T =        check(NoSymbol, scope, pt, tree)      def check[T <: Tree](owner: Symbol, scope: Scope, pt: Type, tree: T): T = {        this.owner = owner        this.scope = scope        hiddenSymbols = List()        val tp1 = apply(tree.tpe)        if (hiddenSymbols.isEmpty || inIDE) tree setType tp1 // @S: because arguments of classes are owned by the classes' owner        else if (hiddenSymbols exists (_.isErroneous)) setError(tree)        else if (isFullyDefined(pt)) tree setType pt //todo: eliminate        else if (tp1.typeSymbol.isAnonymousClass) // todo: eliminate          check(owner, scope, pt, tree setType tp1.typeSymbol.classBound)        else if (owner == NoSymbol)          tree setType packSymbols(hiddenSymbols.reverse, tp1)        else { // privates          val badSymbol = hiddenSymbols.head          error(tree.pos,                (if (badSymbol hasFlag PRIVATE) "private " else "") + badSymbol +                " escapes its defining scope as part of type "+tree.tpe)          setError(tree)        }      }      def addHidden(sym: Symbol) =        if (!(hiddenSymbols contains sym)) hiddenSymbols = sym :: hiddenSymbols      override def apply(t: Type): Type = {        def checkNoEscape(sym: Symbol) {          if (sym.hasFlag(PRIVATE)) {            var o = owner            while (o != NoSymbol && o != sym.owner &&                    !o.isLocal && !o.hasFlag(PRIVATE) &&                   !o.privateWithin.hasTransOwner(sym.owner))              o = o.owner            if (o == sym.owner) addHidden(sym)          } else if (sym.owner.isTerm && !sym.isTypeParameterOrSkolem) {            var e = scope.lookupEntry(sym.name)            var found = false            while (!found && (e ne null) && e.owner == scope) {              if (e.sym == sym) {                found = true                addHidden(sym)              } else {                e = scope.lookupNextEntry(e)              }            }          }        }        mapOver(          t match {            case TypeRef(_, sym, args) =>               checkNoEscape(sym)              if (!hiddenSymbols.isEmpty && hiddenSymbols.head == sym &&                   sym.isAliasType && sym.typeParams.length == args.length) {                hiddenSymbols = hiddenSymbols.tail                t.normalize              } else t            case SingleType(_, sym) =>               checkNoEscape(sym)              t            case _ =>              t          })      }    }    def reenterValueParams(vparamss: List[List[ValDef]]) {      for (vparams <- vparamss)        for (vparam <- vparams)          vparam.symbol = context.scope enter vparam.symbol    }    def reenterTypeParams(tparams: List[TypeDef]): List[Symbol] =      for (tparam <- tparams) yield {        tparam.symbol = context.scope enter tparam.symbol        tparam.symbol.deSkolemize       }     /** The qualifying class of a this or super with prefix <code>qual</code>.     *     *  @param tree ...     *  @param qual ...     *  @return     ...     */    def qualifyingClassContext(tree: Tree, qual: Name): Context = {      if (qual.isEmpty) {        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      }    }    /** The typer for an expression, depending on where we are. If we are before a superclass      *  call, this is a typer over a constructor context; otherwise it is the current typer.     */      def constrTyperIf(inConstr: Boolean): Typer =        if (inConstr) newTyper(context.makeConstructorContext) else this    /** The typer for a label definition. If this is part of a template we     *  first have to enter the label definition.     */    def labelTyper(ldef: LabelDef): Typer =       if (ldef.symbol == NoSymbol) { // labeldef is part of template        val typer1 = newTyper(context.makeNewScope(ldef, context.owner)(LabelScopeKind))        typer1.enterLabelDef(ldef)        typer1      } else this    final val xtypes = false    /** Does the context of tree <code>tree</code> require a stable type?     */    private def isStableContext(tree: Tree, mode: Int, pt: Type) =        isNarrowable(tree.tpe) && ((mode & (EXPRmode | LHSmode)) == EXPRmode) &&       (xtypes ||      (pt.isStable ||       (mode & QUALmode) != 0 && !tree.symbol.isConstant ||       pt.typeSymbol.isAbstractType && pt.bounds.lo.isStable && !(tree.tpe <:< pt)))    /** <p>     *    Post-process an identifier or selection node, performing the following:     *  </p>     *  <ol>     *  <!--(1)--><li>Check that non-function pattern expressions are stable</li>     *  <!--(2)--><li>Check that packages and static modules are not used as values</li>     *  <!--(3)--><li>Turn tree type into stable type if possible and required by context.</li>     *  </ol>     */    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 (tree.tpe.isError) tree      else if ((mode & (PATTERNmode | FUNmode)) == PATTERNmode && tree.isTerm) { // (1)        checkStable(tree)      } else if ((mode & (EXPRmode | QUALmode)) == EXPRmode && !sym.isValue) { // (2)        errorTree(tree, sym+" is not a value")      } else {        if (sym.isStable && pre.isStable && tree.tpe.typeSymbol != ByNameParamClass &&            (isStableContext(tree, mode, pt) || sym.isModule && !sym.isMethod))          tree.setType(singleType(pre, sym))        else tree      }    }    private def isNarrowable(tpe: Type): Boolean = tpe match {      case TypeRef(_, _, _) | RefinedType(_, _) => true      case ExistentialType(_, tpe1) => isNarrowable(tpe1)      case AnnotatedType(_, tpe1, _) => isNarrowable(tpe1)      case PolyType(_, tpe1) => isNarrowable(tpe1)      case _ => !phase.erasedTypes    }     private def stabilizedType(tree: Tree): Type = tree.tpe/*{      val sym = tree.symbol      val res = tree match {        case Ident(_) if (sym.isStable) =>          val pre = if (sym.owner.isClass) sym.owner.thisType else NoPrefix           singleType(pre, sym)        case Select(qual, _) if (qual.tpe.isStable && sym.isStable) =>          singleType(qual.tpe, sym)        case _ =>          tree.tpe      }      res    }*/    /**     *  @param tree ...     *  @param mode ...     *  @param pt   ...     *  @return     ...     */    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 && sym.tpe.paramTypes.isEmpty &&          (isStableContext(tree, mode, pt) || sym.isModule))        tree.setType(MethodType(List(), singleType(pre, sym)))      else tree    }    /** The member with given name of given qualifier tree */    def member(qual: Tree, name: Name) = qual.tpe match {      case ThisType(clazz) if (context.enclClass.owner.hasTransOwner(clazz)) =>        qual.tpe.member(name)      case _  =>        if (phase.next.erasedTypes) qual.tpe.member(name)        else qual.tpe.nonLocalMember(name)    }          def silent(op: Typer => Tree): AnyRef /* in fact, TypeError or Tree */ = try {      if (context.reportGeneralErrors) {        val context1 = context.makeSilent(context.reportAmbiguousErrors)        context1.undetparams = context.undetparams        context1.savedTypeBounds = context.savedTypeBounds        val typer1 = newTyper(context1)        val result = op(typer1)        context.undetparams = context1.undetparams        context.savedTypeBounds = context1.savedTypeBounds        result      } else {        op(this)      }    } catch {      case ex: CyclicReference => throw ex      case ex: TypeError => ex    }    /** 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, if `pt' is a function type and method is not a constructor,     *        convert to function by eta-expansion,     *  (4.3) otherwise, if the method is nullary with a result type compatible to `pt'     *        and it is not a constructor, apply it to ()     *  otherwise issue an error     *  (5) Convert constructors in a pattern as follows:     *  (5.1) If constructor refers to a case class factory, set tree's type to the unique     *        instance of its primary constructor that is a subtype of the expected type.     *  (5.2) If constructor refers to an exractor, convert to application of     *        unapply or unapplySeq method.     *     *  (6) Convert all other types to TypeTree nodes.     *  (7) When in TYPEmode but not FUNmode or HKmode, check that types are fully parameterized     *      (7.1) In HKmode, higher-kinded types are allowed, but they must have the expected kind-arity     *  (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     */    protected def adapt(tree: Tree, mode: Int, pt: Type): Tree = tree.tpe match {      case ct @ ConstantType(value) if ((mode & (TYPEmode | FUNmode)) == 0 && (ct <:< pt) && !inIDE) => // (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 tr @ TypeRef(_, sym, _) 

⌨️ 快捷键说明

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