Skip to content

Commit 91d6df9

Browse files
author
Antonio Cunei
committed
Backport of r25890
1 parent b9ee07a commit 91d6df9

File tree

1 file changed

+64
-38
lines changed

1 file changed

+64
-38
lines changed

src/compiler/scala/tools/nsc/interactive/Global.scala

Lines changed: 64 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import java.io.{ PrintWriter, StringWriter, FileReader, FileWriter }
99
import collection.mutable.{ArrayBuffer, ListBuffer, SynchronizedBuffer, HashMap}
1010

1111
import scala.collection.mutable
12-
import mutable.{LinkedHashMap, SynchronizedMap,LinkedHashSet, SynchronizedSet}
12+
import mutable.{LinkedHashMap, SynchronizedMap, HashSet, LinkedHashSet, SynchronizedSet}
1313
import scala.concurrent.SyncVar
1414
import scala.util.control.ControlThrowable
1515
import scala.tools.nsc.io.{ AbstractFile, LogReplay, Logger, NullLogger, Replayer }
@@ -84,10 +84,16 @@ class Global(settings: Settings, reporter: Reporter, projectName: String = "")
8484
}
8585
}
8686

87-
/** A list containing all those files that need to be removed
87+
/** A set containing all those files that need to be removed
8888
* Units are removed by getUnit, typically once a unit is finished compiled.
8989
*/
90-
protected val toBeRemoved = new ArrayBuffer[AbstractFile] with SynchronizedBuffer[AbstractFile]
90+
protected val toBeRemoved: mutable.Set[AbstractFile] =
91+
new HashSet[AbstractFile] with SynchronizedSet[AbstractFile]
92+
93+
/** A set containing all those files that need to be removed after a full background compiler run
94+
*/
95+
protected val toBeRemovedAfterRun: mutable.Set[AbstractFile] =
96+
new HashSet[AbstractFile] with SynchronizedSet[AbstractFile]
9197

9298
class ResponseMap extends MultiHashMap[SourceFile, Response[Tree]] {
9399
override def += (binding: (SourceFile, Set[Response[Tree]])) = {
@@ -488,6 +494,9 @@ class Global(settings: Settings, reporter: Reporter, projectName: String = "")
488494
}
489495
}
490496

497+
// move units removable after this run to the "to-be-removed" buffer
498+
toBeRemoved ++= toBeRemovedAfterRun
499+
491500
// clean out stale waiting responses
492501
cleanAllResponses()
493502

@@ -614,6 +623,8 @@ class Global(settings: Settings, reporter: Reporter, projectName: String = "")
614623
private def reloadSource(source: SourceFile) {
615624
val unit = new RichCompilationUnit(source)
616625
unitOfFile(source.file) = unit
626+
toBeRemoved -= source.file
627+
toBeRemovedAfterRun -= source.file
617628
reset(unit)
618629
//parseAndEnter(unit)
619630
}
@@ -649,14 +660,20 @@ class Global(settings: Settings, reporter: Reporter, projectName: String = "")
649660
demandNewCompilerRun()
650661
}
651662

663+
/** Arrange for unit to be removed after run, to give a chance to typecheck the unit fully.
664+
* If we do just removeUnit, some problems with default parameters can ensue.
665+
* Calls to this method could probably be replaced by removeUnit once default parameters are handled more robustly.
666+
*/
667+
private def afterRunRemoveUnitOf(source: SourceFile) {
668+
toBeRemovedAfterRun += source.file
669+
}
652670

