scala / scala3

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

Compiler crash in code with some possible variance issues and explicitly extended enum cases #12957

Open bbarker opened 3 years ago

bbarker commented 3 years ago

Compiler version

3.0.0

Minimized code

This code demonstrates the issue, and is somewhat minimized from the actual codebase:

object Types:
  import Widget.*
  import WidgetHandle.*

  enum IO[+E, +A]:
    case Err(error: E)
    case Value(value: A)

  type Callback[V, E, A] = (Result[V, E, A] => IO[E, Unit]) => IO[E, WidgetHandle[V, E, A]]
  object Callback:
    def map[V, E, E1 >: E, A, B](fn: A => B)(cb: Callback[V,E,A]): Callback[V,E,B] = ???  

  object WidgetHandle:
    opaque type WidgetHandle[+V,+E,+A] = IO[E, Callback[V, E, A]]
    def map[V,E,A,B](fn: A => B)(wh: WidgetHandle[V,E,A]): WidgetHandle[V,E,B] = ???

  case class ZipList[A](left: List[A], right: List[A])
  object ZipList:
    def map[A,B](fn: A => B)(zl: ZipList[A]): ZipList[B] =
      ZipList(zl.left.map(fn), zl.right.map(fn))

  enum Result[+V, +E, +A]:
    case View(view: V)
    case Eff(eff: IO[E, Unit])
    case Res[V, E, A](result: A, remaining: Unit => ZipList[Result[V,E,A]]) extends Result[V,E,A]
  object Result:
    def map[V,E, E1 >: E, A,B](fn: A => B)(res: Result[V,E,A]): Result[V,E,B] = res match
      case View(v) => View(v)
      case Eff(e) => Eff(e)
      case Res(res, rem) => Res(fn(res), _ => ZipList.map(Result.map[V,E,E1,A,B](fn))(rem(())) )

  object Widget:
    opaque type Widget[+V, +E, +A] = Callback[V,E,A]

The following code, which removes Callback from the picture, compiles:

object Types:
  import Widget.*
  import WidgetHandle.*

  enum IO[+E, +A]:
    case Err(error: E)
    case Value(value: A)

  object WidgetHandle:
    opaque type WidgetHandle[+V,+E,+A] = IO[E, Result[V, E, A]]
    def map[V,E,A,B](fn: A => B)(wh: WidgetHandle[V,E,A]): WidgetHandle[V,E,B] = ???

  case class ZipList[A](left: List[A], right: List[A])
  object ZipList:
    def map[A,B](fn: A => B)(zl: ZipList[A]): ZipList[B] =
      ZipList(zl.left.map(fn), zl.right.map(fn))

  enum Result[+V, +E, +A]:
    case View(view: V)
    case Eff(eff: IO[E, Unit])
    case Res[V, E, A](result: A, remaining: Unit => ZipList[Result[V,E,A]]) extends Result[V,E,A]
  object Result:
    def map[V,E, E1 >: E, A,B](fn: A => B)(res: Result[V,E,A]): Result[V,E,B] = res match
      case View(v) => View(v)
      case Eff(e) => Eff(e)
      case Res(res, rem) => Res(fn(res), _ => ZipList.map(Result.map[V,E,E1,A,B](fn))(rem(())) )

  object Widget:
    opaque type Widget[+V, +E, +A] = Result[V,E,A]

Output (click arrow to expand)

