Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Compiler hang with covariant type constructor in GADT #14287

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
# for free to join this conversation on GitHub. Already have an account? # to comment