653671
/** A fully attributed tree located at position `pos` */
654672
private def typedTreeAt(pos: Position): Tree = getUnit(pos.source) match {
655673
case None =>
656674
reloadSources(List(pos.source))
657-
val result = typedTreeAt(pos)
658-
removeUnitOf(pos.source)
659-
result
675+
try typedTreeAt(pos)
676+
finally afterRunRemoveUnitOf(pos.source)
660677
case Some(unit) =>
661678
informIDE("typedTreeAt " + pos)
662679
parseAndEnter(unit)
@@ -708,43 +725,52 @@ class Global(settings: Settings, reporter: Reporter, projectName: String = "")
708725

709726
/** Implements CompilerControl.askLinkPos */
710727
private[interactive] def getLinkPos(sym: Symbol, source: SourceFile, response: Response[Position]) {
711-
informIDE("getLinkPos "+sym+" "+source)
712-
respond(response) {
713-
val preExisting = unitOfFile isDefinedAt source.file
728+
729+
/** Find position of symbol `sym` in unit `unit`. Pre: `unit is loaded. */
730+
def findLinkPos(unit: RichCompilationUnit): Position = {
714731
val originalTypeParams = sym.owner.typeParams
715-
reloadSources(List(source))
716-
parseAndEnter(getUnit(source).get)
717-
val owner = sym.owner
718-
if (owner.isClass) {
719-
val pre = adaptToNewRunMap(ThisType(owner))
720-
val newsym = pre.decl(sym.name) filter { alt =>
721-
sym.isType || {
722-
try {
723-
val tp1 = pre.memberType(alt) onTypeError NoType
724-
val tp2 = adaptToNewRunMap(sym.tpe) substSym (originalTypeParams, owner.typeParams)
725-
matchesType(tp1, tp2, false)
726-
} catch {
727-
case ex: Throwable =>
728-
println("error in hyperlinking: "+ex)
729-
ex.printStackTrace()
730-
false
731-
}
732+
parseAndEnter(unit)
733+
val pre = adaptToNewRunMap(ThisType(sym.owner))
734+
val newsym = pre.decl(sym.name) filter { alt =>
735+
sym.isType || {
736+
try {
737+
val tp1 = pre.memberType(alt) onTypeError NoType
738+
val tp2 = adaptToNewRunMap(sym.tpe) substSym (originalTypeParams, sym.owner.typeParams)
739+
matchesType(tp1, tp2, false)
740+
} catch {
741+
case ex: Throwable =>
742+
println("error in hyperlinking: " + ex)
743+
ex.printStackTrace()
744+
false
732745
}
733746
}
734-
if (!preExisting) removeUnitOf(source)
735-
if (newsym == NoSymbol) {
736-
debugLog("link not found "+sym+" "+source+" "+pre)
737-
NoPosition
738-
} else if (newsym.isOverloaded) {
739-
settings.uniqid.value = true
740-
debugLog("link ambiguous "+sym+" "+source+" "+pre+" "+newsym.alternatives)
741-
NoPosition
742-
} else {
743-
debugLog("link found for "+newsym+": "+newsym.pos)
744-
newsym.pos
747+
}
748+
if (newsym == NoSymbol) {
749+
debugLog("link not found " + sym + " " + source + " " + pre)
750+
NoPosition
751+
} else if (newsym.isOverloaded) {
752+
settings.uniqid.value = true
753+
debugLog("link ambiguous " + sym + " " + source + " " + pre + " " + newsym.alternatives)
754+
NoPosition
755+
} else {
756+
debugLog("link found for " + newsym + ": " + newsym.pos)
757+
newsym.pos
758+
}
759+
}
760+
761+
informIDE("getLinkPos "+sym+" "+source)
762+
respond(response) {
763+
if (sym.owner.isClass) {
764+
getUnit(source) match {
765+
case None =>
766+
reloadSources(List(source))
767+
try findLinkPos(getUnit(source).get)
768+
finally afterRunRemoveUnitOf(source)
769+
case Some(unit) =>
770+
findLinkPos(unit)
745771
}
746772
} else {
747-
debugLog("link not in class "+sym+" "+source+" "+owner)
773+
debugLog("link not in class "+sym+" "+source+" "+sym.owner)
748774
NoPosition
749775
}
750776
}

0 commit comments

Comments
 (0)