Skip to content

Commit

Permalink
Compensate loss of transitivity
Browse files Browse the repository at this point in the history
We only have transitivity between givens or between implicits. To cope with that

 - We tank first all implicits, giving a best implicit search result.
 - Then we rank all givens startign with the implicit result. If there is
   a given that is better than the best implicit, the best given will be chosen.
   Otherwise we will stick with the best implicit.
  • Loading branch information
odersky authored and WojciechMazur committed Aug 7, 2024
1 parent 07ccc8d commit 8a41389
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 3 deletions.
18 changes: 15 additions & 3 deletions compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1381,8 +1381,6 @@ trait Implicits:
def disambiguate(alt1: SearchResult, alt2: SearchSuccess) = alt1 match
case alt1: SearchSuccess =>
var diff = compareAlternatives(alt1, alt2, disambiguate = true)
assert(diff <= 0 || isWarnPriorityChangeVersion(Feature.sourceVersion))
// diff > 0 candidates should already have been eliminated in `rank`
if diff == 0 && alt1.ref =:= alt2.ref then
diff = 1 // See i12951 for a test where this happens
else if diff == 0 && alt2.isExtension then
Expand Down Expand Up @@ -1622,7 +1620,21 @@ trait Implicits:
validateOrdering(ord)
throw ex

val result = rank(sort(eligible), NoMatchingImplicitsFailure, Nil)
val sorted = sort(eligible)
val result = sorted match
case first :: rest =>
val firstIsImplicit = first.ref.symbol.is(Implicit)
if rest.exists(_.ref.symbol.is(Implicit) != firstIsImplicit) then
// Mixture of implicits and givens
// Rank implicits first, then, if there is a given that it better than the best implicit(s)
// switch over to givens.
val (sortedImplicits, sortedGivens) = sorted.partition(_.ref.symbol.is(Implicit))
val implicitResult = rank(sortedImplicits, NoMatchingImplicitsFailure, Nil)
rank(sortedGivens, implicitResult, Nil)
else
rank(sorted, NoMatchingImplicitsFailure, Nil)
case _ =>
NoMatchingImplicitsFailure

// Issue all priority change warnings that can affect the result
val shownWarnings = priorityChangeWarnings.toList.collect:
Expand Down
13 changes: 13 additions & 0 deletions tests/pos/given-owner-disambiguate.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class General
class Specific extends General

class LowPriority:
given a:General()

object NormalPriority extends LowPriority:
given b:Specific()

def run =
import NormalPriority.given
val x = summon[General]
val _: Specific = x // <- b was picked

0 comments on commit 8a41389

Please sign in to comment.