summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala4
-rw-r--r--src/compiler/scala/tools/nsc/interactive/CompilerControl.scala26
-rw-r--r--src/compiler/scala/tools/nsc/interactive/ContextTrees.scala6
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Global.scala110
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala4
5 files changed, 106 insertions, 44 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 1f2aad5ddd..3eb7193530 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -132,6 +132,10 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
*/
def registerContext(c: analyzer.Context) {}
+ /** Register top level class (called on entering the class)
+ */
+ def registerTopLevelSym(sym: Symbol) {}
+
// ------------------ Reporting -------------------------------------
def error(msg: String) = reporter.error(NoPosition, msg)
diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala
index d2706b8878..1772f6f722 100644
--- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala
+++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala
@@ -42,14 +42,17 @@ trait CompilerControl { self: Global =>
protected val scheduler = new WorkScheduler
/** The compilation unit corresponding to a source file
+ * if it does not yet exist creat a new one atomically
*/
- def unitOf(s: SourceFile): RichCompilationUnit = unitOfFile get s.file match {
- case Some(unit) =>
- unit
- case None =>
- val unit = new RichCompilationUnit(s)
- unitOfFile(s.file) = unit
- unit
+ def unitOf(s: SourceFile): RichCompilationUnit = unitOfFile.synchronized {
+ unitOfFile get s.file match {
+ case Some(unit) =>
+ unit
+ case None =>
+ val unit = new RichCompilationUnit(s)
+ unitOfFile(s.file) = unit
+ unit
+ }
}
/** The compilation unit corresponding to a position */
@@ -60,6 +63,15 @@ trait CompilerControl { self: Global =>
*/
def removeUnitOf(s: SourceFile) = unitOfFile remove s.file
+ /* returns the top level classes and objects that were deleted
+ * in the editor since last time recentlyDeleted() was called.
+ */
+ def recentlyDeleted(): List[Symbol] = deletedTopLevelSyms.synchronized {
+ val result = deletedTopLevelSyms
+ deletedTopLevelSyms.clear()
+ result.toList
+ }
+
/** Locate smallest tree that encloses position
*/
def locateTree(pos: Position): Tree =
diff --git a/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala b/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala
index 8fa4b86219..11aafea71a 100644
--- a/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala
+++ b/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala
@@ -27,7 +27,7 @@ trait ContextTrees { self: Global =>
/** Optionally returns the smallest context that contains given `pos`, or None if none exists.
*/
- def locateContext(contexts: Contexts, pos: Position): Option[Context] = {
+ def locateContext(contexts: Contexts, pos: Position): Option[Context] = synchronized {
def locateNearestContextTree(contexts: Contexts, pos: Position, recent: Array[ContextTree]): Option[ContextTree] = {
locateContextTree(contexts, pos) match {
case Some(x) =>
@@ -70,7 +70,7 @@ trait ContextTrees { self: Global =>
* If the `context` has a transparent position, add it multiple times
* at the positions of all its solid descendant trees.
*/
- def addContext(contexts: Contexts, context: Context) {
+ def addContext(contexts: Contexts, context: Context): Unit = {
val cpos = context.tree.pos
if (cpos.isTransparent)
for (t <- context.tree.children flatMap solidDescendants)
@@ -82,7 +82,7 @@ trait ContextTrees { self: Global =>
/** Insert a context with non-transparent position `cpos`
* at correct position into a buffer of context trees.
*/
- def addContext(contexts: Contexts, context: Context, cpos: Position) {
+ def addContext(contexts: Contexts, context: Context, cpos: Position): Unit = synchronized {
try {
if (!cpos.isRange) {}
else if (contexts.isEmpty) contexts += new ContextTree(cpos, context)
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index bf901b321a..1f90d6c061 100644
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -3,7 +3,8 @@ package interactive
import java.io.{ PrintWriter, StringWriter }
-import scala.collection.mutable.{LinkedHashMap, SynchronizedMap}
+import scala.collection.mutable
+import mutable.{LinkedHashMap, SynchronizedMap,LinkedHashSet, SynchronizedSet}
import scala.concurrent.SyncVar
import scala.util.control.ControlThrowable
import scala.tools.nsc.io.AbstractFile
@@ -85,7 +86,13 @@ self =>
while(true)
try {
- pollForWork()
+ try {
+ pollForWork()
+ } catch {
+ case ex : Throwable =>
+ if (context.unit != null) integrateNew()
+ throw ex
+ }
if (typerRun == currentTyperRun)
return
@@ -112,6 +119,18 @@ self =>
case _ =>
}
+ /** The top level classes and objects currently seen in the presentation compiler
+ */
+ private val currentTopLevelSyms = new mutable.LinkedHashSet[Symbol]
+
+ /** The top level classes and objects no longer seen in the presentation compiler
+ */
+ val deletedTopLevelSyms = new mutable.LinkedHashSet[Symbol] with mutable.SynchronizedSet[Symbol]
+
+ /** Called from typechecker every time a top-level class or object is entered.
+ */
+ override def registerTopLevelSym(sym: Symbol) { currentTopLevelSyms += sym }
+
// ----------------- Polling ---------------------------------------
/** Called from runner thread and signalDone:
@@ -276,8 +295,18 @@ self =>
activeLocks = 0
currentTyperRun.typeCheck(unit)
unit.status = currentRunId
- // todo: garbage collect any tyop-level symbols whose types are no longer valid for
- // currentRunId
+ syncTopLevelSyms(unit)
+ }
+ }
+
+ def syncTopLevelSyms(unit: RichCompilationUnit) {
+ val deleted = currentTopLevelSyms filter { sym =>
+ sym.sourceFile == unit.source.file && runId(sym.validTo) < currentRunId
+ }
+ for (d <- deleted) {
+ d.owner.info.decls unlink d
+ deletedTopLevelSyms += d
+ currentTopLevelSyms -= d
}
}
@@ -288,19 +317,30 @@ self =>
// ----------------- Implementations of client commands -----------------------
- def respond[T](result: Response[T])(op: => T): Unit = {
+ def respond[T](result: Response[T])(op: => T): Unit =
+ respondGradually(result)(Stream(op))
+
+ def respondGradually[T](response: Response[T])(op: => Stream[T]): Unit = {
val prevResponse = pendingResponse
try {
- pendingResponse = result
- if (!result.isCancelled) result set op
+ pendingResponse = response
+ if (!response.isCancelled) {
+ var results = op
+ while (!response.isCancelled && results.nonEmpty) {
+ val result = results.head
+ results = results.tail
+ if (results.isEmpty) response set result
+ else response setProvisionally result
+ }
+ }
} catch {
case CancelException =>
;
case ex @ FreshRunReq =>
- scheduler.postWorkItem(() => respond(result)(op))
+ scheduler.postWorkItem(() => respondGradually(response)(op))
throw ex
case ex =>
- result raise ex
+ response raise ex
throw ex
} finally {
pendingResponse = prevResponse
@@ -319,8 +359,8 @@ self =>
}
/** Make sure a set of compilation units is loaded and parsed */
- def reload(sources: List[SourceFile], result: Response[Unit]) {
- respond(result)(reloadSources(sources))
+ def reload(sources: List[SourceFile], response: Response[Unit]) {
+ respond(response)(reloadSources(sources))
if (outOfDate) throw FreshRunReq // cancel background compile
else outOfDate = true // proceed normally and enable new background compile
}
@@ -344,14 +384,14 @@ self =>
currentTyperRun.typedTree(unitOf(source))
}
- /** Set sync var `result` to a fully attributed tree located at position `pos` */
- def getTypedTreeAt(pos: Position, result: Response[Tree]) {
- respond(result)(typedTreeAt(pos))
+ /** Set sync var `response` to a fully attributed tree located at position `pos` */
+ def getTypedTreeAt(pos: Position, response: Response[Tree]) {
+ respond(response)(typedTreeAt(pos))
}
- /** Set sync var `result` to a fully attributed tree corresponding to the entire compilation unit */
- def getTypedTree(source : SourceFile, forceReload: Boolean, result: Response[Tree]) {
- respond(result)(typedTree(source, forceReload))
+ /** Set sync var `response` to a fully attributed tree corresponding to the entire compilation unit */
+ def getTypedTree(source : SourceFile, forceReload: Boolean, response: Response[Tree]) {
+ respond(response)(typedTree(source, forceReload))
}
def stabilizedType(tree: Tree): Type = tree match {
@@ -372,8 +412,8 @@ self =>
import analyzer.{SearchResult, ImplicitSearch}
- def getScopeCompletion(pos: Position, result: Response[List[Member]]) {
- respond(result) { scopeMembers(pos) }
+ def getScopeCompletion(pos: Position, response: Response[List[Member]]) {
+ respond(response) { scopeMembers(pos) }
}
val Dollar = newTermName("$")
@@ -415,12 +455,12 @@ self =>
result
}
- def getTypeCompletion(pos: Position, result: Response[List[Member]]) {
- respond(result) { typeMembers(pos) }
+ def getTypeCompletion(pos: Position, response: Response[List[Member]]) {
+ respondGradually(response) { typeMembers(pos) }
if (debugIDE) scopeMembers(pos)
}
- def typeMembers(pos: Position): List[TypeMember] = {
+ def typeMembers(pos: Position): Stream[List[TypeMember]] = {
var tree = typedTreeAt(pos)
// Let's say you have something like val x: List[Int] and ypu want to get completion after List
@@ -478,19 +518,23 @@ self =>
for (sym <- ownerTpe.decls)
addTypeMember(sym, pre, false, NoSymbol)
- for (sym <- ownerTpe.members)
- addTypeMember(sym, pre, true, NoSymbol)
- val applicableViews: List[SearchResult] =
- new ImplicitSearch(tree, functionType(List(ownerTpe), AnyClass.tpe), isView = true, context.makeImplicit(reportAmbiguousErrors = false))
- .allImplicits
- for (view <- applicableViews) {
- val vtree = viewApply(view)
- val vpre = stabilizedType(vtree)
- for (sym <- vtree.tpe.members) {
- addTypeMember(sym, vpre, false, view.tree.symbol)
+ members.values.toList #:: {
+ for (sym <- ownerTpe.members)
+ addTypeMember(sym, pre, true, NoSymbol)
+ members.values.toList #:: {
+ val applicableViews: List[SearchResult] =
+ new ImplicitSearch(tree, functionType(List(ownerTpe), AnyClass.tpe), isView = true, context.makeImplicit(reportAmbiguousErrors = false))
+ .allImplicits
+ for (view <- applicableViews) {
+ val vtree = viewApply(view)
+ val vpre = stabilizedType(vtree)
+ for (sym <- vtree.tpe.members) {
+ addTypeMember(sym, vpre, false, view.tree.symbol)
+ }
+ }
+ Stream(members.values.toList)
}
}
- members.values.toList
}
// ---------------- Helper classes ---------------------------
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 235f067c95..b5d3a939e1 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -216,6 +216,7 @@ trait Namers { self: Analyzer =>
assert(currentRun.canRedefine(clazz) || clazz.sourceFile == currentRun.symSource(c));
currentRun.symSource(c) = clazz.sourceFile
}
+ registerTopLevelSym(clazz)
}
assert(c.name.toString.indexOf('(') == -1)
c
@@ -244,9 +245,10 @@ trait Namers { self: Analyzer =>
m.moduleClass.setFlag(moduleClassFlags(moduleFlags))
setPrivateWithin(tree, m.moduleClass, tree.mods)
}
- if (m.owner.isPackageClass) {
+ if (m.owner.isPackageClass && !m.isPackage) {
m.moduleClass.sourceFile = context.unit.source.file
currentRun.symSource(m) = m.moduleClass.sourceFile
+ registerTopLevelSym(m)
}
m
}