@@ -833,19 +833,41 @@ trait Implicits {
833833 * so that if there is a best candidate it can still be selected.
834834 */
835835 object DivergentImplicitRecovery {
836- // symbol of the implicit that caused the divergence.
837- // Initially null, will be saved on first diverging expansion.
838- private var implicitSym : Symbol = _
839- private var countdown : Int = 1
840-
841- def sym : Symbol = implicitSym
842- def apply (search : SearchResult , i : ImplicitInfo ): SearchResult =
843- if (search.isDivergent && countdown > 0 ) {
844- countdown -= 1
845- implicitSym = i.sym
846- log(s " discarding divergent implicit $implicitSym during implicit search " )
836+ private var divergentError : Option [DivergentImplicitTypeError ] = None
837+
838+ private def saveDivergent (err : DivergentImplicitTypeError ) {
839+ if (divergentError.isEmpty) divergentError = Some (err)
840+ }
841+
842+ def issueSavedDivergentError () {
843+ divergentError foreach (err => context.issue(err))
844+ }
845+
846+ def apply (search : SearchResult , i : ImplicitInfo , errors : Seq [AbsTypeError ]): SearchResult = {
847+ // A divergent error from a nested implicit search will be found in `errors`. Stash that
848+ // aside to be re-issued if this implicit search fails.
849+ errors.collectFirst { case err : DivergentImplicitTypeError => err } foreach saveDivergent
850+
851+ if (search.isDivergent && divergentError.isEmpty) {
852+ // Divergence triggered by `i` at this level of the implicit serach. We haven't
853+ // seen divergence so far, we won't issue this error just yet, and instead temporarily
854+ // treat `i` as a failed candidate.
855+ saveDivergent(DivergentImplicitTypeError (tree, pt, i.sym))
856+ log(s " discarding divergent implicit ${i.sym} during implicit search " )
847857 SearchFailure
848- } else search
858+ } else {
859+ if (search.isFailure) {
860+ // We don't want errors that occur during checking implicit info
861+ // to influence the check of further infos, but we should retain divergent implicit errors
862+ // (except for the one we already squirreled away)
863+ val saved = divergentError.getOrElse(null )
864+ context.reportBuffer.retainErrors {
865+ case err : DivergentImplicitTypeError => err ne saved
866+ }
867+ }
868+ search
869+ }
870+ }
849871 }
850872
851873 /** Sorted list of eligible implicits.
@@ -869,31 +891,33 @@ trait Implicits {
869891 * - if it matches, forget about all others it improves upon
870892 */
871893 @ tailrec private def rankImplicits (pending : Infos , acc : Infos ): Infos = pending match {
872- case Nil => acc
873- case i :: is =>
874- DivergentImplicitRecovery (typedImplicit(i, ptChecked = true , isLocalToCallsite), i) match {
875- case sr if sr.isDivergent =>
876- Nil
877- case sr if sr.isFailure =>
878- // We don't want errors that occur during checking implicit info
879- // to influence the check of further infos.
880- context.reportBuffer.retainErrors {
881- case err : DivergentImplicitTypeError => true
894+ case Nil => acc
895+ case firstPending :: otherPending =>
896+ def firstPendingImproves (alt : ImplicitInfo ) =
897+ firstPending == alt || (
898+ try improves(firstPending, alt)
899+ catch {
900+ case e : CyclicReference =>
901+ debugwarn(s " Discarding $firstPending during implicit search due to cyclic reference. " )
902+ true
882903 }
883- rankImplicits(is, acc)
884- case newBest =>
885- best = newBest
886- val newPending = undoLog undo {
887- is filterNot (alt => alt == i || {
888- try improves(i, alt)
889- catch {
890- case e : CyclicReference =>
891- debugwarn(s " Discarding $i during implicit search due to cyclic reference " )
892- true
893- }
894- })
904+ )
905+
906+ val typedFirstPending = typedImplicit(firstPending, ptChecked = true , isLocalToCallsite)
907+
908+ // Pass the errors to `DivergentImplicitRecovery` so that it can note
909+ // the first `DivergentImplicitTypeError` that is being propagated
910+ // from a nested implicit search; this one will be
911+ // re-issued if this level of the search fails.
912+ DivergentImplicitRecovery (typedFirstPending, firstPending, context.errors) match {
913+ case sr if sr.isDivergent => Nil
914+ case sr if sr.isFailure => rankImplicits(otherPending, acc)
915+ case newBest =>
916+ best = newBest // firstPending is our new best, since we already pruned last time around:
917+ val pendingImprovingBest = undoLog undo {
918+ otherPending filterNot firstPendingImproves
895919 }
896- rankImplicits(newPending, i :: acc)
920+ rankImplicits(pendingImprovingBest, firstPending :: acc)
897921 }
898922 }
899923
@@ -921,12 +945,9 @@ trait Implicits {
921945 }
922946
923947 if (best.isFailure) {
924- /* If there is no winner, and we witnessed and caught divergence,
925- * now we can throw it for the error message.
926- */
927- if (DivergentImplicitRecovery .sym != null ) {
928- DivergingImplicitExpansionError (tree, pt, DivergentImplicitRecovery .sym)(context)
929- }
948+ // If there is no winner, and we witnessed and recorded a divergence error,
949+ // our recovery attempt has failed, so we must now issue it.
950+ DivergentImplicitRecovery .issueSavedDivergentError()
930951
931952 if (invalidImplicits.nonEmpty)
932953 setAddendum(pos, () =>
0 commit comments