-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Type inference regression with implicit extension methods. #9480
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
So I've spent a while staring at this and I think this isn't fixable unfortunatel (skip to the bottom of this message for some actual suggestions on what to do). It can be reduced to: trait Monad[F[_]]
class ST[A, B]
class MonadOps[M[_], A](ma: M[A]) {
def whileM_(p: M[Boolean]): M[Unit] = ???
}
object Test {
def inspect[C, D](f: C => D): ST[C, D] = ???
val increment: ST[Int, Unit] = ???
new MonadOps(increment).whileM_(inspect(i => i > 4))
} In the last expression, we start by typing the new call which gives us: new MonadOps[?M, ?A](increment)
where
?M >: [X] =>> ST[Int, X]
?A := Unit Because we only constrained one bound of object Test {
def foo[A >: List[B], B](x: A)(y: B => Boolean): Unit = ???
val li: List[Int] = ???
foo(li)(x => x > 0) // error
} Intuitively, we'd probably like to infer ?A >: List[?B] | List[Int] If we were to instantiate So why does the original example work in Scala 2? I haven't investigated in details but I suspect it's just because Scala 2 will eagerly instantiate class Bar[+B, A]
object Test {
def foo[F[_]](x: F[Int])(y: F[Int]): F[Unit] = ???
val z = foo(new Bar[String, Int])(new Bar[Int, Int])
// Result type is Bar[String | Int, Unit]
} OK, so what can be done in cats concretely to deal with this? Let's look again at the original extension method: implicit class MonadOps[F[_], A](private val fa: F[A]) extends AnyVal {
def whileM_(p: F[Boolean])(implicit M: Monad[F]): F[Unit] = ???
} The interesting thing is that we don't really need to type the parameter implicit class MonadOps[F[_], A](private val fa: F[A]) extends AnyVal {
def whileM_(using M: Monad[F])(p: F[Boolean]): F[Unit] = ???
} And as if by magic, everything typechecks now! This works because doing the implicit search on I was hoping that using an actual Dotty extension method would also work: trait Monad[F[_]] {
extension [A] (fa: F[A]) def whileM_(p: F[Boolean]): F[Unit] = ???
} But that doesn't seem to work, haven't investigated why yet. Anyway, I'll leave this issue open for a few days but will probably close it as won't fix afterwards. |
Any idea if I can run implicit search before searching for |
Yes, but it'll cost an allocation: implicit class MonadOps[F[_], A](private val fa: F[A]) extends AnyVal {
def whileM_(implicit M: Monad[F]): F[Boolean] => F[Unit] = ???
} It also breaks binary compatibility so not really an option for cats, I think separate source files for the scala 2 and 3 versions can't be avoided. |
That won't work without using |
Okay cool, thanks for your help! |
Seems there's nothing we can do in the short term about this |
Uh oh!
There was an error while loading. Please reload this page.
Minimized code
Output
Expectation
This should compile fine as it does in Scala 2.
The text was updated successfully, but these errors were encountered: