summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonio Cunei <antonio.cunei@epfl.ch>2011-10-27 15:18:50 +0000
committerAntonio Cunei <antonio.cunei@epfl.ch>2011-10-27 15:18:50 +0000
commit91d6df9ac2ef2d493f87095a626d382db831dd43 (patch)
tree30def52985fa110fa1f449f6bc8a1d11830e698d
parentb9ee07a4b5fd2a0dac925dd971fbb372a4d37eeb (diff)
downloadscala-91d6df9ac2ef2d493f87095a626d382db831dd43.tar.gz
scala-91d6df9ac2ef2d493f87095a626d382db831dd43.tar.bz2
scala-91d6df9ac2ef2d493f87095a626d382db831dd43.zip
Backport of r25890
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Global.scala102
1 files changed, 64 insertions, 38 deletions
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index d3d4863c98..bc3490c6e5 100644
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -9,7 +9,7 @@ import java.io.{ PrintWriter, StringWriter, FileReader, FileWriter }
import collection.mutable.{ArrayBuffer, ListBuffer, SynchronizedBuffer, HashMap}
import scala.collection.mutable
-import mutable.{LinkedHashMap, SynchronizedMap,LinkedHashSet, SynchronizedSet}
+import mutable.{LinkedHashMap, SynchronizedMap, HashSet, LinkedHashSet, SynchronizedSet}
import scala.concurrent.SyncVar
import scala.util.control.ControlThrowable
import scala.tools.nsc.io.{ AbstractFile, LogReplay, Logger, NullLogger, Replayer }
@@ -84,10 +84,16 @@ class Global(settings: Settings, reporter: Reporter, projectName: String = "")
}
}
- /** A list containing all those files that need to be removed
+ /** A set containing all those files that need to be removed
* Units are removed by getUnit, typically once a unit is finished compiled.
*/
- protected val toBeRemoved = new ArrayBuffer[AbstractFile] with SynchronizedBuffer[AbstractFile]
+ protected val toBeRemoved: mutable.Set[AbstractFile] =
+ new HashSet[AbstractFile] with SynchronizedSet[AbstractFile]
+
+ /** A set containing all those files that need to be removed after a full background compiler run
+ */
+ protected val toBeRemovedAfterRun: mutable.Set[AbstractFile] =
+ new HashSet[AbstractFile] with SynchronizedSet[AbstractFile]
class ResponseMap extends MultiHashMap[SourceFile, Response[Tree]] {
override def += (binding: (SourceFile, Set[Response[Tree]])) = {
@@ -488,6 +494,9 @@ class Global(settings: Settings, reporter: Reporter, projectName: String = "")
}
}
+ // move units removable after this run to the "to-be-removed" buffer
+ toBeRemoved ++= toBeRemovedAfterRun
+
// clean out stale waiting responses
cleanAllResponses()
@@ -614,6 +623,8 @@ class Global(settings: Settings, reporter: Reporter, projectName: String = "")
private def reloadSource(source: SourceFile) {
val unit = new RichCompilationUnit(source)
unitOfFile(source.file) = unit
+ toBeRemoved -= source.file
+ toBeRemovedAfterRun -= source.file
reset(unit)
//parseAndEnter(unit)
}
@@ -649,14 +660,20 @@ class Global(settings: Settings, reporter: Reporter, projectName: String = "")
demandNewCompilerRun()
}
+ /** Arrange for unit to be removed after run, to give a chance to typecheck the unit fully.
+ * If we do just removeUnit, some problems with default parameters can ensue.
+ * Calls to this method could probably be replaced by removeUnit once default parameters are handled more robustly.
+ */
+ private def afterRunRemoveUnitOf(source: SourceFile) {
+ toBeRemovedAfterRun += source.file
+ }
/** A fully attributed tree located at position `pos` */
private def typedTreeAt(pos: Position): Tree = getUnit(pos.source) match {
case None =>
reloadSources(List(pos.source))
- val result = typedTreeAt(pos)
- removeUnitOf(pos.source)
- result
+ try typedTreeAt(pos)
+ finally afterRunRemoveUnitOf(pos.source)
case Some(unit) =>
informIDE("typedTreeAt " + pos)
parseAndEnter(unit)
@@ -708,43 +725,52 @@ class Global(settings: Settings, reporter: Reporter, projectName: String = "")
/** Implements CompilerControl.askLinkPos */
private[interactive] def getLinkPos(sym: Symbol, source: SourceFile, response: Response[Position]) {
- informIDE("getLinkPos "+sym+" "+source)
- respond(response) {
- val preExisting = unitOfFile isDefinedAt source.file
+
+ /** Find position of symbol `sym` in unit `unit`. Pre: `unit is loaded. */
+ def findLinkPos(unit: RichCompilationUnit): Position = {
val originalTypeParams = sym.owner.typeParams
- reloadSources(List(source))
- parseAndEnter(getUnit(source).get)
- val owner = sym.owner
- if (owner.isClass) {
- val pre = adaptToNewRunMap(ThisType(owner))
- val newsym = pre.decl(sym.name) filter { alt =>
- sym.isType || {
- try {
- val tp1 = pre.memberType(alt) onTypeError NoType
- val tp2 = adaptToNewRunMap(sym.tpe) substSym (originalTypeParams, owner.typeParams)
- matchesType(tp1, tp2, false)
- } catch {
- case ex: Throwable =>
- println("error in hyperlinking: "+ex)
- ex.printStackTrace()
- false
- }
+ parseAndEnter(unit)
+ val pre = adaptToNewRunMap(ThisType(sym.owner))
+ val newsym = pre.decl(sym.name) filter { alt =>
+ sym.isType || {
+ try {
+ val tp1 = pre.memberType(alt) onTypeError NoType
+ val tp2 = adaptToNewRunMap(sym.tpe) substSym (originalTypeParams, sym.owner.typeParams)
+ matchesType(tp1, tp2, false)
+ } catch {
+ case ex: Throwable =>
+ println("error in hyperlinking: " + ex)
+ ex.printStackTrace()
+ false
}
}
- if (!preExisting) removeUnitOf(source)
- if (newsym == NoSymbol) {
- debugLog("link not found "+sym+" "+source+" "+pre)
- NoPosition
- } else if (newsym.isOverloaded) {
- settings.uniqid.value = true
- debugLog("link ambiguous "+sym+" "+source+" "+pre+" "+newsym.alternatives)
- NoPosition
- } else {
- debugLog("link found for "+newsym+": "+newsym.pos)
- newsym.pos
+ }
+ if (newsym == NoSymbol) {
+ debugLog("link not found " + sym + " " + source + " " + pre)
+ NoPosition
+ } else if (newsym.isOverloaded) {
+ settings.uniqid.value = true
+ debugLog("link ambiguous " + sym + " " + source + " " + pre + " " + newsym.alternatives)
+ NoPosition
+ } else {
+ debugLog("link found for " + newsym + ": " + newsym.pos)
+ newsym.pos
+ }
+ }
+
+ informIDE("getLinkPos "+sym+" "+source)
+ respond(response) {
+ if (sym.owner.isClass) {
+ getUnit(source) match {
+ case None =>
+ reloadSources(List(source))
+ try findLinkPos(getUnit(source).get)
+ finally afterRunRemoveUnitOf(source)
+ case Some(unit) =>
+ findLinkPos(unit)
}
} else {
- debugLog("link not in class "+sym+" "+source+" "+owner)
+ debugLog("link not in class "+sym+" "+source+" "+sym.owner)
NoPosition
}
}