diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/StdNames.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 22 | ||||
-rw-r--r-- | src/library/scala/BigDecimal.scala | 1 | ||||
-rw-r--r-- | src/library/scala/collection/TraversableLike.scala | 26 | ||||
-rw-r--r-- | src/library/scala/collection/immutable/GenericRange.scala (renamed from src/library/scala/Range.scala) | 142 | ||||
-rw-r--r-- | src/library/scala/collection/immutable/Range.scala | 229 | ||||
-rw-r--r-- | src/library/scala/package.scala | 3 | ||||
-rw-r--r-- | src/library/scala/runtime/RichDouble.scala | 3 | ||||
-rw-r--r-- | src/library/scala/runtime/RichInt.scala | 7 | ||||
-rw-r--r-- | src/library/scala/runtime/RichLong.scala | 1 | ||||
-rw-r--r-- | test/files/jvm/sync-var.scala | 4 |
12 files changed, 304 insertions, 137 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 41dabd92d5..0b917fa925 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -368,7 +368,7 @@ abstract class TreeBuilder { makeFor(mapName, flatMapName, rest, body)) case ValFrom(pos, pat, rhs) :: Filter(_, test) :: rest => makeFor(mapName, flatMapName, - ValFrom(pos, pat, makeCombination(rhs.pos union test.pos, nme.filter, rhs, pat.duplicate, test)) :: rest, + ValFrom(pos, pat, makeCombination(rhs.pos union test.pos, nme.withFilter, rhs, pat.duplicate, test)) :: rest, body) case ValFrom(pos, pat, rhs) :: rest => val valeqs = rest.take(definitions.MaxTupleArity - 1).takeWhile(_.isInstanceOf[ValEq]); diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index 19cce08224..f356279e25 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -344,6 +344,7 @@ trait StdNames { val value = newTermName("value") val view_ = newTermName("view") val wait_ = newTermName("wait") + val withFilter = newTermName("withFilter") val zip = newTermName("zip") val ZAND = encode("&&") diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 3d88493c86..d9cdb79ea4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3709,7 +3709,27 @@ trait Typers { self: Analyzer => if (util.Statistics.enabled) selcnt += 1 var qual1 = checkDead(typedQualifier(qual, mode)) if (name.isTypeName) qual1 = checkStable(qual1) - val tree1 = typedSelect(qual1, name) + + val tree1 = // temporarily use `filter' and an alternative for `withFilter' + if (name == nme.withFilter) + silent(_ => typedSelect(qual1, name)) match { + case result1: Tree => + result1 + case ex1: TypeError => + silent(_ => typed1(Select(qual1, nme.filter) setPos tree.pos, mode, pt)) match { + case result2: Tree => + unit.deprecationWarning( + tree.pos, "`withFilter' method does not yet exist on "+qual1.tpe.widen+ + ", using `filter' method instead") + result2 + case ex2: TypeError => + reportTypeError(tree.pos, ex1) + setError(tree) + } + } + else + typedSelect(qual1, name) + if (qual1.symbol == RootPackage) treeCopy.Ident(tree1, name) else tree1 diff --git a/src/library/scala/BigDecimal.scala b/src/library/scala/BigDecimal.scala index 15ebaea617..39b3f4b571 100644 --- a/src/library/scala/BigDecimal.scala +++ b/src/library/scala/BigDecimal.scala @@ -12,6 +12,7 @@ package scala import java.{ lang => jl } import java.math.{ MathContext, BigDecimal => BigDec } +import scala.collection.immutable.GenericRange /** Conversions which present a consistent conversion interface * across all the numeric types. diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala index 9f4bdbac7f..2716956cb9 100644 --- a/src/library/scala/collection/TraversableLike.scala +++ b/src/library/scala/collection/TraversableLike.scala @@ -826,4 +826,30 @@ self => * @note view(from, to) is equivalent to view.slice(from, to) */ def view(from: Int, until: Int): TraversableView[A, Repr] = view.slice(from, until) + + class WithFilter(p: A => Boolean) { + + def map[B, That](f: A => B)(implicit bf: BuilderFactory[B, That, Repr]): That = { + val b = bf(repr) + for (x <- self) + if (p(x)) b += f(x) + b.result + } + + def flatMap[B, That](f: A => Traversable[B])(implicit bf: BuilderFactory[B, That, Repr]): That = { + val b = bf(repr) + for (x <- self) + if (p(x)) b ++= f(x) + b.result + } + + def foreach[U](f: A => U): Unit = + for (x <- self) + if (p(x)) f(x) + + def withFilter(q: A => Boolean): WithFilter = + new WithFilter(x => p(x) && q(x)) + } + + def withFilter(p: A => Boolean): WithFilter = new WithFilter(p) } diff --git a/src/library/scala/Range.scala b/src/library/scala/collection/immutable/GenericRange.scala index c808a3db10..886895215b 100644 --- a/src/library/scala/Range.scala +++ b/src/library/scala/collection/immutable/GenericRange.scala @@ -6,9 +6,9 @@ ** |/ ** \* */ -// $Id$ +// $Id: Range.scala 18987 2009-10-08 18:31:44Z odersky $ -package scala +package scala.collection.immutable import annotation.experimental @@ -39,7 +39,11 @@ import util.Hashable abstract class GenericRange[T] (val start: T, val end: T, val step: T, val isInclusive: Boolean = false) (implicit num: Integral[T]) -extends VectorView[T, collection.immutable.Vector[T]] with RangeToString[T] with Hashable { +extends VectorView[T, collection.immutable.Vector[T]] + with RangeToString[T] // !!! I think this does too little to be its trait --> see simplified impl ion Range + with Hashable // !!! not needed because it inherits from Vector +{ + import num._ // todo? - we could lift the length restriction by implementing a range as a sequence of @@ -102,6 +106,7 @@ extends VectorView[T, collection.immutable.Vector[T]] with RangeToString[T] with // The contains situation makes for some interesting code. // This attempts to check containerhood in a range-sensible way, but // falls back on super.contains if the cast ends up failing. + // !!! [Martin] contains should only return `true' for numbers of the form start + n * step. override def contains(_x: Any): Boolean = { def doContains = { // checking for Int is important so for instance BigIntRange from @@ -118,11 +123,16 @@ extends VectorView[T, collection.immutable.Vector[T]] with RangeToString[T] with withinRange && matchesStep } + // !!! [Martin] That's too inefficient foir a core library class in my opinion: catching(classOf[ClassCastException]) opt doContains getOrElse super.contains(_x) + } // Using trueEnd gives us Range(1, 10, 1).inclusive == Range(1, 11, 1) val hashValues = List(start, trueEnd, step) + + // [Martin] !!! this means that GenericRange(0, 0, 1) and GenericRange(0, -1, 1) are not equal, + // which violates the sequence equality conventions. See Range.equals for how it needs to be done. override def equals(other: Any) = other match { case x: GenericRange[_] => this equalHashValues x case _ => false @@ -162,129 +172,3 @@ object GenericRange new Inclusive(start, end, step) } - -/** <p> - * The <code>Range</code> class represents integer values in range - * <code>[start;end)</code> with non-zero step value <code>step</code>. - * Sort of acts like a sequence also (supports length and contains). - * For example: - * </p><pre> - * <b>val</b> r1 = 0 until 10 - * <b>val</b> r2 = r1.start until r1.end by r1.step + 1 - * println(r2.length) // = 5 - * </pre> - * - * @author Martin Odersky - * @version 2.8 - * @since 2.5 - */ -class Range(val start: Int, val end: Int, val step: Int) -extends VectorView[Int, collection.immutable.Vector[Int]] with RangeToString[Int] -{ - require(step != 0) - - protected def underlying = collection.immutable.Vector.empty[Int] - - /** Create a new range with the start and end values of this range and - * a new <code>step</code>. - */ - def by(step: Int): Range = new Range(start, end, step) - - final override def foreach[U](f: Int => U) { - var i = start - if (step > 0) { - while (i < end) { - f(i) - i += step - } - } else { - while (i > end) { - f(i) - i += step - } - } - } - - lazy val length: Int = { - def plen(start: Int, end: Int, step: Int) = - if (end <= start) 0 else (end - start - 1) / step + 1 - if (step > 0) plen(start, end, step) - else plen(end, start, -step) - } - - @inline - final def apply(idx: Int): Int = { - if (idx < 0 || idx >= length) throw new IndexOutOfBoundsException(idx.toString) - start + idx * step - } - - def contains(x: Int): Boolean = - if (step > 0) start <= x && x < end - else start >= x && x > end - - def inclusive = Range.inclusive(start, end, step) - // XXX right now (1 to 10).toList == (1 to 10) but their hashCodes are unequal. - override def equals(other: Any) = other match { - case x: Range => start == x.start && end == x.end && step == x.step - case _ => super.equals(other) - } - override def hashCode = start + end + step -} - -object Range { - @deprecated("use Range.inclusive instead") - final class Inclusive(start: Int, end0: Int, step: Int) - extends Range(start, if (step > 0) end0 + 1 else end0 - 1, step) { self => - override def by(step: Int): Range = new Inclusive(start, end0, step) - } - - // The standard / Int-specific Range. - def apply(start: Int, end: Int, step: Int) = - new Range(start, end, step) - def inclusive(start: Int, end: Int, step: Int): Range = - new Range.Inclusive(start, end, step) - - // BigInt and Long are straightforward generic ranges. - object BigInt { - def apply(start: BigInt, end: BigInt, step: BigInt) = GenericRange(start, end, step) - def inclusive(start: BigInt, end: BigInt, step: BigInt) = GenericRange.inclusive(start, end, step) - } - object Long { - def apply(start: Long, end: Long, step: Long) = GenericRange(start, end, step) - def inclusive(start: Long, end: Long, step: Long) = GenericRange.inclusive(start, end, step) - } - - // BigDecimal uses an alternative implementation of Numeric in which - // it pretends to be Integral[T] instead of Fractional[T]. See Numeric for - // details. The intention is for it to throw an exception anytime - // imprecision or surprises might result from anything, although this may - // not yet be fully implemented. - object BigDecimal { - implicit val bigDecAsIntegral = scala.Numeric.BigDecimalAsIfIntegral - - def apply(start: BigDecimal, end: BigDecimal, step: BigDecimal) = - GenericRange(start, end, step) - def inclusive(start: BigDecimal, end: BigDecimal, step: BigDecimal) = - GenericRange.inclusive(start, end, step) - } - // Double re-uses BigDecimal's range. - object Double { - def apply(start: Double, end: Double, step: Double) = scala.BigDecimal(start) until end by step - def inclusive(start: Double, end: Double, step: Double) = scala.BigDecimal(start) to end by step - } - - // As there is no appealing default step size for not-really-integral ranges, - // we offer a partially constructed object. - class Partial[T, U](f: T => U) { - def by(x: T): U = f(x) - } - - // Illustrating genericity with Int Range, which should have the same behavior - // as the original Range class. However we leave the original Range - // indefinitely, for performance and because the compiler seems to bootstrap - // off it and won't do so with our parameterized version without modifications. - object Int { - def apply(start: Int, end: Int, step: Int) = GenericRange(start, end, step) - def inclusive(start: Int, end: Int, step: Int) = GenericRange.inclusive(start, end, step) - } -} diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala new file mode 100644 index 0000000000..f39b505be2 --- /dev/null +++ b/src/library/scala/collection/immutable/Range.scala @@ -0,0 +1,229 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2006-2009, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id: Range.scala 18987 2009-10-08 18:31:44Z odersky $ + +package scala.collection.immutable + +/** <p> + * The <code>Range</code> class represents integer values in range + * <code>[start;end)</code> with non-zero step value <code>step</code>. + * It's a special case of an indexed sequence. + * For example: + * </p><pre> + * <b>val</b> r1 = 0 until 10 + * <b>val</b> r2 = r1.start until r1.end by r1.step + 1 + * println(r2.length) // = 5 + * </pre> + * + * @author Martin Odersky + * @version 2.8 + * @since 2.5 + */ +class Range(val start: Int, val end: Int, val step: Int) extends Vector[Int] { + + require(step != 0) + + /** Create a new range with the start and end values of this range and + * a new <code>step</code>. + * @note should never be called after `inclusive'. + */ + def by(step: Int): Range = Range(start, end, step) + + override def foreach[U](f: Int => U) { + var i = start + while (if (step > 0) i < end else i > end) { + f(i) + i += step + } + } + + lazy val length: Int = { + def plen(start: Int, end: Int, step: Int) = + if (end <= start) 0 else (end - start - 1) / step + 1 + if (step > 0) plen(start, end, step) + else plen(end, start, -step) + } + + final override def isEmpty = + if (step > 0) start >= end else start <= end + + @inline + final def apply(idx: Int): Int = { + if (idx < 0 || idx >= length) throw new IndexOutOfBoundsException(idx.toString) + start + idx * step + } + + final override def init: Range = + dropRight(1) + + final override def take(n: Int): Range = { + val end1 = start + step * (n max 0) + if (step > 0) Range(start, end1 min end, step) + else Range(start, end1 max end, step) + } + + final override def drop(n: Int): Range = + if (step == 0) this + else Range(start + step * n, end, step) + + final override def slice(from: Int, until: Int): Range = + drop(from).take(until - from) + + final override def takeWhile(p: Int => Boolean): Range = { + var s = start + while (!isEmpty && p(s)) s += step + Range(start, s, step) + } + + final override def dropWhile(p: Int => Boolean): Range = { + var s = start + while (!isEmpty && p(s)) s += step + Range(s, end, step) + } + + final override def span(p: Int => Boolean): (Range, Range) = { + var s = start + while (!isEmpty && p(s)) s += step + (Range(start, s, step), Range(s, end, step)) + } + + final override def splitAt(n: Int) = (take(n), drop(n)) + + final override def takeRight(n: Int): Range = { + val start1 = end - step * (n max 0) + if (step > 0) Range(start1 max start, end, step) + else Range(start1 min start, end, step) + } + + final override def dropRight(n: Int): Range = + Range(start, end - step * n, step) + + final override def reverse: Range = + Range(end, start, -step) + + def contains(x: Int): Boolean = + if (step > 0) start <= x && x < end && (x - start) % step == 0 + else start >= x && x > end && (start - x) % step == 0 + + def inclusive = Range(start, end + Math.signum(step), step) + + override def equals(other: Any) = other match { + case x: Range => + length == x.length && + (length == 0 || + start == x.start && + (length == 1 || step == x.step)) + case _ => + super.equals(other) + } + + /* eliminated, so as to not break the hashcode/equals contract + override def hashCode = start + end + step + */ + + override def toString() = { + val end = if (length > Range.MAX_PRINT) ", ... )" else ")" + take(Range.MAX_PRINT).mkString("Range(", ", ", end) + } +} + +object Range { + private val MAX_PRINT = 512 // some arbitrary value + + @deprecated("use Range.inclusive instead") + final class Inclusive(start: Int, end0: Int, step: Int) + extends Range(start, if (step > 0) end0 + 1 else end0 - 1, step) { self => + override def by(step: Int): Range = new Inclusive(start, end0, step) + } + + // The standard / Int-specific Range. + def apply(start: Int, end: Int, step: Int): Range = + if (step == 1) new ByOne(start, end) + else if (step > 0) new ByPosStep(start, end, step) + else new ByNegStep(start, end, step) + + def inclusive(start: Int, end: Int, step: Int): Range = + apply(start, end + Math.signum(step), step) + + class ByOne(start: Int, end: Int) extends Range(start, end, 1) { + override final def foreach[U](f: Int => U) { + var i = start + while (i < end) { + f(i) + i += 1 + } + } + } + + class ByPosStep(start: Int, end: Int, step: Int) extends Range(start, end, step) { + override final def foreach[U](f: Int => U) { + var i = start + while (i < end) { + f(i) + i += step + } + } + } + + class ByNegStep(start: Int, end: Int, step: Int) extends Range(start, end, step) { + override final def foreach[U](f: Int => U) { + var i = start + while (i > end) { + f(i) + i += step + } + } + } + + // BigInt and Long are straightforward generic ranges. + object BigInt { + def apply(start: BigInt, end: BigInt, step: BigInt) = GenericRange(start, end, step) + def inclusive(start: BigInt, end: BigInt, step: BigInt) = GenericRange.inclusive(start, end, step) + } + + object Long { + def apply(start: Long, end: Long, step: Long) = GenericRange(start, end, step) + def inclusive(start: Long, end: Long, step: Long) = GenericRange.inclusive(start, end, step) + } + + // BigDecimal uses an alternative implementation of Numeric in which + // it pretends to be Integral[T] instead of Fractional[T]. See Numeric for + // details. The intention is for it to throw an exception anytime + // imprecision or surprises might result from anything, although this may + // not yet be fully implemented. + object BigDecimal { + implicit val bigDecAsIntegral = scala.Numeric.BigDecimalAsIfIntegral + + def apply(start: BigDecimal, end: BigDecimal, step: BigDecimal) = + GenericRange(start, end, step) + def inclusive(start: BigDecimal, end: BigDecimal, step: BigDecimal) = + GenericRange.inclusive(start, end, step) + } + + // Double re-uses BigDecimal's range. + object Double { + def apply(start: Double, end: Double, step: Double) = scala.BigDecimal(start) until end by step + def inclusive(start: Double, end: Double, step: Double) = scala.BigDecimal(start) to end by step + } + + // As there is no appealing default step size for not-really-integral ranges, + // we offer a partially constructed object. + class Partial[T, U](f: T => U) { + def by(x: T): U = f(x) + } + + // Illustrating genericity with Int Range, which should have the same behavior + // as the original Range class. However we leave the original Range + // indefinitely, for performance and because the compiler seems to bootstrap + // off it and won't do so with our parameterized version without modifications. + object Int { + def apply(start: Int, end: Int, step: Int) = GenericRange(start, end, step) + def inclusive(start: Int, end: Int, step: Int) = GenericRange.inclusive(start, end, step) + } +} diff --git a/src/library/scala/package.scala b/src/library/scala/package.scala index d7c4bacce3..e18f0fd3bd 100644 --- a/src/library/scala/package.scala +++ b/src/library/scala/package.scala @@ -43,6 +43,9 @@ package object scala { type StringBuilder = scala.collection.mutable.StringBuilder val StringBuilder = scala.collection.mutable.StringBuilder + type Range = scala.collection.immutable.Range + val Range = scala.collection.immutable.Range + @deprecated("use Iterable instead") type Collection[+A] = Iterable[A] @deprecated("use Iterable instead") val Collection = Iterable diff --git a/src/library/scala/runtime/RichDouble.scala b/src/library/scala/runtime/RichDouble.scala index c9e25e4edf..a40b35d8e9 100644 --- a/src/library/scala/runtime/RichDouble.scala +++ b/src/library/scala/runtime/RichDouble.scala @@ -11,6 +11,7 @@ package scala.runtime +import scala.collection.immutable.GenericRange final class RichDouble(x: Double) extends Proxy with Ordered[Double] { // Proxy.self @@ -51,7 +52,7 @@ final class RichDouble(x: Double) extends Proxy with Ordered[Double] { def toRadians: Double = Math.toRadians(x) /** Converts an angle measured in radians to an approximately equivalent - * angle measured in degrees. + * angle measured in degrees * * @param x angle, in radians * @return the measurement of the angle <code>x</code> in degrees. diff --git a/src/library/scala/runtime/RichInt.scala b/src/library/scala/runtime/RichInt.scala index 47d4b458c1..7d3e86377e 100644 --- a/src/library/scala/runtime/RichInt.scala +++ b/src/library/scala/runtime/RichInt.scala @@ -11,6 +11,8 @@ package scala.runtime +import collection.immutable.Range + final class RichInt(val start: Int) extends Proxy with Ordered[Int] { @@ -20,13 +22,12 @@ final class RichInt(val start: Int) extends Proxy with Ordered[Int] { // Ordered[Int] def compare(that: Int): Int = if (start < that) -1 else if (start > that) 1 else 0 - /** See <code>Iterator.range</code>. */ - def until(end: Int): Range = new Range(start, end, 1) def until(end: Int, step: Int): Range = new Range(start, end, step) + def until(end: Int): Range.ByOne = new Range.ByOne(start, end) /** like <code>until</code>, but includes the last index */ - def to(end: Int): Range = Range.inclusive(start, end, 1) def to(end: Int, step: Int): Range = Range.inclusive(start, end, step) + def to(end: Int): Range.ByOne = new Range.ByOne(start, end + 1) def min(that: Int): Int = if (start < that) start else that def max(that: Int): Int = if (start > that) start else that diff --git a/src/library/scala/runtime/RichLong.scala b/src/library/scala/runtime/RichLong.scala index 7eac1e0cab..c2e32a984e 100644 --- a/src/library/scala/runtime/RichLong.scala +++ b/src/library/scala/runtime/RichLong.scala @@ -11,6 +11,7 @@ package scala.runtime +import scala.collection.immutable.GenericRange final class RichLong(x: Long) extends Proxy with Ordered[Long] { diff --git a/test/files/jvm/sync-var.scala b/test/files/jvm/sync-var.scala index aa6ae9fa34..8a6c2badea 100644 --- a/test/files/jvm/sync-var.scala +++ b/test/files/jvm/sync-var.scala @@ -10,7 +10,7 @@ val sum = new AtomicInteger val q = new scala.concurrent.SyncVar[Int] -val producers = (1 to 3).force map { z => new Thread { +val producers = (1 to 3) map { z => new Thread { override def run() { var again = true while (again) { @@ -23,7 +23,7 @@ val producers = (1 to 3).force map { z => new Thread { } } } -val summers = (1 to 7).force map { z => new Thread { +val summers = (1 to 7) map { z => new Thread { override def run() { val x = j.decrementAndGet() if (x >= 0) { |