diff --git a/src/library/scala/collection/immutable/LazyList.scala b/src/library/scala/collection/immutable/LazyList.scala index b6af234150e2..db203126414a 100644 --- a/src/library/scala/collection/immutable/LazyList.scala +++ b/src/library/scala/collection/immutable/LazyList.scala @@ -1230,6 +1230,21 @@ object LazyList extends SeqFactory[LazyList] { at(0) } + override def range[A: Integral](start: A, end: A): LazyList[A] = + newLL(rangeImpl(start, end, step = Integral[A].one, sign = true)) + + override def range[A](start: A, end: A, step: A)(implicit ev: Integral[A]): LazyList[A] = + newLL { + if (ev.equiv(step, ev.zero)) throw new IllegalArgumentException("step cannot be 0.") + else rangeImpl(start, end, step, sign = ev.sign(step) == ev.one) + } + + private[this] def rangeImpl[A](start: A, end: A, step: A, sign: Boolean)(implicit ev: Integral[A]): State[A] = { + val check = if (sign) ev.lt(start, end) else ev.gt(start, end) + if (check) sCons(start, newLL(rangeImpl(ev.plus(start, step), end, step, sign))) + else State.Empty + } + // significantly simpler than the iterator returned by Iterator.unfold override def unfold[A, S](init: S)(f: S => Option[(A, S)]): LazyList[A] = newLL { diff --git a/test/junit/scala/collection/immutable/LazyListTest.scala b/test/junit/scala/collection/immutable/LazyListTest.scala index 8ff9ebb72361..660e1cd6d853 100644 --- a/test/junit/scala/collection/immutable/LazyListTest.scala +++ b/test/junit/scala/collection/immutable/LazyListTest.scala @@ -444,8 +444,21 @@ class LazyListTest { LazyList(1).lazyAppendedAll({ count += 1; Seq(2)}).toList assertEquals(1, count) } + + @Test + def lazyRangeAllowsMoreThanIntMaxValue(): Unit = { + // We use a reverse range to avoid computing a lot of elements. + val maxValue = Int.MaxValue.toLong + val lazyList = LazyList.range( + start = maxValue * 2L, + end = 0, + step = -1L + ) + val nums = lazyList.take(10) + assert(nums.forall(_ > maxValue)) + } } object LazyListTest { var serializationForceCount = 0 -} \ No newline at end of file +}