Skip to content

Commit 36fb21d

Browse files
committed
Fix onwer comparison when sorting eligible implicits
We used the wrong symbols to compare, which in effect meant that we sorted eligible implicits wuthout taking owner subtyping into account. This way, we might consider canidates first that would then later be pruned by another sccesful candidate in a subclass, so the search tree would be larger. Fixes #10964
1 parent 141bf9e commit 36fb21d

File tree

3 files changed

+117
-1
lines changed

3 files changed

+117
-1
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1250,7 +1250,7 @@ trait Implicits:
12501250
val arity2 = sym2.info.firstParamTypes.length
12511251
if arity1 < arity2 then return true
12521252
if arity1 > arity2 then return false
1253-
compareOwner(sym1, sym2) == 1
1253+
compareOwner(sym1.owner, sym2.owner) == 1
12541254

12551255
/** Sort list of implicit references according to `prefer`.
12561256
* This is just an optimization that aims at reducing the average

tests/pos/i10964.scala

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
trait Applicative[F[_]]
2+
3+
trait FooT[F[_], A]
4+
trait BarT[F[_], A]
5+
trait QuxT[F[_], A]
6+
trait BazT[F[_], A]
7+
trait ZepT[F[_], A]
8+
trait JazT[F[_], A]
9+
trait LafT[F[_], A]
10+
trait PogT[F[_], A]
11+
12+
trait Sync[F[_]]
13+
object Sync {
14+
implicit def syncForFooT[F[_]](implicit F0: Sync[F]): Sync[[X] =>> FooT[F, X]] = ???
15+
implicit def syncForBarT[F[_]](implicit F0: Sync[F]): Sync[[X] =>> BarT[F, X]] = ???
16+
implicit def syncForQuxT[F[_]](implicit F0: Sync[F]): Sync[[X] =>> QuxT[F, X]] = ???
17+
implicit def syncForBazT[F[_]](implicit F0: Sync[F]): Sync[[X] =>> BazT[F, X]] = ???
18+
implicit def syncForZepT[F[_]](implicit F0: Sync[F]): Sync[[X] =>> ZepT[F, X]] = ???
19+
implicit def syncForJazT[F[_]](implicit F0: Sync[F]): Sync[[X] =>> JazT[F, X]] = ???
20+
// defining additional implicits beyond the 6 above seems to result in hang/OOM
21+
implicit def syncForLafT[F[_]](implicit F0: Sync[F]): Sync[[X] =>> LafT[F, X]] = ???
22+
implicit def syncForPogT[F[_]](implicit F0: Sync[F]): Sync[[X] =>> PogT[F, X]] = ???
23+
}
24+
25+
trait Ref[F[_], A]
26+
object Ref {
27+
trait Make[F[_]]
28+
object Make extends MakeInstances
29+
30+
trait MakeInstances extends MakeLowPriorityInstances {
31+
implicit def applicativeInstance[F[_]](implicit F: Applicative[F]): Make[F] = ???
32+
}
33+
34+
trait MakeLowPriorityInstances {
35+
implicit def syncInstance[F[_]](implicit F: Sync[F]): Make[F] = ???
36+
}
37+
38+
def of[F[_], A](a: A)(implicit mk: Make[F]): F[Ref[F, A]] = ???
39+
}
40+
41+
class Resource[F[_], A] {
42+
implicit def syncForResource[F[_]](implicit F0: Sync[F]): Sync[[X] =>> Resource[F, X]] = ???
43+
44+
def foo(x: F[Unit])(implicit F: Applicative[F]) = {
45+
Ref.of /*[F, (F[Unit], F[Unit])]*/ ((x, x))
46+
()
47+
}
48+
}

tests/pos/i10964a.scala

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
trait Monoid[A]
2+
trait Semigroup[A]
3+
trait Applicative[F[_]]
4+
5+
trait OptionT[F[_], A]
6+
trait EitherT[F[_], A, B]
7+
trait IorT[F[_], A, B]
8+
trait WriterT[F[_], L, V]
9+
trait Kleisli[F[_], A, B]
10+
11+
final class ApplicativeIdOps[A](private val a: A) extends AnyVal {
12+
def pure[F[_]](implicit F: Applicative[F]): F[A] = ???
13+
}
14+
15+
object ApplicativeSyntax {
16+
implicit final def syntaxApplicativeId[A](a: A): ApplicativeIdOps[A] = new ApplicativeIdOps[A](a)
17+
}
18+
19+
trait Sync[F[_]]
20+
21+
object Sync {
22+
implicit def syncForOptionT[F[_]](implicit F0: Sync[F]): Sync[[X] =>> OptionT[F, X]] = ???
23+
implicit def syncForEitherT[F[_], E](implicit F0: Sync[F]): Sync[[X] =>> EitherT[F, E, X]] = ???
24+
implicit def syncForIorT[F[_], L](implicit F0: Sync[F], L0: Semigroup[L]): Sync[[X] =>> IorT[F, L, X]] = ???
25+
implicit def syncForWriterT[F[_], L](implicit F0: Sync[F], L0: Monoid[L]): Sync[[X] =>> WriterT[F, L, X]] = ???
26+
implicit def syncForKleisli[F[_], R](implicit F0: Sync[F]): Sync[[X] =>> Kleisli[F, R, X]] = ???
27+
}
28+
29+
trait Async[F[_]] extends Sync[F]
30+
31+
object Async {
32+
implicit def asyncForOptionT[F[_]](implicit F0: Async[F]): Async[[X] =>> OptionT[F, X]] = ???
33+
implicit def asyncForEitherT[F[_], E](implicit F0: Async[F]): Async[[X] =>> EitherT[F, E, X]] = ???
34+
implicit def asyncForIorT[F[_], L](implicit F0: Async[F], L0: Semigroup[L]): Async[[X] =>> IorT[F, L, X]] = ???
35+
implicit def asyncForWriterT[F[_], L](implicit F0: Async[F], L0: Monoid[L]): Async[[X] =>> WriterT[F, L, X]] = ???
36+
implicit def asyncForKleisli[F[_], R](implicit F0: Async[F]): Async[[X] =>> Kleisli[F, R, X]] = ???
37+
}
38+
39+
trait Concurrent[F[_], E] extends Applicative[F]
40+
41+
trait Ref[F[_], A]
42+
43+
object Ref {
44+
trait Make[F[_]]
45+
object Make extends MakeInstances
46+
47+
trait MakeInstances extends MakeLowPriorityInstances {
48+
implicit def concurrentInstance[F[_]](implicit F: Concurrent[F, _]): Make[F] = ???
49+
}
50+
51+
trait MakeLowPriorityInstances {
52+
implicit def syncInstance[F[_]](implicit F: Sync[F]): Make[F] = ???
53+
}
54+
55+
def of[F[_], A](a: A)(implicit mk: Make[F]): F[Ref[F, A]] = ???
56+
}
57+
58+
59+
class Resource[F[_], A] {
60+
import ApplicativeSyntax._
61+
62+
implicit def asyncForResource[F[_]](implicit F0: Async[F]): Async[[X] =>> Resource[F, X]] = ???
63+
64+
def parZip(implicit F: Concurrent[F, Throwable]) = {
65+
Ref.of /*[F, (F[Unit], F[Unit])]*/ (().pure[F] -> ().pure[F])
66+
()
67+
}
68+
}

0 commit comments

Comments
 (0)