File tree Expand file tree Collapse file tree 2 files changed +29
-1
lines changed
main/scala-2.11_2.12/scala/collection/compat/immutable
test/scala/test/scala/collection Expand file tree Collapse file tree 2 files changed +29
-1
lines changed Original file line number Diff line number Diff line change @@ -231,9 +231,16 @@ final class LazyList[+A] private (private[this] var lazyState: () => LazyList.St
231231
232232 @ volatile private [this ] var stateEvaluated : Boolean = false
233233 @ inline private def stateDefined : Boolean = stateEvaluated
234+ private [this ] var midEvaluation = false
234235
235236 private lazy val state : State [A ] = {
236- val res = lazyState()
237+ // if it's already mid-evaluation, we're stuck in an infinite
238+ // self-referential loop (also it's empty)
239+ if (midEvaluation) {
240+ throw new RuntimeException (" self-referential LazyList or a derivation thereof has no more elements" )
241+ }
242+ midEvaluation = true
243+ val res = try lazyState() finally midEvaluation = false
237244 // if we set it to `true` before evaluating, we may infinite loop
238245 // if something expects `state` to already be evaluated
239246 stateEvaluated = true
Original file line number Diff line number Diff line change @@ -355,4 +355,25 @@ class LazyListTest {
355355 assertEquals(1 to 10 , build(_ ++= LazyList .from(1 ).take(10 )))
356356 assertEquals(1 to 10 , build(_ ++= Iterator .from(1 ).take(10 )))
357357 }
358+
359+ @ Test
360+ def selfReferentialFailure (): Unit = {
361+ def assertNoStackOverflow [A ](lazyList : LazyList [A ]): Unit = {
362+ // don't hang the test if we've made a programming error in this test
363+ val finite = lazyList.take(1000 )
364+ // AssertUtil.assertThrows[RuntimeException](finite.force, _ contains "self-referential")
365+ try {
366+ finite.force
367+ fail(" Expected RuntimeException to be thrown" )
368+ } catch { case e : RuntimeException => assertTrue(e.getMessage.contains(" self-referential" )) }
369+ }
370+ assertNoStackOverflow { class L { val ll : LazyList [Nothing ] = LazyList .empty #::: ll }; (new L ).ll }
371+ assertNoStackOverflow { class L { val ll : LazyList [Int ] = 1 #:: ll.map(_ + 1 ).filter(_ % 2 == 0 ) }; (new L ).ll }
372+ class L {
373+ lazy val a : LazyList [Nothing ] = LazyList .empty #::: b
374+ lazy val b : LazyList [Nothing ] = LazyList .empty #::: a
375+ }
376+ assertNoStackOverflow((new L ).a)
377+ assertNoStackOverflow((new L ).b)
378+ }
358379}
You can’t perform that action at this time.
0 commit comments