diff options
Diffstat (limited to 'src')
5 files changed, 351 insertions, 128 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala index 8d52a7bd2c..f9c818daf0 100755 --- a/src/compiler/scala/tools/nsc/ast/DocComments.scala +++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala @@ -99,7 +99,7 @@ trait DocComments { self: Global => */ def useCases(sym: Symbol, site: Symbol): List[(Symbol, String, Position)] = { def getUseCases(dc: DocComment) = { - for (uc <- dc.useCases; defn <- uc.expandedDefs(site)) yield + for (uc <- dc.useCases; defn <- uc.expandedDefs(sym, site)) yield (defn, expandVariables(merge(cookedDocComment(sym), uc.comment.raw, defn), sym, site), uc.pos) @@ -346,7 +346,7 @@ trait DocComments { self: Global => var defined: List[Symbol] = List() // initialized by Typer var aliases: List[Symbol] = List() // initialized by Typer - def expandedDefs(site: Symbol): List[Symbol] = { + def expandedDefs(sym: Symbol, site: Symbol): List[Symbol] = { def select(site: Type, name: Name, orElse: => Type): Type = { val member = site.nonPrivateMember(name) @@ -424,8 +424,10 @@ trait DocComments { self: Global => } for (defn <- defined) yield { - defn.cloneSymbol.setFlag(Flags.SYNTHETIC).setInfo( - substAliases(defn.info).asSeenFrom(site.thisType, defn.owner)) + val useCase = defn.cloneSymbol + useCase.owner = sym.owner + useCase.flags = sym.flags + useCase.setFlag(Flags.SYNTHETIC).setInfo(substAliases(defn.info).asSeenFrom(site.thisType, sym.owner)) } } } diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 1fe96ed447..7eb8c393f3 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -100,11 +100,15 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { if (inTpl == null) None else thisFactory.comment(sym, inTpl) override def inTemplate = inTpl override def toRoot: List[MemberImpl] = this :: inTpl.toRoot - def inDefinitionTemplates = - if (inTpl == null) - makeRootPackage.toList - else - makeTemplate(sym.owner) :: (sym.allOverriddenSymbols map { inhSym => makeTemplate(inhSym.owner) }) + def inDefinitionTemplates = this match { + case mb: NonTemplateMemberEntity if (mb.useCaseOf.isDefined) => + mb.useCaseOf.get.inDefinitionTemplates + case _ => + if (inTpl == null) + makeRootPackage.toList + else + makeTemplate(sym.owner) :: (sym.allOverriddenSymbols map { inhSym => makeTemplate(inhSym.owner) }) + } def visibility = { if (sym.isPrivateLocal) PrivateInInstance() else if (sym.isProtectedLocal) ProtectedInInstance() @@ -119,18 +123,14 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { else Public() } } - def flags = this match { - // workaround for uninitialized flags in use cases - see SI-5054 - case m: NonTemplateMemberEntity if (m.useCaseOf.isDefined) => - m.useCaseOf.get.flags - case _ => - val fgs = mutable.ListBuffer.empty[Paragraph] - if (sym.isImplicit) fgs += Paragraph(Text("implicit")) - if (sym.isSealed) fgs += Paragraph(Text("sealed")) - if (!sym.isTrait && (sym hasFlag Flags.ABSTRACT)) fgs += Paragraph(Text("abstract")) - if (!sym.isTrait && (sym hasFlag Flags.DEFERRED)) fgs += Paragraph(Text("abstract")) - if (!sym.isModule && (sym hasFlag Flags.FINAL)) fgs += Paragraph(Text("final")) - fgs.toList + def flags = { + val fgs = mutable.ListBuffer.empty[Paragraph] + if (sym.isImplicit) fgs += Paragraph(Text("implicit")) + if (sym.isSealed) fgs += Paragraph(Text("sealed")) + if (!sym.isTrait && (sym hasFlag Flags.ABSTRACT)) fgs += Paragraph(Text("abstract")) + if (!sym.isTrait && (sym hasFlag Flags.DEFERRED)) fgs += Paragraph(Text("abstract")) + if (!sym.isModule && (sym hasFlag Flags.FINAL)) fgs += Paragraph(Text("final")) + fgs.toList } def deprecation = if (sym.isDeprecated) diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index 531eac6c01..c6f056bd81 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -277,6 +277,9 @@ sealed abstract class List[+A] extends AbstractSeq[A] override def toStream : Stream[A] = if (isEmpty) Stream.Empty else new Stream.Cons(head, tail.toStream) + + @deprecated("use `distinct` instead", "2.8.0") + def removeDuplicates: List[A] = distinct } /** The empty list. @@ -343,6 +346,8 @@ final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extend */ object List extends SeqFactory[List] { + import scala.collection.{Iterable, Seq, IndexedSeq} + /** $genericCanBuildFromInfo */ implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, List[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] @@ -352,6 +357,248 @@ object List extends SeqFactory[List] { override def empty[A]: List[A] = Nil override def apply[A](xs: A*): List[A] = xs.toList + + /** Create a sorted list with element values `v,,>n+1,, = step(v,,n,,)` + * where `v,,0,, = start` and elements are in the range between `start` + * (inclusive) and `end` (exclusive). + * + * @param start the start value of the list + * @param end the end value of the list + * @param step the increment function of the list, which given `v,,n,,`, + * computes `v,,n+1,,`. Must be monotonically increasing + * or decreasing. + * @return the sorted list of all integers in range `[start;end)`. + */ + @deprecated("use `iterate` instead", "2.8.0") + 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 = start + while ((!up || i < end) && (!down || i > end)) { + b += i + val next = step(i) + if (i == next) + throw new IllegalArgumentException("the step function did not make any progress on "+ i) + i = next + } + b.toList + } + + /** Create a list containing several copies of an element. + * + * @param n the length of the resulting list + * @param elem the element composing the resulting list + * @return a list composed of `n` elements all equal to `elem` + */ + @deprecated("use `fill` instead", "2.8.0") + def make[A](n: Int, elem: A): List[A] = { + val b = new ListBuffer[A] + var i = 0 + while (i < n) { + b += elem + i += 1 + } + b.toList + } + + /** Concatenate all the elements of a given list of lists. + * + * @param xss the list of lists that are to be concatenated + * @return the concatenation of all the lists + */ + @deprecated("use `xss.flatten` instead of `List.flatten(xss)`", "2.8.0") + def flatten[A](xss: List[List[A]]): List[A] = { + val b = new ListBuffer[A] + for (xs <- xss) { + var xc = xs + while (!xc.isEmpty) { + b += xc.head + xc = xc.tail + } + } + b.toList + } + + /** Transforms a list of pairs into a pair of lists. + * + * @param xs the list of pairs to unzip + * @return a pair of lists. + */ + @deprecated("use `xs.unzip` instead of `List.unzip(xs)`", "2.8.0") + def unzip[A,B](xs: List[(A,B)]): (List[A], List[B]) = { + val b1 = new ListBuffer[A] + val b2 = new ListBuffer[B] + var xc = xs + while (!xc.isEmpty) { + b1 += xc.head._1 + b2 += xc.head._2 + xc = xc.tail + } + (b1.toList, b2.toList) + } + + /** Transforms an iterable of pairs into a pair of lists. + * + * @param xs the iterable of pairs to unzip + * @return a pair of lists. + */ + @deprecated("use `xs.unzip` instead of `List.unzip(xs)`", "2.8.0") + def unzip[A,B](xs: Iterable[(A,B)]): (List[A], List[B]) = + xs.foldRight[(List[A], List[B])]((Nil, Nil)) { + case ((x, y), (xs, ys)) => (x :: xs, y :: ys) + } + + /** + * Returns the `Left` values in the given `Iterable` of `Either`s. + */ + @deprecated("use `xs collect { case Left(x: A) => x }` instead of `List.lefts(xs)`", "2.8.0") + def lefts[A, B](es: Iterable[Either[A, B]]) = + es.foldRight[List[A]](Nil)((e, as) => e match { + case Left(a) => a :: as + case Right(_) => as + }) + + /** + * Returns the `Right` values in the given `Iterable` of `Either`s. + */ + @deprecated("use `xs collect { case Right(x: B) => x }` instead of `List.rights(xs)`", "2.8.0") + def rights[A, B](es: Iterable[Either[A, B]]) = + es.foldRight[List[B]](Nil)((e, bs) => e match { + case Left(_) => bs + case Right(b) => b :: bs + }) + + /** Transforms an Iterable of Eithers into a pair of lists. + * + * @param xs the iterable of Eithers to separate + * @return a pair of lists. + */ + @deprecated("use `(for (Left(x) <- es) yield x, for (Right(x) <- es) yield x)` instead", "2.8.0") + def separate[A,B](es: Iterable[Either[A, B]]): (List[A], List[B]) = + es.foldRight[(List[A], List[B])]((Nil, Nil)) { + case (Left(a), (lefts, rights)) => (a :: lefts, rights) + case (Right(b), (lefts, rights)) => (lefts, b :: rights) + } + + /** Converts an iterator to a list. + * + * @param it the iterator to convert + * @return a list that contains the elements returned by successive + * calls to `it.next` + */ + @deprecated("use `it.toList` instead of `List.toList(it)`", "2.8.0") + def fromIterator[A](it: Iterator[A]): List[A] = it.toList + + /** Converts an array into a list. + * + * @param arr the array to convert + * @return a list that contains the same elements than `arr` + * in the same order + */ + @deprecated("use `array.toList` instead of `List.fromArray(array)`", "2.8.0") + def fromArray[A](arr: Array[A]): List[A] = fromArray(arr, 0, arr.length) + + /** Converts a range of an array into a list. + * + * @param arr the array to convert + * @param start the first index to consider + * @param len the length of the range to convert + * @return a list that contains the same elements than `arr` + * in the same order + */ + @deprecated("use `array.view(start, end).toList` instead of `List.fromArray(array, start, end)`", "2.8.0") + def fromArray[A](arr: Array[A], start: Int, len: Int): List[A] = { + var res: List[A] = Nil + var i = start + len + while (i > start) { + i -= 1 + res = arr(i) :: res + } + res + } + + /** Returns the list resulting from applying the given function `f` + * to corresponding elements of the argument lists. + * + * @param f function to apply to each pair of elements. + * @return `[f(a,,0,,,b,,0,,), ..., f(a,,n,,,b,,n,,)]` if the lists are + * `[a,,0,,, ..., a,,k,,]`, `[b,,0,,, ..., b,,l,,]` and + * `n = min(k,l)` + */ + @deprecated("use `(xs, ys).zipped.map(f)` instead of `List.map2(xs, ys)(f)`", "2.8.0") + def map2[A,B,C](xs: List[A], ys: List[B])(f: (A, B) => C): List[C] = { + val b = new ListBuffer[C] + var xc = xs + var yc = ys + while (!xc.isEmpty && !yc.isEmpty) { + b += f(xc.head, yc.head) + xc = xc.tail + yc = yc.tail + } + b.toList + } + + /** Tests whether the given predicate `p` holds + * for all corresponding elements of the argument lists. + * + * @param p function to apply to each pair of elements. + * @return `(p(a<sub>0</sub>,b<sub>0</sub>) && + * ... && p(a<sub>n</sub>,b<sub>n</sub>))]` + * if the lists are `[a<sub>0</sub>, ..., a<sub>k</sub>]`; + * `[b<sub>0</sub>, ..., b<sub>l</sub>]` + * and `n = min(k,l)` + */ + @deprecated("use `(xs, ys).zipped.forall(f)` instead of `List.forall2(xs, ys)(f)`", "2.8.0") + def forall2[A,B](xs: List[A], ys: List[B])(f: (A, B) => Boolean): Boolean = { + var xc = xs + var yc = ys + while (!xc.isEmpty && !yc.isEmpty) { + if (!f(xc.head, yc.head)) return false + xc = xc.tail + yc = yc.tail + } + true + } + + /** Tests whether the given predicate `p` holds + * for some corresponding elements of the argument lists. + * + * @param p function to apply to each pair of elements. + * @return `n != 0 && (p(a<sub>0</sub>,b<sub>0</sub>) || + * ... || p(a<sub>n</sub>,b<sub>n</sub>))]` if the lists are + * `[a<sub>0</sub>, ..., a<sub>k</sub>]`, + * `[b<sub>0</sub>, ..., b<sub>l</sub>]` and + * `n = min(k,l)` + */ + @deprecated("use `(xs, ys).zipped.exists(f)` instead of `List.exists2(xs, ys)(f)`", "2.8.0") + def exists2[A,B](xs: List[A], ys: List[B])(f: (A, B) => Boolean): Boolean = { + var xc = xs + var yc = ys + while (!xc.isEmpty && !yc.isEmpty) { + if (f(xc.head, yc.head)) return true + xc = xc.tail + yc = yc.tail + } + false + } + + /** Transposes a list of lists. + * pre: All element lists have the same length. + * + * @param xss the list of lists + * @return the transposed list of lists + */ + @deprecated("use `xss.transpose` instead of `List.transpose(xss)`", "2.8.0") + def transpose[A](xss: List[List[A]]): List[List[A]] = { + val buf = new ListBuffer[List[A]] + var yss = xss + while (!yss.head.isEmpty) { + buf += (yss map (_.head)) + yss = (yss map (_.tail)) + } + buf.toList + } } /** Only used for list serialization */ diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala index 16d7e68dee..c92c0268b6 100644 --- a/src/library/scala/collection/immutable/Range.scala +++ b/src/library/scala/collection/immutable/Range.scala @@ -51,15 +51,35 @@ extends collection.AbstractSeq[Int] { override def par = new ParRange(this) - // This member is designed to enforce conditions: - // (step != 0) && (length <= Int.MaxValue), - // but cannot be evaluated eagerly because we have a pattern where ranges - // are constructed like: "x to y by z" - // The "x to y" piece should not trigger an exception. So the calculation - // is delayed, which means it will not fail fast for those cases where failing - // was correct. - private lazy val numRangeElements: Int = Range.count(start, end, step, isInclusive) - + private def gap = end.toLong - start.toLong + private def isExact = gap % step == 0 + private def hasStub = isInclusive || !isExact + private def longLength = gap / step + ( if (hasStub) 1 else 0 ) + + // Check cannot be evaluated eagerly because we have a pattern where + // ranges are constructed like: "x to y by z" The "x to y" piece + // should not trigger an exception. So the calculation is delayed, + // which means it will not fail fast for those cases where failing was + // correct. + override final val isEmpty = ( + (start > end && step > 0) + || (start < end && step < 0) + || (start == end && !isInclusive) + ) + final val numRangeElements: Int = { + if (step == 0) throw new IllegalArgumentException("step cannot be 0.") + else if (isEmpty) 0 + else { + val len = longLength + if (len > scala.Int.MaxValue) -1 + else len.toInt + } + } + final val lastElement = start + (numRangeElements - 1) * step + final val terminalElement = start + numRangeElements * step + + override def last = if (isEmpty) Nil.last else lastElement + protected def copy(start: Int, end: Int, step: Int): Range = new Range(start, end, step) /** Create a new range with the `start` and `end` values of this range and @@ -71,93 +91,46 @@ extends collection.AbstractSeq[Int] def isInclusive = false - override def length: Int = numRangeElements - override lazy val last: Int = - if (length == 0) Nil.last - else locationAfterN(length - 1) - - final override def isEmpty = length == 0 - - @inline - final def apply(idx: Int): Int = { - if (idx < 0 || idx >= length) throw new IndexOutOfBoundsException(idx.toString) - locationAfterN(idx) + override def size = length + override def length = if (numRangeElements < 0) fail() else numRangeElements + + private def description = "%d %s %d by %s".format(start, if (isInclusive) "to" else "until", end, step) + private def fail() = throw new IllegalArgumentException(description + ": seqs cannot contain more than Int.MaxValue elements.") + private def validateMaxLength() { + if (numRangeElements < 0) + fail() } - /** @note Making foreach run as fast as a while loop is a challenge. - * The key elements which I can observe making a difference are: - * - * - the inner loop should be as small as possible - * - the inner loop should be monomorphic - * - the inner loop should perform no boxing and no avoidable tests - * - * This is achieved by: - * - * - keeping initialization logic out of the inner loop - * - dispatching to custom variations based on initial conditions - * - tricking the compiler into always calling Function1#apply$mcVI$sp - * - * The last one is important and less than obvious. Even when foreach - * was specialized on Unit, only Int => Unit arguments benefited from it. - * Other function types would be accepted, but in the absence of full - * specialization the integer argument was boxed on every call. For example: - * - class A { - final def f(x: Int): Int = x + 1 - // Calls Range.foreach, which calls Function1.apply - def g1 = 1 until 100 foreach { x => f(x) } - // Calls Range.foreach$mVc$sp, which calls Function1.apply$mcVI$sp - def g2 = 1 until 100 foreach { x => f(x) ; () } - } - * - * However! Since the result of the closure is always discarded, we - * simply cast it to Int => Unit, thereby executing the fast version. - * The seemingly looming ClassCastException can never arrive. - */ - @inline final override def foreach[U](f: Int => U) { - if (step < 0) { - if (isInclusive) foreachDownIn(f.asInstanceOf[Int => Unit]) - else foreachDownEx(f.asInstanceOf[Int => Unit]) - } - else { - if (isInclusive) foreachUpIn(f.asInstanceOf[Int => Unit]) - else foreachUpEx(f.asInstanceOf[Int => Unit]) + def validateRangeBoundaries(f: Int => Any): Boolean = { + validateMaxLength() + + start != Int.MinValue || end != Int.MinValue || { + var count = 0 + var num = start + while (count < numRangeElements) { + f(num) + count += 1 + num += step + } + false } } - /** !!! These methods must be public or they will not be inlined. - * But they are certainly not intended to be part of the API. - * This collision between inlining requirements and access semantics - * is highly unfortunate and must be resolved. - * - * Proposed band-aid: an @internal annotation. - */ - @inline final def foreachDownIn(f: Int => Unit) { - var i = start - while (i >= end) { - f(i) - i += step - } - } - @inline final def foreachUpIn(f: Int => Unit) { - var i = start - while (i <= end) { - f(i) - i += step - } + @inline final def apply(idx: Int): Int = { + validateMaxLength() + if (idx < 0 || idx >= numRangeElements) throw new IndexOutOfBoundsException(idx.toString) + else start + (step * idx) } - @inline final def foreachDownEx(f: Int => Unit) { - var i = start - while (i > end) { - f(i) - i += step - } - } - @inline final def foreachUpEx(f: Int => Unit) { - var i = start - while (i < end) { - f(i) - i += step + + @inline final override def foreach[@specialized(Unit) U](f: Int => U) { + if (validateRangeBoundaries(f)) { + var i = start + val terminal = terminalElement + val step = this.step + while (i != terminal) { + f(i) + i += step + } } } @@ -169,8 +142,8 @@ extends collection.AbstractSeq[Int] * @return a new range consisting of `n` first elements. */ final override def take(n: Int): Range = ( - if (n <= 0 || length == 0) newEmptyRange(start) - else if (n >= length) this + if (n <= 0 || isEmpty) newEmptyRange(start) + else if (n >= numRangeElements) this else new Range.Inclusive(start, locationAfterN(n - 1), step) ) @@ -182,8 +155,8 @@ extends collection.AbstractSeq[Int] * @return a new range consisting of all the elements of this range except `n` first elements. */ final override def drop(n: Int): Range = ( - if (n <= 0 || length == 0) this - else if (n >= length) newEmptyRange(end) + if (n <= 0 || isEmpty) this + else if (n >= numRangeElements) newEmptyRange(end) else copy(locationAfterN(n), end, step) ) @@ -218,7 +191,7 @@ extends collection.AbstractSeq[Int] var current = start var counted = 0 - while (counted < length && p(current)) { + while (counted < numRangeElements && p(current)) { counted += 1 current += step } @@ -226,7 +199,7 @@ extends collection.AbstractSeq[Int] } // Tests whether a number is within the endpoints, without testing // whether it is a member of the sequence (i.e. when step > 1.) - private def isWithinBoundaries(elem: Int) = (length > 0) && ( + private def isWithinBoundaries(elem: Int) = !isEmpty && ( (step > 0 && start <= elem && elem <= last ) || (step < 0 && last <= elem && elem <= start) ) @@ -255,21 +228,21 @@ extends collection.AbstractSeq[Int] * * $doesNotUseBuilders */ - final override def takeRight(n: Int): Range = drop(length - n) + final override def takeRight(n: Int): Range = drop(numRangeElements - n) /** Creates a new range consisting of the initial `length - n` elements of the range. * * $doesNotUseBuilders */ - final override def dropRight(n: Int): Range = take(length - n) + final override def dropRight(n: Int): Range = take(numRangeElements - n) /** Returns the reverse of this range. * * $doesNotUseBuilders */ final override def reverse: Range = - if (length > 0) new Range.Inclusive(last, start, -step) - else this + if (isEmpty) this + else new Range.Inclusive(last, start, -step) /** Make range inclusive. */ @@ -280,10 +253,9 @@ extends collection.AbstractSeq[Int] final def contains(x: Int) = isWithinBoundaries(x) && ((x - start) % step == 0) final override def sum[B >: Int](implicit num: Numeric[B]): Int = { - val len = length - if (len == 0) 0 - else if (len == 1) head - else (len.toLong * (head + last) / 2).toInt + if (isEmpty) 0 + else if (numRangeElements == 1) head + else (numRangeElements.toLong * (head + last) / 2).toInt } override def toIterable = this @@ -293,7 +265,7 @@ extends collection.AbstractSeq[Int] override def equals(other: Any) = other match { case x: Range => (x canEqual this) && (length == x.length) && ( - (length == 0) || // all empty sequences are equal + isEmpty || // all empty sequences are equal (start == x.start && last == x.last) // same length and same endpoints implies equality ) case _ => @@ -304,7 +276,7 @@ extends collection.AbstractSeq[Int] */ override def toString() = { - val endStr = if (length > Range.MAX_PRINT) ", ... )" else ")" + val endStr = if (numRangeElements > Range.MAX_PRINT) ", ... )" else ")" take(Range.MAX_PRINT).mkString("Range(", ", ", endStr) } } @@ -415,3 +387,4 @@ object Range { // super.foreach(f) } } +
\ No newline at end of file diff --git a/src/partest/scala/tools/partest/nest/CompileManager.scala b/src/partest/scala/tools/partest/nest/CompileManager.scala index f4ebfb7e7d..68688ff949 100644 --- a/src/partest/scala/tools/partest/nest/CompileManager.scala +++ b/src/partest/scala/tools/partest/nest/CompileManager.scala @@ -75,7 +75,8 @@ class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler { val logWriter = new FileWriter(log) // check whether there is a ".flags" file - val flagsFileName = "%s.flags" format (basename(log.getName) dropRight 4) // 4 is "-run" or similar + val logFile = basename(log.getName) + val flagsFileName = "%s.flags" format (logFile.substring(0, logFile.lastIndexOf("-"))) val argString = (io.File(log).parent / flagsFileName) ifFile (x => updatePluginPath(x.slurp())) getOrElse "" val allOpts = fileManager.SCALAC_OPTS.toList ::: argString.split(' ').toList.filter(_.length > 0) val args = allOpts.toList |