@@ -80,7 +80,7 @@ trait Implicits {
8080 printTyping(" typing implicit: %s %s" .format(tree, context.undetparamsString))
8181 val implicitSearchContext = context.makeImplicit(reportAmbiguous)
8282 val result = new ImplicitSearch (tree, pt, isView, implicitSearchContext, pos).bestImplicit
83- if (saveAmbiguousDivergent && implicitSearchContext.hasErrors) {
83+ if (result.isFailure && saveAmbiguousDivergent && implicitSearchContext.hasErrors) {
8484 context.updateBuffer(implicitSearchContext.reportBuffer.errors.filter(err => err.kind == ErrorKinds .Ambiguous || err.kind == ErrorKinds .Divergent ))
8585 debuglog(" update buffer: " + implicitSearchContext.reportBuffer.errors)
8686 }
@@ -152,13 +152,19 @@ trait Implicits {
152152
153153 def isFailure = false
154154 def isAmbiguousFailure = false
155+ def isDivergent = false
155156 final def isSuccess = ! isFailure
156157 }
157158
158159 lazy val SearchFailure = new SearchResult (EmptyTree , EmptyTreeTypeSubstituter ) {
159160 override def isFailure = true
160161 }
161162
163+ lazy val DivergentSearchFailure = new SearchResult (EmptyTree , EmptyTreeTypeSubstituter ) {
164+ override def isFailure = true
165+ override def isDivergent = true
166+ }
167+
162168 lazy val AmbiguousSearchFailure = new SearchResult (EmptyTree , EmptyTreeTypeSubstituter ) {
163169 override def isFailure = true
164170 override def isAmbiguousFailure = true
@@ -397,22 +403,18 @@ trait Implicits {
397403 (context.openImplicits find { case (tp, tree1) => tree1.symbol == tree.symbol && dominates(pt, tp)}) match {
398404 case Some (pending) =>
399405 // println("Pending implicit "+pending+" dominates "+pt+"/"+undetParams) //@MDEBUG
400- throw DivergentImplicit
406+ DivergentSearchFailure
401407 case None =>
402408 try {
403409 context.openImplicits = (pt, tree) :: context.openImplicits
404410 // println(" "*context.openImplicits.length+"typed implicit "+info+" for "+pt) //@MDEBUG
405- typedImplicit0(info, ptChecked, isLocal)
406- } catch {
407- case ex : DivergentImplicit =>
411+ val result = typedImplicit0(info, ptChecked, isLocal)
412+ if (result.isDivergent) {
408413 // println("DivergentImplicit for pt:"+ pt +", open implicits:"+context.openImplicits) //@MDEBUG
409- if (context.openImplicits.tail.isEmpty) {
410- if (! (pt.isErroneous))
411- DivergingImplicitExpansionError (tree, pt, info.sym)(context)
412- SearchFailure
413- } else {
414- throw DivergentImplicit
415- }
414+ if (context.openImplicits.tail.isEmpty && ! pt.isErroneous)
415+ DivergingImplicitExpansionError (tree, pt, info.sym)(context)
416+ }
417+ result
416418 } finally {
417419 context.openImplicits = context.openImplicits.tail
418420 }
@@ -789,16 +791,21 @@ trait Implicits {
789791 /** Preventing a divergent implicit from terminating implicit search,
790792 * so that if there is a best candidate it can still be selected.
791793 */
792- private var divergence = false
793- private val divergenceHandler : PartialFunction [Throwable , SearchResult ] = {
794- var remaining = 1 ;
795- { case x : DivergentImplicit if remaining > 0 =>
796- remaining -= 1
797- divergence = true
798- log(" discarding divergent implicit during implicit search" )
794+ object DivergentImplicitRecovery {
795+ // symbol of the implicit that caused the divergence.
796+ // Initially null, will be saved on first diverging expansion.
797+ private var implicitSym : Symbol = _
798+ private var countdown : Int = 1
799+
800+ def sym : Symbol = implicitSym
801+ def apply (search : SearchResult , i : ImplicitInfo ): SearchResult =
802+ if (search.isDivergent && countdown > 0 ) {
803+ countdown -= 1
804+ implicitSym = i.sym
805+ log(" discarding divergent implicit ${implicitSym} during implicit search" )
799806 SearchFailure
800- }
801- }
807+ } else search
808+ }
802809
803810 /** Sorted list of eligible implicits.
804811 */
@@ -826,11 +833,9 @@ trait Implicits {
826833 @ tailrec private def rankImplicits (pending : Infos , acc : Infos ): Infos = pending match {
827834 case Nil => acc
828835 case i :: is =>
829- def tryImplicitInfo (i : ImplicitInfo ) =
830- try typedImplicit(i, ptChecked = true , isLocal)
831- catch divergenceHandler
832-
833- tryImplicitInfo(i) match {
836+ DivergentImplicitRecovery (typedImplicit(i, ptChecked = true , isLocal), i) match {
837+ case sr if sr.isDivergent =>
838+ Nil
834839 case sr if sr.isFailure =>
835840 // We don't want errors that occur during checking implicit info
836841 // to influence the check of further infos.
@@ -882,10 +887,9 @@ trait Implicits {
882887 /* If there is no winner, and we witnessed and caught divergence,
883888 * now we can throw it for the error message.
884889 */
885- if (divergence)
886- throw DivergentImplicit
887-
888- if (invalidImplicits.nonEmpty)
890+ if (DivergentImplicitRecovery .sym != null ) {
891+ DivergingImplicitExpansionError (tree, pt, DivergentImplicitRecovery .sym)(context)
892+ } else if (invalidImplicits.nonEmpty)
889893 setAddendum(pos, () =>
890894 " \n Note: implicit " + invalidImplicits.head+ " is not applicable here" +
891895 " because it comes after the application point and it lacks an explicit result type" )
@@ -1438,6 +1442,3 @@ object ImplicitsStats {
14381442 val implicitCacheAccs = Statistics .newCounter (" implicit cache accesses" , " typer" )
14391443 val implicitCacheHits = Statistics .newSubCounter(" implicit cache hits" , implicitCacheAccs)
14401444}
1441-
1442- class DivergentImplicit extends Exception
1443- object DivergentImplicit extends DivergentImplicit
0 commit comments