From 5ffe50c3dfc793eb983f341f4e9e816de3636a4f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 6 Feb 2008 18:43:12 +0000 Subject: fixed problems with ranges --- src/library/scala/Iterator.scala | 32 ++++++++++++++++++++------------ src/library/scala/List.scala | 40 +++++++++++++++++++++++++--------------- src/library/scala/Stream.scala | 18 +++++++++++------- test/files/neg/t0345.check | 4 ++++ test/files/neg/t0345.scala | 15 +++++++++++++++ test/files/neg/t0351.check | 4 ++++ test/files/neg/t0351.scala | 3 +++ test/files/run/iterators.scala | 16 ++++++++++------ 8 files changed, 92 insertions(+), 40 deletions(-) create mode 100644 test/files/neg/t0345.check create mode 100755 test/files/neg/t0345.scala create mode 100644 test/files/neg/t0351.check create mode 100755 test/files/neg/t0351.scala diff --git a/src/library/scala/Iterator.scala b/src/library/scala/Iterator.scala index fbfd4c3e5c..d0377c5692 100644 --- a/src/library/scala/Iterator.scala +++ b/src/library/scala/Iterator.scala @@ -119,33 +119,41 @@ object Iterator { /** Create an iterator with elements * en+1 = en + step * where e0 = start - * and ei < end. Will return an empty range - * for nonsensical range/step arguments. + * and elements are in the range between start (inclusive) + * and end (exclusive) * * @param start the start value of the iterator * @param end the end value of the iterator * @param step the increment value of the iterator (must be positive or negative) * @return the iterator with values in range [start;end). */ - def range(start: Int, end: Int, step: Int): Iterator[Int] = range(start, end, {(_:Int) + step}) + def range(start: Int, end: Int, step: Int) = new Iterator[Int] { + private var i = start + def hasNext: Boolean = (step <= 0 || i < end) && (step >= 0 || i > end) + def next(): Int = + if (hasNext) { val j = i; i = i + step; j } + else throw new NoSuchElementException("next on empty iterator") + } /** Create an iterator with elements * en+1 = step(en) * where e0 = start - * and ei < end. + * and elements are in the range between start (inclusive) + * and end (exclusive) * * @param start the start value of the iterator * @param end the end value of the iterator - * @param step the increment function of the iterator + * @param step the increment function of the iterator, must be monotonically increasing or decreasing * @return the iterator with values in range [start;end). */ - def range(start: Int, end: Int, step: Int => Int): Iterator[Int] = - new Iterator[Int] { - private var i = start - def hasNext: Boolean = i < end - def next(): Int = - if (i < end) { val j = i; i = step(i); j } - else throw new NoSuchElementException("next on empty iterator") + def range(start: Int, end: Int, step: Int => Int) = new Iterator[Int] { + private val up = step(start) > start + private val down = step(start) < start + private var i = start + def hasNext: Boolean = (!up || i < end) && (!down || i > end) + def next(): Int = + if (hasNext) { val j = i; i = step(i); j } + else throw new NoSuchElementException("next on empty iterator") } /** Create an iterator with elements diff --git a/src/library/scala/List.scala b/src/library/scala/List.scala index c0adc30db2..c2158b9f2a 100644 --- a/src/library/scala/List.scala +++ b/src/library/scala/List.scala @@ -39,37 +39,47 @@ object List { * @param end the end value of the list * @return the sorted list of all integers in range [from;end). */ - def range(from: Int, end: Int): List[Int] = - range(from, end, 1) + def range(start: Int, end: Int): List[Int] = + range(start, end, 1) - /** Create a sorted list of all integers in a range. + /** Create a list with element values + * vn+1 = vn + step + * where v0 = start + * and elements are in the range between start (inclusive) + * and end (exclusive) * - * @param from the start value of the list + * @param start the start value of the list * @param end the end value of the list * @param step the increment value of the list - * @return the sorted list of all integers in range [from;end). + * @return the sorted list of all integers in range [start;end). */ - def range(from: Int, end: Int, step: Int): List[Int] = { + def range(start: Int, end: Int, step: Int): List[Int] = { val b = new ListBuffer[Int] - var i = from - while (i < end) { + var i = start + while ((step <= 0 || i < end) && (step >= 0 || i > end)) { b += i i += step } b.toList } - /** Create a sorted list of all integers in a range. + /** Create a sorted list with element values + * vn+1 = step(vn) + * where v0 = start + * and elements are in the range between start (inclusive) + * and end (exclusive) * - * @param from the start value of the list + * @param start the start value of the list * @param end the end value of the list - * @param step the increment function of the list - * @return the sorted list of all integers in range [from;end). + * @param step the increment function of the list, must be monotonically increasing or decreasing + * @return the sorted list of all integers in range [start;end). */ - def range(from: Int, end: Int, step: Int => Int): List[Int] = { + def range(start: Int, end: Int, step: Int => Int): List[Int] = { + val up = step(start) > start + val down = step(start) < start val b = new ListBuffer[Int] - var i = from - while (i < end) { + var i = start + while ((!up || i < end) && (!down || i > end)) { b += i i += step(i) } diff --git a/src/library/scala/Stream.scala b/src/library/scala/Stream.scala index 1415e3ad06..f16085080e 100644 --- a/src/library/scala/Stream.scala +++ b/src/library/scala/Stream.scala @@ -103,7 +103,8 @@ object Stream { * Create a stream with element values * vn+1 = vn + step * where v0 = start - * and vi < end. + * and elements are in the range between start (inclusive) + * and end (exclusive) * * @param start the start value of the stream * @param end the end value of the stream @@ -112,8 +113,8 @@ object Stream { */ def range(start: Int, end: Int, step: Int): Stream[Int] = { def loop(lo: Int): Stream[Int] = - if (lo >= end) empty - else cons(lo, loop(lo + step)) + if ((step <= 0 || lo < end) && (step >= 0 || lo > end)) cons(lo, loop(lo + step)) + else empty loop(start) } @@ -121,17 +122,20 @@ object Stream { * Create a stream with element values * vn+1 = step(vn) * where v0 = start - * and vi < end. + * and elements are in the range between start (inclusive) + * and end (exclusive) * * @param start the start value of the stream * @param end the end value of the stream - * @param step the increment function of the stream + * @param step the increment function of the stream, must be monotonically increasing or decreasing * @return the stream starting at value start. */ def range(start: Int, end: Int, step: Int => Int): Stream[Int] = { + val up = step(start) > start + val down = step(start) < start def loop(lo: Int): Stream[Int] = - if (lo >= end) empty - else cons(lo, loop(step(lo))) + if ((!up || lo < end) && (!down || lo > end)) cons(lo, loop(step(lo))) + else empty loop(start) } diff --git a/test/files/neg/t0345.check b/test/files/neg/t0345.check new file mode 100644 index 0000000000..f4a5275336 --- /dev/null +++ b/test/files/neg/t0345.check @@ -0,0 +1,4 @@ +t0345.scala:2: error: object creation impossible, since method cons in trait Lizt of type (Nothing)Unit is not defined + val empty = new Lizt[Nothing] { + ^ +one error found diff --git a/test/files/neg/t0345.scala b/test/files/neg/t0345.scala new file mode 100755 index 0000000000..f3652c183b --- /dev/null +++ b/test/files/neg/t0345.scala @@ -0,0 +1,15 @@ +object Lizt { + val empty = new Lizt[Nothing] { + def cons[A](a : A) {} + } +} + +trait Lizt[A] { + def cons(a : A) : Unit +} +class Test { + abstract class C[A] {} + val c = new C[Int] { + def f[A](x: A) {} + } + } diff --git a/test/files/neg/t0351.check b/test/files/neg/t0351.check new file mode 100644 index 0000000000..d374c905ed --- /dev/null +++ b/test/files/neg/t0351.check @@ -0,0 +1,4 @@ +t0351.scala:2: error: no by-name parameter type allowed here + def identity[T](x : => T) : (=> T) + ^ +one error found diff --git a/test/files/neg/t0351.scala b/test/files/neg/t0351.scala new file mode 100755 index 0000000000..665bd89da4 --- /dev/null +++ b/test/files/neg/t0351.scala @@ -0,0 +1,3 @@ +abstract class Foo { + def identity[T](x : => T) : (=> T) +} diff --git a/test/files/run/iterators.scala b/test/files/run/iterators.scala index 714861ef68..7972418059 100644 --- a/test/files/run/iterators.scala +++ b/test/files/run/iterators.scala @@ -22,10 +22,13 @@ object Test { } def check_range2: Int = { - val r1 = Iterator.range(0, 10) - val r2 = Iterator.range(r1.start, r1.end, r1.step + 1) - val r3 = Iterator.range(r1.end, r1.start, -r1.step) - val r4 = Iterator.range(0, 10, 11) + val r1start = 0 + val r1end = 10 + val r1step = 1 + val r1 = Iterator.range(r1start, r1end, r1step) toList; + val r2 = Iterator.range(r1start, r1end, r1step + 1) toList; + val r3 = Iterator.range(r1end, r1start, -r1step) toList; + val r4 = Iterator.range(0, 10, 11) toList; // 10 + 5 + 10 + 1 r1.length + r2.length + r3.length + r4.length } @@ -34,8 +37,9 @@ object Test { def trues(xs: List[Boolean]) = xs.foldLeft(0)((a, b) => if (b) a+1 else a) val r1 = Iterator.range(0, 10) val xs1 = List(r1 contains 5, r1 contains 6) - val r2 = Iterator.range(0, 10, 2) - val xs2 = List(r2 contains 5, r2 contains 6) + val r2a = Iterator.range(0, 10, 2) + val r2b = Iterator.range(0, 10, 2) + val xs2 = List(r2a contains 5, r2b contains 6) val r3 = Iterator.range(0, 10, 11) val xs3 = List(r3 contains 5, r3 contains 6) // 2 + 1 + 0 -- cgit v1.2.3