summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Suereth <joshua.suereth@gmail.com>2011-12-14 17:42:00 -0500
committerJosh Suereth <joshua.suereth@gmail.com>2011-12-14 17:42:00 -0500
commit2f150c026785854b47132335fe44347dd16d0427 (patch)
treed90befc62e656c73683f09becd88da2ddfe048a8
parent981a9a028cfdae3198687b6591f8d9c2732ef0a8 (diff)
parent249be0ce81c89302b06aa3ed6444aa5bd55659db (diff)
downloadscala-2f150c026785854b47132335fe44347dd16d0427.tar.gz
scala-2f150c026785854b47132335fe44347dd16d0427.tar.bz2
scala-2f150c026785854b47132335fe44347dd16d0427.zip
Merge branch 'xsbt' of github.com:scala/scala into xsbt
-rw-r--r--build.xml6
-rw-r--r--project/ShaResolve.scala13
-rw-r--r--src/compiler/scala/reflect/internal/Chars.scala36
-rw-r--r--src/compiler/scala/reflect/internal/Symbols.scala4
-rw-r--r--src/compiler/scala/tools/ant/templates/tool-windows.tmpl1
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala4
-rw-r--r--src/library/scala/collection/immutable/Map.scala1
-rw-r--r--src/library/scala/collection/immutable/Range.scala89
-rw-r--r--src/library/scala/collection/parallel/immutable/ParRange.scala2
-rw-r--r--test/benchmarks/src/scala/collection/immutable/range-bench.scala61
-rwxr-xr-xtest/files/jvm/mkLibNatives.bat2
-rw-r--r--test/files/pos/t4063.scala39
-rw-r--r--test/files/pos/t4273.scala8
-rw-r--r--test/files/run/t4024.scala11
-rwxr-xr-xtest/partest.bat1
-rwxr-xr-xtools/get-scala-revision10
16 files changed, 246 insertions, 42 deletions
diff --git a/build.xml b/build.xml
index d179b8e240..1770da7317 100644
--- a/build.xml
+++ b/build.xml
@@ -213,8 +213,7 @@ INITIALISATION
<property name="scalac.args.optimise" value=""/>
<!-- scalac.args.quickonly are added to quick.* targets but not others (particularly, locker.)
This is to facilitate testing new command line options which do not yet exist in starr. -->
- <property name="scalac.args.quickonly" value=""/>
-
+ <property name="scalac.args.quickonly" value=""/>
<property name="scalac.args.all" value="${scalac.args} ${scalac.args.optimise}"/>
<property name="scalac.args.quick" value="${scalac.args.all} ${scalac.args.quickonly}"/>
<!-- Setting-up Ant contrib tasks -->
@@ -233,7 +232,6 @@ INITIALISATION
<exec osfamily="windows" executable="tools/get-scala-revision.bat" outputproperty="git.describe" failifexecutionfails="false" />
<!-- some default in case something went wrong getting the revision -->
<property name="git.describe" value="-unknown-"/>
-
<property name="init.avail" value="yes"/>
<!-- Generating version number -->
@@ -241,7 +239,7 @@ INITIALISATION
<property
name="version.number"
value="${version.major}.${version.minor}.${version.patch}.${git.describe}"/>
-
+
<!-- And print-out what we are building -->
<echo message=" build time: ${time.human}" />
<echo message=" java version: ${java.vm.name} ${java.version}" />
diff --git a/project/ShaResolve.scala b/project/ShaResolve.scala
index c6034bbf01..5cc99fd9cf 100644
--- a/project/ShaResolve.scala
+++ b/project/ShaResolve.scala
@@ -4,7 +4,7 @@ import Build._
import Keys._
import Project.Initialize
import scala.collection.{ mutable, immutable }
-
+import scala.collection.parallel.CompositeThrowable
@@ -22,17 +22,24 @@ object ShaResolve {
pullBinaryLibs in ThisBuild <<= (baseDirectory, binaryLibCache, streams) map resolveLibs
)
- def resolveLibs(dir: File, cacheDir: File, s: TaskStreams): Unit = {
+ def resolveLibs(dir: File, cacheDir: File, s: TaskStreams): Unit = loggingParallelExceptions(s) {
val files = (dir / "test" / "files" ** "*.desired.sha1") +++ (dir / "lib" ** "*.desired.sha1")
for {
(file, name) <- (files x relativeTo(dir)).par
- uri = name.dropRight(13)
+ uri = name.dropRight(13).replace('\\', '/')
jar = dir / uri
if !jar.exists || !isValidSha(file)
sha = getShaFromShafile(file)
} pullFile(jar, sha + "/" + uri, cacheDir, s)
}
+ @inline final def loggingParallelExceptions[U](s: TaskStreams)(f: => U): U = try f catch {
+ case t: CompositeThrowable =>
+ s.log.error("Error during parallel execution, GET READ FOR STACK TRACES!!")
+ t.throwables foreach (t2 => s.log.trace(t2))
+ throw t
+ }
+
def getShaFromShafile(file: File): String = (IO read file split "\\s" headOption) getOrElse error("No SHA found for " + file)
diff --git a/src/compiler/scala/reflect/internal/Chars.scala b/src/compiler/scala/reflect/internal/Chars.scala
index 7bd37618ed..f2c90a6721 100644
--- a/src/compiler/scala/reflect/internal/Chars.scala
+++ b/src/compiler/scala/reflect/internal/Chars.scala
@@ -21,27 +21,31 @@ trait Chars {
final val SU = '\u001A'
/** Convert a character digit to an Int according to given base,
- * -1 if no success */
+ * -1 if no success
+ */
def digit2int(ch: Char, base: Int): Int = {
- if ('0' <= ch && ch <= '9' && ch < '0' + base)
- ch - '0'
- else if ('A' <= ch && ch < 'A' + base - 10)
- ch - 'A' + 10
- else if ('a' <= ch && ch < 'a' + base - 10)
- ch - 'a' + 10
- else
- -1
+ val num = (
+ if (ch <= '9') ch - '0'
+ else if ('a' <= ch && ch <= 'z') ch - 'a' + 10
+ else if ('A' <= ch && ch <= 'Z') ch - 'A' + 10
+ else -1
+ )
+ if (0 <= num && num < base) num else -1
}
+ /** Buffer for creating '\ u XXXX' strings. */
+ private[this] val char2uescapeArray = Array[Char]('\\', 'u', 0, 0, 0, 0)
/** Convert a character to a backslash-u escape */
def char2uescape(c: Char): String = {
- var rest = c.toInt
- val buf = new StringBuilder
- for (i <- 1 to 4) {
- buf ++= (rest % 16).toHexString
- rest = rest / 16
- }
- "\\u" + buf.toString.reverse
+ @inline def hexChar(ch: Int): Char =
+ ( if (ch < 10) '0' else 'A' - 10 ) + ch toChar
+
+ char2uescapeArray(2) = hexChar((c >> 12) )
+ char2uescapeArray(3) = hexChar((c >> 8) % 16)
+ char2uescapeArray(4) = hexChar((c >> 4) % 16)
+ char2uescapeArray(5) = hexChar((c ) % 16)
+
+ new String(char2uescapeArray)
}
/** Is character a line break? */
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala
index 75fd733e7e..bc0c81a54b 100644
--- a/src/compiler/scala/reflect/internal/Symbols.scala
+++ b/src/compiler/scala/reflect/internal/Symbols.scala
@@ -1097,6 +1097,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def typeParams: List[Symbol] =
if (isMonomorphicType) Nil
else {
+ // analogously to the "info" getter, here we allow for two completions:
+ // one: sourceCompleter to LazyType, two: LazyType to completed type
+ if (validTo == NoPeriod)
+ atPhase(phaseOf(infos.validFrom))(rawInfo load this)
if (validTo == NoPeriod)
atPhase(phaseOf(infos.validFrom))(rawInfo load this)
diff --git a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl
index c59d46683e..9f1fbc4524 100644
--- a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl
+++ b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl
@@ -86,3 +86,4 @@ goto :eof
:end
@@endlocal
+exit /b %errorlevel%
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/src/library/scala/collection/immutable/Map.scala b/src/library/scala/collection/immutable/Map.scala
index 45cf088dd9..bbefd983fd 100644
--- a/src/library/scala/collection/immutable/Map.scala
+++ b/src/library/scala/collection/immutable/Map.scala
@@ -47,6 +47,7 @@ trait Map[A, +B] extends Iterable[(A, B)]
def withDefault[B1 >: B](d: A => B1): immutable.Map[A, B1] = new Map.WithDefault[A, B1](this, d)
/** The same map with a given default value.
+ * Note: `get`, `contains`, `iterator`, `keys`, etc are not affected by `withDefaultValue`.
*
* Invoking transformer methods (e.g. `map`) will not preserve the default value.
*
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/src/library/scala/collection/parallel/immutable/ParRange.scala b/src/library/scala/collection/parallel/immutable/ParRange.scala
index 2a10458457..350e64739f 100644
--- a/src/library/scala/collection/parallel/immutable/ParRange.scala
+++ b/src/library/scala/collection/parallel/immutable/ParRange.scala
@@ -88,7 +88,7 @@ self =>
/* accessors */
override def foreach[U](f: Int => U): Unit = {
- rangeleft.foreach(f)
+ rangeleft.foreach(f.asInstanceOf[Int => Unit])
ind = len
}
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)
+ }
+ }
+}
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/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
+ }
+ }
+
+ }
+}
+
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
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(): _*)
+ }
+}
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%
diff --git a/tools/get-scala-revision b/tools/get-scala-revision
index 3977a61040..b27b6ddc82 100755
--- a/tools/get-scala-revision
+++ b/tools/get-scala-revision
@@ -7,8 +7,8 @@
# not like releases come out so often that we are duty-bound
# to recalculate this every time.
-# git merge-base v2.9.1 master
-devbase="d6f3184fc8"
+# git merge-base v2.8.2 v2.9.1 master
+devbase="df13e31bbb"
# reimplementing git describe hopefully in a way which works
# without any particular tags, branches, or recent versions of git.
@@ -16,7 +16,9 @@ devbase="d6f3184fc8"
# dev-NNNN-g<sha>
# where NNNN is the number of commits since devbase, which
# is the merge-base of the most recent release and master.
-# Presently hardcoded to reduce uncertainty, v2.9.1/master.
+# Presently hardcoded to reduce uncertainty, v2.8.2/v2.9.1/master.
commits=$(git --no-pager log --pretty=oneline $devbase..HEAD | wc -l)
sha=$(git rev-list -n 1 HEAD)
-printf "dev-%s-g%s\n" $commits ${sha:0:7}
+datestr=$(date "+%Y-%m-%d")
+
+printf "rdev-%s-%s-g%s\n" $commits $datestr ${sha:0:7}