summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-04-05 22:53:54 -0700
committerPaul Phillips <paulp@improving.org>2012-04-05 22:53:54 -0700
commit9ccfce6bbc750dd03c11b0694a3cdc8ad51d7288 (patch)
treee507da821c9aa554116dd2a6797f865beb013d9a
parent296b7061ccef8600c011140fa6fd64afec244ed0 (diff)
parentc10f5c9adef27b02fb0bedc09efcfcf58cb31380 (diff)
downloadscala-9ccfce6bbc750dd03c11b0694a3cdc8ad51d7288.tar.gz
scala-9ccfce6bbc750dd03c11b0694a3cdc8ad51d7288.tar.bz2
scala-9ccfce6bbc750dd03c11b0694a3cdc8ad51d7288.zip
Merge branch 'develop'
-rw-r--r--src/library/scala/StringContext.scala28
-rw-r--r--src/library/scala/annotation/ClassfileAnnotation.scala2
-rw-r--r--src/library/scala/annotation/switch.scala4
-rw-r--r--src/library/scala/collection/parallel/TaskSupport.scala2
-rw-r--r--src/library/scala/concurrent/ConcurrentPackageObject.scala9
-rw-r--r--src/library/scala/concurrent/ExecutionContext.scala17
-rw-r--r--src/library/scala/concurrent/impl/ExecutionContextImpl.scala18
-rw-r--r--test/files/jvm/scala-concurrent-tck.scala290
-rw-r--r--test/files/run/t5614.check3
-rw-r--r--test/files/run/t5614.flags1
-rw-r--r--test/files/run/t5614.scala5
11 files changed, 329 insertions, 50 deletions
diff --git a/src/library/scala/StringContext.scala b/src/library/scala/StringContext.scala
index 1b01355108..be9e0c290a 100644
--- a/src/library/scala/StringContext.scala
+++ b/src/library/scala/StringContext.scala
@@ -79,15 +79,13 @@ case class StringContext(parts: String*) {
* start a format specifier), then the string format specifier `%s` is inserted.
*
* 2. Any `%` characters not in formatting positions are left in the resulting
- * string literally. This is achieved by replacing each such occurrence by a string
- * format specifier `%s` and adding a corresponding argument string `"%"`.
+ * string literally. This is achieved by replacing each such occurrence by the
+ * format specifier `%%`.
*/
def f(args: Any*) = {
checkLengths(args: _*)
val pi = parts.iterator
- val ai = args.iterator
val bldr = new java.lang.StringBuilder
- val args1 = new ArrayBuffer[Any]
def copyString(first: Boolean): Unit = {
val str = treatEscapes(pi.next())
val strIsEmpty = str.length == 0
@@ -98,23 +96,23 @@ case class StringContext(parts: String*) {
bldr append "%s"
idx = 1
}
- val len = str.length
- while (idx < len) {
- if (str(idx) == '%') {
- bldr append (str substring (start, idx)) append "%s"
- args1 += "%"
- start = idx + 1
+ if (!strIsEmpty) {
+ val len = str.length
+ while (idx < len) {
+ if (str(idx) == '%') {
+ bldr append (str substring (start, idx)) append "%%"
+ start = idx + 1
+ }
+ idx += 1
}
- idx += 1
+ bldr append (str substring (start, idx))
}
- if (!strIsEmpty) bldr append (str substring (start, idx))
}
copyString(first = true)
while (pi.hasNext) {
- args1 += ai.next()
copyString(first = false)
}
- bldr.toString format (args1: _*)
+ bldr.toString format (args: _*)
}
}
@@ -144,7 +142,7 @@ object StringContext {
var cur = 0
var idx = 0
def output(ch: Char) = {
- bldr append str substring (start, cur)
+ bldr append str.substring (start, cur)
bldr append ch
start = idx
}
diff --git a/src/library/scala/annotation/ClassfileAnnotation.scala b/src/library/scala/annotation/ClassfileAnnotation.scala
index 582e51996a..2fde5aae80 100644
--- a/src/library/scala/annotation/ClassfileAnnotation.scala
+++ b/src/library/scala/annotation/ClassfileAnnotation.scala
@@ -9,7 +9,7 @@
package scala.annotation
/** A base class for classfile annotations. These are stored as
- * [[http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html#_top Java annotations]]]
+ * [[http://docs.oracle.com/javase/7/docs/technotes/guides/language/annotations.html#_top Java annotations]]]
* in classfiles.
*
* @author Martin Odersky
diff --git a/src/library/scala/annotation/switch.scala b/src/library/scala/annotation/switch.scala
index 3734686b27..ee068f50d4 100644
--- a/src/library/scala/annotation/switch.scala
+++ b/src/library/scala/annotation/switch.scala
@@ -9,8 +9,8 @@ package scala.annotation
/** An annotation to be applied to a match expression. If present,
* the compiler will verify that the match has been compiled to a
- * [[http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2.doc14.html tableswitch]]
- * or [[http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2.doc8.html#lookupswitch lookupswitch]]
+ * [[http://docs.oracle.com/javase/specs/jvms/se5.0/html/Instructions2.doc14.html tableswitch]]
+ * or [[http://docs.oracle.com/javase/specs/jvms/se5.0/html/Instructions2.doc8.html#lookupswitch lookupswitch]]
* and issue an error if it instead compiles into a series of conditional expressions.
* Example usage:
{{{
diff --git a/src/library/scala/collection/parallel/TaskSupport.scala b/src/library/scala/collection/parallel/TaskSupport.scala
index 59b75f523f..2eaa861429 100644
--- a/src/library/scala/collection/parallel/TaskSupport.scala
+++ b/src/library/scala/collection/parallel/TaskSupport.scala
@@ -48,7 +48,7 @@ extends TaskSupport with AdaptiveWorkStealingThreadPoolTasks
* By default, parallel collections are parametrized with this task support object, so parallel collections
* share the same execution context backend as the rest of the `scala.concurrent` package.
*/
-class ExecutionContextTaskSupport(val environment: ExecutionContext = scala.concurrent.executionContext)
+class ExecutionContextTaskSupport(val environment: ExecutionContext = scala.concurrent.defaultExecutionContext)
extends TaskSupport with ExecutionContextTasks
diff --git a/src/library/scala/concurrent/ConcurrentPackageObject.scala b/src/library/scala/concurrent/ConcurrentPackageObject.scala
index 0f882540f2..d185ade8a4 100644
--- a/src/library/scala/concurrent/ConcurrentPackageObject.scala
+++ b/src/library/scala/concurrent/ConcurrentPackageObject.scala
@@ -20,8 +20,7 @@ import ConcurrentPackageObject._
abstract class ConcurrentPackageObject {
/** A global execution environment for executing lightweight tasks.
*/
- lazy val executionContext =
- new impl.ExecutionContextImpl()
+ lazy val defaultExecutionContext = new impl.ExecutionContextImpl(null)
private val currentExecutionContext = new ThreadLocal[ExecutionContext]
@@ -42,7 +41,7 @@ abstract class ConcurrentPackageObject {
case Left(t: scala.util.control.ControlThrowable) => Left(new ExecutionException("Boxed ControlThrowable", t))
case Left(t: InterruptedException) => Left(new ExecutionException("Boxed InterruptedException", t))
case Left(e: Error) => Left(new ExecutionException("Boxed Error", e))
- case _ => source
+ case _ => source
}
private[concurrent] def resolver[T] =
@@ -50,10 +49,10 @@ abstract class ConcurrentPackageObject {
/* concurrency constructs */
- def future[T](body: =>T)(implicit execctx: ExecutionContext = executionContext): Future[T] =
+ def future[T](body: =>T)(implicit execctx: ExecutionContext = defaultExecutionContext): Future[T] =
Future[T](body)
- def promise[T]()(implicit execctx: ExecutionContext = executionContext): Promise[T] =
+ def promise[T]()(implicit execctx: ExecutionContext = defaultExecutionContext): Promise[T] =
Promise[T]()
/** Wraps a block of code into an awaitable object. */
diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala
index 16d9a1f980..e1d4276396 100644
--- a/src/library/scala/concurrent/ExecutionContext.scala
+++ b/src/library/scala/concurrent/ExecutionContext.scala
@@ -11,7 +11,7 @@ package scala.concurrent
import java.util.concurrent.atomic.{ AtomicInteger }
-import java.util.concurrent.{ Executors, Future => JFuture, Callable }
+import java.util.concurrent.{ Executors, Future => JFuture, Callable, ExecutorService, Executor }
import scala.concurrent.util.Duration
import scala.concurrent.forkjoin.{ ForkJoinPool, RecursiveTask => FJTask, RecursiveAction, ForkJoinWorkerThread }
import scala.collection.generic.CanBuildFrom
@@ -36,5 +36,20 @@ trait ExecutionContext {
}
+/** Contains factory methods for creating execution contexts.
+ */
+object ExecutionContext {
+
+ implicit def defaultExecutionContext: ExecutionContext = scala.concurrent.defaultExecutionContext
+
+ /** Creates an `ExecutionContext` from the given `ExecutorService`.
+ */
+ def fromExecutorService(e: ExecutorService): ExecutionContext with Executor = new impl.ExecutionContextImpl(e)
+
+ /** Creates an `ExecutionContext` from the given `Executor`.
+ */
+ def fromExecutor(e: Executor): ExecutionContext with Executor = new impl.ExecutionContextImpl(e)
+
+}
diff --git a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
index 9a94bfca4f..52c834359d 100644
--- a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
+++ b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
@@ -10,20 +10,20 @@ package scala.concurrent.impl
-import java.util.concurrent.{Callable, ExecutorService, Executors, ThreadFactory}
+import java.util.concurrent.{Callable, Executor, ExecutorService, Executors, ThreadFactory}
import scala.concurrent.forkjoin._
import scala.concurrent.{ExecutionContext, resolver, Awaitable, body2awaitable}
import scala.concurrent.util.{ Duration }
-private[scala] class ExecutionContextImpl() extends ExecutionContext {
+private[scala] class ExecutionContextImpl(es: AnyRef) extends ExecutionContext with Executor {
import ExecutionContextImpl._
- val executorService: AnyRef = getExecutorService
+ val executorService: AnyRef = if (es eq null) getExecutorService else es
// to ensure that the current execution context thread local is properly set
- private def executorsThreadFactory = new ThreadFactory {
+ def executorsThreadFactory = new ThreadFactory {
def newThread(r: Runnable) = new Thread(new Runnable {
override def run() {
currentExecutionContext.set(ExecutionContextImpl.this)
@@ -33,7 +33,7 @@ private[scala] class ExecutionContextImpl() extends ExecutionContext {
}
// to ensure that the current execution context thread local is properly set
- private def forkJoinPoolThreadFactory = new ForkJoinPool.ForkJoinWorkerThreadFactory {
+ def forkJoinPoolThreadFactory = new ForkJoinPool.ForkJoinWorkerThreadFactory {
def newThread(fjp: ForkJoinPool) = new ForkJoinWorkerThread(fjp) {
override def onStart() {
currentExecutionContext.set(ExecutionContextImpl.this)
@@ -41,7 +41,7 @@ private[scala] class ExecutionContextImpl() extends ExecutionContext {
}
}
- private def getExecutorService: AnyRef =
+ def getExecutorService: AnyRef =
if (scala.util.Properties.isJavaAtLeast("1.6")) {
val vendor = scala.util.Properties.javaVmVendor
if ((vendor contains "Oracle") || (vendor contains "Sun") || (vendor contains "Apple"))
@@ -62,8 +62,8 @@ private[scala] class ExecutionContextImpl() extends ExecutionContext {
} else {
fj.execute(runnable)
}
- case executorService: ExecutorService =>
- executorService execute runnable
+ case executor: Executor =>
+ executor execute runnable
}
def execute[U](body: () => U): Unit = execute(new Runnable {
@@ -86,7 +86,7 @@ private[scala] class ExecutionContextImpl() extends ExecutionContext {
object ExecutionContextImpl {
- private[concurrent] def currentExecutionContext: ThreadLocal[ExecutionContextImpl] = new ThreadLocal[ExecutionContextImpl] {
+ private[concurrent] def currentExecutionContext: ThreadLocal[ExecutionContext] = new ThreadLocal[ExecutionContext] {
override protected def initialValue = null
}
diff --git a/test/files/jvm/scala-concurrent-tck.scala b/test/files/jvm/scala-concurrent-tck.scala
index b3470d275d..f0ca438774 100644
--- a/test/files/jvm/scala-concurrent-tck.scala
+++ b/test/files/jvm/scala-concurrent-tck.scala
@@ -147,59 +147,185 @@ trait FutureCallbacks extends TestBase {
trait FutureCombinators extends TestBase {
- // map: stub
def testMapSuccess(): Unit = once {
done =>
- done()
+ val f = future { 5 }
+ val g = f map { x => "result: " + x }
+ g onSuccess {
+ case s =>
+ done()
+ assert(s == "result: 5")
+ }
+ g onFailure {
+ case _ =>
+ done()
+ assert(false)
+ }
}
def testMapFailure(): Unit = once {
done =>
- done()
+ val f = future {
+ throw new Exception("exception message")
+ }
+ val g = f map { x => "result: " + x }
+ g onSuccess {
+ case _ =>
+ done()
+ assert(false)
+ }
+ g onFailure {
+ case t =>
+ done()
+ assert(t.getMessage() == "exception message")
+ }
}
- // flatMap: stub
def testFlatMapSuccess(): Unit = once {
done =>
- done()
+ val f = future { 5 }
+ val g = f flatMap { _ => future { 10 } }
+ g onSuccess {
+ case x =>
+ done()
+ assert(x == 10)
+ }
+ g onFailure {
+ case _ =>
+ done()
+ assert(false)
+ }
}
def testFlatMapFailure(): Unit = once {
done =>
- done()
+ val f = future {
+ throw new Exception("exception message")
+ }
+ val g = f flatMap { _ => future { 10 } }
+ g onSuccess {
+ case _ =>
+ done()
+ assert(false)
+ }
+ g onFailure {
+ case t =>
+ done()
+ assert(t.getMessage() == "exception message")
+ }
}
- // filter: stub
def testFilterSuccess(): Unit = once {
done =>
- done()
+ val f = future { 4 }
+ val g = f filter { _ % 2 == 0 }
+ g onSuccess {
+ case x: Int =>
+ done()
+ assert(x == 4)
+ }
+ g onFailure {
+ case _ =>
+ done()
+ assert(false)
+ }
}
def testFilterFailure(): Unit = once {
done =>
- done()
+ val f = future { 4 }
+ val g = f filter { _ % 2 == 1 }
+ g onSuccess {
+ case x: Int =>
+ done()
+ assert(false)
+ }
+ g onFailure {
+ case e: NoSuchElementException =>
+ done()
+ assert(true)
+ case _ =>
+ done()
+ assert(false)
+ }
}
- // collect: stub
def testCollectSuccess(): Unit = once {
done =>
- done()
+ val f = future { -5 }
+ val g = f collect {
+ case x if x < 0 => -x
+ }
+ g onSuccess {
+ case x: Int =>
+ done()
+ assert(x == 5)
+ }
+ g onFailure {
+ case _ =>
+ done()
+ assert(false)
+ }
}
def testCollectFailure(): Unit = once {
done =>
- done()
+ val f = future { -5 }
+ val g = f collect {
+ case x if x > 0 => x * 2
+ }
+ g onSuccess {
+ case _ =>
+ done()
+ assert(false)
+ }
+ g onFailure {
+ case e: NoSuchElementException =>
+ done()
+ assert(true)
+ case _ =>
+ done()
+ assert(false)
+ }
}
- // foreach: stub
def testForeachSuccess(): Unit = once {
done =>
- done()
+ val p = promise[Int]()
+ val f = future[Int] { 5 }
+ f foreach { x => p.success(x * 2) }
+ val g = p.future
+
+ g.onSuccess {
+ case res: Int =>
+ done()
+ assert(res == 10)
+ }
+ g.onFailure {
+ case _ =>
+ done()
+ assert(false)
+ }
}
def testForeachFailure(): Unit = once {
done =>
- done()
+ val p = promise[Int]()
+ val f = future[Int] { throw new Exception }
+ f foreach { x => p.success(x * 2) }
+ f onFailure { case _ => p.failure(new Exception) }
+ val g = p.future
+
+ g.onSuccess {
+ case _ =>
+ done()
+ assert(false)
+ }
+ g.onFailure {
+ case _ =>
+ done()
+ assert(true)
+ }
}
def testRecoverSuccess(): Unit = once {
@@ -237,6 +363,132 @@ trait FutureCombinators extends TestBase {
}
}
+ def testRecoverWithSuccess(): Unit = once {
+ done =>
+ val cause = new RuntimeException
+ val f = future {
+ throw cause
+ } recoverWith {
+ case re: RuntimeException =>
+ future { "recovered" }
+ } onSuccess {
+ case x =>
+ done()
+ assert(x == "recovered")
+ } onFailure { case any =>
+ done()
+ assert(false)
+ }
+ }
+
+ def testRecoverWithFailure(): Unit = once {
+ done =>
+ val cause = new RuntimeException
+ val f = future {
+ throw cause
+ } recoverWith {
+ case te: TimeoutException =>
+ future { "timeout" }
+ } onSuccess {
+ case x =>
+ done()
+ assert(false)
+ } onFailure { case any =>
+ done()
+ assert(any == cause)
+ }
+ }
+
+ def testZipSuccess(): Unit = once {
+ done =>
+ val f = future { 5 }
+ val g = future { 6 }
+ val h = f zip g
+ h onSuccess {
+ case (l: Int, r: Int) =>
+ done()
+ assert(l+r == 11)
+ }
+ h onFailure {
+ case _ =>
+ done()
+ assert(false)
+ }
+ }
+
+ def testZipFailureLeft(): Unit = once {
+ done =>
+ val cause = new Exception("exception message")
+ val f = future { throw cause }
+ val g = future { 6 }
+ val h = f zip g
+ h onSuccess {
+ case _ =>
+ done()
+ assert(false)
+ }
+ h onFailure {
+ case e: Exception =>
+ done()
+ assert(e.getMessage == "exception message")
+ }
+ }
+
+ def testZipFailureRight(): Unit = once {
+ done =>
+ val cause = new Exception("exception message")
+ val f = future { 5 }
+ val g = future { throw cause }
+ val h = f zip g
+ h onSuccess {
+ case _ =>
+ done()
+ assert(false)
+ }
+ h onFailure {
+ case e: Exception =>
+ done()
+ assert(e.getMessage == "exception message")
+ }
+ }
+
+ def testFallbackTo(): Unit = once {
+ done =>
+ val f = future { sys.error("failed") }
+ val g = future { 5 }
+ val h = f fallbackTo g
+
+ h onSuccess {
+ case x: Int =>
+ done()
+ assert(x == 5)
+ }
+ h onFailure {
+ case _ =>
+ done()
+ assert(false)
+ }
+ }
+
+ def testFallbackToFailure(): Unit = once {
+ done =>
+ val cause = new Exception
+ val f = future { throw cause }
+ val g = future { sys.error("failed") }
+ val h = f fallbackTo g
+
+ h onSuccess {
+ case _ =>
+ done()
+ assert(false)
+ }
+ h onFailure {
+ case e: Exception =>
+ done()
+ assert(e == cause)
+ }
+ }
+
testMapSuccess()
testMapFailure()
testFlatMapSuccess()
@@ -249,7 +501,13 @@ trait FutureCombinators extends TestBase {
testForeachFailure()
testRecoverSuccess()
testRecoverFailure()
-
+ testRecoverWithSuccess()
+ testRecoverWithFailure()
+ testZipSuccess()
+ testZipFailureLeft()
+ testZipFailureRight()
+ testFallbackTo()
+ testFallbackToFailure()
}
diff --git a/test/files/run/t5614.check b/test/files/run/t5614.check
new file mode 100644
index 0000000000..f659f2da3b
--- /dev/null
+++ b/test/files/run/t5614.check
@@ -0,0 +1,3 @@
+3
+a
+b
diff --git a/test/files/run/t5614.flags b/test/files/run/t5614.flags
new file mode 100644
index 0000000000..48fd867160
--- /dev/null
+++ b/test/files/run/t5614.flags
@@ -0,0 +1 @@
+-Xexperimental
diff --git a/test/files/run/t5614.scala b/test/files/run/t5614.scala
new file mode 100644
index 0000000000..7c85c33f12
--- /dev/null
+++ b/test/files/run/t5614.scala
@@ -0,0 +1,5 @@
+object Test extends App {
+ val str = s"a\nb"
+ println(str.length)
+ println(str)
+}