diff options
author | Paul Phillips <paulp@improving.org> | 2011-03-19 19:55:42 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2011-03-19 19:55:42 +0000 |
commit | aa0cc8e415cca88285b36e76842b759c59f66be7 (patch) | |
tree | 7aeda2d3872bcada8d9b33469200eba511db35df /src/compiler/scala/tools/nsc/typechecker/Implicits.scala | |
parent | 4b0531b55a8d4971b7e297413e514072a99385e7 (diff) | |
download | scala-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.scala | 39 |
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 } } |