typers.scala

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

SCALA
1,553
字号
/* NSC -- new Scala compiler * Copyright 2005-2008 LAMP/EPFL * @author  Martin Odersky */// $Id: Typers.scala 14550 2008-04-08 10:54:54Z odersky $//todo: rewrite or disllow new T where T is a mixin (currently: <init> not a member of T)//todo: use inherited type info also for vars and values//todo: disallow C#D in superclass//todo: treat :::= correctlypackage scala.tools.nsc.typecheckerimport scala.collection.mutable.{HashMap, ListBuffer}import scala.compat.Platform.currentTimeimport scala.tools.nsc.util.{HashSet, Position, Set, NoPosition, SourceFile}import symtab.Flags._import util.HashSet// Suggestion check whether we can do without priminng scopes with symbols of outer scopes,// like the IDE does. /** This trait provides methods to assign types to trees. * *  @author  Martin Odersky *  @version 1.0 */trait Typers { self: Analyzer =>  import global._  import definitions._  import posAssigner.atPos  var appcnt = 0  var idcnt = 0  var selcnt = 0  var implcnt = 0  var impltime = 0l  private val transformed = new HashMap[Tree, Tree]  private val superDefs = new HashMap[Symbol, ListBuffer[Tree]]  def resetTyper() {    resetContexts    resetNamer()    transformed.clear    superDefs.clear  }  object UnTyper extends Traverser {    override def traverse(tree: Tree) = {      if (tree != EmptyTree) tree.tpe = null      if (tree.hasSymbol) tree.symbol = NoSymbol      super.traverse(tree)    }  }   // IDE hooks  def newTyper(context: Context): Typer = new NormalTyper(context)  private class NormalTyper(context : Context) extends Typer(context)  // hooks for auto completion  /** when in 1.4 mode the compiler accepts and ignores useless   *  type parameters of Java generics   */  def onePointFourMode = true // todo changeto: settings.target.value == "jvm-1.4"  // Mode constants  /** The three mode <code>NOmode</code>, <code>EXPRmode</code>   *  and <code>PATTERNmode</code> are mutually exclusive.   */  val NOmode        = 0x000  val EXPRmode      = 0x001  val PATTERNmode   = 0x002  val TYPEmode      = 0x004   /** The mode <code>SCCmode</code> is orthogonal to above. When set we are   *  in the this or super constructor call of a constructor.   */  val SCCmode       = 0x008  /** The mode <code>FUNmode</code> is orthogonal to above.   *  When set we are looking for a method or constructor.   */  val FUNmode       = 0x010  /** The mode <code>POLYmode</code> is orthogonal to above.   *  When set expression types can be polymorphic.   */  val POLYmode      = 0x020  /** The mode <code>QUALmode</code> is orthogonal to above. When set   *  expressions may be packages and Java statics modules.   */  val QUALmode      = 0x040  /** The mode <code>TAPPmode</code> is set for the function/type constructor   *  part of a type application. When set we do not decompose PolyTypes.   */  val TAPPmode      = 0x080  /** The mode <code>SUPERCONSTRmode</code> is set for the <code>super</code>   *  in a superclass constructor call <code>super.&lt;init&gt;</code>.   */  val SUPERCONSTRmode = 0x100  /** The mode <code>SNDTRYmode</code> indicates that an application is typed   *  for the 2nd time. In that case functions may no longer be coerced with   *  implicit views.   */  val SNDTRYmode    = 0x200  /** The mode <code>LHSmode</code> is set for the left-hand side of an   *  assignment.   */  val LHSmode       = 0x400  /** The mode <code>REGPATmode</code> is set when regular expression patterns   *  are allowed.    */  val REGPATmode    = 0x1000  /** The mode <code>ALTmode</code> is set when we are under a pattern alternative */  val ALTmode       = 0x2000    /** The mode <code>HKmode</code> is set when we are typing a higher-kinded type   * adapt should then check kind-arity based on the prototypical type's kind arity   * type arguments should not be inferred   */  val HKmode        = 0x4000 // @M: could also use POLYmode | TAPPmode   private val stickyModes: Int  = EXPRmode | PATTERNmode | TYPEmode | ALTmode  private def funMode(mode: Int) = mode & (stickyModes | SCCmode) | FUNmode | POLYmode  private def argMode(fun: Tree, mode: Int) =    if (treeInfo.isSelfOrSuperConstrCall(fun)) mode | SCCmode else mode   private val DivergentImplicit = new Exception()  abstract class Typer(context0: Context) {    import context0.unit    val infer = new Inferencer(context0) {      override def isCoercible(tp: Type, pt: Type): Boolean = (        tp.isError || pt.isError ||        context0.implicitsEnabled && // this condition prevents chains of views        inferView(NoPosition, tp, pt, false) != EmptyTree      )    }    /**     *  @param pos             ...     *  @param from            ...     *  @param to              ...     *  @param reportAmbiguous ...     *  @return                ...     */    private def inferView(pos: Position, from: Type, to: Type, reportAmbiguous: Boolean): Tree = {      if (settings.debug.value) log("infer view from "+from+" to "+to)//debug      if (phase.id > currentRun.typerPhase.id) EmptyTree      else from match {        case MethodType(_, _) => EmptyTree        case OverloadedType(_, _) => EmptyTree        case PolyType(_, _) => EmptyTree        case _ =>          val result = inferImplicit(pos, MethodType(List(from), to), reportAmbiguous)          if (result != EmptyTree) result          else inferImplicit(            pos,            MethodType(List(appliedType(ByNameParamClass.typeConstructor, List(from))), to),            reportAmbiguous)      }    }    /**     *  @param pos             ...     *  @param from            ...     *  @param name            ...     *  @param tp              ...     *  @param reportAmbiguous ...     *  @return                ...     */    private def inferView(pos: Position, from: Type, name: Name, tp: Type, reportAmbiguous: Boolean): Tree = {      val to = refinedType(List(WildcardType), NoSymbol)      var psym = (if (name.isTypeName) to.typeSymbol.newAbstractType(pos, name)                   else to.typeSymbol.newValue(pos, name))       psym = to.decls enter psym      psym setInfo tp      inferView(pos, from, to, reportAmbiguous)    }    import infer._    private var namerCache: Namer = null    def namer = {      if ((namerCache eq null) || namerCache.context != context)        namerCache = newNamer(context)      namerCache    }    private[typechecker] var context = context0    def context1 = context    /** Report a type error.     *     *  @param pos0   The position where to report the error     *  @param ex     The exception that caused the error     */    def reportTypeError(pos0: Position, ex: TypeError) {      if (settings.debug.value) ex.printStackTrace()      val pos = if (ex.pos == NoPosition) pos0 else ex.pos      ex match {        case CyclicReference(sym, info: TypeCompleter) =>          val msg =             info.tree match {              case ValDef(_, _, tpt, _) if (tpt.tpe eq null) =>                "recursive "+sym+" needs type"              case DefDef(_, _, _, _, tpt, _) if (tpt.tpe eq null) =>                (if (sym.owner.isClass && sym.owner.info.member(sym.name).hasFlag(OVERLOADED)) "overloaded "                 else "recursive ")+sym+" needs result type"              case _ =>                ex.getMessage()            }          if (context.retyping) context.error(pos, msg)           else context.unit.error(pos, msg)          if (sym == ObjectClass)             throw new FatalError("cannot redefine root "+sym)        case _ =>          context.error(pos, ex)      }    }    /** Check that <code>tree</code> is a stable expression.     *     *  @param tree ...     *  @return     ...     */    def checkStable(tree: Tree): Tree =      if (treeInfo.isPureExpr(tree)) tree      else errorTree(tree, "stable identifier required, but " + tree + " found.")    /** Check that `tpt' refers to a non-refinement class type */    def checkClassType(tpt: Tree, existentialOK: Boolean) {      def check(tpe: Type): Unit = tpe.normalize match {        case TypeRef(_, sym, _) if sym.isClass && !sym.isRefinementClass => ;        case ErrorType => ;        case PolyType(_, restpe) => check(restpe)        case ExistentialType(_, restpe) if existentialOK => check(restpe)        case t => error(tpt.pos, "class type required but "+t+" found")      }      check(tpt.tpe)    }    /** Check that type <code>tp</code> is not a subtype of itself.     *     *  @param pos ...     *  @param tp  ...     *  @return    <code>true</code> if <code>tp</code> is not a subtype of itself.     */    def checkNonCyclic(pos: Position, tp: Type): Boolean = {      def checkNotLocked(sym: Symbol): Boolean = {        sym.initialize        if (sym hasFlag LOCKED) {          error(pos, "cyclic aliasing or subtyping involving "+sym); false        } else true      }      tp match {        case TypeRef(pre, sym, args) =>          (checkNotLocked(sym)) && (            !sym.isTypeMember ||            checkNonCyclic(pos, appliedType(pre.memberInfo(sym), args), sym)   // @M! info for a type ref to a type parameter now returns a polytype            // @M was: checkNonCyclic(pos, pre.memberInfo(sym).subst(sym.typeParams, args), sym)          )        case SingleType(pre, sym) =>          checkNotLocked(sym)/*        case TypeBounds(lo, hi) =>          var ok = true          for (t <- lo) ok = ok & checkNonCyclic(pos, t)          ok*/        case st: SubType =>          checkNonCyclic(pos, st.supertype)        case ct: CompoundType =>          var p = ct.parents          while (!p.isEmpty && checkNonCyclic(pos, p.head)) p = p.tail          p.isEmpty        case _ =>          true      }    }    def checkNonCyclic(pos: Position, tp: Type, lockedSym: Symbol): Boolean = {      lockedSym.setFlag(LOCKED)      val result = checkNonCyclic(pos, tp)      lockedSym.resetFlag(LOCKED)      result    }    def checkNonCyclic(sym: Symbol) {      if (!checkNonCyclic(sym.pos, sym.tpe)) sym.setInfo(ErrorType)    }    def checkNonCyclic(defn: Tree, tpt: Tree) {      if (!checkNonCyclic(defn.pos, tpt.tpe, defn.symbol)) {        tpt.tpe = ErrorType        defn.symbol.setInfo(ErrorType)      }    }    def checkParamsConvertible(pos: Position, tpe: Type) {      tpe match {

⌨️ 快捷键说明

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