diff options
author | Martin Odersky <odersky@gmail.com> | 2009-07-31 16:27:28 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2009-07-31 16:27:28 +0000 |
commit | 1a4566278cdaed86891f7c675c3d52a52379f029 (patch) | |
tree | 0520278c6bd0955ad42bac643c1afb4f1996e294 | |
parent | 24471facbd9ece2a972e47dfe792b0fae3356c50 (diff) | |
download | scala-1a4566278cdaed86891f7c675c3d52a52379f029.tar.gz scala-1a4566278cdaed86891f7c675c3d52a52379f029.tar.bz2 scala-1a4566278cdaed86891f7c675c3d52a52379f029.zip |
hooks for scope completion; background presenta...
hooks for scope completion; background presentation compiler is no more
incremental. Refactorings in IDE support
7 files changed, 109 insertions, 57 deletions
diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index d46b5b4b89..942a6f5c86 100644 --- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala @@ -54,11 +54,17 @@ trait CompilerControl { self: Global => def locateTree(pos: Position): Tree = new Locator(pos) locateIn unitOf(pos).body - /** Locate smallest context that encloses position + /** Locates smallest context that encloses position as an optional value. */ def locateContext(pos: Position): Option[Context] = locateContext(unitOf(pos).contexts, pos) + /** Returns the smallest context that contains given `pos`, throws FatalError if none exists. + */ + def doLocateContext(pos: Position): Context = locateContext(pos) getOrElse { + throw new FatalError("no context found for "+pos) + } + /** Make sure a set of compilation units is loaded and parsed. * Return () to syncvar `result` on completion. */ @@ -76,10 +82,23 @@ trait CompilerControl { self: Global => override def toString = "typeat "+pos.source+" "+pos.show } - def askCompletion(pos: Position, result: Response[List[Member]]) = + /** Set sync var `result' to list of members that are visible + * as members of the tree enclosing `pos`, possibly reachable by an implicit. + * - if `selection` is false, as identifiers in the scope enclosing `pos` + */ + def askTypeCompletion(pos: Position, result: Response[List[Member]]) = + scheduler postWorkItem new WorkItem { + def apply() = self.getTypeCompletion(pos, result) + override def toString = "type completion "+pos.source+" "+pos.show + } + + /** Set sync var `result' to list of members that are visible + * as members of the scope enclosing `pos`. + */ + def askScopeCompletion(pos: Position, result: Response[List[Member]]) = scheduler postWorkItem new WorkItem { - def apply() = self.completion(pos, result) - override def toString = "completion "+pos.source+" "+pos.show + def apply() = self.getScopeCompletion(pos, result) + override def toString = "scope completion "+pos.source+" "+pos.show } /** Ask to do unit first on present and subsequent type checking passes */ diff --git a/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala b/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala index 70557ac5c6..aea858c68b 100755 --- a/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala +++ b/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala @@ -24,7 +24,7 @@ trait ContextTrees { self: Global => override def toString = "ContextTree("+pos+", "+children+")" } - /** Optionally return the smallest context that contains given `pos`, or None if none exists. + /** Optionally returns the smallest context that contains given `pos`, or None if none exists. */ def locateContext(contexts: Contexts, pos: Position): Option[Context] = { if (contexts.isEmpty) None diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index a4ba711d95..4b87a9e030 100755 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -45,15 +45,12 @@ self => /** Is a background compiler run needed? */ private var outOfDate = false + /** Units compiled by a run with id >= minRunId are considered up-to-date */ + private[interactive] var minRunId = 1 + /** Is a reload/background compiler currently running? */ private var acting = false - /** The status value of a unit that has not yet been loaded */ - final val NotLoaded = -1 - - /** The status value of a unit that has not yet been typechecked */ - final val JustParsed = 0 - // ----------- Overriding hooks in nsc.Global ----------------------- /** Called from typechecker, which signal hereby that a node has been completely typechecked. @@ -113,7 +110,11 @@ self => def pollForWork() { scheduler.pollException() match { case Some(ex: CancelActionReq) => if (acting) throw ex - case Some(ex: FreshRunReq) => if (outOfDate) throw ex + case Some(ex: FreshRunReq) => + currentTyperRun = new TyperRun() + minRunId = currentRunId + if (outOfDate) throw ex + else outOfDate = true case Some(ex: Throwable) => throw ex case _ => } @@ -121,14 +122,14 @@ self => case Some(action) => try { acting = true - //println("picked up work item: "+action) + println("picked up work item: "+action) action() - //println("done with work item: "+action) + println("done with work item: "+action) } catch { case ex: CancelActionReq => - //println("cancelled work item: "+action) + println("cancelled work item: "+action) } finally { - //println("quitting work item: "+action) + println("quitting work item: "+action) acting = false } case None => @@ -159,7 +160,7 @@ self => } val completionResponse = new Response[List[Member]] - askCompletion(pos, completionResponse) + askTypeCompletion(pos, completionResponse) val completion = completionResponse.get.left.toOption match { case Some(members) => members mkString "\n" @@ -210,13 +211,13 @@ self => /** Compile all given units */ private def backgroundCompile() { - //inform("Starting new presentation compiler type checking pass") + 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) + val units = prefix ::: (unitOfFile.values.toList diff prefix) filter (!_.isUpToDate) recompile(units) - //inform("Everything is now up to date") + inform("Everything is now up to date") } /** Reset unit to just-parsed state */ @@ -312,42 +313,50 @@ self => import analyzer.{SearchResult, ImplicitSearch} - def completion(pos: Position, result: Response[List[Member]]) { - respond(result) { - val tree = typedTreeAt(pos) - locateContext(pos) match { - case Some(context) => - val superAccess = tree.isInstanceOf[Super] - 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) - 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("completion 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))) - decls ::: inherited ::: (implicits filter isVisible) - case None => - throw new FatalError("no context found for "+pos) - } + def getScopeCompletion(pos: Position, result: Response[List[Member]]) { + respond(result) { scopeMembers(pos) } + } + + def scopeMembers(pos: Position): List[Member] = { + val context = doLocateContext(pos) + List() // to be completed + } + + def getTypeCompletion(pos: Position, result: Response[List[Member]]) { + respond(result) { typeMembers(pos) } + } + + def typeMembers(pos: Position): List[Member] = { + val tree = typedTreeAt(pos) + val context = doLocateContext(pos) + val superAccess = tree.isInstanceOf[Super] + 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) + 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] = @@ -394,6 +403,8 @@ self => /** The typer run */ class TyperRun extends Run { + println("new typer run") + // units is always empty // symSource, symData are ignored override def compiles(sym: Symbol) = false diff --git a/src/compiler/scala/tools/nsc/interactive/REPL.scala b/src/compiler/scala/tools/nsc/interactive/REPL.scala index 993dd617b8..f3b1900ef2 100644 --- a/src/compiler/scala/tools/nsc/interactive/REPL.scala +++ b/src/compiler/scala/tools/nsc/interactive/REPL.scala @@ -92,7 +92,7 @@ object REPL { show(typeatResult) } def doComplete(pos: Position) { - comp.askCompletion(pos, completeResult) + comp.askTypeCompletion(pos, completeResult) show(completeResult) } loop { line => diff --git a/src/compiler/scala/tools/nsc/interactive/RichCompilationUnits.scala b/src/compiler/scala/tools/nsc/interactive/RichCompilationUnits.scala index 8e6ba614e6..5c71ab4f73 100644 --- a/src/compiler/scala/tools/nsc/interactive/RichCompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/interactive/RichCompilationUnits.scala @@ -5,6 +5,12 @@ import scala.tools.nsc.util.{SourceFile, Position, NoPosition} trait RichCompilationUnits { self: Global => + /** The status value of a unit that has not yet been loaded */ + final val NotLoaded = -1 + + /** The status value of a unit that has not yet been typechecked */ + final val JustParsed = 0 + class RichCompilationUnit(source: SourceFile) extends CompilationUnit(source) { /** The runid of the latest compiler run that typechecked this unit, @@ -12,6 +18,15 @@ trait RichCompilationUnits { self: Global => */ var status: Int = NotLoaded + /** Unit has been parsed */ + def isParsed: Boolean = status >= JustParsed + + /** Unit has been typechecked, but maybe not in latest runs */ + def isTypeChecked: Boolean = status > JustParsed + + /** Unit has been typechecked and is up to date */ + def isUpToDate: Boolean = status >= minRunId + /** the current edit point offset */ var editPoint: Int = -1 diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index 364ed5432d..c551fcc240 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -622,6 +622,12 @@ trait Symbols { def ownerChain: List[Symbol] = this :: owner.ownerChain + def ownersIterator: Iterator[Symbol] = new Iterator[Symbol] { + private var current = Symbol.this + def hasNext = current ne NoSymbol + def next = { val r = current; current = current.owner; r } + } + // same as ownerChain contains sym, but more efficient def hasTransOwner(sym: Symbol) = { var o = this @@ -1869,6 +1875,7 @@ trait Symbols { override def owner: Symbol = throw new Error("no-symbol does not have owner") override def sourceFile: AbstractFile = null override def ownerChain: List[Symbol] = List() + override def ownersIterator: Iterator[Symbol] = Iterator.empty override def alternatives: List[Symbol] = List() override def reset(completer: Type) {} override def info: Type = NoType diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index bd969eb13f..78b2e29048 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -392,7 +392,7 @@ trait Contexts { self: Analyzer => def isAccessible(sym: Symbol, pre: Type, superAccess: Boolean): Boolean = { /** Are we inside definition of `sym'? */ - def accessWithin(sym: Symbol): Boolean = this.owner.ownerChain contains sym + def accessWithin(sym: Symbol): Boolean = this.owner.ownersIterator contains sym /* var c = this while (c != NoContext && c.owner != owner) { |