diff options
9 files changed, 148 insertions, 1186 deletions
diff --git a/src/compiler/scala/tools/nsc/IdeSupport.scala b/src/compiler/scala/tools/nsc/IdeSupport.scala deleted file mode 100644 index ab1580e124..0000000000 --- a/src/compiler/scala/tools/nsc/IdeSupport.scala +++ /dev/null @@ -1,54 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2009 LAMP/EPFL - * @author Martin Odersky - */ -// $Id$ - -package scala.tools.nsc - -import scala.tools.nsc.io._ - -trait IdeSupport extends Global with symtab.IdeSupport { - /** to do no dependency tracking */ - protected def normalCompile[T](f: => T): T = f - override def unpickleIDEHook: (( => Type) => Type) = f => normalCompile(f) - - class IdeRun extends Run { - override def compiles(sym: Symbol): Boolean = false // throw new Error - override def compileLate(file: AbstractFile) = { - reloadSource(file) - normalCompile(super.compileLate(file)) - } - override def stopPhase(name : String) = - name == "superaccessors" || super.stopPhase(name) - } - - // load a source file without us caring about adapt. - def loadSource(file: AbstractFile): Option[CompilationUnit] = { - val run = new IdeRun - reloadSource(file) - val source = getSourceFile(file) - try { - normalCompile(run.compileSources(source :: Nil)) - run.units.find(_.source == source) - } catch { - case e => - logError("error in presentation normal compile ", e) - None - } - } - - object loaders1 extends { - val global: IdeSupport.this.type = IdeSupport.this - } with scala.tools.nsc.symtab.SymbolLoaders { - import global._ - protected override def completeClassfile(root: global.Symbol, loader: ClassfileLoader)(f: => Unit) { - global.normalCompile(f) - } - override def computeDepends(from: PackageLoader): global.PackageScopeDependMap = - IdeSupport.this.computeDepends(from.asInstanceOf[IdeSupport.this.loaders.PackageLoader]) - } - - def computeDepends(from: loaders.PackageLoader): PackageScopeDependMap = null - override lazy val loaders = loaders1 -} diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index b22cc9098d..069516bbf4 100644 --- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala @@ -20,10 +20,13 @@ trait CompilerControl { self: Global => /** Info given for every member found by completion */ - case class Member(val sym: Symbol, val tpe: Type, val accessible: Boolean, val inherited: Boolean, val viaView: Symbol) { - def shadows(other: Member) = - sym.name == other.sym.name && (sym.tpe matches other.sym.tpe) - } + case class Member(val sym: Symbol, val tpe: Type, val accessible: Boolean) + + class TypeMember(sym: Symbol, tpe: Type, accessible: Boolean, val inherited: Boolean, val viaView: Symbol = NoSymbol) + extends Member(sym, tpe, accessible) + + class ScopeMember(sym: Symbol, tpe: Type, accessible: Boolean, val viaImport: Tree = EmptyTree) + extends Member(sym, tpe, accessible) /** The scheduler by which client and compiler communicate * Must be initialized before starting compilerRunner diff --git a/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala b/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala index aea858c68b..e78a4cc19f 100755 --- a/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala +++ b/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala @@ -7,6 +7,7 @@ import util.Position trait ContextTrees { self: Global => type Context = analyzer.Context + val NoContext = analyzer.NoContext type Contexts = ArrayBuffer[ContextTree] /** A context tree contains contexts that are indexed by positions. diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index 4ca2203bb2..d055e5ec41 100755 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -24,6 +24,8 @@ self => import definitions._ + final val debugIDE = false + override def onlyPresentation = true /** A list indicating in which order some units should be typechecked. @@ -120,14 +122,14 @@ self => case Some(action) => try { acting = true - //println("picked up work item: "+action) + if (debugIDE) println("picked up work item: "+action) action() - //println("done with work item: "+action) + if (debugIDE) println("done with work item: "+action) } catch { case ex: CancelActionReq => - //println("cancelled work item: "+action) + if (debugIDE) println("cancelled work item: "+action) } finally { - //println("quitting work item: "+action) + if (debugIDE) println("quitting work item: "+action) acting = false } case None => @@ -209,13 +211,13 @@ self => /** Compile all given units */ private def backgroundCompile() { - //inform("Starting new presentation compiler type checking pass") + if (debugIDE) inform("Starting new presentation compiler type checking pass") reporter.reset firsts = firsts filter (s => unitOfFile contains (s.file)) val prefix = firsts map unitOf val units = prefix ::: (unitOfFile.values.toList diff prefix) filter (!_.isUpToDate) recompile(units) - //inform("Everything is now up to date") + if (debugIDE) inform("Everything is now up to date") } /** Reset unit to just-parsed state */ @@ -244,11 +246,11 @@ self => def recompile(units: List[RichCompilationUnit]) { for (unit <- units) { reset(unit) - //inform("parsing: "+unit) + if (debugIDE) inform("parsing: "+unit) parse(unit) } for (unit <- units) { - //inform("type checking: "+unit) + if (debugIDE) inform("type checking: "+unit) activeLocks = 0 currentTyperRun.typeCheck(unit) unit.status = currentRunId @@ -329,59 +331,85 @@ self => respond(result) { scopeMembers(pos) } } - def scopeMembers(pos: Position): List[Member] = { + /** Return all members visible without prefix in context enclosing `pos`. */ + def scopeMembers(pos: Position): List[ScopeMember] = { + typedTreeAt(pos) // to make sure context is entered val context = doLocateContext(pos) - List() // to be completed + val locals = new LinkedHashMap[Name, ScopeMember] + def addScopeMember(sym: Symbol, pre: Type, viaImport: Tree) = + if (!(locals contains sym.name)) { + locals(sym.name) = new ScopeMember( + sym, + pre.memberType(sym), + context.isAccessible(sym, pre, false), + viaImport) + } + var cx = context + while (cx != NoContext) { + for (sym <- cx.scope) + addScopeMember(sym, NoPrefix, EmptyTree) + cx = cx.enclClass + val pre = cx.prefix + for (sym <- pre.members) + addScopeMember(sym, pre, EmptyTree) + cx = cx.outer + } + for (imp <- context.imports) { + val pre = imp.qual.tpe + for (sym <- imp.allImportedSymbols) { + addScopeMember(sym, pre, imp.qual) + } + } + locals.valuesIterator.toList } def getTypeCompletion(pos: Position, result: Response[List[Member]]) { respond(result) { typeMembers(pos) } } - def typeMembers(pos: Position): List[Member] = { + def typeMembers(pos: Position): List[TypeMember] = { val tree = typedTreeAt(pos) + println("typeMembers at "+tree+" "+tree.tpe) val context = doLocateContext(pos) val superAccess = tree.isInstanceOf[Super] + val scope = newScope + val members = new LinkedHashMap[Symbol, TypeMember] + def addTypeMember(sym: Symbol, pre: Type, inherited: Boolean, viaView: Symbol) { + val symtpe = pre.memberType(sym) + if (scope.lookupAll(sym.name) forall (sym => !(members(sym).tpe matches symtpe))) { + scope enter sym + members(sym) = new TypeMember( + sym, + symtpe, + context.isAccessible(sym, pre, superAccess && (viaView == NoSymbol)), + inherited, + viaView) + } + } + def viewApply(view: SearchResult): Tree = { + assert(view.tree != EmptyTree) + try { + analyzer.newTyper(context.makeImplicit(false)).typed(Apply(view.tree, List(tree)) setPos tree.pos) + } catch { + case ex: TypeError => EmptyTree + } + } val pre = stabilizedType(tree) - def member(sym: Symbol, inherited: Boolean) = new Member( - sym, - pre memberType sym, - context.isAccessible(sym, pre, superAccess), - inherited, - NoSymbol - ) - def implicitMembers(s: SearchResult): List[Member] = { - val vtree = viewApply(s, tree, context) + for (sym <- tree.tpe.decls) + addTypeMember(sym, pre, false, NoSymbol) + for (sym <- tree.tpe.members) + addTypeMember(sym, pre, true, NoSymbol) + val applicableViews: List[SearchResult] = + new ImplicitSearch(tree, functionType(List(tree.tpe), AnyClass.tpe), true, context.makeImplicit(false)) + .allImplicits + for (view <- applicableViews) { + val vtree = viewApply(view) val vpre = stabilizedType(vtree) - vtree.tpe.members map { sym => new Member( - sym, - vpre memberType sym, - context.isAccessible(sym, vpre, false), - false, - s.tree.symbol - )} - } - println("typeMembers at "+tree+" "+tree.tpe) - val decls = tree.tpe.decls.toList map (member(_, false)) - val inherited = tree.tpe.members.toList diff decls map (member(_, true)) - val implicits = applicableViews(tree, context) flatMap implicitMembers - def isVisible(m: Member) = - !(decls exists (_.shadows(m))) && !(inherited exists (_.shadows(m))) - val allMembers = decls ::: inherited ::: (implicits filter isVisible) - allMembers // filter (_.sym.name.startsWith(prefix)) - } - - def applicableViews(tree: Tree, context: Context): List[SearchResult] = - new ImplicitSearch(tree, functionType(List(tree.tpe), AnyClass.tpe), true, context.makeImplicit(false)) - .allImplicits - - def viewApply(view: SearchResult, tree: Tree, context: Context): Tree = { - assert(view.tree != EmptyTree) - try { - analyzer.newTyper(context.makeImplicit(false)).typed(Apply(view.tree, List(tree)) setPos tree.pos) - } catch { - case ex: TypeError => EmptyTree + for (sym <- vtree.tpe.members) { + addTypeMember(sym, vpre, false, view.tree.symbol) + } } + members.valuesIterator.toList } // ---------------- Helper classes --------------------------- diff --git a/src/compiler/scala/tools/nsc/symtab/IdeSupport.scala b/src/compiler/scala/tools/nsc/symtab/IdeSupport.scala deleted file mode 100644 index 3a61095430..0000000000 --- a/src/compiler/scala/tools/nsc/symtab/IdeSupport.scala +++ /dev/null @@ -1,664 +0,0 @@ -package scala.tools.nsc -package symtab -import scala.tools.nsc.util._ -import scala.collection.mutable._ -import scala.tools.nsc.io._ - -trait IdeSupport extends SymbolTable { // added to global, not analyzers. - trait ScopeClient { - def changed : Unit = {} - def addTo(set : => LinkedHashSet[ScopeClient]): Unit = set += this - def notify(name : Name, scope : HookedScope) : Boolean = false - def notify(name : Name, sym : Symbol) : Unit = {} - def verifyAndPrioritize[T](verify : Symbol => Symbol)(pt : Type)(f : => T) : T = f - def makeNoChanges : Boolean = false - } - def check(condition : Boolean, msg : => String) = { - assert(condition) - condition - } - - import CompatibleResult._ - trait TrackedPosition extends Position with ReallyHasClients { - // symbols without scopes! - def asOffset : Option[(Int,AbstractFile)] - private var recycled : List[Symbol] = Nil - def recycle(sym : Symbol) : Symbol = { - recycled.foreach{existing => compatible(existing,sym) match { - case NotCompatible => false - case GoResult(existing) => return existing - }} - recycled = sym :: recycled; sym - } - private var scopes : List[((ScopeKind,AnyRef),PersistentScope)] = Nil - def scopeFor(key : (ScopeKind,AnyRef)) : PersistentScope = - scopes.find{ - case (key0,scope) if key == key0 => true - case _ => false - } match { - case Some((_,scope)) => reuse(scope) - case None => - val scope = new PersistentScope(key,this) - scopes = (key,scope) :: scopes - scope - } - } - // dynamic context - private object NullClient extends ScopeClient { - override def addTo(clients : => LinkedHashSet[ScopeClient]) = {} - } - - def currentClient : ScopeClient = NullClient - abstract class HookedScope(entry : ScopeEntry) extends Scope(entry) { - def record(client : ScopeClient, name : Name) = {} - override def lookupEntry(name : Name) = { - val client = currentClient - if (client.notify(name, this)) null // not found - else { - record(client, name) - super.lookupEntry(name) - } - } - } - private val topDefs = new LinkedHashMap[AbstractFile,LinkedHashSet[ClassSymbol]] { - override def default(what : AbstractFile) = { - val set = new LinkedHashSet[ClassSymbol] - this(what) = set; set - } - } - private val emptySet = new ListBuffer[Symbol] - val reuseMap = new LinkedHashMap[PersistentScope,ListBuffer[Symbol]] { - override def default(key : PersistentScope) = emptySet - } - def reuse(scope : PersistentScope, sym : Symbol) = { - var e = scope.lookupEntry(sym.name) - var delete = List[Symbol]() - while (e != null && e.sym != sym) { - if (false && !e.sym.rawInfo.isComplete) { - - delete = e.sym :: delete - } - e = scope.lookupNextEntry(e) - } - delete.foreach(scope.unlink) - if (e != null && e.sym == sym) { - - val list = reuseMap.get(scope) match { - case Some(list) => list - case None => - val list = new ListBuffer[Symbol] - reuseMap(scope) = list; list - } - check(!sym.isPackage, "" +sym) - import symtab.Flags._ - // if def is abstract, will only unlink its name - if (sym.isGetter) { - val setter = scope lookup nme.getterToSetter(sym.name) - if (setter != NoSymbol && setter.isSetter) { - list += setter - scope unlink setter - //Console.println("RS-UNLINK: " + setter) - } - } else if (sym.hasGetter) { - e = scope lookupEntry nme.getterName(sym.name) - while (e != null && !e.sym.isGetter && (!e.sym.hasFlag(ACCESSOR) || e.sym.accessed != sym)) { - e = scope lookupNextEntry e - } - if (e != null && check(e.sym.accessed == sym, "accessed" + e.sym.accessed +" vs. " + sym) && check(!e.sym.isSetter, "setter: " + e.sym)) { - val getter = e.sym - check(e.sym.accessed == sym && !e.sym.isSetter, e.sym.toString) - list += getter - scope unlink getter - //Console.println("RS-UNLINK: " + getter) - e = scope lookupEntry nme.getterToSetter(getter.name) - while (e != null && !e.sym.isSetter) e = scope lookupNextEntry e - if (e != null) { - check(getter.accessed == sym, "" + getter + " vs. " + sym) - val setter = e.sym - list += setter - scope unlink setter - //Console.println("RS-UNLINK: " + setter) - } - } - } else if (sym.hasFlag(Flags.LAZY)) { - val getter = sym.lazyAccessor - if (getter != NoSymbol) { - list += getter - scope unlink getter - } - } - //Console.println("RS-UNLINK: " + sym) - list += sym - scope unlink sym // clear from scope. - } - } - private def reuse(scope : PersistentScope) : PersistentScope = { - if (currentClient.makeNoChanges) return scope - val buf = new ListBuffer[Symbol] - scope.toList.foreach{sym => - if (false && sym.hasFlag(Flags.CASE) && sym.hasFlag(Flags.SYNTHETIC)) { - check(sym != null, "") - } else { - buf += sym - scope unlink sym - } - } - if (!buf.isEmpty) { - - reuseMap.get(scope) match { - case Some(buf0) => buf.foreach(buf0.+=) - case None => reuseMap(scope) = buf - } - } - scope - } - - def reloadSource(file : AbstractFile) = { - if (!currentClient.makeNoChanges) - topDefs removeKey file match { - case None => ; - case Some(symbols) => - symbols.foreach{ - sym => - def f(sym : Symbol) = sym.owner.info.decls match { - case scope : PersistentScope => reuse(scope, (sym)) - case scope => - check(false, scope + " is not persistent") - } - if (sym.isModuleClass) { - if (check(sym.name.isTypeName,"") && sym.hasRawInfo) - if (sym.linkedModuleOfClass != NoSymbol) f(sym.linkedModuleOfClass) - } else { - if (check(sym.name.isTypeName, "")) - f(sym) - } - } - } - } - - override def attachSource(clazz : ClassSymbol, file : io.AbstractFile) = { - topDefs(file) += clazz - super.attachSource(clazz, file) - } - def finishTyping = { - val clear = reuseMap.toList - reuseMap.clear - clear.foreach{ - case (scope,old) => old.foreach{ - case NoSymbol => - case sym => - // note that we didn't unlink them - val scope0 = scope - Console.println("RECYCLE: " + sym + ":" + sym.id + " in " + sym.owner); // + " " + scope0 + " " + scope0.key); - scope0.invalidate(sym.name) - }} - reuseMap.clear - tracedTypes.toList.foreach{case (sym,oldType) => - if (sym.rawInfo != NoType && !sym.rawInfo.isComplete) { - Console.println("XXX uncompleted: " + sym) - } - val syminfo = try { - sym.info - } catch { - case e => check(false, ""+e); NoType - } - - val resetType = syminfo == NoType || hasError(syminfo) - if (!resetType && !compareTypes(syminfo, oldType,Nil)(sym => tracedTypes.get(sym) match { - case None => syminfo - case Some(oldType) => oldType - })) (trackedTypes.removeKey(sym) match { - case Some(set) => set.foreach(_.changed) - case None => - }) - if (resetType) { - - sym.setInfo(oldType) // restore old good type. - } - } - tracedTypes.clear - } - def oldTypeFor(sym : Symbol) = tracedTypes.get(sym) match { - case Some(tpe) => tpe - case None => NoType - } - - private def compare0(newP : Any, oldP : Any, syms : List[Symbol])(implicit oldType : Symbol => Type) : Boolean = ((newP,oldP) match { - case (newP:AnyRef,oldP:AnyRef) if newP eq oldP => true - case (newP:Type,oldP:Type) => compareTypes(newP,oldP, syms) - case (newS:Symbol,oldS:Symbol) if compareSyms(newS,oldS,syms) => true - case (newL:List[a],oldL:List[b]) => - var va = newL; var vb = oldL - while (!va.isEmpty && !vb.isEmpty) { - if (!compare0(va.head,vb.head,syms)) return false - va = va.tail; vb = vb.tail - } - va.isEmpty && vb.isEmpty - case (newS:Scope,oldS:Scope) => - val set = new LinkedHashSet[Symbol] - set ++= newS.toList - oldS.toList.forall{oldS => if (!set.remove(oldS)) { - var other = newS.lookupEntry(oldS.name) - while (other != null && !compareTypes(other.sym.info,oldType(oldS), syms)) - other = newS.lookupNextEntry(other) - other != null - } else true} - case (newP,oldP) => newP == oldP - }) - private def compareSyms(newS : Symbol, oldS : Symbol, syms : List[Symbol])(implicit oldType : Symbol => Type) = - if (oldS eq newS) { - if (syms.contains(oldS)) true - else { - compareTypes(newS.info, oldType(oldS), newS :: syms) - } - } else { - if (syms.contains(oldS) && syms.contains(newS)) true - else newS.name == oldS.name && newS.owner == oldS.owner && newS.flags == oldS.flags && - compareTypes(newS.info,oldType(oldS), newS :: oldS :: syms) - } - - def hasError(infoA : Type) : Boolean = { - if (infoA == ErrorType) return true - infoA match { - case MethodType(args,ret) => hasError(ret) || infoA.paramTypes.exists(hasError) - case PolyType(params,ret) => hasError(ret) - case TypeBounds(lo,hi) => hasError(lo) || hasError(hi) - case TypeRef(pre,_,args) => hasError(pre) || args.exists(hasError) - case _ => false - } - } - def compareTypes(newInfo : Type, oldInfo : Type, syms : List[Symbol])(implicit oldType : Symbol => Type) : Boolean = (newInfo eq oldInfo) || (newInfo.getClass == oldInfo.getClass && ((newInfo,oldInfo) match { - case (newInfo:ThisType,oldInfo:ThisType) if compare0(newInfo.typeSymbol,oldInfo.typeSymbol,syms) => true - case (newInfo:Product, oldInfo:Product) => - (0 until newInfo.productArity).forall(i => - compare0(newInfo.productElement(i), oldInfo.productElement(i),syms)) - })) - - trait HasClients { - def record(client : ScopeClient, name : Name) : Unit - def record(client : Function1[PersistentScope,Unit]) : Unit - def invalidate(from : PersistentScope, name : Name) : Unit - } - - trait ReallyHasClients extends HasClients { - private var clients : Map = null - private var anyClients : LinkedHashSet[Function1[PersistentScope,Unit]] = null - private class Map extends LinkedHashMap[Int,LinkedHashSet[ScopeClient]] { - override def default(hash : Int) = { - val set = new LinkedHashSet[ScopeClient] - this(hash) = set; set - } - } - def record(client : ScopeClient, name : Name) : Unit = - client.addTo({ - if (clients eq null) clients = new Map - clients(name.start) - }) - def record(client : Function1[PersistentScope,Unit]) = { - if (anyClients == null) anyClients = new LinkedHashSet[Function1[PersistentScope,Unit]] - anyClients += client - } - - override def invalidate(from : PersistentScope, name : Name) : Unit = { - if (clients ne null) clients.removeKey(name.start) match { - case Some(clients) => clients.foreach(_.changed) - case None => - } - if (anyClients != null) { - var c = anyClients - anyClients = null - c.foreach(_.apply(from)) - } - } - } - - - class PersistentScope(val key : AnyRef, val owner : HasClients) extends HookedScope(null) { - override def record(client : ScopeClient, name : Name) = - owner.record(client, name) - override def invalidate(name : Name) : Unit = owner.invalidate(this,name) - override def enter(symbol : Symbol) : Symbol = { - if (currentClient.makeNoChanges) { // might have unpickles. - return if (lookupEntry(symbol.name) == null) - super.enter(symbol) - else symbol - } - def finish(symbol : Symbol) = { - if (symbol.isTypeSkolem) { - - } - if (symbol.owner.isPackageClass && !symbol.isPackageClass && symbol.sourceFile != null) { - - topDefs(symbol.sourceFile) += (symbol match { - case symbol : ClassSymbol => symbol - case symbol : ModuleSymbol => symbol.moduleClass.asInstanceOf[ClassSymbol] - }) - } - super.enter(symbol) - } - def nuke(existing: Symbol) : Unit = { - if (existing.isMonomorphicType) existing.resetFlag(Flags.MONOMORPHIC) - assert(!existing.isPackage) - existing.setAnnotations(Nil) // reset annotations, we don't look at these. - if (existing.isModuleClass) { - //Console.println("NUKE_N: " + existing + " " + existing.id) - } else { - existing.setInfo(if (symbol.hasRawInfo) symbol.rawInfo else NoType) - } - if (existing.isModule && existing.moduleClass != NoSymbol){ - //Console.println("NUKE_0: " + existing + " " + existing.id) - //Console.println("NUKE_1: " + existing.moduleClass + " " + existing.moduleClass.id) - existing.moduleClass.setInfo(if (symbol.moduleClass.hasRawInfo) symbol.moduleClass.rawInfo else NoType) - } - } - - def reuse(existing : Symbol) : Symbol = { - def record(existing : Symbol) = if (existing.hasRawInfo && - existing.rawInfo.isComplete && existing.rawInfo != NoType && !hasError(existing.rawInfo)) { - tracedTypes(existing) = existing.info - } - record(existing) - nuke(existing) - if (existing.pos == NoPosition) { - - } - - finish(existing) - } - val symX = lookup(symbol.name) - if (symX != NoSymbol) { - if (symX == symbol) return (symX) - if (!symbol.hasRawInfo && symX.hasRawInfo && symX.rawInfo.isComplete && - symbol.pos.isInstanceOf[TrackedPosition] && symX.pos.isInstanceOf[TrackedPosition] && - symbol.pos == symX.pos) compatible(symX, symbol) match { - case NotCompatible => // do nothing - case code@GoResult(existing0) => - val existing = existing0 - if (code.isInstanceOf[Updated]) { - invalidate(existing.name) - } - nuke(existing) - return (existing) - } - } - if (symbol == NoSymbol) return symbol - // catch double defs. - record(currentClient, symbol.name) - - // Martin: I changed rest of methods to avoid Iterator.remove - val buf = reuseMap(this) - if (buf contains symbol) { - buf -= symbol - finish(symbol) - } else buf find { existing => - if (existing.hasFlag(symtab.Flags.SYNTHETIC) && existing.name == symbol.name) true - else (symbol.pos,existing.pos) match { - case (apos : TrackedPosition, bpos : TrackedPosition) => apos == bpos - case (apos : OffsetPosition , bpos : OffsetPosition) => apos == bpos - case _ => existing.name == symbol.name - } - } match { - case Some(existing) => - if (check(existing != NoSymbol,"")) { - val oldName = existing.name - compatible(existing, symbol) match { - case NotCompatible => - - case code@GoResult(existing0) => - buf -= existing - if (code.isInstanceOf[Updated]) { - invalidate(oldName) - invalidate(existing0.name) - } - return (reuse(existing0)) - } - } - case None => - } - invalidate(symbol.name) - return finish(symbol) - } - } - private val tops = new LinkedHashMap[OffsetPosition,Symbol] - - protected def compatible(existing : Symbol, symbol : Symbol) : Result = { - import scala.tools.nsc.symtab.Flags._ - if (existing.hasRawInfo && symbol.hasRawInfo) { - - - } - - - if (existing.getClass != symbol.getClass) (existing,symbol) match { - case (existing:TypeSkolem,symbol:TypeSymbol) => - val other = existing.deSkolemize - return if (!other.isSkolem) - compatible(other,symbol) - else NotCompatible - case _ => return NotCompatible - } - if (existing.isGetter != symbol.isGetter) return NotCompatible - if (existing.isSetter != symbol.isSetter) return NotCompatible - if (existing.owner != symbol.owner) return NotCompatible - if (existing.name != symbol.name || existing.name.length != symbol.name.length) { - val ret = (!existing.name.toString.contains('$') && - !symbol.name.toString.contains('$') && - !(existing hasFlag SYNTHETIC) && !(symbol hasFlag SYNTHETIC) && { - existing.name.isTypeName == symbol.name.isTypeName && - nme.isSetterName(existing.name) == nme.isSetterName(symbol.name) && - nme.isLocalName(existing.name) == nme.isLocalName(symbol.name) - }) - if (!ret) return NotCompatible - } - // because module var shares space with monomorphic. - if (existing.isModuleVar != symbol.isModuleVar) return NotCompatible - if ((existing.flags|LOCKED|INTERFACE|MONOMORPHIC|DEFERRED|ABSTRACT|PRIVATE|PROTECTED|FINAL|SEALED|CASE|SYNTHETIC) != - (symbol. flags|LOCKED|INTERFACE|MONOMORPHIC|DEFERRED|ABSTRACT|PRIVATE|PROTECTED|FINAL|SEALED|CASE|SYNTHETIC)) { - return NotCompatible - } - if (((existing.flags&(MONOMORPHIC|INTERFACE)) != 0) || - ((symbol .flags&(MONOMORPHIC|INTERFACE)) != 0)) { - - } - val ret = (existing.owner == symbol.owner || { - existing.owner.name == symbol.owner.name && // why???? - (existing.owner.name == nme.ANON_FUN_NAME||symbol.owner.name == nme.ANON_FUN_NAME) && - existing.owner.pos == symbol.owner.pos - }) - if (!ret) return NotCompatible - existing.setPos(symbol.pos) // not significant for updating purposes. - if ((existing.privateWithin != symbol.privateWithin || - existing.name != symbol.name || ((existing.flags|LOCKED|MONOMORPHIC|INTERFACE) != (symbol.flags|LOCKED|MONOMORPHIC|INTERFACE)))) { - existing.name = (symbol.name) - // don't reset the monomorphic bit until we reset the type. - existing.flags = symbol.flags - existing.privateWithin = symbol.privateWithin - return new Updated(existing) - } - return new Compatible(existing) - } - protected object CompatibleResult { - abstract class Result { - def map(symbol : Symbol) : Result = this - } - case object NotCompatible extends Result - case class GoResult(val symbol : Symbol) extends Result { - } - class Compatible(override val symbol : Symbol) extends GoResult(symbol) { - override def map(symbol : Symbol) = new Compatible(symbol) - } - class Updated(override val symbol : Symbol) extends GoResult(symbol) { - override def map(symbol : Symbol) = new Updated(symbol) - } - } - - private class DefInfo extends ReallyHasClients { - var ref : scala.ref.WeakReference[Symbol] = _ - var scopes : List[(PersistentScope)] = Nil - def scope(kind : ScopeKind) = scopes.find(_.key == kind) match { - case Some(scope) => scope - case None => - val scope = new PersistentScope(kind,this) - check(scope.key == kind, ""+scope.key + " " + scope.toString) - scopes = (scope) :: scopes - scope - } - } - - private val defMap = new WeakHashMap[Symbol,DefInfo] { - override def default(clazz : Symbol) = { - val ref = new scala.ref.WeakReference(clazz) - val info = new DefInfo - this(clazz) = info - info.ref = ref - info - } - } - override def newClassScope(clazz : Symbol) = { - newDefScope0({ - if (clazz.isModuleClass && !clazz.isPackageClass) { - - clazz - } else if (clazz.isModule && !clazz.isPackage) { - - clazz.moduleClass - } else clazz - }, ClassKind) - } - private lazy val ClassKind = allocateScopeKind("class") - private def newDefScope0(sym : Symbol, key : ScopeKind) = reuse(defMap(sym).scope(key)) - - override def recycle(sym : Symbol) = sym.pos match { - case pos : TrackedPosition => pos.recycle(sym) - case _ => super.recycle(sym) - } - override def newLocalDummy(clazz : Symbol, pos : util.Position) = - recycle(super.newLocalDummy(clazz,pos)).asInstanceOf[TermSymbol] - - def newScope(pos : Position, key : (ScopeKind,AnyRef), old : Option[Scope]) : Scope = pos match { - case pos : TrackedPosition => pos.scopeFor(key) - case _ if old.isEmpty => newScope(null : ScopeEntry) - case _ => super.scopeFor(old.get, null,key._1) - } - - private def scopeFor00(tree : Tree, old : Option[Scope], kind : ScopeKind) = (tree,tree.symbol) match { - case (_,null|NoSymbol) => newScope(tree.pos, (kind,tree.getClass), (old)) - case (tree : DefTree, sym) => newDefScope0((sym),kind) // indexed by symbol - case _ => newScope(tree.pos, (kind,tree.getClass), old) - } - - override def scopeFor(old : Scope, tree : Tree, kind : ScopeKind) = scopeFor00(tree, Some(old), kind) - override def scopeFor(tree : Tree, kind : ScopeKind) = scopeFor00(tree, None, kind) - override def newScope(initElements : ScopeEntry) : Scope = { - object owner extends ReallyHasClients - new PersistentScope(null, owner) - } - override def newPackageScope(depends0 : PackageScopeDependMap) : PackageScope = { - object owner extends ReallyHasClients - object myPackageScope extends PersistentScope(null, owner) with PackageScope { - val depends = depends0 - } - myPackageScope - } - - - override def newTempScope : Scope = new TemporaryScope - private class TemporaryScope extends HookedScope(null) { - override def hashCode = toList.map(_.hashCode).foldLeft(0)(_ + _) - override def equals(that : Any) = that match { - case that : TemporaryScope if this eq that => true - case that : TemporaryScope => // do a brute force comparison - val l0 = this.toList - val l1 = that.toList - l0.size == l1.size && l0.forall(l1.contains) - case _ => false - } - } - private class ThrowAwayScope(decls : List[Symbol]) extends HookedScope(null:ScopeEntry) { - decls.foreach(d => enter(d)) - } - override def newThrowAwayScope(decls : List[Symbol]) : Scope= new ThrowAwayScope(decls) - - private val trackedTypes = new LinkedHashMap[Symbol,LinkedHashSet[ScopeClient]] { - override def default(sym : Symbol) = { - val set = new LinkedHashSet[ScopeClient] - this(sym) = set; set - } - } - // trace symbols whose types are watched! - private val tracedTypes = new LinkedHashMap[Symbol,Type] - - override def trackTypeIDE(sym : Symbol): Boolean = if (sym != NoSymbol && !sym.isPackageClass && !sym.isPackage) { - // will wind up watching a lot of stuff! - currentClient.addTo(trackedTypes(sym)) - super.trackTypeIDE(sym) - } else super.trackTypeIDE(sym) - override def mkConstantType(value: Constant): ConstantType = { - super.mkConstantType(Constant(value.value match { - case _ : Int => 0 : Int - case _ : Long => 0 : Long - case _ : Byte => 0 : Byte - case _ : Char => 0 : Char - case _ : Short => 0 : Short - case _ : Float => 0 : Float - case _ : Double => 0 : Double - case _ : String => "string" - case _ : scala.Symbol => Symbol("symbol") - case value => value - })) - } - // mostly intellisense hacks. - override def verifyAndPrioritize[T](verify : Symbol => Symbol)(pt : Type)(f : => T) : T = { - try { - currentClient.verifyAndPrioritize(verify)(pt)(f) - } catch {case e : Error=> - throw e - } - } - override def compare(sym : Symbol, name : Name) = { - val client = currentClient - sym.info.decls match { - case scope : HookedScope => - scope.record(client, name) - case _ => - } - client.notify(name, sym) - super.compare(sym, name) - } - override def notifyImport(what : Name, container : Type, from : Name, to : Name) : Unit = { - super.notifyImport(what, container, from, to) - // sanity checking. - if ((container eq null) || - (what eq null) || - (from eq null) || - (currentClient eq null)) return - val from0 = if (what.isTypeName) from.toTypeName else from.toTermName - val result = container.member(from0) - if (result != NoSymbol) - currentClient.notify(what, result) - } - - object lightDuplicator extends Transformer { - override val treeCopy = new StrictTreeCopier - } - // make the trees less detailed. - override def sanitize(tree : Tree) : Tree = lightDuplicator.transform(tree match { - case Template(_,vdef,_) => Template(Nil, sanitize(vdef).asInstanceOf[ValDef], Nil) - case PackageDef(pid, _) => PackageDef(pid, Nil) - case DefDef(mods, _, _, _, _:TypeTree, _) => DefDef(NoMods, nme.ERROR, Nil, Nil, TypeTree(), Literal(())) - case DefDef(mods, _, _, _, restpt, _) => DefDef(NoMods, nme.ERROR, Nil, Nil, sanitize(restpt), Literal(())) - case ValDef(_, _, _ : TypeTree, _) => ValDef(NoMods, nme.ERROR, TypeTree(), EmptyTree) - case ValDef(_, _, restpt, _) => ValDef(NoMods, nme.ERROR, sanitize(restpt), EmptyTree) - case ModuleDef(_, _, impl) => - ModuleDef(NoMods, nme.ERROR, sanitize(impl).asInstanceOf[Template]) - case ClassDef(_, _, tparams, impl) => - ClassDef(NoMods, nme.ERROR.toTypeName, Nil, sanitize(impl).asInstanceOf[Template]) - case DocDef(_, definition) => sanitize(definition) - case CaseDef(x, y, z) => CaseDef(Literal(()), EmptyTree, Literal(())) - case Block(_, _) => Block(Nil, Literal(())) - case Function(vparams,body) => - Function(vparams.map(sanitize).asInstanceOf[List[ValDef]],Literal(())) - case _ => tree - }).setPos(tree.pos) - -} diff --git a/src/compiler/scala/tools/nsc/symtab/Scopes.scala b/src/compiler/scala/tools/nsc/symtab/Scopes.scala index 6170964a22..8a09d361cb 100644 --- a/src/compiler/scala/tools/nsc/symtab/Scopes.scala +++ b/src/compiler/scala/tools/nsc/symtab/Scopes.scala @@ -7,15 +7,21 @@ package scala.tools.nsc package symtab +// Martin: I am about 1/4 way on a cleanup of scopes. +// The most important change is that scopes are now Iterables. +// This removed the need for the various iterators on ScopeEntries. +// ScopeEntries are conceptually an internal representation detail, +// so it's better not to return them in public iterators. +// It's true that other code also references ScopeEntries but that's +// done for performance (and could be reviewed). +// Another addition is a lookupAll method that returns all symbols with +// a name in a scopein an iterator. +// I still have to remove all the cruft about PackageScope's and the like +// that's a leftover from the old Eclipse plugin days. +// trait Scopes { self: SymbolTable => - def entryIterator(e: ScopeEntry): Iterator[ScopeEntry] = - if (e == null) Iterator.empty else e.entryIterator - - def bucketIterator(e: ScopeEntry): Iterator[ScopeEntry] = - if (e == null) Iterator.empty else e.bucketIterator - class ScopeEntry(val sym: Symbol, val owner: Scope) { /** the next entry in the hash bucket */ @@ -25,19 +31,6 @@ trait Scopes { */ var next: ScopeEntry = null - class ScopeEntryIterator(f: ScopeEntry => ScopeEntry) extends Iterator[ScopeEntry] { - private var buf: ScopeEntry = ScopeEntry.this - def hasNext = buf != null - def next = { - val res = buf - buf = f(buf) - res - } - } - - def bucketIterator: Iterator[ScopeEntry] = new ScopeEntryIterator(_.tail) - def entryIterator: Iterator[ScopeEntry] = new ScopeEntryIterator(_.next) - override def hashCode(): Int = sym.name.start override def toString(): String = sym.toString() } @@ -54,7 +47,11 @@ trait Scopes { e } - object NoScopeEntry extends ScopeEntry(NoSymbol, null) + // Martin: This code contains a lot of stuff for the old Eclipse plugin. + // Now it's just needless complexity, which should be eleminated. + // We should make the elems list doubly-linked, + // and have scopes inherit from LinearSequence, + // that way, we need to do way fewer toList than before. /** * @param initElems ... @@ -128,7 +125,7 @@ trait Scopes { } } - abstract class Scope(initElems: ScopeEntry) { + abstract class Scope(initElems: ScopeEntry) extends Iterable[Symbol] { var elems: ScopeEntry = initElems @@ -139,9 +136,6 @@ trait Scopes { /** the hash table */ private var hashtable: Array[ScopeEntry] = null - private def hashtableIterator(index: Int): Iterator[ScopeEntry] = - if (hashtable == null) Iterator.empty - else bucketIterator(hashtable(index)) /** a cache for all elements, to be used by symbol iterator. */ @@ -186,10 +180,18 @@ trait Scopes { /** is the scope empty? */ - def isEmpty: Boolean = elems eq null + override def isEmpty: Boolean = elems eq null /** the number of entries in this scope */ - def size: Int = entryIterator(elems).length + override def size: Int = { + var s = 0 + var e = elems + while (e ne null) { + s += 1 + e = e.next + } + s + } /** enter a scope entry * @@ -303,6 +305,15 @@ trait Scopes { val e = lookupEntry(name) if (e eq null) NoSymbol else e.sym } + + /** Returns an iterator eidling every symbol with given name in this scope. + */ + def lookupAll(name: Name): Iterator[Symbol] = new Iterator[Symbol] { + var e = lookupEntry(name) + def hasNext: Boolean = e ne null + def next: Symbol = { val r = e.sym; e = lookupNextEntry(e); r } + } + /** Can lookup symbols and trace who the client is. */ def lookupEntryWithContext(name : Name)(from : Symbol) : ScopeEntry = lookupEntry(name) @@ -345,7 +356,7 @@ trait Scopes { /** Return all symbols as a list in the order they were entered in this scope. */ - def toList: List[Symbol] = { + override def toList: List[Symbol] = { if (elemsCache eq null) { elemsCache = Nil var e = elems @@ -361,12 +372,12 @@ trait Scopes { */ def iterator: Iterator[Symbol] = toList.iterator - @deprecated("use `iterator'") def elements = iterator + override def foreach[U](p: Symbol => U): Unit = toList foreach p - def filter(p: Symbol => Boolean): Scope = + override def filter(p: Symbol => Boolean): Scope = if (!(toList forall p)) newScope(toList filter p) else this - def mkString(start: String, sep: String, end: String) = + override def mkString(start: String, sep: String, end: String) = toList.map(_.defString).mkString(start, sep, end) override def toString(): String = mkString("{\n ", ";\n ", "\n}") @@ -389,16 +400,21 @@ trait Scopes { /** The error scope. */ class ErrorScope(owner: Symbol) extends Scope(null: ScopeEntry) { + /* The following method was intended to be here, + * but it was written (in two different iterations!) so that + * it was actually a no-op. That's why I am leaving it comment-out + * for now. override def lookupEntry(name: Name): ScopeEntry = { - def errorScope = + def errorSym = if (name.isTermName) owner newErrorValue name else owner newErrorClass name - super.lookupEntry(name) match { - case NoScopeEntry => enter(errorScope) ; super.lookupEntry(name) - case e => e + super.lookupEntry(name) match { + case null => enter(errorSym); lookupEntry(name) + case e => e } } + */ } } diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 42a8f3848a..8636866c52 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -65,10 +65,8 @@ abstract class ExplicitOuter extends InfoTransform def outerAccessor(clazz: Symbol): Symbol = { val firstTry = clazz.info.decl(clazz expandedName nme.OUTER) if (firstTry != NoSymbol && firstTry.outerSource == clazz) firstTry - else - entryIterator(clazz.info.decls.elems) . - find (_.sym.outerSource == clazz) map (_.sym) getOrElse (NoSymbol) - } + else clazz.info.decls find (_.outerSource == clazz) getOrElse NoSymbol + } /** <p> * The type transformation method: diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 78b2e29048..fcb4833df7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -575,6 +575,18 @@ trait Contexts { self: Analyzer => result } + def allImportedSymbols: List[Symbol] = + qual.tpe.members flatMap (transformImport(tree.selectors, _)) + + private def transformImport(selectors: List[(Name, Name)], sym: Symbol): List[Symbol] = selectors match { + case List() => List() + case List((nme.WILDCARD, _)) => List(sym) + case (from, to) :: _ if (from == sym.name) => + if (to == nme.WILDCARD) List() + else { val sym1 = sym.cloneSymbol; sym1.name = to; List(sym1) } + case _ :: rest => transformImport(rest, sym) + } + override def toString() = tree.toString() override def hashCode = tree.hashCodeStructure + depth diff --git a/src/compiler/scala/tools/nsc/typechecker/IdeSupport.scala b/src/compiler/scala/tools/nsc/typechecker/IdeSupport.scala deleted file mode 100644 index db48683213..0000000000 --- a/src/compiler/scala/tools/nsc/typechecker/IdeSupport.scala +++ /dev/null @@ -1,378 +0,0 @@ -package scala.tools.nsc -package typechecker; -import scala.collection.mutable.{WeakHashMap, LinkedHashSet} -trait IdeSupport extends Analyzer { - val global : Global with symtab.IdeSupport - import global._ - - private class ContextInternMap extends WeakHashMap[Context,ref.WeakReference[Context]] { - var lastContext : Context = _ - override def default(txt : Context) : ref.WeakReference[Context] = { - if (txt eq NoContext) new ref.WeakReference(NoContext) - val txt0 = txt.intern0 - lastContext = 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) - try { - sym.info // force completion. - } catch { - case e => - } - return sym - } - object tpe0 extends LazyType with SimpleTypeProxy { - override def underlying = tpe - override def complete(sym0 : Symbol) : Unit = { - if (sym ne sym0) { - logError("DUPLICATE: " + sym.fullNameString + " "+sym.id + " vs. " + sym0.id, null) - toComplete -= sym0 - } - toComplete -= sym - val pos = sym0.pos match { - case pos : TrackedPosition => pos - } - val oldType = oldTypeFor(sym0) - oldType match { - case PolyType(xxx,_) => - val i = xxx.iterator - var pause = false - while (i.hasNext) { - if (i.next.pos == util.NoPosition) pause = true - } - if (pause) { - 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 && (!sym0.rawInfo.isComplete || sym0.info == NoType || sym0.info == ErrorType)) { - // 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) { - /* !!! Miles, do we need still this? It's broken as it is because we have to return a Symbol not a Context - override def qualifyingClassContext(tree: Tree, qual: Name, packageOK: Boolean): Context = { - if (qual.isEmpty) super.qualifyingClassContext(tree, qual, packageOK) - 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 => - try { - super.typed1(tree, mode, pt) - } catch { - case e : TypeError => throw e - case e : Error => global.check(false, "tree: " + tree + " " + e); throw e - } - } - } - private val toComplete = new 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) { - Console.println("BAD: " + sym + " " + sym.id + " vs. " + tree.symbol.id) - } - import symtab.Flags._ - val set = reuseMap.get(namer.context.scope.asInstanceOf[PersistentScope]) - // 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) - } - } else if (sym.hasFlag(symtab.Flags.LAZY) && sym.lazyAccessor != NoSymbol) { - if (set.get.find(sym0 => sym0 == sym.lazyAccessor).isDefined) { - namer.enterInScope(sym.lazyAccessor) - } - } - } - case _ => - }; if (trees.isEmpty) NoSymbol else trees.last.symbol } - import symtab.Flags._ - if (!typeIsDirty) lastTyped.foreach{ - case tree :DefTree if tree.symbol != null && tree.symbol != NoSymbol && tree.symbol.isClass && tree.symbol.hasFlag(CASE) => - var e = namer.context.scope.lookupEntry(tree.symbol.name.toTermName) - while (e != null && !e.sym.hasFlag(MODULE)) e = namer.context.scope.lookupNextEntry(e) - Console.println("CHECKING: " + e + " " + (if (e != null) caseClassOfModuleClass.contains(e.sym.moduleClass))) - if (e == null) dirtyTyped - // we don't clear caseClassOfModuleClass unless we have to. - else if (!caseClassOfModuleClass.contains(e.sym.moduleClass)) dirtyTyped - case tree : DefTree if tree.symbol != null && tree.symbol != NoSymbol => - case _ => - } - - 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) { - 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 => - namer.enterSym(tree) - } - } catch { - case te : TypeError => typeError(te.getMessage) - }) - if (!makeNoChanges) use.foreach{tree=> - if (tree.symbol != null && - tree.symbol.isClass && - tree.symbol.hasFlag(symtab.Flags.CASE) && - tree.symbol.owner != null && - tree.symbol.owner.rawInfo.isComplete) { - var e = tree.symbol.owner.info.decls.lookupEntry(tree.symbol.name.toTermName) - if (e != null) e.sym.pos match { // retype the object if its in the scope. - case pos : TrackedPosition if pos.owner != null && pos.owner != MemoizedTree.this => - pos.owner.dirtyTyped // hope this works! - case _ => - } - () - } - } - 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) - } - use.last.symbol - } - def doTyper = try { - if (typerTxt ne NoContext) updateTyper(newTyper(typerTxt), mode, pt) - } catch { - case e => logError("doTyper crash", e) - } - def updateTyper(typer : Typer, mode : Int, pt : Type) : Type = { - 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) { - 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) - } - 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 - } - 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 - } - })) { - 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 = this //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 - } -} |