scala3
scala3 copied to clipboard
Compiler cannot choose correct overloaded method with default argument
Compiler version
3.2.0, 3.2.1-RC1, haven't checked earlier versions
Minimized code
Original code
//> using scala "3.2.1-RC1"
//> using lib "org.typelevel::cats-core:2.8.0"
//> using lib "org.typelevel::cats-effect:3.3.11"
import cats.Functor
import cats.Monad
import cats.Parallel
import cats.effect.Concurrent
import cats.effect.IO
import cats.effect.Resource
import cats.effect.Temporal
import cats.syntax.all._
import scala.concurrent.duration.FiniteDuration
import scala.concurrent.duration._
trait Cache[F[_], K, V]
object Cache {
final case class Refresh[-K, +V](interval: FiniteDuration, value: K => V)
final case class Config[F[_], -K, V](
expireAfterRead: FiniteDuration,
expireAfterWrite: Option[FiniteDuration] = None,
maxSize: Option[Int] = None,
refresh: Option[Refresh[K, F[Option[V]]]] = None
)
def expiring[F[_]: Concurrent: Temporal: Parallel, K, V](
expireAfter: FiniteDuration
): Resource[F, Cache[F, K, V]] = ???
def expiring[F[_]: Temporal: Parallel, K, V](
config: Config[F, K, V],
partitions: Option[Int] = None
): Resource[F, Cache[F, K, V]] = ???
/* Without partitions being specified, error is yielded */
val notCompiling = expiring[IO, Int, Int](
config = Config[IO, Int, Int](expireAfterRead = 1.minute),
)
val compiling = expiring[IO, Int, Int](
config = Config[IO, Int, Int](expireAfterRead = 1.minute),
partitions = None
)
}
Minimized reproduction
//> using scala "3.2.1-RC1"
//> using lib "org.typelevel::cats-effect:3.3.11"
import scala.concurrent.duration.FiniteDuration
import scala.concurrent.duration._
import cats.effect.kernel.Resource
import cats.effect.IO
trait Cache[F[_], K, V]
object Cache {
final case class Config(expireAfterRead: FiniteDuration)
def expiring[F[_], K, V](
expireAfter: FiniteDuration
): Resource[F, Cache[F, K, V]] = ???
def expiring[F[_], K, V](
config: Config,
partitions: Option[Int] = None
): Resource[F, Cache[F, K, V]] = ???
/* Without partitions being specified, error is yielded */
val notCompiling = expiring[IO, Int, Int](
config = Config(expireAfterRead = 1.minute)
)
val compiling = expiring[IO, Int, Int](
config = Config(expireAfterRead = 1.minute),
partitions = None
)
}
Output
None of the overloaded alternatives of method expiring in object Cache with types
[F[_$3], K, V]
(config: Cache.Config, partitions: Option[Int]):
cats.effect.kernel.Resource[F, Cache[F, K, V]]
[F[_$2], K, V]
(expireAfter: concurrent.duration.FiniteDuration):
cats.effect.kernel.Resource[F, Cache[F, K, V]]
match type arguments [cats.effect.IO, Int, Int] and arguments (Cache.Config)
Expectation
Compiler is able to pick correct overloaded method even without partitions specified explicitly.
It seems like this code was able to compile (I've checked 3.0, 3.1 versions too.). A possible workaround until fixing it in compiler:
val x: Resource[IO, Cache[IO, Int, Int]] = expiring(
config = Config(expireAfterRead = 1.minute)
)
works on 3.2.2, 3.3.x, 2.13.11
Here's a minimization without the Cats Effect dependency. Maybe it can be added as a regression test and we can close this issue?
//> using scala "3.2.1-RC1"
import scala.concurrent.duration.FiniteDuration
import scala.concurrent.duration._
trait Resource[F[_], A]
trait IO[A]
trait Cache[F[_], K, V]
object Cache {
final case class Config(expireAfterRead: FiniteDuration)
def expiring[F[_], K, V](
expireAfter: FiniteDuration
): Resource[F, Cache[F, K, V]] = ???
def expiring[F[_], K, V](
config: Config,
partitions: Option[Int] = None
): Resource[F, Cache[F, K, V]] = ???
/* Without partitions being specified, error is yielded */
val notCompiling = expiring[IO, Int, Int](
config = Config(expireAfterRead = 1.minute)
)
val compiling = expiring[IO, Int, Int](
config = Config(expireAfterRead = 1.minute),
partitions = None
)
}
Ha, I didn't understand where you were going in chat. Yes, I had that minimization locally last year. Today I was trying out the OP before deleting my local test.
It never hurts to add a test (generally). Possibly this progression must surely be covered, but I did not investigate what fixed it.
By coincidence, another issue deserves a test and it's less trivial https://github.com/lampepfl/dotty/issues/17601#issuecomment-1685478600
So either the test is trivial and must already exist, or it's too non-trivial to be worth the maintenance?
Probably ChatGPT could tell us what existing tests look similar.