@@ -257,9 +257,9 @@ object Implicits {
257
257
sealed abstract class SearchResult extends Showable {
258
258
def tree : tpd.Tree
259
259
def toText (printer : Printer ): Text = printer.toText(this )
260
- def orElse (other : => SearchResult ) = this match {
260
+ def recoverWith (other : SearchFailure => SearchResult ) = this match {
261
261
case _ : SearchSuccess => this
262
- case _ => other
262
+ case fail : SearchFailure => other(fail)
263
263
}
264
264
}
265
265
@@ -484,14 +484,8 @@ trait ImplicitRunInfo { self: RunInfo =>
484
484
iscope(rootTp)
485
485
}
486
486
487
- /** A map that counts the number of times an implicit ref was picked */
488
- val useCount = new mutable.HashMap [TermRef , Int ] {
489
- override def default (key : TermRef ) = 0
490
- }
491
-
492
487
def clear () = {
493
488
implicitScopeCache.clear()
494
- useCount.clear()
495
489
}
496
490
}
497
491
@@ -836,12 +830,6 @@ trait Implicits { self: Typer =>
836
830
typedImplicit(cand)(nestedContext().setNewTyperState().setSearchHistory(history))
837
831
}
838
832
839
- def tryInOrder (cand1 : Candidate , cand2 : Candidate ) =
840
- tryImplicit(cand1) match {
841
- case success : SearchSuccess => success
842
- case _ => tryImplicit(cand2)
843
- }
844
-
845
833
def compareCandidate (prev : SearchSuccess , ref : TermRef , level : Int ): Int =
846
834
if (prev.ref eq ref) 0
847
835
else ctx.typerState.test(compare(prev.ref, ref, prev.level, level)(nestedContext()))
@@ -866,6 +854,14 @@ trait Implicits { self: Typer =>
866
854
case _ : SearchFailure => alt2
867
855
}
868
856
857
+ def healAmbiguous (pending : List [Candidate ], fail : SearchFailure ) = {
858
+ val ambi = fail.reason.asInstanceOf [AmbiguousImplicits ]
859
+ val newPending = pending.filter(cand =>
860
+ compareCandidate(ambi.alt1, cand.ref, cand.level) < 0 &&
861
+ compareCandidate(ambi.alt2, cand.ref, cand.level) < 0 )
862
+ rank(newPending, fail, Nil ).recoverWith(_ => fail)
863
+ }
864
+
869
865
def rank (pending : List [Candidate ], found : SearchResult , rfailures : List [SearchFailure ]): SearchResult = pending match {
870
866
case cand :: pending1 =>
871
867
tryImplicit(cand) match {
@@ -888,164 +884,17 @@ trait Implicits { self: Typer =>
888
884
}
889
885
case nil =>
890
886
if (rfailures.isEmpty) found
891
- else found.orElse(rfailures.reverse.maxBy(_.tree.treeSize))
892
- }
893
-
894
- def healAmbiguous (pending : List [Candidate ], fail : SearchFailure ) = {
895
- val ambi = fail.reason.asInstanceOf [AmbiguousImplicits ]
896
- val newPending = pending.filter(cand =>
897
- compareCandidate(ambi.alt1, cand.ref, cand.level) < 0 &&
898
- compareCandidate(ambi.alt2, cand.ref, cand.level) < 0 )
899
- rank(newPending, fail, Nil ).orElse(fail)
900
- }
901
-
902
- def go : SearchResult = eligible match {
903
- case Nil =>
904
- SearchFailure (new NoMatchingImplicits (pt, argument))
905
- case cand :: Nil =>
906
- tryImplicit(cand)
907
- case cand1 :: cand2 :: Nil =>
908
- def compareTwo = cmpCandidates(cand1, cand2) match {
909
- case 1 => tryInOrder(cand1, cand2)
910
- case - 1 => tryInOrder(cand2, cand1)
911
- case 0 =>
912
- val alt1 = tryImplicit(cand1)
913
- val alt2 = tryImplicit(cand2)
914
- alt2 match {
915
- case alt2 : SearchSuccess => disambiguate(alt1, alt2)
916
- case _ =>
917
- alt1 match {
918
- case alt1 : SearchSuccess => alt1
919
- case _ => if (alt1.tree.treeSize < alt2.tree.treeSize) alt2 else alt1
920
- }
921
- }
922
- }
923
- compareTwo
924
- case _ =>
925
- val cands = eligible.toArray
926
- val pg = new PriorityGraph (cands, cmpCandidates)
927
-
928
- def loop (found : SearchResult , rfailures : List [SearchFailure ]): SearchResult =
929
- if (pg.hasNextSource())
930
- tryImplicit(cands(pg.nextSource())) match {
931
- case fail : SearchFailure =>
932
- if (fail.isAmbiguous) fail
933
- else {
934
- pg.dropLastSource()
935
- loop(found, fail :: rfailures)
936
- }
937
- case best : SearchSuccess =>
938
- if (ctx.mode.is(Mode .ImplicitExploration ) || isCoherent)
939
- best
940
- else disambiguate(found, best) match {
941
- case retained : SearchSuccess => loop(retained, rfailures)
942
- case ambi => ambi
943
- }
944
- }
945
- else if (found.isInstanceOf [SearchSuccess ]) found
946
- else rfailures.reverse.maxBy(_.tree.treeSize)
947
-
948
- loop(NoMatchingImplicitsFailure , Nil )
949
- }
950
-
951
- /** Given a list of implicit references, produce a list of search results,
952
- * which is either a list of successes or a list of failures.
953
- * - if one of the references produces an ambiguity error, return it
954
- * as only element
955
- * - if some of the references produce successful searches, return those that do
956
- * - otherwise return a list of all failures
957
- *
958
- * If mode is ImplicitExploration or we assume coherence, stop at first
959
- * succesfull search.
960
- *
961
- * @param pending The list of implicit references that remain to be investigated
962
- */
963
- def rankImplicits (pending : List [Candidate ],
964
- successes : List [SearchSuccess ],
965
- rfailures : List [SearchFailure ]): List [SearchResult ] =
966
- pending match {
967
- case cand :: pending1 =>
968
- val history = ctx.searchHistory nest wildProto
969
- val result =
970
- if (history eq ctx.searchHistory)
971
- SearchFailure (new DivergingImplicit (cand.ref, pt, argument))
972
- else
973
- typedImplicit(cand)(nestedContext().setNewTyperState().setSearchHistory(history))
974
- result match {
975
- case fail : SearchFailure =>
976
- if (fail.isAmbiguous) fail :: Nil
977
- else rankImplicits(pending1, successes, fail :: rfailures)
978
- case best : SearchSuccess =>
979
- if (ctx.mode.is(Mode .ImplicitExploration ) || isCoherent)
980
- best :: Nil
981
- else {
982
- val newPending = pending1.filter(cand1 =>
983
- ctx.typerState.test(isAsGood(cand1.ref, best.ref, cand1.level, best.level)(nestedContext())))
984
- rankImplicits(newPending, best :: successes, rfailures)
985
- }
986
- }
987
- case nil =>
988
- if (successes.nonEmpty) successes else rfailures.reverse
989
- }
990
-
991
- /** If the (result types of) the expected type, and both alternatives
992
- * are all numeric value types, return the alternative which has
993
- * the smaller numeric subtype as result type, if it exists.
994
- * (This alternative is then discarded).
995
- */
996
- def numericValueTieBreak (alt1 : SearchSuccess , alt2 : SearchSuccess ): SearchResult = {
997
- def isNumeric (tp : Type ) = tp.typeSymbol.isNumericValueClass
998
- def isProperSubType (tp1 : Type , tp2 : Type ) =
999
- tp1.isValueSubType(tp2) && ! tp2.isValueSubType(tp1)
1000
- val rpt = pt.resultType
1001
- val rt1 = alt1.ref.widen.resultType
1002
- val rt2 = alt2.ref.widen.resultType
1003
- if (isNumeric(rpt) && isNumeric(rt1) && isNumeric(rt2))
1004
- if (isProperSubType(rt1, rt2)) alt1
1005
- else if (isProperSubType(rt2, rt1)) alt2
1006
- else NoMatchingImplicitsFailure
1007
- else NoMatchingImplicitsFailure
887
+ else found.recoverWith(_ => rfailures.reverse.maxBy(_.tree.treeSize))
1008
888
}
1009
889
1010
- /** Convert a (possibly empty) list of search results into a single search result
1011
- * - if the list consists of one or more successes
1012
- * - if a following success is as good as the first one, issue an ambiguity error
1013
- * - otherwise return the first success
1014
- * - if the list consists of one or more failues, pick the failure with the largest
1015
- * associated tree.
1016
- * - if the list is empty, issue a "no matching implicits" error.
1017
- */
1018
- def condense (results : List [SearchResult ]): SearchResult = results match {
1019
- case (best : SearchSuccess ) :: (alts : List [SearchSuccess ] @ unchecked) =>
1020
- alts.find(alt =>
1021
- ctx.typerState.test(isAsGood(alt.ref, best.ref, alt.level, best.level))) match {
1022
- case Some (alt) =>
1023
- implicits.println(i " ambiguous implicits for $pt: ${best.ref} @ ${best.level}, ${alt.ref} @ ${alt.level}" )
1024
- /* !!! DEBUG
1025
- println(i"ambiguous refs: ${hits map (_.ref) map (_.show) mkString ", "}")
1026
- isAsGood(best.ref, alt.ref, explain = true)(ctx.fresh.withExploreTyperState)
1027
- */
1028
- numericValueTieBreak(best, alt) match {
1029
- case eliminated : SearchSuccess =>
1030
- condense(results.filter(_ ne eliminated))
1031
- case _ =>
1032
- SearchFailure (new AmbiguousImplicits (best, alt, pt, argument))
1033
- }
1034
- case None =>
1035
- ctx.runInfo.useCount(best.ref) += 1
1036
- best
1037
- }
1038
- case (fail : SearchFailure ) :: _ =>
1039
- results.maxBy(_.tree.treeSize)
1040
- case Nil =>
1041
- SearchFailure (new NoMatchingImplicits (pt, argument))
1042
- }
1043
-
1044
- def ranking (cand : Candidate ) = - ctx.runInfo.useCount(cand.ref)
1045
-
1046
- /** Prefer `cand1` over `cand2` if they are in the same compilation unit
1047
- * and `cand1` is defined before `cand2`, or they are in different units and
1048
- * `cand1` has been selected as an implicit more often than `cand2`.
890
+ /** A relation that imfluences the order in which implicits are tried.
891
+ * We prefer (in order of importance)
892
+ * 1. more deeply nested definitions
893
+ * 2. definitions in subclasses
894
+ * 3. definitions with fewer implicit parameters
895
+ * The reason for (3) is that we want to fail fast if the search type
896
+ * is underconstrained. So we look for "small" goals first, because that
897
+ * will give an ambiguity quickly.
1049
898
*/
1050
899
def prefer (cand1 : Candidate , cand2 : Candidate ): Boolean = {
1051
900
val level1 = cand1.level
@@ -1064,9 +913,7 @@ trait Implicits { self: Typer =>
1064
913
false
1065
914
}
1066
915
1067
- /** Sort list of implicit references according to their popularity
1068
- * (# of times each was picked in current run).
1069
- */
916
+ /** Sort list of implicit references according to `prefer` */
1070
917
def sort (eligible : List [Candidate ]) = eligible match {
1071
918
case Nil => eligible
1072
919
case e1 :: Nil => eligible
@@ -1077,23 +924,19 @@ trait Implicits { self: Typer =>
1077
924
eligible.sortWith(prefer)
1078
925
}
1079
926
1080
- if (true ) rank(sort(eligible), NoMatchingImplicitsFailure , Nil )
1081
- else if (true ) go
1082
- else condense(rankImplicits(sort(eligible), Nil , Nil ))
1083
- }
927
+ rank(sort(eligible), NoMatchingImplicitsFailure , Nil )
928
+ } // end searchImplicits
1084
929
1085
930
/** Find a unique best implicit reference */
1086
931
def bestImplicit (contextual : Boolean ): SearchResult = {
1087
932
val eligible =
1088
933
if (contextual) ctx.implicits.eligible(wildProto)
1089
934
else implicitScope(wildProto).eligible
1090
- searchImplicits(eligible, contextual) match {
1091
- case success : SearchSuccess => success
1092
- case failure : SearchFailure =>
1093
- failure.reason match {
1094
- case (_ : AmbiguousImplicits ) | (_ : DivergingImplicit ) => failure
1095
- case _ => if (contextual) bestImplicit(contextual = false ) else failure
1096
- }
935
+ searchImplicits(eligible, contextual).recoverWith {
936
+ failure => failure.reason match {
937
+ case (_ : AmbiguousImplicits ) | (_ : DivergingImplicit ) => failure
938
+ case _ => if (contextual) bestImplicit(contextual = false ) else failure
939
+ }
1097
940
}
1098
941
}
1099
942
0 commit comments