Skip to content

Compiler hang with covariant type constructor in GADT #14287

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

Closed
mpilquist opened this issue Jan 17, 2022 · 1 comment · Fixed by #15683
Closed

Compiler hang with covariant type constructor in GADT #14287

mpilquist opened this issue Jan 17, 2022 · 1 comment · Fixed by #15683

Comments

@mpilquist
Copy link
Contributor

mpilquist commented Jan 17, 2022

Compiler version

3.1.1-RC2

Minimized code

// using scala 3.1.1-RC2

enum Free[+F[_], A]:
  case Return(a: A)
  case Suspend(s: F[A])
  case FlatMap[F[_], A, B](
    s: Free[F, A],
    f: A => Free[F, B]) extends Free[F, B]

  def flatMap[F2[x] >: F[x], B](f: A => Free[F2,B]): Free[F2,B] =
    FlatMap(this, f)

  @annotation.tailrec
  final def step: Free[F, A] = this match
    case FlatMap(FlatMap(fx, f), g) => fx.flatMap(x => f(x).flatMap(y => g(y))).step
    case FlatMap(Return(x), f) => f(x).step
    case _ => this

Output

Compilation hangs when using scala-cli. In a larger code base, I've seen crashes with stacks like the following, though I haven't reproduced the crash in a standalone program. The hang & crash are both related to making F covariant in the definition of Free.

In the example above, changing the left-associated flatMap case to case FlatMap(FlatMap(fx, f), g) => ??? fixes the issue.

[error] dotty.tools.dotc.core.TypeOps$.dotty$tools$dotc$core$TypeOps$$anon$1$$_$op$proxy5$1(TypeOps.scala:451)
[error] dotty.tools.dotc.core.TypeOps$$anon$1.apply(TypeOps.scala:451)
[error] dotty.tools.dotc.core.TypeOps$$anon$1.apply(TypeOps.scala:451)
[error] dotty.tools.dotc.core.TypeOps$.dotty$tools$dotc$core$TypeOps$$anon$1$$_$op$proxy5$1(TypeOps.scala:451)
[error] dotty.tools.dotc.core.TypeOps$$anon$1.apply(TypeOps.scala:451)
[error] dotty.tools.dotc.core.TypeOps$$anon$1.apply(TypeOps.scala:451)
[error] dotty.tools.dotc.core.TypeOps$.dotty$tools$dotc$core$TypeOps$$anon$1$$_$op$proxy5$1(TypeOps.scala:451)
[error] dotty.tools.dotc.core.TypeOps$$anon$1.apply(TypeOps.scala:451)
[error] dotty.tools.dotc.core.TypeOps$$anon$1.apply(TypeOps.scala:451)
[error] dotty.tools.dotc.core.TypeOps$.dotty$tools$dotc$core$TypeOps$$anon$1$$_$op$proxy5$1(TypeOps.scala:451)

Another workaround is explicitly providing types to the flatMap calls in the problematic expression:

    case FlatMap(FlatMap(fx, f), g) =>
      fx.flatMap[F, A](x => f(x).flatMap[F, A](g)).step
@mpilquist mpilquist changed the title Compiler hang with covariant type constructor Compiler hang with covariant type constructor in GADT Jan 17, 2022
@dwijnand
Copy link
Member

Minimised to

enum Foo[+H[_]]:
  case Bar[F[_]](f: Foo[F]) extends Foo[F]
  case Baz()

  def test: Foo[H] = this match
    case Bar(Bar(f)) => Bar(f)
    case _           => this

It's a case of TypeBounds with circular infos:

avoid F$1 #18787  >: F$2 <: F
avoid F$2 #18891  <: F$1
avoid F$1 #18787  >: F$2 <: F
avoid F$2 #18891  <: F$1

@dwijnand dwijnand linked a pull request Jan 17, 2022 that will close this issue
@anatoliykmetyuk anatoliykmetyuk added stat:needs triage Every issue needs to have an "area" and "itype" label area:gadt and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Jan 25, 2022
@abgruszecki abgruszecki self-assigned this Jul 19, 2022
@dwijnand dwijnand linked a pull request Jul 19, 2022 that will close this issue
@Kordyjan Kordyjan modified the milestones: 3.3.1, 3.3.0 Aug 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment