Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 23 additions & 15 deletions compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1474,25 +1474,33 @@ trait Implicits:
case _ => fail
end healAmbiguous

inline def unrecoverableDivergentImplicit(failure: DivergingImplicit): Boolean =
(pt frozen_=:= failure.expectedType) && remaining.forall(compareAlternatives(_, cand) == 0)

negateIfNot(tryImplicit(cand, contextual)) match {
case fail: SearchFailure =>
if fail eq ImplicitSearchTooLargeFailure then
fail
else if (fail.isAmbiguous)
if migrateTo3 then
val result = rank(remaining, found, NoMatchingImplicitsFailure :: rfailures)
if (result.isSuccess)
warnAmbiguousNegation(fail.reason.asInstanceOf[AmbiguousImplicits])
result
else
// The ambiguity happened in a nested search: to recover we
// need a candidate better than `cand`
healAmbiguous(fail, cand :: Nil)
else
// keep only warnings that don't involve the failed candidate reference
priorityChangeWarnings.filterInPlace: (critical, _) =>
!critical.contains(cand.ref)
rank(remaining, found, fail :: rfailures)
else fail.reason match {
case failure: DivergingImplicit if unrecoverableDivergentImplicit(failure)
=> found.recoverWith(_ => (fail :: rfailures).reverse.maxBy(_.tree.treeSize))
case _ =>
if (fail.isAmbiguous)
if migrateTo3 then
val result = rank(remaining, found, NoMatchingImplicitsFailure :: rfailures)
if (result.isSuccess)
warnAmbiguousNegation(fail.reason.asInstanceOf[AmbiguousImplicits])
result
else
// The ambiguity happened in a nested search: to recover we
// need a candidate better than `cand`
healAmbiguous(fail, cand :: Nil)
else
// keep only warnings that don't involve the failed candidate reference
priorityChangeWarnings.filterInPlace: (critical, _) =>
!critical.contains(cand.ref)
rank(remaining, found, fail :: rfailures)
}
case best: SearchSuccess =>
if (ctx.mode.is(Mode.ImplicitExploration) || isCoherent)
best
Expand Down
40 changes: 40 additions & 0 deletions tests/neg/i24193.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//> using options -Xkind-projector

def summonClock[F[_] : Clock] = ???
def testsummon = {
summonClock // error
}

trait Monad[F[_]]
implicit def inst1[F[_]]: Monad[F] = ???
implicit def inst2[F[_]]: Monad[F] = ???

trait Clock[F[_]]
object Clock {
trait A[F[_], T]
trait B[F[_], T]
trait C[F[_], T]
trait D[F[_], T]
trait E[F[_], T]
trait F1[F[_], T]
trait G[F[_], T]
trait H[F[_], T]

implicit def clockForOptionT[F[_]](implicit F0: Monad[F],
C0: Clock[F]): Clock[A[F, *]] = ???
implicit def clockForEitherT[F[_]](implicit F0: Monad[F],
C0: Clock[F]): Clock[B[F, *]] = ???
implicit def clockForStateT[F[_]](implicit F0: Monad[F],
C0: Clock[F]): Clock[C[F, *]] = ???
implicit def clockForWriterT[F[_]](implicit F0: Monad[F],
C0: Clock[F]): Clock[D[F, *]] = ???
implicit def clockForIorT[F[_]](implicit F0: Monad[F],
C0: Clock[F]): Clock[E[F, *]] = ???

implicit def clockForKleisli[F[_]](implicit F0: Monad[F],
C0: Clock[F]): Clock[F1[F, *]] = ???
implicit def clockForContT[F[_]](implicit F0: Monad[F],
C0: Clock[F]): Clock[G[F, *]] = ???
implicit def clockForReaderWriterStateT[F[_]](implicit F0: Monad[F],
C0: Clock[F]): Clock[H[F, *]] = ???
}
Loading