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
231
231
232
232
@ volatile private [this ] var stateEvaluated : Boolean = false
233
233
@ inline private def stateDefined : Boolean = stateEvaluated
234
+ private [this ] var midEvaluation = false
234
235
235
236
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
237
244
// if we set it to `true` before evaluating, we may infinite loop
238
245
// if something expects `state` to already be evaluated
239
246
stateEvaluated = true
Original file line number Diff line number Diff line change @@ -355,4 +355,25 @@ class LazyListTest {
355
355
assertEquals(1 to 10 , build(_ ++= LazyList .from(1 ).take(10 )))
356
356
assertEquals(1 to 10 , build(_ ++= Iterator .from(1 ).take(10 )))
357
357
}
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
+ }
358
379
}
You can’t perform that action at this time.
0 commit comments