@@ -305,7 +305,7 @@ object Implicits {
305305
306306 def msg (implicit ctx : Context ): Message = explanation
307307
308- /** If search was a for an implicit conversion, a note describing the failure
308+ /** If search was for an implicit conversion, a note describing the failure
309309 * in more detail - this is either empty or starts with a '\n'
310310 */
311311 def whyNoConversion (implicit ctx : Context ): String = " "
@@ -878,14 +878,18 @@ trait Implicits { self: Typer =>
878878 def disambiguate (alt1 : SearchResult , alt2 : SearchSuccess ) = alt1 match {
879879 case alt1 : SearchSuccess =>
880880 val diff = compareCandidate(alt1, alt2.ref, alt2.level)
881- assert(diff <= 0 )
881+ assert(diff <= 0 ) // diff > 0 candidates should already have been eliminated in `rank`
882882 if (diff < 0 ) alt2
883883 else
884884 // numericValueTypeBreak(alt1, alt2) recoverWith
885885 SearchFailure (new AmbiguousImplicits (alt1, alt2, pt, argument))
886886 case _ : SearchFailure => alt2
887887 }
888888
889+ /** Faced with an ambiguous implicits failure `fail`, try to find another
890+ * alternative among `pending` that is strictly better than both ambiguous
891+ * alternatives. If that fails, return `fail`
892+ */
889893 def healAmbiguous (pending : List [Candidate ], fail : SearchFailure ) = {
890894 val ambi = fail.reason.asInstanceOf [AmbiguousImplicits ]
891895 val newPending = pending.filter(cand =>
@@ -894,42 +898,66 @@ trait Implicits { self: Typer =>
894898 rank(newPending, fail, Nil ).recoverWith(_ => fail)
895899 }
896900
897- def rank (pending : List [Candidate ], found : SearchResult , rfailures : List [SearchFailure ]): SearchResult = pending match {
898- case cand :: pending1 =>
899- tryImplicit(cand) match {
900- case fail : SearchFailure =>
901- if (isNot)
902- SearchSuccess (ref(defn.Not_value ), defn.Not_value .termRef, 0 )(ctx.typerState)
903- else if (fail.isAmbiguous)
904- if (ctx.scala2Mode) {
905- val result = rank(pending1, found, NoMatchingImplicitsFailure :: rfailures)
906- if (result.isSuccess)
907- warnAmbiguousNegation(fail.reason.asInstanceOf [AmbiguousImplicits ])
908- result
909- }
910- else
911- healAmbiguous(pending1, fail)
912- else
913- rank(pending1, found, fail :: rfailures)
914- case best : SearchSuccess =>
915- if (isNot)
916- NoMatchingImplicitsFailure
917- else if (ctx.mode.is(Mode .ImplicitExploration ) || isCoherent)
918- best
919- else disambiguate(found, best) match {
920- case retained : SearchSuccess =>
921- val newPending =
922- if (retained eq found) pending1
923- else pending1.filter(cand =>
924- compareCandidate(retained, cand.ref, cand.level) <= 0 )
925- rank(newPending, retained, rfailures)
926- case fail : SearchFailure =>
927- healAmbiguous(pending1, fail)
901+ /** Try to find a best matching implicit term among all the candidates in `pending`.
902+ * @param pending The list of candidates that remain to be tested
903+ * @param found The result obtained from previously tried candidates
904+ * @param rfailures A list of all failures from previously tried candidates in reverse order
905+ *
906+ * The scheme is to try candidates one-by-one. If a trial is successful:
907+ * - if the query term is a `Not[T]` treat it a failure,
908+ * - otherwise, if a previous search was also successful, handle the ambiguity
909+ * in `disambiguate`,
910+ * - otherwise, continue the search with all candidates that are not strictly
911+ * worse than the succesful candidate.
912+ * If a trial failed:
913+ * - if the query term is a `Not[T]` treat it as a success,
914+ * - otherwise, if the failure is an ambiguity, try to heal it (see @healAmbiguous)
915+ * and return an ambiguous error otherwise. However, under Scala2 mode this is
916+ * treated as a simple failure, with a warning that semantics will change.
917+ * - otherwise add the failure to `rfailures` and continue testing the other candidates.
918+ */
919+ def rank (pending : List [Candidate ], found : SearchResult , rfailures : List [SearchFailure ]): SearchResult = {
920+ def recur (result : SearchResult , remaining : List [Candidate ]): SearchResult = result match {
921+ case fail : SearchFailure =>
922+ if (isNot)
923+ recur(
924+ SearchSuccess (ref(defn.Not_value ), defn.Not_value .termRef, 0 )(
925+ ctx.typerState.fresh().setCommittable(true ))
926+ remaining)
927+ else if (fail.isAmbiguous)
928+ if (ctx.scala2Mode) {
929+ val result = rank(remaining, found, NoMatchingImplicitsFailure :: rfailures)
930+ if (result.isSuccess)
931+ warnAmbiguousNegation(fail.reason.asInstanceOf [AmbiguousImplicits ])
932+ result
928933 }
929- }
930- case nil =>
931- if (rfailures.isEmpty) found
932- else found.recoverWith(_ => rfailures.reverse.maxBy(_.tree.treeSize))
934+ else
935+ healAmbiguous(remaining, fail)
936+ else
937+ rank(remaining, found, fail :: rfailures)
938+ case best : SearchSuccess =>
939+ if (isNot)
940+ recur(NoMatchingImplicitsFailure , remaining)
941+ else if (ctx.mode.is(Mode .ImplicitExploration ) || isCoherent)
942+ best
943+ else disambiguate(found, best) match {
944+ case retained : SearchSuccess =>
945+ val newPending =
946+ if (retained eq found) remaining
947+ else remaining.filter(cand =>
948+ compareCandidate(retained, cand.ref, cand.level) <= 0 )
949+ rank(newPending, retained, rfailures)
950+ case fail : SearchFailure =>
951+ healAmbiguous(remaining, fail)
952+ }
953+ }
954+ pending match {
955+ case cand :: pending1 =>
956+ recur(tryImplicit(cand), pending1)
957+ case nil =>
958+ if (rfailures.isEmpty) found
959+ else found.recoverWith(_ => rfailures.reverse.maxBy(_.tree.treeSize))
960+ }
933961 }
934962
935963 def warnAmbiguousNegation (ambi : AmbiguousImplicits ) =
0 commit comments