summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-03-19 19:55:42 +0000
committerPaul Phillips <paulp@improving.org>2011-03-19 19:55:42 +0000
commitaa0cc8e415cca88285b36e76842b759c59f66be7 (patch)
tree7aeda2d3872bcada8d9b33469200eba511db35df /src/compiler/scala/tools/nsc/typechecker/Implicits.scala
parent4b0531b55a8d4971b7e297413e514072a99385e7 (diff)
downloadscala-aa0cc8e415cca88285b36e76842b759c59f66be7.tar.gz
scala-aa0cc8e415cca88285b36e76842b759c59f66be7.tar.bz2
scala-aa0cc8e415cca88285b36e76842b759c59f66be7.zip
Prevent a divergent implicit from terminating i...
Prevent a divergent implicit from terminating implicit search, so that there can still be a winner, as endorsed by martin over a cheese plate. Closes #3883, review by dmharrah.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Implicits.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala39
1 files changed, 31 insertions, 8 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 655e5dfe09..3fc8344d8d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -591,7 +591,7 @@ trait Implicits {
* If it is null, no shadowing.
*/
class ImplicitComputation(iss: Infoss, shadowed: util.HashSet[Name]) {
- private var _best: SearchResult = SearchFailure
+ private var best: SearchResult = SearchFailure
/** True if a given ImplicitInfo (already known isValid) is eligible.
*/
@@ -612,6 +612,18 @@ trait Implicits {
*/
private def checkValid(sym: Symbol) = isValid(sym) || { invalidImplicits += sym ; false }
+ /** Preventing a divergent implicit from terminating implicit search,
+ * so that if there is a best candidate it can still be selected.
+ */
+ private var divergence = false
+ private val MaxDiverges = 1 // not sure if this should be > 1
+ private val divergenceHandler = util.Exceptional.expiringHandler(MaxDiverges) {
+ case x: DivergentImplicit =>
+ divergence = true
+ log("discarding divergent implicit during implicit search")
+ SearchFailure
+ }
+
/** Sorted list of eligible implicits.
*/
val eligible = {
@@ -635,10 +647,14 @@ trait Implicits {
@tailrec private def rankImplicits(pending: Infos, acc: Infos): Infos = pending match {
case Nil => acc
case i :: is =>
- typedImplicit(i, true) match {
+ def tryImplicitInfo(i: ImplicitInfo) =
+ try typedImplicit(i, true)
+ catch divergenceHandler
+
+ tryImplicitInfo(i) match {
case SearchFailure => rankImplicits(is, acc)
case newBest =>
- _best = newBest
+ best = newBest
val newPending = undoLog undo {
is filterNot (alt => alt == i || {
try improves(i, alt)
@@ -671,13 +687,20 @@ trait Implicits {
}
}
- if (_best == SearchFailure && invalidImplicits.nonEmpty) {
- setAddendum(tree.pos, () =>
- "\n Note: implicit "+invalidImplicits.head+" is not applicable here"+
- " because it comes after the application point and it lacks an explicit result type")
+ if (best == SearchFailure) {
+ /** If there is no winner, and we witnessed and caught divergence,
+ * now we can throw it for the error message.
+ */
+ if (divergence)
+ throw DivergentImplicit
+
+ if (invalidImplicits.nonEmpty)
+ setAddendum(tree.pos, () =>
+ "\n Note: implicit "+invalidImplicits.head+" is not applicable here"+
+ " because it comes after the application point and it lacks an explicit result type")
}
- _best
+ best
}
}