@@ -35,18 +35,24 @@ import collection.mutable
35
35
/** Implicit resolution */
36
36
object Implicits {
37
37
38
+ /** An eligible implicit candidate, consisting of an implicit reference and a nesting level */
39
+ case class Candidate (ref : TermRef , level : Int )
40
+
38
41
/** A common base class of contextual implicits and of-type implicits which
39
42
* represents a set of implicit references.
40
43
*/
41
44
abstract class ImplicitRefs (initctx : Context ) {
42
45
implicit val ctx : Context =
43
46
if (initctx == NoContext ) initctx else initctx retractMode Mode .ImplicitsEnabled
44
47
48
+ /** The nesting level of this context. Non-zero only in ContextialImplicits */
49
+ def level : Int = 0
50
+
45
51
/** The implicit references */
46
52
def refs : List [TermRef ]
47
53
48
54
/** Return those references in `refs` that are compatible with type `pt`. */
49
- protected def filterMatching (pt : Type )(implicit ctx : Context ): List [TermRef ] = track(" filterMatching" ) {
55
+ protected def filterMatching (pt : Type )(implicit ctx : Context ): List [Candidate ] = track(" filterMatching" ) {
50
56
51
57
def refMatches (ref : TermRef )(implicit ctx : Context ) = /* ctx.traceIndented(i"refMatches $ref $pt")*/ {
52
58
@@ -97,8 +103,9 @@ object Implicits {
97
103
}
98
104
}
99
105
100
- if (refs.isEmpty) refs
101
- else refs filter (refMatches(_)(ctx.fresh.addMode(Mode .TypevarsMissContext ).setExploreTyperState)) // create a defensive copy of ctx to avoid constraint pollution
106
+ if (refs.isEmpty) Nil
107
+ else refs.filter(refMatches(_)(ctx.fresh.addMode(Mode .TypevarsMissContext ).setExploreTyperState)) // create a defensive copy of ctx to avoid constraint pollution
108
+ .map(Candidate (_, level))
102
109
}
103
110
}
104
111
@@ -114,8 +121,8 @@ object Implicits {
114
121
buf.toList
115
122
}
116
123
117
- /** The implicit references that are eligible for expected type `tp` */
118
- lazy val eligible : List [TermRef ] =
124
+ /** The candidates that are eligible for expected type `tp` */
125
+ lazy val eligible : List [Candidate ] =
119
126
/* >|>*/ track(" eligible in tpe" ) /* <|<*/ {
120
127
/* >|>*/ ctx.traceIndented(i " eligible( $tp), companions = ${companionRefs.toList}%, % " , implicitsDetailed, show = true ) /* <|<*/ {
121
128
if (refs.nonEmpty && monitored) record(s " check eligible refs in tpe " , refs.length)
@@ -135,10 +142,15 @@ object Implicits {
135
142
* @param outerCtx the next outer context that makes visible further implicits
136
143
*/
137
144
class ContextualImplicits (val refs : List [TermRef ], val outerImplicits : ContextualImplicits )(initctx : Context ) extends ImplicitRefs (initctx) {
138
- private val eligibleCache = new mutable.AnyRefMap [Type , List [TermRef ]]
145
+ private val eligibleCache = new mutable.AnyRefMap [Type , List [Candidate ]]
146
+
147
+ override val level : Int =
148
+ if (outerImplicits == null ) 1
149
+ else if (ctx.scope eq outerImplicits.ctx.scope) outerImplicits.level
150
+ else outerImplicits.level + 1
139
151
140
152
/** The implicit references that are eligible for type `tp`. */
141
- def eligible (tp : Type ): List [TermRef ] = /* >|>*/ track(s " eligible in ctx " ) /* <|<*/ {
153
+ def eligible (tp : Type ): List [Candidate ] = /* >|>*/ track(s " eligible in ctx " ) /* <|<*/ {
142
154
if (tp.hash == NotCached ) computeEligible(tp)
143
155
else eligibleCache get tp match {
144
156
case Some (eligibles) =>
@@ -162,13 +174,13 @@ object Implicits {
162
174
}
163
175
}
164
176
165
- private def computeEligible (tp : Type ): List [TermRef ] = /* >|>*/ ctx.traceIndented(i " computeEligible $tp in $refs%, % " , implicitsDetailed) /* <|<*/ {
177
+ private def computeEligible (tp : Type ): List [Candidate ] = /* >|>*/ ctx.traceIndented(i " computeEligible $tp in $refs%, % " , implicitsDetailed) /* <|<*/ {
166
178
if (monitored) record(s " check eligible refs in ctx " , refs.length)
167
179
val ownEligible = filterMatching(tp)
168
180
if (outerImplicits == NoContext .implicits) ownEligible
169
181
else ownEligible ::: {
170
- val shadowed = ( ownEligible map (_.name) ).toSet
171
- outerImplicits.eligible(tp) filterNot (ref => shadowed contains ref.name)
182
+ val shadowed = ownEligible. map(_.ref. name).toSet
183
+ outerImplicits.eligible(tp). filterNot(cand => shadowed. contains(cand. ref.name) )
172
184
}
173
185
}
174
186
@@ -198,7 +210,7 @@ object Implicits {
198
210
* @param tree The typed tree that needs to be inserted
199
211
* @param ctx The context after the implicit search
200
212
*/
201
- case class SearchSuccess (tree : tpd.Tree , ref : TermRef , tstate : TyperState ) extends SearchResult {
213
+ case class SearchSuccess (tree : tpd.Tree , ref : TermRef , level : Int , tstate : TyperState ) extends SearchResult {
202
214
override def toString = s " SearchSuccess( $tree, $ref) "
203
215
}
204
216
@@ -478,7 +490,7 @@ trait Implicits { self: Typer =>
478
490
*/
479
491
def inferImplicitArg (formal : Type , error : (String => String ) => Unit , pos : Position )(implicit ctx : Context ): Tree =
480
492
inferImplicit(formal, EmptyTree , pos) match {
481
- case SearchSuccess (arg, _, _) =>
493
+ case SearchSuccess (arg, _, _, _ ) =>
482
494
arg
483
495
case ambi : AmbiguousImplicits =>
484
496
error(where => s " ambiguous implicits: ${ambi.explanation} of $where" )
@@ -621,12 +633,13 @@ trait Implicits { self: Typer =>
621
633
protected def failedSearch : SearchFailure = NoImplicitMatches
622
634
623
635
/** Search a list of eligible implicit references */
624
- def searchImplicits (eligible : List [TermRef ], contextual : Boolean ): SearchResult = {
636
+ def searchImplicits (eligible : List [Candidate ], contextual : Boolean ): SearchResult = {
625
637
val constr = ctx.typerState.constraint
626
638
627
639
/** Try to typecheck an implicit reference */
628
- def typedImplicit (ref : TermRef )(implicit ctx : Context ): SearchResult = track(" typedImplicit" ) { ctx.traceIndented(i " typed implicit $ref, pt = $pt, implicitsEnabled == ${ctx.mode is ImplicitsEnabled }" , implicits, show = true ) {
640
+ def typedImplicit (cand : Candidate )(implicit ctx : Context ): SearchResult = track(" typedImplicit" ) { ctx.traceIndented(i " typed implicit ${cand. ref} , pt = $pt, implicitsEnabled == ${ctx.mode is ImplicitsEnabled }" , implicits, show = true ) {
629
641
assert(constr eq ctx.typerState.constraint)
642
+ val ref = cand.ref
630
643
var generated : Tree = tpd.ref(ref).withPos(pos)
631
644
if (! argument.isEmpty)
632
645
generated = typedUnadapted(
@@ -667,7 +680,7 @@ trait Implicits { self: Typer =>
667
680
if fn.symbol == defn.Predef_eqAny && ! validEqAnyArgs(arg1.tpe, arg2.tpe) =>
668
681
nonMatchingImplicit(ref, Nil )
669
682
case _ =>
670
- SearchSuccess (generated1, ref, ctx.typerState)
683
+ SearchSuccess (generated1, ref, cand.level, ctx.typerState)
671
684
}
672
685
}}
673
686
@@ -676,19 +689,20 @@ trait Implicits { self: Typer =>
676
689
* @param pending The list of implicit references that remain to be investigated
677
690
* @param acc An accumulator of successful matches found so far.
678
691
*/
679
- def rankImplicits (pending : List [TermRef ], acc : List [SearchSuccess ]): List [SearchSuccess ] = pending match {
680
- case ref :: pending1 =>
692
+ def rankImplicits (pending : List [Candidate ], acc : List [SearchSuccess ]): List [SearchSuccess ] = pending match {
693
+ case cand :: pending1 =>
681
694
val history = ctx.searchHistory nest wildProto
682
695
val result =
683
- if (history eq ctx.searchHistory) divergingImplicit(ref)
684
- else typedImplicit(ref )(nestedContext.setNewTyperState.setSearchHistory(history))
696
+ if (history eq ctx.searchHistory) divergingImplicit(cand. ref)
697
+ else typedImplicit(cand )(nestedContext.setNewTyperState.setSearchHistory(history))
685
698
result match {
686
699
case fail : SearchFailure =>
687
700
rankImplicits(pending1, acc)
688
701
case best : SearchSuccess =>
689
702
if (ctx.mode.is(Mode .ImplicitExploration )) best :: Nil
690
703
else {
691
- val newPending = pending1 filter (isAsGood(_, best.ref)(nestedContext.setExploreTyperState))
704
+ val newPending = pending1.filter(cand1 =>
705
+ isAsGood(cand1.ref, best.ref, cand1.level, best.level)(nestedContext.setExploreTyperState))
692
706
rankImplicits(newPending, best :: acc)
693
707
}
694
708
}
@@ -717,7 +731,7 @@ trait Implicits { self: Typer =>
717
731
/** Convert a (possibly empty) list of search successes into a single search result */
718
732
def condense (hits : List [SearchSuccess ]): SearchResult = hits match {
719
733
case best :: alts =>
720
- alts find (alt => isAsGood(alt.ref, best.ref)(ctx.fresh.setExploreTyperState)) match {
734
+ alts find (alt => isAsGood(alt.ref, best.ref, alt.level, best.level )(ctx.fresh.setExploreTyperState)) match {
721
735
case Some (alt) =>
722
736
/* !!! DEBUG
723
737
println(i"ambiguous refs: ${hits map (_.ref) map (_.show) mkString ", "}")
@@ -735,16 +749,18 @@ trait Implicits { self: Typer =>
735
749
failedSearch
736
750
}
737
751
752
+ def ranking (cand : Candidate ) = - ctx.runInfo.useCount(cand.ref)
753
+
738
754
/** Sort list of implicit references according to their popularity
739
755
* (# of times each was picked in current run).
740
756
*/
741
- def sort (eligible : List [TermRef ]) = eligible match {
757
+ def sort (eligible : List [Candidate ]) = eligible match {
742
758
case Nil => eligible
743
759
case e1 :: Nil => eligible
744
760
case e1 :: e2 :: Nil =>
745
- if (ctx.runInfo.useCount(e1 ) < ctx.runInfo.useCount(e2 )) e2 :: e1 :: Nil
761
+ if (ranking(e2 ) < ranking(e1 )) e2 :: e1 :: Nil
746
762
else eligible
747
- case _ => eligible.sortBy(- ctx.runInfo.useCount(_) )
763
+ case _ => eligible.sortBy(ranking )
748
764
}
749
765
750
766
condense(rankImplicits(sort(eligible), Nil ))
0 commit comments