diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Implicits.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Implicits.scala | 67 |
1 files changed, 34 insertions, 33 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index b0c8baae20..59ed64ac03 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -80,7 +80,7 @@ trait Implicits { printTyping("typing implicit: %s %s".format(tree, context.undetparamsString)) val implicitSearchContext = context.makeImplicit(reportAmbiguous) val result = new ImplicitSearch(tree, pt, isView, implicitSearchContext, pos).bestImplicit - if (saveAmbiguousDivergent && implicitSearchContext.hasErrors) { + if (result.isFailure && saveAmbiguousDivergent && implicitSearchContext.hasErrors) { context.updateBuffer(implicitSearchContext.reportBuffer.errors.filter(err => err.kind == ErrorKinds.Ambiguous || err.kind == ErrorKinds.Divergent)) debuglog("update buffer: " + implicitSearchContext.reportBuffer.errors) } @@ -152,6 +152,7 @@ trait Implicits { def isFailure = false def isAmbiguousFailure = false + def isDivergent = false final def isSuccess = !isFailure } @@ -159,6 +160,11 @@ trait Implicits { override def isFailure = true } + lazy val DivergentSearchFailure = new SearchResult(EmptyTree, EmptyTreeTypeSubstituter) { + override def isFailure = true + override def isDivergent = true + } + lazy val AmbiguousSearchFailure = new SearchResult(EmptyTree, EmptyTreeTypeSubstituter) { override def isFailure = true override def isAmbiguousFailure = true @@ -397,22 +403,18 @@ trait Implicits { (context.openImplicits find { case (tp, tree1) => tree1.symbol == tree.symbol && dominates(pt, tp)}) match { case Some(pending) => //println("Pending implicit "+pending+" dominates "+pt+"/"+undetParams) //@MDEBUG - throw DivergentImplicit + DivergentSearchFailure case None => try { context.openImplicits = (pt, tree) :: context.openImplicits // println(" "*context.openImplicits.length+"typed implicit "+info+" for "+pt) //@MDEBUG - typedImplicit0(info, ptChecked, isLocal) - } catch { - case ex: DivergentImplicit => + val result = typedImplicit0(info, ptChecked, isLocal) + if (result.isDivergent) { //println("DivergentImplicit for pt:"+ pt +", open implicits:"+context.openImplicits) //@MDEBUG - if (context.openImplicits.tail.isEmpty) { - if (!(pt.isErroneous)) - DivergingImplicitExpansionError(tree, pt, info.sym)(context) - SearchFailure - } else { - throw DivergentImplicit - } + if (context.openImplicits.tail.isEmpty && !pt.isErroneous) + DivergingImplicitExpansionError(tree, pt, info.sym)(context) + } + result } finally { context.openImplicits = context.openImplicits.tail } @@ -789,16 +791,21 @@ trait Implicits { /** 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 divergenceHandler: PartialFunction[Throwable, SearchResult] = { - var remaining = 1; - { case x: DivergentImplicit if remaining > 0 => - remaining -= 1 - divergence = true - log("discarding divergent implicit during implicit search") + object DivergentImplicitRecovery { + // symbol of the implicit that caused the divergence. + // Initially null, will be saved on first diverging expansion. + private var implicitSym: Symbol = _ + private var countdown: Int = 1 + + def sym: Symbol = implicitSym + def apply(search: SearchResult, i: ImplicitInfo): SearchResult = + if (search.isDivergent && countdown > 0) { + countdown -= 1 + implicitSym = i.sym + log("discarding divergent implicit ${implicitSym} during implicit search") SearchFailure - } - } + } else search + } /** Sorted list of eligible implicits. */ @@ -826,11 +833,9 @@ trait Implicits { @tailrec private def rankImplicits(pending: Infos, acc: Infos): Infos = pending match { case Nil => acc case i :: is => - def tryImplicitInfo(i: ImplicitInfo) = - try typedImplicit(i, ptChecked = true, isLocal) - catch divergenceHandler - - tryImplicitInfo(i) match { + DivergentImplicitRecovery(typedImplicit(i, ptChecked = true, isLocal), i) match { + case sr if sr.isDivergent => + Nil case sr if sr.isFailure => // We don't want errors that occur during checking implicit info // to influence the check of further infos. @@ -882,10 +887,9 @@ trait Implicits { /* 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) + if (DivergentImplicitRecovery.sym != null) { + DivergingImplicitExpansionError(tree, pt, DivergentImplicitRecovery.sym)(context) + } else if (invalidImplicits.nonEmpty) setAddendum(pos, () => "\n Note: implicit "+invalidImplicits.head+" is not applicable here"+ " because it comes after the application point and it lacks an explicit result type") @@ -1438,6 +1442,3 @@ object ImplicitsStats { val implicitCacheAccs = Statistics.newCounter ("implicit cache accesses", "typer") val implicitCacheHits = Statistics.newSubCounter("implicit cache hits", implicitCacheAccs) } - -class DivergentImplicit extends Exception -object DivergentImplicit extends DivergentImplicit |