scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
230 stars 21 forks source link

`LinearSeqOps.lengthCompare` calls `isEmpty`, which calls `lengthCompare`, hence `StackOverflowException` #12805

Closed noresttherein closed 1 year ago

noresttherein commented 1 year ago

Reproduction steps

Scala version: 2.13.11

    class ConstSeq[X](override val head :X, override val knownSize :Int) extends AbstractSeq[X] with LinearSeq[X] {
        override def tail :LinearSeq[X] = {
            if (knownSize == 0)
                throw new UnsupportedOperationException("Seq.empty.tail")
            new ConstSeq(head, knownSize - 1)
        }
    }
    new ConstSeq(42, 2).isEmpty

Problem

Exception in thread "main" java.lang.StackOverflowError
    at scala.collection.LinearSeqOps.lengthCompare(LinearSeq.scala:95)
    at scala.collection.LinearSeqOps.lengthCompare$(LinearSeq.scala:86)
    at Playground$ConstSeq.lengthCompare(Playground.scala:12)
    at scala.collection.SeqOps.isEmpty(Seq.scala:843)
    at scala.collection.SeqOps.isEmpty$(Seq.scala:843)
    at scala.collection.AbstractSeq.isEmpty(Seq.scala:1189)
    at scala.collection.LinearSeqOps.loop$1(LinearSeq.scala:89)
    at scala.collection.LinearSeqOps.lengthCompare(LinearSeq.scala:96)
    at scala.collection.LinearSeqOps.lengthCompare$(LinearSeq.scala:86)
    at Playground$ConstSeq.lengthCompare(Playground.scala:12)
    at scala.collection.SeqOps.isEmpty(Seq.scala:843)
    at scala.collection.SeqOps.isEmpty$(Seq.scala:843)
    at scala.collection.AbstractSeq.isEmpty(Seq.scala:1189)
    at scala.collection.LinearSeqOps.loop$1(LinearSeq.scala:89)
    at scala.collection.LinearSeqOps.lengthCompare(LinearSeq.scala:96)
    at scala.collection.LinearSeqOps.lengthCompare$(LinearSeq.scala:86)
    at Playground$ConstSeq.lengthCompare(Playground.scala:12)
    at scala.collection.SeqOps.isEmpty(Seq.scala:843)
    at scala.collection.SeqOps.isEmpty$(Seq.scala:843)
    at scala.collection.AbstractSeq.isEmpty(Seq.scala:1189)
    at scala.collection.LinearSeqOps.loop$1(LinearSeq.scala:89)
    at scala.collection.LinearSeqOps.lengthCompare(LinearSeq.scala:96)
    at scala.collection.LinearSeqOps.lengthCompare$(LinearSeq.scala:86)
    at Playground$ConstSeq.lengthCompare(Playground.scala:12)

Now, a 'fix' for this could be just as well mentioning in the docs that isEmpty must be overridden, or similar, but the current situation is not ideal. Also, perhaps both should try knownSize first? The current implementation is a bit too specific to our immutable.List, while an immutable list implementation of a known size (nomen omen) is not unheard of.

SethTisue commented 1 year ago

@scala/collections

som-snytt commented 1 year ago

Duplicates https://github.com/scala/bug/issues/11697 and https://github.com/scala/scala-library-next/issues/128

https://github.com/scala/scala/pull/10106

Possibly this is the Scaladoc bug where it drops text in the presence of macros.

It's visible in Scala 3:

image