idesupport.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 351 行

SCALA
351
字号
package scala.tools.nsc.typechecker;import scala.collection.jcl.WeakHashMaptrait IdeSupport extends Analyzer {  val global : Global with symtab.IdeSupport  import global._   private class ContextInternMap extends WeakHashMap[Context,ref.WeakReference[Context]] {    var last : Context = _    override def default(txt : Context) : ref.WeakReference[Context] = {      if (txt eq NoContext) new ref.WeakReference(NoContext)      val txt0 = txt.intern0      last = txt0 // to prevent collection      val ret = new ref.WeakReference(txt0)      this(txt0) = ret      ret    }    def intern(txt : Context) = this(txt).get.get  }  private val internMap = new ContextInternMap  override def intern(txt : Context) =     if (false) super.intern(txt)    else if (txt.outer eq txt) txt    else internMap.intern(txt)     override def newNamer(context : Context) : Namer = new Namer(context)  class Namer(context: Context) extends super.Namer(context) {    override protected def setInfo[Sym <: Symbol](sym : Sym)(tpe : LazyType) : Sym = {      assert(!sym.hasRawInfo || sym.rawInfo == NoType) // type information has already been reset.      if (currentClient.makeNoChanges) {        sym.setInfo(tpe)        sym.info  // force completion.        return sym      }      object tpe0 extends LazyType with SimpleTypeProxy {        override def underlying = tpe        override def complete(sym0 : Symbol) : Unit = {          if (sym ne sym0) {            logError(sym + " "+sym.id + " vs. " + sym0.id + " we have a problem!", null)          }          toComplete -= sym          val pos = sym0.pos match {          case pos : TrackedPosition => pos          }          val oldType = oldTypeFor(sym0)          oldType match {            case PolyType(xxx,_) =>               val i = xxx.elements              var pause = false              while (i.hasNext) {                if (i.next.pos == util.NoPosition) pause = true              }              if (pause) {                assert(true)                assert(true)              }            case _=>          }          assert(sym0.rawInfo == this)          val hadTypeErrors = pos.owner != null && pos.owner.hasTypeErrors          if (pos.owner == null) underlying.complete(sym0) else pos.owner.activate(try {            underlying.complete(sym0)          } catch {          case te : TypeError =>             pos.owner.typeError(te.getMessage)            sym0.setInfo(ErrorType)          })          (oldType,sym0.info) match {            case (PolyType(xxx,_),PolyType(yyy,_)) if xxx != yyy =>              val oldc = xxx              val newc = yyy              Console.print("DIFF old=" + oldc.map(sym => sym0 + ":" + sym0.pos).mkString("",",",""))              Console.println(" new=" + newc.map(sym => sym0+ ":" + sym0.pos).mkString("",",",""))            case _ =>          }                    //if (!hadTypeErrors && pos.owner != null && pos.owner.hasTypeErrors) pos.owner.dirtyTyped          if (pos.owner != null && pos.owner.hasTypeErrors) {            // go back to original type.            val oldType = oldTypeFor(sym0)            if (oldType != NoType)              sym0.setInfo(oldType)          }        }      }      toComplete += sym      super.setInfo(sym)(tpe0)    }    override def enterSym(tree : Tree) : Context = tree match {    case tree : StubTree =>      if (tree.symbol == NoSymbol) // reset stub symbol on refresh.        tree.symbol = tree.underlying.updateNamer(this)      context    case tree => super.enterSym(tree)    }  }  override def newTyper(txt : Context) : Typer = new Typer(txt)  class Typer(context : Context) extends super.Typer(context) {    override def qualifyingClassContext(tree: Tree, qual: Name): Context = {      if (qual.isEmpty) super.qualifyingClassContext(tree, qual)      else {        var c = context.enclClass        val client = currentClient        while (c != NoContext && {          // register dependency.           client.notify(qual, c.owner)          c.owner.owner.info.decls match {          case scope : HookedScope => scope.record(client, qual)          case _ =>          }          true        } && c.owner.name != qual) c = c.outer.enclClass        c      }    }    // no adapting.    override protected def adapt(tree: Tree, mode: Int, pt: Type): Tree = super.adapt(tree,mode,pt)    override def typed1(tree: Tree, mode: Int, pt: Type): Tree = tree match {    case tree : StubTree =>       if (tree.tpe == null)         tree.tpe = tree.underlying.updateTyper(this, mode, pt)      tree    case tree => super.typed1(tree, mode, pt)    }   }  private val toComplete = new scala.collection.jcl.LinkedHashSet[Symbol]  def finishTyping = while (!toComplete.isEmpty) {    toComplete.toList.foreach(sym => if (sym.pos match {    case pos : TrackedPosition if !pos.isValid => toComplete.remove(sym); false    case _ => true    }){      if (sym.info.isComplete) toComplete.remove(sym)      else {        sym.info        if (!sym.info.isComplete) {          Console.println("not-completing: " + sym)          toComplete remove sym        }      }    })  }  trait TrackedPosition extends global.TrackedPosition {    def owner : MemoizedTree    def isValid : Boolean  }  trait MemoizedTree {    def kind : TreeKind    def pos : TrackedPosition    def typeIsDirty : Boolean    def dirtyTyped : Unit    def useTrees : List[Tree]    def setUseTrees(uses : List[Tree]) : Unit    def lastTyped : List[Tree]    def activate(f : => Unit) : Unit    def typeError(msg : String) : Unit    def hasTypeErrors : Boolean    def shouldBeTyped : Boolean = true    // probably invalidate parent if its not being validated now    // most type changes detected via setType.    protected def typeChanged : Unit    protected def highlightChanged : Unit    def lastSymbol = if (lastTyped.isEmpty) NoSymbol else lastTyped.last.symbol    def lastType = if (lastTyped.isEmpty) null else lastTyped.last.tpe    protected var namerTxt : Context = NoContext    protected var typerTxt : Context = NoContext    protected var mode : Int = 0    protected var pt : Type = NoType    def doNamer = if (namerTxt ne NoContext) updateNamer(newNamer(namerTxt))    def updateNamer(namer : Namer) : Symbol = {      val makeNoChanges = currentClient.makeNoChanges      val namerTxt = intern(namer.context)      if (!makeNoChanges && (this.namerTxt ne namerTxt)) {        assert(namerTxt.scope ne EmptyScope)        assert(namerTxt.owner ne NoSymbol)        this.namerTxt = namerTxt        dirtyTyped      }      val lastSymbol = this.lastSymbol      def fakeUpdate(trees : List[Tree]) : Symbol = { trees.foreach{      case tree : DefTree if (tree.symbol != NoSymbol && tree.symbol != null) =>        // becareful, the symbol could have been rentered!        var e = namer.context.scope.lookupEntry(tree.symbol.name)        while (e != null && e.sym != tree.symbol) e = namer.context.scope.lookupNextEntry(e)        if (e == null) {          //Console.println("FK-ENTER: " + tree.symbol)          val sym = namer.enterInScope(tree.symbol)          if (sym != tree.symbol) {            assert(true)            assert(true)            Console.println("SCREWED: " + sym + " " + sym.id + " vs. " + tree.symbol.id)          }          import symtab.Flags._          val set = reuseMap.get(namer.context.scope.asInstanceOf[PersistentScope])          if (set.isDefined && sym.isClass && sym.hasFlag(CASE)) {            val name = sym.name.toTermName            val factory = set.get.find(_.name == name).get            val sym0 = namer.enterInScope(factory)            assert(sym0 == factory)          }          // could be getter or local, then we need to re-add getter/setter          if (sym.isGetter && set.isDefined)             set.get.find(sym0 => sym0.name == nme.getterToSetter(sym.name) && sym0.isSetter) match {          case None =>           case Some(setter) =>            val setter0 = namer.enterInScope(setter)            assert(setter0 == setter)          } else if (sym.hasGetter && set.isDefined)             set.get.find(sym0 => {              sym0.name == nme.getterName(sym.name) &&                 sym0.isGetter            }) match {          case None =>          case Some(getter) =>            val getter0 = namer.enterInScope(getter)            assert(getter0 == getter)            if (set.isDefined)               set.get.find(sym => sym.name == nme.getterToSetter(getter.name) && sym.isSetter) match {            case None =>             case Some(setter) =>              val setter0 = namer.enterInScope(setter)              assert(setter0 == setter)            }          }        }       case _ =>      }; if (trees.isEmpty) NoSymbol else trees.last.symbol }            if (makeNoChanges) {}      else if (!typeIsDirty && !lastTyped.isEmpty)         return fakeUpdate(lastTyped)      else if (namerTxt != NoContext && shouldBeTyped) {} else return fakeUpdate(lastTyped)      val use = useTrees      if (makeNoChanges) {}      else if (use.isEmpty || use.last.symbol != NoSymbol) {        assert(true)        return fakeUpdate(use) // already named      }            if (kind.isTop) namer.context.unit.source.file match {      case file : io.PlainFile => reloadSource(file)      case _ =>      }      // before we retype, unlink/recycle our previously defined symbols.      if (!makeNoChanges) lastTyped.foreach{tree =>         if (tree.symbol != NoSymbol && tree.symbol != null) (namer.context.scope,tree) match {        case (scope : PersistentScope,tree : DefTree) => if (!tree.symbol.isPackage) reuse(scope, tree.symbol)         case _ =>         }      }      activate(try {        use.foreach{tree =>           if (tree.isInstanceOf[DefTree]) {            assert(true)            //Console.println("RENAME: " + tree)          }          namer.enterSym(tree)        }      } catch {        case te : TypeError => typeError(te.getMessage)      })      if (makeNoChanges) {}      else if (hasTypeErrors && lastSymbol != null && lastSymbol != NoSymbol && use.last.symbol != lastSymbol) {        if (use.last.symbol != null && use.last.symbol != NoSymbol) {          namer.context.scope unlink use.last.symbol        }        Console.println("ER-LINK: " + lastSymbol)        val sym = namer.enterInScope(lastSymbol)        assert(sym == lastSymbol)        use.last.symbol = lastSymbol      }      if (lastSymbol != NoSymbol && lastSymbol != use.last.symbol) {        assert(true)        assert(true)      }      use.last.symbol    }    def doTyper = if (typerTxt ne NoContext) updateTyper(newTyper(typerTxt), mode, pt)    def updateTyper(typer : Typer, mode : Int, pt : Type) : Type = {      assert(true)      val typerTxt = intern(typer.context)      val makeNoChanges = currentClient.makeNoChanges      if (!makeNoChanges && ((this.typerTxt ne typerTxt) || (this.pt != pt) || (this.mode != mode))) {        this.typerTxt = typerTxt        this.pt = pt        this.mode = mode        dirtyTyped      }      val lastType = this.lastType      if (makeNoChanges) {}      else if (typeIsDirty && shouldBeTyped && typerTxt != NoContext) {              } else if (lastType == null) {        assert(true)        assert(true)        return NoType      } else return lastType      var use = useTrees      if (use.isEmpty) return lastType;       if ((use.last.tpe != null)) return use.last.tpe      if (use.last.symbol == NoSymbol && namerTxt != NoContext)        updateNamer(newNamer(namerTxt))      if (makeNoChanges) {        assert(true)          assert(true)      }      activate(try {        setUseTrees{use = use.map{typer.typed(_,mode,pt)}; use}      } catch {        case te : TypeError => typeError(te.getMessage)      })      if (!makeNoChanges && hasTypeErrors && lastType != null) {        use.last.tpe = lastType      }      if (!makeNoChanges && !hasTypeErrors && use.last.tpe != null && lastType != null &&           !compareTypes(use.last.tpe, lastType,Nil)(_.info)) {         // the type changed in a good way.        typeChanged      }      assert(true)      if (!makeNoChanges && (use.length != lastTyped.length || !use.zip(lastTyped).forall{        case (t0,t1) => t0.equalsStructure0(t1){        case (t0:StubTree,t1:StubTree) if t0.underlying == t0.underlying || true => true        case _ => false        }      })) {        assert(true)        highlightChanged      }      if (use.last.tpe == null) ErrorType else use.last.tpe    }  }  trait StubTree extends global.StubTree {    def underlying : MemoizedTree    override var symbol : Symbol = NoSymbol    override def duplicate : this.type = throw new Error("not supported")     override def isType = underlying.kind.isType    override def isTerm = underlying.kind.isTerm    override def isDef = underlying.kind.isDef    override def hasSymbol = underlying.kind.hasSymbol    override def hashCode = underlying.hashCode    override def equals(that : Any) = that match {    case that : StubTree => that.underlying == underlying    case _ => false    }    override def toString = "st-" + underlying.toString    override def pos = util.NoPosition  }}

⌨️ 快捷键说明

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