sbt:scala-zio-concur> concurJVM/compile
[info] compiling 1 Scala source to /home/brandon/workspace/scala-zio-concur/concur/jvm/target/scala-3.0.0/classes ...
Error while emitting Types.scala
java.lang.StackOverflowError while compiling /home/brandon/workspace/scala-zio-concur/concur/shared/src/main/scala/concur/Types.scala
[error] ## Exception when compiling 2 sources to /home/brandon/workspace/scala-zio-concur/concur/jvm/target/scala-3.0.0/classes
[error] java.lang.StackOverflowError
[error] dotty.tools.dotc.core.Types$TypeAccumulator.foldOver(Types.scala:5623)
[error] dotty.tools.dotc.transform.GenericSignatures$NeedsSigCollector.apply(GenericSignatures.scala:484)
[error] dotty.tools.dotc.transform.GenericSignatures$.needs$1(GenericSignatures.scala:458)
[error] dotty.tools.dotc.transform.GenericSignatures$.needsJavaSig(GenericSignatures.scala:459)
[error] dotty.tools.dotc.transform.GenericSignatures$.classSig$2(GenericSignatures.scala:206)
[error] dotty.tools.dotc.transform.GenericSignatures$.jsig$1(GenericSignatures.scala:288)
[error] dotty.tools.dotc.transform.GenericSignatures$.boxedSig$1(GenericSignatures.scala:67)
[error] dotty.tools.dotc.transform.GenericSignatures$.argSig$1(GenericSignatures.scala:201)
[error] dotty.tools.dotc.transform.GenericSignatures$.classSig$1$$anonfun$1(GenericSignatures.scala:233)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error] scala.collection.immutable.List.foreach(List.scala:333)
[error] dotty.tools.dotc.transform.GenericSignatures$.classSig$2(GenericSignatures.scala:233)
[error] dotty.tools.dotc.transform.GenericSignatures$.jsig$1(GenericSignatures.scala:288)
[error] dotty.tools.dotc.transform.GenericSignatures$.boxedSig$1(GenericSignatures.scala:67)
[error] dotty.tools.dotc.transform.GenericSignatures$.argSig$1(GenericSignatures.scala:201)
[error] dotty.tools.dotc.transform.GenericSignatures$.classSig$1$$anonfun$1(GenericSignatures.scala:233)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error] scala.collection.immutable.List.foreach(List.scala:333)
[error] dotty.tools.dotc.transform.GenericSignatures$.classSig$2(GenericSignatures.scala:233)
[error] dotty.tools.dotc.transform.GenericSignatures$.jsig$1(GenericSignatures.scala:288)
[error] dotty.tools.dotc.transform.GenericSignatures$.boxedSig$1(GenericSignatures.scala:67)
[error] dotty.tools.dotc.transform.GenericSignatures$.argSig$1(GenericSignatures.scala:201)
[error] dotty.tools.dotc.transform.GenericSignatures$.classSig$1$$anonfun$1(GenericSignatures.scala:233)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error] scala.collection.immutable.List.foreach(List.scala:333)
[error] dotty.tools.dotc.transform.GenericSignatures$.classSig$2(GenericSignatures.scala:233)
[error] dotty.tools.dotc.transform.GenericSignatures$.jsig$1(GenericSignatures.scala:288)
[error] dotty.tools.dotc.transform.GenericSignatures$.boxedSig$1(GenericSignatures.scala:67)
[error] dotty.tools.dotc.transform.GenericSignatures$.argSig$1(GenericSignatures.scala:201)
[error] dotty.tools.dotc.transform.GenericSignatures$.classSig$1$$anonfun$1(GenericSignatures.scala:233)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error] scala.collection.immutable.List.foreach(List.scala:333)
[error] dotty.tools.dotc.transform.GenericSignatures$.classSig$2(GenericSignatures.scala:233)
[error] dotty.tools.dotc.transform.GenericSignatures$.jsig$1(GenericSignatures.scala:288)
[error] dotty.tools.dotc.transform.GenericSignatures$.boxedSig$1(GenericSignatures.scala:67)
[error] dotty.tools.dotc.transform.GenericSignatures$.argSig$1(GenericSignatures.scala:201)
[error] dotty.tools.dotc.transform.GenericSignatures$.classSig$1$$anonfun$1(GenericSignatures.scala:233)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error] scala.collection.immutable.List.foreach(List.scala:333)

Truncated (thousands of lines follow)

griggt commented 3 years ago

This smaller example seems to exhibit the same StackOverflowError:

import WidgetHandle.*

type Callback[A] = A => WidgetHandle[A]
object Callback:
  def foo[A](cb: Callback[A]): Unit = ???

object WidgetHandle:
  opaque type WidgetHandle[A] = Callback[A]