Skip to content

Commit c1c9198

Browse files
committed
Refine order in which implicit candidates are tried
1 parent beb90b4 commit c1c9198

File tree

1 file changed

+23
-2
lines changed

1 file changed

+23
-2
lines changed

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -915,16 +915,37 @@ trait Implicits { self: Typer =>
915915

916916
def ranking(cand: Candidate) = -ctx.runInfo.useCount(cand.ref)
917917

918+
/** Prefer `cand1` over `cand2` if they are in the same compilation unit
919+
* and `cand1` is defined before `cand2`, or they are in different units and
920+
* `cand1` has been selected as an implicit more often than `cand2`.
921+
*/
922+
def prefer(cand1: Candidate, cand2: Candidate): Boolean = {
923+
val sym1 = cand1.ref.symbol
924+
val sym2 = cand2.ref.symbol
925+
if (sym1.associatedFile == sym2.associatedFile) {
926+
val coord1 = sym1.coord
927+
val coord2 = sym2.coord
928+
if (coord1.isPosition && coord2.isPosition) {
929+
val pos1 = coord1.toPosition
930+
val pos2 = coord2.toPosition
931+
return pos1.exists && (!pos2.exists || pos1.start < pos2.start)
932+
}
933+
if (coord1.isIndex && coord2.isIndex)
934+
return coord1.toIndex < coord2.toIndex
935+
}
936+
ranking(cand1) < ranking(cand2)
937+
}
938+
918939
/** Sort list of implicit references according to their popularity
919940
* (# of times each was picked in current run).
920941
*/
921942
def sort(eligible: List[Candidate]) = eligible match {
922943
case Nil => eligible
923944
case e1 :: Nil => eligible
924945
case e1 :: e2 :: Nil =>
925-
if (ranking(e2) < ranking(e1)) e2 :: e1 :: Nil
946+
if (prefer(e2, e1)) e2 :: e1 :: Nil
926947
else eligible
927-
case _ => eligible.sortBy(ranking)
948+
case _ => eligible.sortWith(prefer)
928949
}
929950

930951
val (successes, failures) = rankImplicits(sort(eligible), Nil, new mutable.ListBuffer)

0 commit comments

Comments
 (0)