From d718a7c7f31afee174958f63d23ede87394a7a4a Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 9 Dec 2011 22:33:01 +0100 Subject: Batch files no longer swallow exit codes Usually scripts like scala.bat and scalac.bat correctly propagate exit codes from underlying Java invocations. However, if you run these scripts as follows: "cmd /c scala ...", then errorlevel gets swallowed. This simple patch fixes the aforementioned problem. Fixes SI-5295, no review. --- test/files/jvm/mkLibNatives.bat | 2 +- test/partest.bat | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/files/jvm/mkLibNatives.bat b/test/files/jvm/mkLibNatives.bat index e11b6ee21c..2f99f7aab5 100755 --- a/test/files/jvm/mkLibNatives.bat +++ b/test/files/jvm/mkLibNatives.bat @@ -67,4 +67,4 @@ goto end :end if "%OS%"=="Windows_NT" @endlocal - +exit /b %errorlevel% diff --git a/test/partest.bat b/test/partest.bat index 0b3f5fbf33..4c97a53122 100755 --- a/test/partest.bat +++ b/test/partest.bat @@ -101,3 +101,4 @@ goto end :end if "%OS%"=="Windows_NT" @endlocal +exit /b %errorlevel% -- cgit v1.2.3 From 4cfc633fc6cb2ab0f473c2e5141724017d444dc6 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 12 Dec 2011 06:40:18 -0800 Subject: Range.foreach optimization. This makes code like 0 to 100 foreach (x += _) as fast as (often faster than, in fact) a while loop. See the comment in Range for the gory details. More investigation should be done regarding total impact on inlining behavior. Review by @odersky. --- src/library/scala/collection/immutable/Range.scala | 89 +++++++++++++++++++--- .../scala/collection/immutable/range-bench.scala | 61 +++++++++++++++ 2 files changed, 138 insertions(+), 12 deletions(-) create mode 100644 test/benchmarks/src/scala/collection/immutable/range-bench.scala (limited to 'test') diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala index e891f8bec8..16d7e68dee 100644 --- a/src/library/scala/collection/immutable/Range.scala +++ b/src/library/scala/collection/immutable/Range.scala @@ -71,18 +71,6 @@ extends collection.AbstractSeq[Int] def isInclusive = false - @inline final override def foreach[@specialized(Unit) U](f: Int => U) { - if (length > 0) { - val last = this.last - var i = start - while (i != last) { - f(i) - i += step - } - f(i) - } - } - override def length: Int = numRangeElements override lazy val last: Int = if (length == 0) Nil.last @@ -95,6 +83,83 @@ extends collection.AbstractSeq[Int] if (idx < 0 || idx >= length) throw new IndexOutOfBoundsException(idx.toString) locationAfterN(idx) } + + /** @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]) + } + } + + /** !!! 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 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 + } + } /** Creates a new range containing the first `n` elements of this range. * diff --git a/test/benchmarks/src/scala/collection/immutable/range-bench.scala b/test/benchmarks/src/scala/collection/immutable/range-bench.scala new file mode 100644 index 0000000000..e167ff04e8 --- /dev/null +++ b/test/benchmarks/src/scala/collection/immutable/range-bench.scala @@ -0,0 +1,61 @@ +package scala.collection.immutable +package benchmarks + +object RangeTest { + // not inlined any more, needs investigation + // + // class XXS { + // private val array = Array.range(0, 100) + // def tst = { var sum = 0; for (i <- 0 until array.length) sum += array(i); sum } + // } + + var x: Int = 0 + + def foreachSum(max: Int): Int = { + var sum = 0 + 1 to max foreach (sum += _) + sum + } + def whileSum(max: Int) = { + var sum = 0 + var num = 1 + while (num <= max) { + sum += num + num += 1 + } + sum + } + + def show(max: Int, foreachNanos: Long, whileNanos: Long) { + val winner = if (foreachNanos < whileNanos) "foreachSum" else "whileSum" + val ratio = if (foreachNanos < whileNanos) foreachNanos.toDouble / whileNanos else whileNanos.toDouble / foreachNanos + println("1 to %d:, %12s wins, %.3f: foreach %.3f while %.3f".format( + max, winner, ratio, + foreachNanos.toDouble / 1000000L, + whileNanos.toDouble / 1000000L) + ) + } + + def run(max: Int) = { + val foreachFirst = util.Random.nextBoolean + val t1 = System.nanoTime + x = if (foreachFirst) foreachSum(max) else whileSum(max) + val t2 = System.nanoTime + x = if (foreachFirst) whileSum(max) else foreachSum(max) + val t3 = System.nanoTime + + val foreachNanos = if (foreachFirst) t2 - t1 else t3 - t2 + val whileNanos = if (foreachFirst) t3 - t2 else t2 - t1 + show(max, foreachNanos, whileNanos) + } + + def main(args: Array[String]): Unit = { + var max = if (args.isEmpty) 100 else args(0).toInt + while (max > 0) { + run(max) + run(max) + run(max) + max += (max / 7) + } + } +} -- cgit v1.2.3 From 5aebaac08a0debfdc366330937e3a8ecf6892f78 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 12 Dec 2011 23:17:23 -0800 Subject: Test case closes SI-4273. --- test/files/pos/t4273.scala | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 test/files/pos/t4273.scala (limited to 'test') diff --git a/test/files/pos/t4273.scala b/test/files/pos/t4273.scala new file mode 100644 index 0000000000..9a942e8325 --- /dev/null +++ b/test/files/pos/t4273.scala @@ -0,0 +1,8 @@ +class A { + implicit def compareComparables[T](x: T)(implicit ord: Ordering[T]) = new ord.Ops(x) + + class Bippy + implicit val bippyOrdering = new Ordering[Bippy] { def compare(x: Bippy, y: Bippy) = util.Random.nextInt } + + (new Bippy) < (new Bippy) +} \ No newline at end of file -- cgit v1.2.3 From 177baffa6133a5f3e1308f6e3f1306cfa4804ce0 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 12 Dec 2011 23:21:24 -0800 Subject: Test case closes SI-4063. --- test/files/pos/t4063.scala | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 test/files/pos/t4063.scala (limited to 'test') diff --git a/test/files/pos/t4063.scala b/test/files/pos/t4063.scala new file mode 100644 index 0000000000..5e19c42edc --- /dev/null +++ b/test/files/pos/t4063.scala @@ -0,0 +1,39 @@ +trait Parallel +trait Parallelizable[+ParRepr <: Parallel] + +trait PIterableLike[+T, +Repr <: Parallel] extends Parallel with Parallelizable[PIterableLike[T, Repr]] + +trait PMap[K, V] extends PIterableLike[(K, V), PMap[K, V]] +trait PSet[T] extends PIterableLike[T, PSet[T]] + +trait CIterableLike[+T, +Repr] + +trait CSet[T] extends CIterableLike[T, CSet[T]] with Parallelizable[PSet[T]] + +trait CMap[K, V] extends CIterableLike[(K, V), CMap[K, V]] with Parallelizable[PMap[K, V]] + +object Test { + var x = 0 + + def main() { + val map: CMap[Int, CSet[Int]] = new CMap[Int, CSet[Int]] {} + val set: CSet[Int] = new CSet[Int] {} + + // should infer type argument + //map.synchronized[CIterableLike[Any, Any] with Parallelizable[PIterableLike[Any, Parallel with Parallelizable[Parallel]]]] { + // or: + //map.synchronized[CIterableLike[Any, Any] with Parallelizable[PIterableLike[Any, Parallel]]] { + // or, maybe it could also infer existential types: + //map.synchronized[CIterableLike[Any, _] with Parallelizable[PIterableLike[Any, _]]] { + + map.synchronized { + if (x == 0) { + map + } else { + set + } + } + + } +} + -- cgit v1.2.3 From 6912ff828db28a4277ab78fea8266f2904bc2a6b Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 12 Dec 2011 23:59:05 -0800 Subject: Fix for seq/array varargs crasher. Closes SI-4024. --- src/compiler/scala/tools/nsc/transform/UnCurry.scala | 4 +++- test/files/run/t4024.scala | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 91ac00d946..f319abd060 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -374,7 +374,9 @@ abstract class UnCurry extends InfoTransform assert(toArraySym != NoSymbol) def getManifest(tp: Type): Tree = { val manifestOpt = localTyper.findManifest(tp, false) - if (!manifestOpt.tree.isEmpty) manifestOpt.tree + // Don't want bottom types getting any further than this (SI-4024) + if (tp.typeSymbol.isBottomClass) getManifest(AnyClass.tpe) + else if (!manifestOpt.tree.isEmpty) manifestOpt.tree else if (tp.bounds.hi ne tp) getManifest(tp.bounds.hi) else localTyper.getManifestTree(tree.pos, tp, false) } diff --git a/test/files/run/t4024.scala b/test/files/run/t4024.scala index ef768beb99..7c62a3fc6e 100644 --- a/test/files/run/t4024.scala +++ b/test/files/run/t4024.scala @@ -5,5 +5,16 @@ object Test extends App { val m = x.getClass.getMethod("toString") assert(m.invoke(x, (Nil: List[AnyRef]): _*) == "abc") + + Test2.main(Array()) } + +object Test2 { + def main(args: Array[String]): Unit = { + val x = "abc" + val m = x.getClass.getMethod("toString") + m.invoke(x, Nil: _*) + m.invoke(x, Seq(): _*) + } +} -- cgit v1.2.3 From bf2643764614f03eb7eb820a5f0c08f6ec799254 Mon Sep 17 00:00:00 2001 From: "Daniel C. Sobral" Date: Thu, 15 Dec 2011 18:14:03 -0200 Subject: Improve quality of scalacheck range tests input and output. Remove some dead code, activate ByOne generator again, add generators for inclusive ranges, add generators that concentrate on the boundaries, and add some print statements next to exceptions that might get eaten by out of memory errors. --- test/files/scalacheck/range.scala | 81 ++++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 26 deletions(-) (limited to 'test') diff --git a/test/files/scalacheck/range.scala b/test/files/scalacheck/range.scala index 56295f204c..72979115be 100644 --- a/test/files/scalacheck/range.scala +++ b/test/files/scalacheck/range.scala @@ -12,10 +12,16 @@ class Counter(r: Range) { if (cnt % 500000000L == 0L) { println("Working: %s %d %d" format (str, cnt, x)) } - if (cnt > (Int.MaxValue.toLong + 1) * 2) - error("Count exceeds maximum possible for an Int Range") - if ((r.step > 0 && last.exists(_ > x)) || (r.step < 0 && last.exists(_ < x))) - error("Range wrapped: %d %s" format (x, last.toString)) + if (cnt > (Int.MaxValue.toLong + 1) * 2) { + val msg = "Count exceeds maximum possible for an Int Range: %s" format str + println(msg) // exception is likely to be eaten by an out of memory error + sys error msg + } + if ((r.step > 0 && last.exists(_ > x)) || (r.step < 0 && last.exists(_ < x))) { + val msg = "Range %s wrapped: %d %s" format (str, x, last.toString) + println(msg) // exception is likely to be eaten by an out of memory error + sys error msg + } last = Some(x) } } @@ -23,29 +29,40 @@ class Counter(r: Range) { abstract class RangeTest(kind: String) extends Properties("Range "+kind) { def myGen: Gen[Range] - val genRange = for { - start <- arbitrary[Int] - end <- arbitrary[Int] - step <- Gen.choose(1, (start - end).abs + 1) - } yield if (start < end) Range(start, end, step) else Range(start, end, -step) - - val genReasonableSizeRange = for { - start <- choose(-Int.MinValue, Int.MaxValue) - end <- choose(-Int.MinValue, Int.MaxValue) + def genReasonableSizeRange = oneOf(genArbitraryRange, genBoundaryRange) + + def genArbitraryRange = for { + start <- choose(Int.MinValue, Int.MaxValue) + end <- choose(Int.MinValue, Int.MaxValue) step <- choose(-Int.MaxValue, Int.MaxValue) } yield Range(start, end, if (step == 0) 100 else step) - val genSmallRange = for { + def genBoundaryRange = for { + boundary <- oneOf(Int.MinValue, -1, 0, 1, Int.MaxValue) + isStart <- arbitrary[Boolean] + size <- choose(1, 100) + step <- choose(1, 101) + } yield { + val signum = if (boundary == 0) 1 else boundary.signum + if (isStart) Range(boundary, boundary - size * boundary.signum, - step * signum) + else Range(boundary - size * boundary.signum, boundary, step * signum) + } + + + def genSmallRange = for { start <- choose(-100, 100) end <- choose(-100, 100) step <- choose(1, 1) } yield if (start < end) Range(start, end, step) else Range(start, end, -step) - val genRangeByOne = for { - start <- arbitrary[Int] - end <- arbitrary[Int] - if (end.toLong - start.toLong).abs <= 10000000L - } yield if (start < end) Range(start, end) else Range(end, start) + def genRangeByOne = oneOf(genRangeOpenByOne, genRangeClosedByOne) + + def genRangeOpenByOne = for { + r <- oneOf(genSmallRange, genBoundaryRange) + if (r.end.toLong - r.start.toLong).abs <= 10000000L + } yield if (r.start < r.end) Range(r.start, r.end) else Range(r.end, r.start) + + def genRangeClosedByOne = for (r <- genRangeOpenByOne) yield r.start to r.end def str(r: Range) = "Range["+r.start+", "+r.end+", "+r.step+(if (r.isInclusive) "]" else ")") @@ -71,7 +88,8 @@ abstract class RangeTest(kind: String) extends Properties("Range "+kind) { def multiple(r: Range, x: Int) = (x.toLong - r.start) % r.step == 0 - property("foreach.step") = forAll(myGen) { r => + property("foreach.step") = forAllNoShrink(myGen) { r => +// println("foreach.step "+str(r)) var allValid = true val cnt = new Counter(r) // println("--------------------") @@ -84,6 +102,7 @@ abstract class RangeTest(kind: String) extends Properties("Range "+kind) { } property("foreach.inside.range") = forAll(myGen) { r => +// println("foreach.inside.range "+str(r)) var allValid = true var last: Option[Int] = None val cnt = new Counter(r) @@ -94,6 +113,7 @@ abstract class RangeTest(kind: String) extends Properties("Range "+kind) { } property("foreach.visited.size") = forAll(myGen) { r => +// println("foreach.visited.size "+str(r)) var visited = 0L val cnt = new Counter(r) r foreach { x => cnt(x) @@ -108,14 +128,17 @@ abstract class RangeTest(kind: String) extends Properties("Range "+kind) { } property("length") = forAll(myGen suchThat (r => expectedSize(r).toInt == expectedSize(r))) { r => +// println("length "+str(r)) (r.length == expectedSize(r)) :| str(r) } property("isEmpty") = forAll(myGen suchThat (r => expectedSize(r).toInt == expectedSize(r))) { r => +// println("isEmpty "+str(r)) (r.isEmpty == (expectedSize(r) == 0L)) :| str(r) } property("contains") = forAll(myGen, arbInt.arbitrary) { (r, x) => +// println("contains "+str(r)) // println("----------------") // println(str(r)) // println(x) @@ -126,11 +149,13 @@ abstract class RangeTest(kind: String) extends Properties("Range "+kind) { } property("take") = forAll(myGen suchThat (r => expectedSize(r).toInt == expectedSize(r)), arbInt.arbitrary) { (r, x) => +// println("take "+str(r)) val t = r take x (t.size == (0 max x min r.size) && t.start == r.start && t.step == r.step) :| str(r)+" / "+str(t)+": "+x } property("init") = forAll(myGen suchThat (r => expectedSize(r).toInt == expectedSize(r))) { r => +// println("init "+str(r)) (r.size == 0) || { val t = r.init (t.size + 1 == r.size) && (t.isEmpty || t.head == r.head) @@ -138,6 +163,7 @@ abstract class RangeTest(kind: String) extends Properties("Range "+kind) { } property("takeWhile") = forAll(myGen suchThat (r => expectedSize(r).toInt == expectedSize(r)), arbInt.arbitrary) { (r, x) => +// println("takeWhile "+str(r)) val t = (if (r.step > 0) r takeWhile (_ <= x) else r takeWhile(_ >= x)) if (r.size == 0) { (t.size == 0) :| str(r)+" / "+str(t)+": "+x @@ -148,6 +174,7 @@ abstract class RangeTest(kind: String) extends Properties("Range "+kind) { } property("reverse.toSet.equal") = forAll(myGen) { r => +// println("reverse.toSet.equal "+str(r)) val reversed = r.reverse val aresame = r.toSet == reversed.toSet if (!aresame) { @@ -157,7 +184,7 @@ abstract class RangeTest(kind: String) extends Properties("Range "+kind) { println(r.toSet) println(reversed.toSet) } - aresame + aresame :| str(r) } } @@ -178,11 +205,11 @@ object InclusiveRangeTest extends RangeTest("inclusive") { } object ByOneRangeTest extends RangeTest("byOne") { - override def myGen = genSmallRange + override def myGen = genRangeByOne } object InclusiveByOneRangeTest extends RangeTest("inclusiveByOne") { - override def myGen = for (r <- genSmallRange) yield r.inclusive + override def myGen = for (r <- genRangeByOne) yield r.inclusive } object SmallValuesRange extends RangeTest("smallValues") { @@ -207,9 +234,11 @@ object TooLargeRange extends Properties("Too Large Range") { object Test extends Properties("Range") { import org.scalacheck.{ Test => STest } - List(NormalRangeTest, InclusiveRangeTest, ByOneRangeTest, InclusiveByOneRangeTest, TooLargeRange) foreach { ps => - STest.checkProperties(STest.Params(testCallback = ConsoleReporter(0)), ps) - } + include(NormalRangeTest) + include(InclusiveRangeTest) + include(ByOneRangeTest) + include(InclusiveByOneRangeTest) + include(TooLargeRange) } /* Mini-benchmark -- cgit v1.2.3 From 2f5f7c16870ae1fa97bbca1642659ab8c104b442 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Thu, 15 Dec 2011 14:19:45 -0800 Subject: Fixed scalacheck test to fail if it's failing. --- test/files/scalacheck/CheckEither.scala | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'test') diff --git a/test/files/scalacheck/CheckEither.scala b/test/files/scalacheck/CheckEither.scala index a7e50877a7..0145d3321f 100644 --- a/test/files/scalacheck/CheckEither.scala +++ b/test/files/scalacheck/CheckEither.scala @@ -8,7 +8,7 @@ import org.scalacheck.Test.{Params, check} import org.scalacheck.ConsoleReporter.testStatsEx import Function.tupled -object CheckEither extends Properties("Either") { +object Test extends Properties("Either") { implicit def arbitraryEither[X, Y](implicit xa: Arbitrary[X], ya: Arbitrary[Y]): Arbitrary[Either[X, Y]] = Arbitrary[Either[X, Y]](oneOf(arbitrary[X].map(Left(_)), arbitrary[Y].map(Right(_)))) @@ -186,9 +186,3 @@ object CheckEither extends Properties("Either") { STest.checkProperties(STest.Params(testCallback = ConsoleReporter(0)), this) } } - -object Test { - def main(args: Array[String]): Unit = { - CheckEither.runTests() - } -} -- cgit v1.2.3 From 98108febce145b9f2842937d3ac4a9c1d24f6108 Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Fri, 16 Dec 2011 21:18:38 +0100 Subject: Fixed "Definition Classes" in bug #5287 --- src/compiler/scala/tools/nsc/ast/DocComments.scala | 10 +- .../scala/tools/nsc/doc/model/ModelFactory.scala | 34 ++-- .../scala/tools/partest/nest/CompileManager.scala | 3 +- test/scaladoc/resources/SI_5054_q7.scala | 8 +- test/scaladoc/resources/SI_5287.scala | 17 ++ test/scaladoc/scala/html.flags | 1 + test/scaladoc/scala/html/HtmlFactoryTest.flags | 1 + test/scaladoc/scala/html/HtmlFactoryTest.scala | 183 +++++++++------------ 8 files changed, 129 insertions(+), 128 deletions(-) create mode 100644 test/scaladoc/resources/SI_5287.scala create mode 100644 test/scaladoc/scala/html.flags create mode 100644 test/scaladoc/scala/html/HtmlFactoryTest.flags (limited to 'test') 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/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 diff --git a/test/scaladoc/resources/SI_5054_q7.scala b/test/scaladoc/resources/SI_5054_q7.scala index 26d4b5fcf4..1bd120e30c 100644 --- a/test/scaladoc/resources/SI_5054_q7.scala +++ b/test/scaladoc/resources/SI_5054_q7.scala @@ -6,17 +6,17 @@ trait SI_5054_q7 { * * @param lost a lost parameter * @return some integer - * @usecase def test(): Int + * @usecase def test1(): Int * * This takes the implicit value in scope. * - * Example: `test()` + * Example: `test1()` * - * @usecase def test(explicit: Int): Int + * @usecase def test2(explicit: Int): Int * * This takes the explicit value passed. * - * Example: `test(3)` + * Example: `test2(3)` */ def test(implicit lost: Int): Int } diff --git a/test/scaladoc/resources/SI_5287.scala b/test/scaladoc/resources/SI_5287.scala new file mode 100644 index 0000000000..141ab15325 --- /dev/null +++ b/test/scaladoc/resources/SI_5287.scala @@ -0,0 +1,17 @@ +trait SI_5287_A { + def method(implicit a: Int): Int = a +} + +trait SI_5287_B extends SI_5287_A { + override def method(implicit a: Int): Int = a + 1 +} + +trait SI_5287 extends SI_5287_B{ + /** + * Some explanation + * + * @usecase def method(): Int + * The usecase explanation + */ + override def method(implicit a: Int): Int = a + 3 +} \ No newline at end of file diff --git a/test/scaladoc/scala/html.flags b/test/scaladoc/scala/html.flags new file mode 100644 index 0000000000..b2264ec4f4 --- /dev/null +++ b/test/scaladoc/scala/html.flags @@ -0,0 +1 @@ +-encoding UTF-8 \ No newline at end of file diff --git a/test/scaladoc/scala/html/HtmlFactoryTest.flags b/test/scaladoc/scala/html/HtmlFactoryTest.flags new file mode 100644 index 0000000000..b2264ec4f4 --- /dev/null +++ b/test/scaladoc/scala/html/HtmlFactoryTest.flags @@ -0,0 +1 @@ +-encoding UTF-8 \ No newline at end of file diff --git a/test/scaladoc/scala/html/HtmlFactoryTest.scala b/test/scaladoc/scala/html/HtmlFactoryTest.scala index d1bfbb023f..5b17affbf0 100644 --- a/test/scaladoc/scala/html/HtmlFactoryTest.scala +++ b/test/scaladoc/scala/html/HtmlFactoryTest.scala @@ -21,6 +21,9 @@ object XMLUtil { } object Test extends Properties("HtmlFactory") { + + final val RESOURCES = "test/scaladoc/resources/" + import scala.tools.nsc.doc.{DocFactory, Settings} import scala.tools.nsc.doc.model.IndexModelFactory import scala.tools.nsc.doc.html.HtmlFactory @@ -47,7 +50,7 @@ object Test extends Properties("HtmlFactory") { def createTemplates(basename: String) = { val result = scala.collection.mutable.Map[String, scala.xml.NodeSeq]() - createFactory.makeUniverse(List("test/scaladoc/resources/"+basename)) match { + createFactory.makeUniverse(List(RESOURCES+basename)) match { case Some(universe) => { val index = IndexModelFactory.makeIndex(universe) (new HtmlFactory(universe, index)).writeTemplates((page) => { @@ -61,7 +64,7 @@ object Test extends Properties("HtmlFactory") { } def createReferenceIndex(basename: String) = { - createFactory.makeUniverse(List("test/scaladoc/resources/"+basename)) match { + createFactory.makeUniverse(List(RESOURCES+basename)) match { case Some(universe) => { val index = IndexModelFactory.makeIndex(universe) val pages = index.firstLetterIndex.map({ @@ -81,6 +84,52 @@ object Test extends Properties("HtmlFactory") { val html = scala.stripSuffix(".scala") + ".html" createTemplates(scala)(html) } + + /** + * See checkTextOnly(scalaFile: String, checks: List[String]) + */ + def checkText1(scalaFile: String, check: String, debug: Boolean = true): Boolean = checkText(scalaFile, List(check), debug) + + /** + * This tests the text without the markup - ex: + * + *

+ * + * implicit + * def + * + * + * test(): Int + * + *

+ * + * becomes: + * + * implicit def test(): Int + * + * and is required to contain the text in the given checks + * + * NOTE: Comparison is done ignoring all whitespace + */ + def checkText(scalaFile: String, checks: List[String], debug: Boolean = true): Boolean = { + val htmlFile = scalaFile.stripSuffix(".scala") + ".html" + val htmlText = createTemplates(scalaFile)(htmlFile).text.replace('→',' ').replaceAll("\\s+","") + var result = true + + for (check <- checks) { + val checkText = check.replace('→',' ').replaceAll("\\s+","") + val checkValue = htmlText.contains(checkText) + if (debug && (!checkValue)) { + Console.err.println("Check failed: ") + Console.err.println("HTML: " + htmlText) + Console.err.println("Check: " + checkText) + } + result &&= checkValue + } + + result + } + def shortComments(root: scala.xml.Node) = XMLUtil.stripGroup(root).descendant.flatMap { @@ -377,113 +426,43 @@ object Test extends Properties("HtmlFactory") { createTemplate("SI_4898.scala") true } - - // A piece of the signature - corresponding to the use case - def signature(no: Int, modifier: String) = (""" -
  • - -

    - - """ + modifier + """ - def - - - test(): Int - -

    -

    [use case] -

    -
  • """).replaceAll("\\s+", "") - property("Use cases should override their original members") = { - createTemplate("SI_5054_q1.scala") match { - case node: scala.xml.Node => - node.toString.replaceAll("\\s+","").contains(signature(1, "")) - case _ => false - } - } - - property("Use cases should keep their flags - final should not be lost") = { - createTemplate("SI_5054_q2.scala") match { - case node: scala.xml.Node => - node.toString.replaceAll("\\s+","").contains(signature(2, "final")) - case _ => false - } - } + property("Use cases should override their original members") = + checkText1("SI_5054_q1.scala", """def test(): Int""") && + !checkText1("SI_5054_q1.scala", """def test(implicit lost: Int): Int""") - property("Use cases should keep their flags - implicit should not be lost") = { - createTemplate("SI_5054_q3.scala") match { - case node: scala.xml.Node => - node.toString.replaceAll("\\s+","").contains(signature(3, "implicit")) - case _ => false - } - } - property("Use cases should keep their flags - real abstract should not be lost") = { - createTemplate("SI_5054_q4.scala") match { - case node: scala.xml.Node => - node.toString.replaceAll("\\s+","").contains(signature(4, "abstract")) - case _ => false - } - } - - property("Use cases should keep their flags - traits should not be affected") = { - createTemplate("SI_5054_q5.scala") match { - case node: scala.xml.Node => - node.toString.replaceAll("\\s+","").contains(signature(5, "")) - case _ => false - } - } - - property("Use cases should keep their flags - traits should not be affected") = { - createTemplate("SI_5054_q6.scala") match { - case node: scala.xml.Node => - node.toString.replaceAll("\\s+","").contains(signature(6, "abstract")) - case _ => false - } - } + property("Use cases should keep their flags - final should not be lost") = + checkText1("SI_5054_q2.scala", """final def test(): Int""") - val useCaseExplanation = """ -
  • - -

    - - abstract - def - - - test(): Int - -

    -

    [use case] This takes the implicit value in scope.

    [use case]

    This takes the implicit value in scope.

    Example: test()

    returns

    some integer -

    -
  • - -

    - - abstract - def - - - test(explicit: Int): Int - -

    -

    [use case] This takes the explicit value passed.

    [use case]

    This takes the explicit value passed.

    Example: test(3)

    returns

    some integer -

    -
  • - """.replaceAll("\\s+","") - - property("Use case individual signature test") = { - createTemplate("SI_5054_q7.scala") match { - case node: scala.xml.Node => - node.toString.replaceAll("\\s+","").contains(useCaseExplanation) - case _ => false - } - } + property("Use cases should keep their flags - implicit should not be lost") = + checkText1("SI_5054_q3.scala", """implicit def test(): Int""") + + property("Use cases should keep their flags - real abstract should not be lost") = + checkText1("SI_5054_q4.scala", """abstract def test(): Int""") + + property("Use cases should keep their flags - traits should not be affected") = + checkText1("SI_5054_q5.scala", """def test(): Int""") + + property("Use cases should keep their flags - traits should not be affected") = + checkText1("SI_5054_q6.scala", """abstract def test(): Int""") + + property("Use case individual signature test") = + checkText("SI_5054_q7.scala", List( + """abstract def test2(explicit: Int): Int [use case] This takes the explicit value passed.""", + """abstract def test1(): Int [use case] This takes the implicit value in scope.""")) + + property("Display correct \"Definition classes\"") = + checkText1("SI_5287.scala", + """def method(): Int + [use case] The usecase explanation + [use case] The usecase explanation + Definition Classes SI_5287 SI_5287_B SI_5287_A""", debug=true) + // explanation appears twice, as small comment and full comment { val files = createTemplates("basic.scala") - println(files) + //println(files) property("class") = files.get("com/example/p1/Clazz.html") match { case Some(node: scala.xml.Node) => { -- cgit v1.2.3 From ab07db12cc09fd34cfab5abca9dd0f01df5f77a5 Mon Sep 17 00:00:00 2001 From: Josh Suereth Date: Sun, 18 Dec 2011 12:05:12 -0500 Subject: unzip(3) on view now returns view. * Added unzip and unzip3 to TraversableViewLike * Added partest tests for unzip on views returning specific collection types. Closes SI-5053 Review by @paulp --- .../scala/collection/TraversableViewLike.scala | 6 ++++++ test/files/run/t5053.check | 6 ++++++ test/files/run/t5053.scala | 20 ++++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 test/files/run/t5053.check create mode 100644 test/files/run/t5053.scala (limited to 'test') diff --git a/src/library/scala/collection/TraversableViewLike.scala b/src/library/scala/collection/TraversableViewLike.scala index 60870cc835..fbecad98fe 100644 --- a/src/library/scala/collection/TraversableViewLike.scala +++ b/src/library/scala/collection/TraversableViewLike.scala @@ -192,6 +192,12 @@ trait TraversableViewLike[+A, override def groupBy[K](f: A => K): immutable.Map[K, This] = thisSeq groupBy f mapValues (xs => newForced(xs)) + override def unzip[A1, A2](implicit asPair: A => (A1, A2)) = + (newMapped(x => asPair(x)._1), newMapped(x => asPair(x)._2)) // TODO - Performance improvements. + + override def unzip3[A1, A2, A3](implicit asTriple: A => (A1, A2, A3)) = + (newMapped(x => asTriple(x)._1), newMapped(x => asTriple(x)._2), newMapped(x => asTriple(x)._3)) // TODO - Performance improvements. + override def toString = viewToString } diff --git a/test/files/run/t5053.check b/test/files/run/t5053.check new file mode 100644 index 0000000000..5ec39bbdeb --- /dev/null +++ b/test/files/run/t5053.check @@ -0,0 +1,6 @@ +true +true +true +true +true +true diff --git a/test/files/run/t5053.scala b/test/files/run/t5053.scala new file mode 100644 index 0000000000..e46dad5ac6 --- /dev/null +++ b/test/files/run/t5053.scala @@ -0,0 +1,20 @@ +object Test extends App { + { + val (left, right) = Seq((1, "a"), (1, "a"), (1, "a"), (3, "c")).view.unzip + println(left.isInstanceOf[scala.collection.SeqViewLike[_,_,_]]) + val (l, m, r) = Seq((1, 1.0, "a"), (1, 1.0, "a"), (1, 1.0, "a"), (3, 3.0, "c")).view.unzip3 + println(l.isInstanceOf[scala.collection.SeqViewLike[_,_,_]]) + } + { + val (left, right) = Iterable((1, "a"), (1, "a"), (1, "a"), (3, "c")).view.unzip + println(left.isInstanceOf[scala.collection.IterableViewLike[_,_,_]]) + val (l, m, r) = Iterable((1, 1.0, "a"), (1, 1.0, "a"), (1, 1.0, "a"), (3, 3.0, "c")).view.unzip3 + println(l.isInstanceOf[scala.collection.IterableViewLike[_,_,_]]) + } + { + val (left, right) = Traversable((1, "a"), (1, "a"), (1, "a"), (3, "c")).view.unzip + println(left.isInstanceOf[scala.collection.TraversableViewLike[_,_,_]]) + val (l, m, r) = Traversable((1, 1.0, "a"), (1, 1.0, "a"), (1, 1.0, "a"), (3, 3.0, "c")).view.unzip3 + println(l.isInstanceOf[scala.collection.TraversableViewLike[_,_,_]]) + } +} -- cgit v1.2.3