bug
bug copied to clipboard
StackOverflowError in typer when an existential type is passed to unapply
Reproduction steps
Ok, this little pos is a bit complex:
trait POS[O] { type Value }
trait BigPOS[V, O] extends POS[O] { type Value = V }
trait BadJoke[V, +T[_]]
trait Root[V] extends BadJoke[V, Root]
trait Bugger[M[O] <: POS[O]] extends Root[M[Unit]#Value]
trait Fokker[M[O] <: BigPOS[V, O], V] extends Bugger[M]
object Root {
def unapply[X](e :Root[X]) :Option[Unit] = None
}
object Bugger {
def unapply[X](e :Root[X]) :Option[Fokker[M, V]] forSome { type M[O] <: BigPOS[V, O]; type V } = ???
def error[X](e :Root[X]) = e match {
case Bugger(Root(_)) => ()
}
}
Problem
Crucial factors:
M[Unit]#Valueused as the type argument toRootunapply, or at least using anOptionor otherwise wrapping the result ofBugger.unapply, as dropping theOption[_]wrapper from theunapplyresults and composing the calls normally works.- What's most amusing here, is that
BadJokewhich seems to do nothing here, is actually crucial: removing it makes the whole clusterf$$$ compile.
java.lang.StackOverflowError
at scala.reflect.internal.Types$TypeVar.registerTypeEquality(Types.scala:3701)
at scala.reflect.internal.tpe.TypeComparers.mutateNonTypeConstructs$1(TypeComparers.scala:217)
at scala.reflect.internal.tpe.TypeComparers.isSameType2(TypeComparers.scala:261)
at scala.reflect.internal.tpe.TypeComparers.isSameType2$(TypeComparers.scala:198)
at scala.reflect.internal.SymbolTable.isSameType2(SymbolTable.scala:28)
at scala.reflect.internal.tpe.TypeComparers.isSameType1(TypeComparers.scala:142)
at scala.reflect.internal.tpe.TypeComparers.isSameType(TypeComparers.scala:117)
at scala.reflect.internal.tpe.TypeComparers.isSameType$(TypeComparers.scala:105)
at scala.reflect.internal.SymbolTable.isSameType(SymbolTable.scala:28)
at scala.reflect.internal.Types$Type.$eq$colon$eq(Types.scala:864)
at scala.reflect.internal.Types$TypeVar.checkIsSameType$1(Types.scala:3697)
at scala.reflect.internal.Types$TypeVar.registerTypeEquality(Types.scala:3702)
at scala.reflect.internal.tpe.TypeComparers.mutateNonTypeConstructs$1(TypeComparers.scala:217)
at scala.reflect.internal.tpe.TypeComparers.isSameType2(TypeComparers.scala:261)
at scala.reflect.internal.tpe.TypeComparers.isSameType2$(TypeComparers.scala:198)
at scala.reflect.internal.SymbolTable.isSameType2(SymbolTable.scala:28)
at scala.reflect.internal.tpe.TypeComparers.isSameType1(TypeComparers.scala:142)
at scala.reflect.internal.tpe.TypeComparers.isSameType(TypeComparers.scala:117)
at scala.reflect.internal.tpe.TypeComparers.isSameType$(TypeComparers.scala:105)
at scala.reflect.internal.SymbolTable.isSameType(SymbolTable.scala:28)
at scala.reflect.internal.Types$Type.$eq$colon$eq(Types.scala:864)
at scala.reflect.internal.Types$TypeVar.checkIsSameType$1(Types.scala:3697)
at scala.reflect.internal.Types$TypeVar.registerTypeEquality(Types.scala:3702)
at scala.reflect.internal.tpe.TypeComparers.mutateNonTypeConstructs$1(TypeComparers.scala:217)
I lost a loving week on isolating it, and looking at how it involves both existentials and abstract type projection, I know it's unlikely to ever get fixed :,,(
in Scala 3 there isn't forSome at all, so... neither fixed or not fixed in Scala 3
though, is the forSome actual crucial to the minimization here?
regardless, you're also using # on a type parameter, which Scala 3 doesn't allow