Skip to content

Commit 0de4a2f

Browse files
Fix healAmbiguous to compareAlternatives with disambiguate = true
On the final result, compared with all the ambiguous candidates we are trying to recover from. We should still use `disambiguate = false` when filtering the `pending` candidates for the purpose of warnings, as in the other cases. Before, we could heal an ambiguous SearchFailure with a candidate which was considered better only under the alternative given prioritization scheme, see scala#21045 for details.
1 parent 9b6a73e commit 0de4a2f

File tree

4 files changed

+21
-23
lines changed

4 files changed

+21
-23
lines changed

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

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,9 +1439,14 @@ trait Implicits:
14391439
* candidate that is strictly better than the failed candidate(s).
14401440
* If no such candidate is found, we propagate the ambiguity.
14411441
*/
1442-
def healAmbiguous(fail: SearchFailure, betterThanFailed: Candidate => Boolean) =
1443-
val newPending = remaining.filter(betterThanFailed)
1444-
rank(newPending, fail, Nil).recoverWith(_ => fail)
1442+
def healAmbiguous(fail: SearchFailure, ambiguousCands: List[RefAndLevel]) =
1443+
def betterThanAll(newCand: RefAndLevel, disambiguate: Boolean): Boolean =
1444+
ambiguousCands.forall(compareAlternatives(newCand, _, disambiguate) > 0)
1445+
1446+
val newPending = remaining.filter(betterThanAll(_, disambiguate = false))
1447+
rank(newPending, fail, Nil) match
1448+
case found: SearchSuccess if betterThanAll(found, disambiguate = true) => found
1449+
case _ => fail
14451450

14461451
negateIfNot(tryImplicit(cand, contextual)) match {
14471452
case fail: SearchFailure =>
@@ -1456,8 +1461,7 @@ trait Implicits:
14561461
else
14571462
// The ambiguity happened in a nested search: to recover we
14581463
// need a candidate better than `cand`
1459-
healAmbiguous(fail, newCand =>
1460-
compareAlternatives(newCand, cand) > 0)
1464+
healAmbiguous(fail, cand :: Nil)
14611465
else
14621466
// keep only warnings that don't involve the failed candidate reference
14631467
priorityChangeWarnings.filterInPlace: (critical, _) =>
@@ -1476,9 +1480,7 @@ trait Implicits:
14761480
// The ambiguity happened in the current search: to recover we
14771481
// need a candidate better than the two ambiguous alternatives.
14781482
val ambi = fail.reason.asInstanceOf[AmbiguousImplicits]
1479-
healAmbiguous(fail, newCand =>
1480-
compareAlternatives(newCand, ambi.alt1) > 0 &&
1481-
compareAlternatives(newCand, ambi.alt2) > 0)
1483+
healAmbiguous(fail, ambi.alt1 :: ambi.alt2 :: Nil)
14821484
}
14831485
}
14841486
case nil =>

tests/neg/i21212.check

Lines changed: 0 additions & 4 deletions
This file was deleted.

tests/neg/i21212.scala

Lines changed: 0 additions & 11 deletions
This file was deleted.

tests/pos/i21212.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,14 @@ class UsingArguments[F[_]](using Temporal[F])(using err: MonadError[F, Throwable
2020
val bool: F[Boolean] = ???
2121
def works = toFunctorOps(bool).map(_ => ()) // warns under -source:3.5
2222

23+
24+
object Minimization:
25+
26+
trait A
27+
trait B extends A
28+
29+
def test1(using a1: A)(using b1: B) = summon[A] // picks (most general) a1
30+
def test2(using a2: A)(implicit b2: B) = summon[A] // picks (most general) a2, was ambiguous
31+
def test3(implicit a3: A, b3: B) = summon[A] // picks (most specific) b3
32+
33+
end Minimization

0 commit comments

Comments
 (0)