scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.86k stars 1.06k forks source link

Typer regression due to GADT changes #15920

Closed WojciechMazur closed 2 years ago

WojciechMazur commented 2 years ago

Compiler version

Works in 3.1.3 Works in 3.2.0-RC4 Fails in 3.2.1 nighty builds

From bisect tool:

Last good release: 3.2.1-RC1-bin-20220711-6efd92d-NIGHTLY
First bad release: 3.2.1-RC1-bin-20220712-7e20b81-NIGHTLY

first bad commit 8b8ba7269eb317d0338141a9378d71600a2ba854 by @dwijnand

Minimized code

final class EitherIdOps[A](private val obj: A) extends AnyVal:
  def asLeft[B]: Either[A, B] = Left(obj)
  def asRight[B]: Either[B, A] = Right(obj)

object either:
  implicit final def catsSyntaxEitherId[A](a: A): EitherIdOps[A] = ???

trait ApplicativeError[F[_], E]
final class ApplicativeErrorOps[F[_], E, A](private val fa: F[A])
    extends AnyVal {
  def handleError(f: E => A): F[A] = ???
}
final def catsSyntaxApplicativeError[F[_], E, A](fa: F[A])(implicit
    F: ApplicativeError[F, E]
): ApplicativeErrorOps[F, E, A] = ???

object IO:
  case class Attempt[+A](ioa: IO[A]) extends IO[Either[Throwable, A]]
sealed abstract class IO[+A]:
  def attempt: IO[Either[Throwable, A]] = IO.Attempt(this)
  def syncStep: SyncIO[Either[IO[A], A]] = {
    def interpret[B](io: IO[B]): SyncIO[Either[IO[B], B]] =
      io match {
        case IO.Attempt(ioe) =>
          import either.given
          catsSyntaxApplicativeError {
            interpret(ioe)
              .map {
                case Left(io) => Left(io.attempt)
                case Right(a) => Right(a.asRight[Throwable])
              }
          }.handleError(t => Right(t.asLeft[IO[B]])) // error
      }

    interpret(this)
  }

object SyncIO:
  implicit def syncForSyncIO: ApplicativeError[SyncIO, Throwable] = ???

sealed abstract class SyncIO[+A]:
  def map[B](f: A => B): SyncIO[B] = ???

Output

Compiling project (Scala 3.2.1-RC1-bin-20220823-3ad97df-NIGHTLY, JVM)
[error] ./test.scala:32:36: Found:    Either[Throwable, IO[B]]
[error] Required: B
[error] 
[error] where:    B is a type in method interpret with bounds >: Either[Throwable, A$1]
[error]           }.handleError(t => Right(t.asLeft[IO[B]]))
[error]                                    ^^^^^^^^^^^^^^^

Expectation

Should compile

dwijnand commented 2 years ago

Yeah, if you look at the rest of the PR there's associated the change to cats-effect, i.e. https://github.com/dotty-staging/cats-effect/commit/3a32c0e5b7b61665e5bb94ccf0ed92beb66615dd so this isn't a regression.