diff options
author | Heather Miller <heather.miller@epfl.ch> | 2012-04-03 10:17:33 +0200 |
---|---|---|
committer | Heather Miller <heather.miller@epfl.ch> | 2012-04-03 10:17:33 +0200 |
commit | 457172dca3f3fea505f2421a99f86976141c7e75 (patch) | |
tree | d432670bceb25ea2dc751466612f782bcd587df9 | |
parent | 40334826eb573eed527cbd396ab406e7376edbcc (diff) | |
download | scala-457172dca3f3fea505f2421a99f86976141c7e75.tar.gz scala-457172dca3f3fea505f2421a99f86976141c7e75.tar.bz2 scala-457172dca3f3fea505f2421a99f86976141c7e75.zip |
Remedies Try/Either signature disparity for source compat. w/ Akka
-rw-r--r-- | src/library/scala/concurrent/ConcurrentPackageObject.scala | 27 | ||||
-rw-r--r-- | src/library/scala/concurrent/ExecutionContext.scala | 1 | ||||
-rw-r--r-- | src/library/scala/concurrent/Future.scala | 81 | ||||
-rw-r--r-- | src/library/scala/concurrent/Promise.scala | 17 | ||||
-rw-r--r-- | src/library/scala/concurrent/impl/ExecutionContextImpl.scala | 1 | ||||
-rw-r--r-- | src/library/scala/concurrent/impl/Future.scala | 9 | ||||
-rw-r--r-- | src/library/scala/concurrent/impl/Promise.scala | 46 | ||||
-rw-r--r-- | src/library/scala/util/Try.scala | 53 | ||||
-rw-r--r-- | test/files/jvm/scala-concurrent-tck.scala | 80 |
9 files changed, 197 insertions, 118 deletions
diff --git a/src/library/scala/concurrent/ConcurrentPackageObject.scala b/src/library/scala/concurrent/ConcurrentPackageObject.scala index f4744a8757..0f882540f2 100644 --- a/src/library/scala/concurrent/ConcurrentPackageObject.scala +++ b/src/library/scala/concurrent/ConcurrentPackageObject.scala @@ -8,11 +8,8 @@ package scala.concurrent - - import java.util.concurrent.{ Executors, ExecutorService, ThreadFactory } import scala.concurrent.forkjoin.{ ForkJoinPool, ForkJoinWorkerThread } -import scala.util.{ Try, Success, Failure } import scala.concurrent.util.Duration import ConcurrentPackageObject._ @@ -40,16 +37,16 @@ abstract class ConcurrentPackageObject { case _ => true } - private[concurrent] def resolve[T](source: Try[T]): Try[T] = source match { - case Failure(t: scala.runtime.NonLocalReturnControl[_]) => Success(t.value.asInstanceOf[T]) - case Failure(t: scala.util.control.ControlThrowable) => Failure(new ExecutionException("Boxed ControlThrowable", t)) - case Failure(t: InterruptedException) => Failure(new ExecutionException("Boxed InterruptedException", t)) - case Failure(e: Error) => Failure(new ExecutionException("Boxed Error", e)) + private[concurrent] def resolve[T](source: Either[Throwable, T]): Either[Throwable, T] = source match { + case Left(t: scala.runtime.NonLocalReturnControl[_]) => Right(t.value.asInstanceOf[T]) + 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 } private[concurrent] def resolver[T] = - resolverFunction.asInstanceOf[PartialFunction[Throwable, Try[T]]] + resolverFunction.asInstanceOf[PartialFunction[Throwable, Either[Throwable, T]]] /* concurrency constructs */ @@ -104,11 +101,11 @@ private[concurrent] object ConcurrentPackageObject { // compiling a subset of sources; it seems that the wildcard is not // properly handled, and you get messages like "type _$1 defined twice". // This is consistent with other package object breakdowns. - private val resolverFunction: PartialFunction[Throwable, Try[_]] = { - case t: scala.runtime.NonLocalReturnControl[_] => Success(t.value) - case t: scala.util.control.ControlThrowable => Failure(new ExecutionException("Boxed ControlThrowable", t)) - case t: InterruptedException => Failure(new ExecutionException("Boxed InterruptedException", t)) - case e: Error => Failure(new ExecutionException("Boxed Error", e)) - case t => Failure(t) + private val resolverFunction: PartialFunction[Throwable, Either[Throwable, _]] = { + case t: scala.runtime.NonLocalReturnControl[_] => Right(t.value) + case t: scala.util.control.ControlThrowable => Left(new ExecutionException("Boxed ControlThrowable", t)) + case t: InterruptedException => Left(new ExecutionException("Boxed InterruptedException", t)) + case e: Error => Left(new ExecutionException("Boxed Error", e)) + case t => Left(t) } } diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala index f639f76dc9..16d9a1f980 100644 --- a/src/library/scala/concurrent/ExecutionContext.scala +++ b/src/library/scala/concurrent/ExecutionContext.scala @@ -13,7 +13,6 @@ package scala.concurrent import java.util.concurrent.atomic.{ AtomicInteger } import java.util.concurrent.{ Executors, Future => JFuture, Callable } import scala.concurrent.util.Duration -import scala.util.{ Try, Success, Failure } import scala.concurrent.forkjoin.{ ForkJoinPool, RecursiveTask => FJTask, RecursiveAction, ForkJoinWorkerThread } import scala.collection.generic.CanBuildFrom import collection._ diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index 8cecadc605..5f703ac23b 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -17,7 +17,6 @@ import java.util.{ LinkedList => JLinkedList } import java.{ lang => jl } import java.util.concurrent.atomic.{ AtomicReferenceFieldUpdater, AtomicInteger, AtomicBoolean } -import scala.util.{ Try, Success, Failure } import scala.concurrent.util.Duration import scala.Option @@ -97,8 +96,8 @@ self => * $multipleCallbacks */ def onSuccess[U](pf: PartialFunction[T, U]): this.type = onComplete { - case Failure(t) => // do nothing - case Success(v) => if (pf isDefinedAt v) pf(v) else { /*do nothing*/ } + case Left(t) => // do nothing + case Right(v) => if (pf isDefinedAt v) pf(v) else { /*do nothing*/ } } /** When this future is completed with a failure (i.e. with a throwable), @@ -114,8 +113,8 @@ self => * $multipleCallbacks */ def onFailure[U](callback: PartialFunction[Throwable, U]): this.type = onComplete { - case Failure(t) => if (isFutureThrowable(t) && callback.isDefinedAt(t)) callback(t) else { /*do nothing*/ } - case Success(v) => // do nothing + case Left(t) => if (isFutureThrowable(t) && callback.isDefinedAt(t)) callback(t) else { /*do nothing*/ } + case Right(v) => // do nothing } /** When this future is completed, either through an exception, a timeout, or a value, @@ -126,7 +125,7 @@ self => * * $multipleCallbacks */ - def onComplete[U](func: Try[T] => U): this.type + def onComplete[U](func: Either[Throwable, T] => U): this.type /* Miscellaneous */ @@ -151,7 +150,7 @@ self => * if it contains a valid result, or `Some(Failure(error))` if it contains * an exception. */ - def value: Option[Try[T]] + def value: Option[Either[Throwable, T]] /* Projections */ @@ -175,8 +174,8 @@ self => val p = newPromise[Throwable] onComplete { - case Failure(t) => p success t - case Success(v) => p failure noSuchElem(v) + case Left(t) => p success t + case Right(v) => p failure noSuchElem(v) } p.future @@ -190,8 +189,8 @@ self => * Will not be called if the future fails. */ def foreach[U](f: T => U): Unit = onComplete { - case Success(r) => f(r) - case Failure(_) => // do nothing + case Right(r) => f(r) + case Left(_) => // do nothing } /** Creates a new future by applying a function to the successful result of @@ -204,8 +203,8 @@ self => val p = newPromise[S] onComplete { - case Failure(t) => p failure t - case Success(v) => + case Left(t) => p failure t + case Right(v) => try p success f(v) catch { case t => p complete resolver(t) @@ -226,12 +225,12 @@ self => val p = newPromise[S] onComplete { - case Failure(t) => p failure t - case Success(v) => + case Left(t) => p failure t + case Right(v) => try { f(v) onComplete { - case Failure(t) => p failure t - case Success(v) => p success v + case Left(t) => p failure t + case Right(v) => p success v } } catch { case t: Throwable => p complete resolver(t) @@ -261,8 +260,8 @@ self => val p = newPromise[T] onComplete { - case Failure(t) => p failure t - case Success(v) => + case Left(t) => p failure t + case Right(v) => try { if (pred(v)) p success v else p failure new NoSuchElementException("Future.filter predicate is not satisfied by: " + v) @@ -310,8 +309,8 @@ self => val p = newPromise[S] onComplete { - case Failure(t) => p failure t - case Success(v) => + case Left(t) => p failure t + case Right(v) => try { if (pf.isDefinedAt(v)) p success pf(v) else p failure new NoSuchElementException("Future.collect partial function is not defined at: " + v) @@ -339,7 +338,7 @@ self => val p = newPromise[U] onComplete { - case Failure(t) if pf isDefinedAt t => + case Left(t) if pf isDefinedAt t => try { p success pf(t) } catch { case t: Throwable => p complete resolver(t) } case otherwise => p complete otherwise @@ -365,7 +364,7 @@ self => val p = newPromise[U] onComplete { - case Failure(t) if pf isDefinedAt t => + case Left(t) if pf isDefinedAt t => try { p completeWith pf(t) } catch { @@ -389,8 +388,8 @@ self => val p = newPromise[(T, U)] this onComplete { - case Failure(t) => p failure t - case Success(r) => that onSuccess { + case Left(t) => p failure t + case Right(r) => that onSuccess { case r2 => p success ((r, r2)) } } @@ -420,11 +419,11 @@ self => val p = newPromise[U] onComplete { - case Failure(t) => that onComplete { - case Failure(_) => p failure t - case Success(v) => p success v + case Left(t) => that onComplete { + case Left(_) => p failure t + case Right(v) => p success v } - case Success(v) => p success v + case Right(v) => p success v } p.future @@ -437,12 +436,12 @@ self => val p = newPromise[S] onComplete { - case l: Failure[_] => p complete l.asInstanceOf[Try[S]] - case Success(t) => + case l: Left[Throwable, _] => p complete l.asInstanceOf[Either[Throwable, S]] + case Right(t) => p complete (try { - Success(impl.Future.boxedType(m.erasure).cast(t).asInstanceOf[S]) + Right(impl.Future.boxedType(m.erasure).cast(t).asInstanceOf[S]) } catch { - case e: ClassCastException => Failure(e) + case e: ClassCastException => Left(e) }) } @@ -472,7 +471,7 @@ self => * } * }}} */ - def andThen[U](pf: PartialFunction[Try[T], U]): Future[T] = { + def andThen[U](pf: PartialFunction[Either[Throwable, T], U]): Future[T] = { val p = newPromise[T] onComplete { @@ -500,9 +499,9 @@ self => def either[U >: T](that: Future[U]): Future[U] = { val p = self.newPromise[U] - val completePromise: PartialFunction[Try[U], _] = { - case Failure(t) => p tryFailure t - case Success(v) => p trySuccess v + val completePromise: PartialFunction[Either[Throwable, U], _] = { + case Left(t) => p tryFailure t + case Right(v) => p trySuccess v } self onComplete completePromise @@ -541,7 +540,7 @@ object Future { def firstCompletedOf[T](futures: Traversable[Future[T]])(implicit executor: ExecutionContext): Future[T] = { val p = Promise[T]() - val completeFirst: Try[T] => Unit = p tryComplete _ + val completeFirst: Either[Throwable, T] => Unit = p tryComplete _ futures.foreach(_ onComplete completeFirst) p.future @@ -554,14 +553,14 @@ object Future { else { val result = Promise[Option[T]]() val ref = new AtomicInteger(futures.size) - val search: Try[T] => Unit = v => try { + val search: Either[Throwable, T] => Unit = v => try { v match { - case Success(r) => if (predicate(r)) result tryComplete Success(Some(r)) + case Right(r) => if (predicate(r)) result tryComplete Right(Some(r)) case _ => } } finally { if (ref.decrementAndGet == 0) - result tryComplete Success(None) + result tryComplete Right(None) } futures.foreach(_ onComplete search) diff --git a/src/library/scala/concurrent/Promise.scala b/src/library/scala/concurrent/Promise.scala index 61e21606e6..8f2bce5d1a 100644 --- a/src/library/scala/concurrent/Promise.scala +++ b/src/library/scala/concurrent/Promise.scala @@ -8,11 +8,6 @@ package scala.concurrent -import scala.util.{ Try, Success, Failure } - - - - /** Promise is an object which can be completed with a value or failed * with an exception. * @@ -40,7 +35,7 @@ trait Promise[T] { * * $promiseCompletion */ - def complete(result:Try[T]): this.type = if (tryComplete(result)) this else throwCompleted + def complete(result: Either[Throwable, T]): this.type = if (tryComplete(result)) this else throwCompleted /** Tries to complete the promise with either a value or the exception. * @@ -48,7 +43,7 @@ trait Promise[T] { * * @return If the promise has already been completed returns `false`, or `true` otherwise. */ - def tryComplete(result: Try[T]): Boolean + def tryComplete(result: Either[Throwable, T]): Boolean /** Completes this promise with the specified future, once that future is completed. * @@ -75,7 +70,7 @@ trait Promise[T] { * * @return If the promise has already been completed returns `false`, or `true` otherwise. */ - def trySuccess(value: T): Boolean = tryComplete(Success(value)) + def trySuccess(value: T): Boolean = tryComplete(Right(value)) /** Completes the promise with an exception. * @@ -93,7 +88,7 @@ trait Promise[T] { * * @return If the promise has already been completed returns `false`, or `true` otherwise. */ - def tryFailure(t: Throwable): Boolean = tryComplete(Failure(t)) + def tryFailure(t: Throwable): Boolean = tryComplete(Left(t)) /** Wraps a `Throwable` in an `ExecutionException` if necessary. TODO replace with `resolver` from scala.concurrent * @@ -118,11 +113,11 @@ object Promise { /** Creates an already completed Promise with the specified exception */ - def failed[T](exception: Throwable)(implicit executor: ExecutionContext): Promise[T] = new impl.Promise.KeptPromise[T](Failure(exception)) + def failed[T](exception: Throwable)(implicit executor: ExecutionContext): Promise[T] = new impl.Promise.KeptPromise[T](Left(exception)) /** Creates an already completed Promise with the specified result */ - def successful[T](result: T)(implicit executor: ExecutionContext): Promise[T] = new impl.Promise.KeptPromise[T](Success(result)) + def successful[T](result: T)(implicit executor: ExecutionContext): Promise[T] = new impl.Promise.KeptPromise[T](Right(result)) } diff --git a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala index 2cfd6f22cd..9a94bfca4f 100644 --- a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala +++ b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala @@ -13,7 +13,6 @@ package scala.concurrent.impl import java.util.concurrent.{Callable, ExecutorService, Executors, ThreadFactory} import scala.concurrent.forkjoin._ import scala.concurrent.{ExecutionContext, resolver, Awaitable, body2awaitable} -import scala.util.{ Try, Success, Failure } import scala.concurrent.util.{ Duration } diff --git a/src/library/scala/concurrent/impl/Future.scala b/src/library/scala/concurrent/impl/Future.scala index 1111aa4753..615ab061a5 100644 --- a/src/library/scala/concurrent/impl/Future.scala +++ b/src/library/scala/concurrent/impl/Future.scala @@ -11,11 +11,8 @@ package scala.concurrent.impl import scala.concurrent.{Awaitable, ExecutionContext} -import scala.util.{ Try, Success, Failure } import scala.collection.mutable.Stack - - private[concurrent] trait Future[+T] extends scala.concurrent.Future[T] with Awaitable[T] { implicit def executor: ExecutionContext @@ -36,9 +33,9 @@ private[concurrent] trait Future[+T] extends scala.concurrent.Future[T] with Awa * if it contains a valid result, or Some(Left(error)) if it contains * an exception. */ - def value: Option[Try[T]] + def value: Option[Either[Throwable, T]] - def onComplete[U](func: Try[T] => U): this.type + def onComplete[U](func: Either[Throwable, T] => U): this.type } @@ -67,7 +64,7 @@ object Future { def run = { promise complete { try { - Success(body) + Right(body) } catch { case e => scala.concurrent.resolver(e) } diff --git a/src/library/scala/concurrent/impl/Promise.scala b/src/library/scala/concurrent/impl/Promise.scala index f05e306088..f7e073cb78 100644 --- a/src/library/scala/concurrent/impl/Promise.scala +++ b/src/library/scala/concurrent/impl/Promise.scala @@ -15,7 +15,6 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater import scala.concurrent.{Awaitable, ExecutionContext, resolve, resolver, blocking, CanAwait, TimeoutException} //import scala.util.continuations._ import scala.concurrent.util.Duration -import scala.util.Try import scala.util import scala.annotation.tailrec //import scala.concurrent.NonDeterministic @@ -84,18 +83,18 @@ object Promise { * * [adriaan] it's unsound to make FState covariant (tryComplete won't type check) */ - sealed trait FState[T] { def value: Option[Try[T]] } + sealed trait FState[T] { def value: Option[Either[Throwable, T]] } - case class Pending[T](listeners: List[Try[T] => Any] = Nil) extends FState[T] { - def value: Option[Try[T]] = None + case class Pending[T](listeners: List[Either[Throwable, T] => Any] = Nil) extends FState[T] { + def value: Option[Either[Throwable, T]] = None } - case class Success[T](value: Option[util.Success[T]] = None) extends FState[T] { - def result: T = value.get.get + case class Success[T](value: Option[Either[Throwable, T]] = None) extends FState[T] { + def result: T = value.get.right.get } - case class Failure[T](value: Option[util.Failure[T]] = None) extends FState[T] { - def exception: Throwable = value.get.exception + case class Failure[T](value: Option[Either[Throwable, T]] = None) extends FState[T] { + def exception: Throwable = value.get.left.get } private val emptyPendingValue = Pending[Nothing](Nil) @@ -136,11 +135,11 @@ object Promise { def result(atMost: Duration)(implicit permit: CanAwait): T = ready(atMost).value.get match { - case util.Failure(e) => throw e - case util.Success(r) => r + case Left(e) => throw e + case Right(r) => r } - def value: Option[Try[T]] = getState.value + def value: Option[Either[Throwable, T]] = getState.value @inline private[this] final def updater = AbstractPromise.updater.asInstanceOf[AtomicReferenceFieldUpdater[AbstractPromise, FState[T]]] @@ -151,16 +150,16 @@ object Promise { @inline protected final def getState: FState[T] = updater.get(this) - def tryComplete(value: Try[T]): Boolean = { - val callbacks: List[Try[T] => Any] = { + def tryComplete(value: Either[Throwable, T]): Boolean = { + val callbacks: List[Either[Throwable, T] => Any] = { try { @tailrec - def tryComplete(v: Try[T]): List[Try[T] => Any] = { + def tryComplete(v: Either[Throwable, T]): List[Either[Throwable, T] => Any] = { getState match { case cur @ Pending(listeners) => val newState = - if (v.isFailure) Failure(Some(v.asInstanceOf[util.Failure[T]])) - else Success(Some(v.asInstanceOf[util.Success[T]])) + if (v.isLeft) Failure(Some(v.asInstanceOf[Left[Throwable, T]])) + else Success(Some(v.asInstanceOf[Right[Throwable, T]])) if (updateState(cur, newState)) listeners else tryComplete(v) @@ -184,7 +183,7 @@ object Promise { } } - def onComplete[U](func: Try[T] => U): this.type = { + def onComplete[U](func: Either[Throwable, T] => U): this.type = { @tailrec // Returns whether the future has already been completed or not def tryAddCallback(): Boolean = { val cur = getState @@ -206,7 +205,7 @@ object Promise { this } - private final def notifyCompleted(func: Try[T] => Any, result: Try[T]) { + private final def notifyCompleted(func: Either[Throwable, T] => Any, result: Either[Throwable, T]) { try { func(result) } catch { @@ -219,12 +218,13 @@ object Promise { * * Useful in Future-composition when a value to contribute is already available. */ - final class KeptPromise[T](suppliedValue: Try[T])(implicit val executor: ExecutionContext) extends Promise[T] { + final class KeptPromise[T](suppliedValue: Either[Throwable, T])(implicit val executor: ExecutionContext) extends Promise[T] { + val value = Some(resolve(suppliedValue)) - def tryComplete(value: Try[T]): Boolean = false + def tryComplete(value: Either[Throwable, T]): Boolean = false - def onComplete[U](func: Try[T] => U): this.type = { + def onComplete[U](func: Either[Throwable, T] => U): this.type = { val completedAs = value.get Future.dispatchFuture(executor, { () => func(completedAs) @@ -235,8 +235,8 @@ object Promise { def ready(atMost: Duration)(implicit permit: CanAwait): this.type = this def result(atMost: Duration)(implicit permit: CanAwait): T = value.get match { - case util.Failure(e) => throw e - case util.Success(r) => r + case Left(e) => throw e + case Right(r) => r } } diff --git a/src/library/scala/util/Try.scala b/src/library/scala/util/Try.scala index c9bde81317..efa2fcabb8 100644 --- a/src/library/scala/util/Try.scala +++ b/src/library/scala/util/Try.scala @@ -101,9 +101,9 @@ sealed abstract class Try[+T] { } -final case class Failure[+T](val exception: Throwable) extends Try[T] { - def isFailure = true - def isSuccess = false +final class Failure[+T](val exception: Throwable) extends Try[T] { + def isFailure: Boolean = true + def isSuccess: Boolean = false def rescue[U >: T](rescueException: PartialFunction[Throwable, Try[U]]): Try[U] = { try { if (rescueException.isDefinedAt(exception)) rescueException(exception) else this @@ -129,30 +129,49 @@ final case class Failure[+T](val exception: Throwable) extends Try[T] { } -final case class Success[+T](r: T) extends Try[T] { - def isFailure = false - def isSuccess = true - def rescue[U >: T](rescueException: PartialFunction[Throwable, Try[U]]): Try[U] = Success(r) - def get = r +final class Success[+T](value: T) extends Try[T] { + def isFailure: Boolean = false + def isSuccess: Boolean = true + def rescue[U >: T](rescueException: PartialFunction[Throwable, Try[U]]): Try[U] = Success(value) + def get = value def flatMap[U](f: T => Try[U]): Try[U] = - try f(r) + try f(value) catch { case e => Failure(e) } - def flatten[U](implicit ev: T <:< Try[U]): Try[U] = r - def foreach[U](f: T => U): Unit = f(r) - def map[U](f: T => U): Try[U] = Try[U](f(r)) + def flatten[U](implicit ev: T <:< Try[U]): Try[U] = value + def foreach[U](f: T => U): Unit = f(value) + def map[U](f: T => U): Try[U] = Try[U](f(value)) def collect[U](pf: PartialFunction[T, U]): Try[U] = - if (pf isDefinedAt r) Success(pf(r)) - else Failure[U](new NoSuchElementException("Partial function not defined at " + r)) + if (pf isDefinedAt value) Success(pf(value)) + else Failure[U](new NoSuchElementException("Partial function not defined at " + value)) def filter(p: T => Boolean): Try[T] = - if (p(r)) this - else Failure(new NoSuchElementException("Predicate does not hold for " + r)) + if (p(value)) this + else Failure(new NoSuchElementException("Predicate does not hold for " + value)) def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = this - def exists(p: T => Boolean): Boolean = p(r) + def exists(p: T => Boolean): Boolean = p(value) def failed: Try[Throwable] = Failure(new UnsupportedOperationException("Success.failed")) } +object Failure { + def apply[T](e: Throwable): Failure[T] = new Failure(e) + def unapply(scrutinizee: Any): Option[Throwable] = scrutinizee match { + case Right(_) => None + case Left(e) => Some(e.asInstanceOf[Throwable]) + case s: Success[_] => None + case f: Failure[_] => Some(f.exception) + } +} + +object Success { + def apply[T](value: T): Success[T] = new Success(value) + def unapply[T](scrutinizee: Any): Option[T] = scrutinizee match { + case Right(v) => Some(v.asInstanceOf[T]) + case Left(_) => None + case s: Success[_] => Some(s.get.asInstanceOf[T]) + case f: Failure[Throwable] => None + } +} object Try { diff --git a/test/files/jvm/scala-concurrent-tck.scala b/test/files/jvm/scala-concurrent-tck.scala index 75e2b92ff6..b3470d275d 100644 --- a/test/files/jvm/scala-concurrent-tck.scala +++ b/test/files/jvm/scala-concurrent-tck.scala @@ -1,6 +1,3 @@ - - - import scala.concurrent.{ Future, Promise, @@ -398,6 +395,80 @@ trait Exceptions extends TestBase { } +trait TryEitherExtractor extends TestBase { + + import scala.util.{Try, Success, Failure} + + def testSuccessMatch(): Unit = once { + done => + val thisIsASuccess = Success(42) + thisIsASuccess match { + case Success(v) => + done() + assert(v == 42) + case Failure(e) => + done() + assert(false) + case other => + done() + assert(false) + } + } + + def testRightMatch(): Unit = once { + done => + val thisIsNotASuccess: Right[Throwable, Int] = Right(43) + thisIsNotASuccess match { + case Success(v) => + done() + assert(v == 43) + case Failure(e) => + done() + assert(false) + case other => + done() + assert(false) + } + } + + def testFailureMatch(): Unit = once { + done => + val thisIsAFailure = Failure(new Exception("I'm an exception")) + thisIsAFailure match { + case Success(v) => + done() + assert(false) + case Failure(e) => + done() + assert(e.getMessage == "I'm an exception") + case other => + done() + assert(false) + } + } + + def testLeftMatch(): Unit = once { + done => + val thisIsNotAFailure: Left[Throwable, Int] = Left(new Exception("I'm an exception")) + thisIsNotAFailure match { + case Success(v) => + done() + assert(false) + case Failure(e) => + done() + assert(e.getMessage == "I'm an exception") + case other => + done() + assert(false) + } + + } + + testSuccessMatch() + testRightMatch() + testFailureMatch() + testLeftMatch() +} object Test extends App @@ -406,8 +477,11 @@ with FutureCombinators with FutureProjections with Promises with Exceptions +with TryEitherExtractor { System.exit(0) } + + |