@@ -305,7 +305,7 @@ object Implicits {
305
305
306
306
def msg (implicit ctx : Context ): Message = explanation
307
307
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
309
309
* in more detail - this is either empty or starts with a '\n'
310
310
*/
311
311
def whyNoConversion (implicit ctx : Context ): String = " "
@@ -878,14 +878,18 @@ trait Implicits { self: Typer =>
878
878
def disambiguate (alt1 : SearchResult , alt2 : SearchSuccess ) = alt1 match {
879
879
case alt1 : SearchSuccess =>
880
880
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`
882
882
if (diff < 0 ) alt2
883
883
else
884
884
// numericValueTypeBreak(alt1, alt2) recoverWith
885
885
SearchFailure (new AmbiguousImplicits (alt1, alt2, pt, argument))
886
886
case _ : SearchFailure => alt2
887
887
}
888
888
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
+ */
889
893
def healAmbiguous (pending : List [Candidate ], fail : SearchFailure ) = {
890
894
val ambi = fail.reason.asInstanceOf [AmbiguousImplicits ]
891
895
val newPending = pending.filter(cand =>
@@ -894,42 +898,66 @@ trait Implicits { self: Typer =>
894
898
rank(newPending, fail, Nil ).recoverWith(_ => fail)
895
899
}
896
900
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
928
933
}
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
+ }
933
961
}
934
962
935
963
def warnAmbiguousNegation (ambi : AmbiguousImplicits ) =
0 commit comments