This is a problem with "recursive" nested objects, whose creation can loop infinitely. The above example can be reduced even more, as follows:
object stackOverflow {
object m { m }
def main(args: Array[String]): Unit = { m; }
}
This gets expanded by RefCheck to:
// Scala source: bug216.scala
final class stackOverflow() extends scala.Object() {
final class m() extends scala.Object() {
stackOverflow.m
};
private var m$: stackOverflow.m = null;
final def m: stackOverflow.m = {
if (null.$eq$eq(stackOverflow.m$))
stackOverflow.m$ = new stackOverflow.m()
else
{
};
stackOverflow.m$
};
private def m_$eq(m: stackOverflow.m): scala.Unit = stackOverflow.m$ = m;
final def main(args: scala.Array[java.lang.String]): scala.Unit = {
stackOverflow.m;
{
}
}
};
final /*object*/ val stackOverflow: stackOverflow = new stackOverflow();
Here we see that to build m we need m itself, which results in an endless chain of calls to the m() function. For top-level modules, this has been fixed by assigning the field containing the module instance at the very beginning of the module's constructor. Something similar could be done here, by adding a
stackOverflow.m$ = this;
at the very beginning of class m so that this is the first thing done at construction. However, this is a bit fragile since we have no way of guaranteeing that later phases won't put code before that assignment. I don't see a clean solution with the current tree.
|