summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/library/scala/concurrent/Future.scala3
-rw-r--r--src/library/scala/concurrent/impl/ExecutionContextImpl.scala1
-rw-r--r--src/library/scala/concurrent/impl/Future.scala1
-rw-r--r--src/library/scala/package.scala9
-rw-r--r--src/library/scala/util/Either.scala (renamed from src/library/scala/Either.scala)2
-rw-r--r--src/library/scala/util/Try.scala202
-rw-r--r--src/library/scala/util/control/NonFatal.scala (renamed from src/library/scala/concurrent/impl/NonFatal.scala)23
-rw-r--r--test/disabled/run/syncchannel.check (renamed from test/files/run/syncchannel.check)0
-rw-r--r--test/disabled/run/syncchannel.scala (renamed from test/files/run/syncchannel.scala)0
-rw-r--r--test/files/jvm/scala-concurrent-tck.scala156
-rw-r--r--test/files/jvm/try-type-tests.scala250
-rw-r--r--test/files/neg/t5589neg.check4
12 files changed, 478 insertions, 173 deletions
diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala
index 2a52d0ac0b..2de0c57253 100644
--- a/src/library/scala/concurrent/Future.scala
+++ b/src/library/scala/concurrent/Future.scala
@@ -18,8 +18,9 @@ import java.{ lang => jl }
import java.util.concurrent.atomic.{ AtomicReferenceFieldUpdater, AtomicInteger, AtomicBoolean }
import scala.concurrent.util.Duration
-import scala.concurrent.impl.NonFatal
+import scala.util.control.NonFatal
import scala.Option
+import scala.util.{Try, Success, Failure}
import scala.annotation.tailrec
import scala.collection.mutable.Stack
diff --git a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
index 7549bf8314..4c6347dce0 100644
--- a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
+++ b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
@@ -15,6 +15,7 @@ import java.util.Collection
import scala.concurrent.forkjoin._
import scala.concurrent.{ ExecutionContext, Awaitable }
import scala.concurrent.util.Duration
+import scala.util.control.NonFatal
diff --git a/src/library/scala/concurrent/impl/Future.scala b/src/library/scala/concurrent/impl/Future.scala
index 6a3487adde..8012ea6a93 100644
--- a/src/library/scala/concurrent/impl/Future.scala
+++ b/src/library/scala/concurrent/impl/Future.scala
@@ -13,6 +13,7 @@ package scala.concurrent.impl
import scala.concurrent.util.Duration
import scala.concurrent.{Awaitable, ExecutionContext, CanAwait}
import scala.collection.mutable.Stack
+import scala.util.control.NonFatal
private[concurrent] trait Future[+T] extends scala.concurrent.Future[T] with Awaitable[T] {
diff --git a/src/library/scala/package.scala b/src/library/scala/package.scala
index e3890d7a9d..c4a8585563 100644
--- a/src/library/scala/package.scala
+++ b/src/library/scala/package.scala
@@ -105,6 +105,15 @@ package object scala {
type PartialOrdering[T] = scala.math.PartialOrdering[T]
type PartiallyOrdered[T] = scala.math.PartiallyOrdered[T]
+ type Either[+A, +B] = scala.util.Either[A, B]
+ val Either = scala.util.Either
+
+ type Left[+A, +B] = scala.util.Left[A, B]
+ val Left = scala.util.Left
+
+ type Right[+A, +B] = scala.util.Right[A, B]
+ val Right = scala.util.Right
+
// Annotations which we might move to annotation.*
/*
type SerialVersionUID = annotation.SerialVersionUID
diff --git a/src/library/scala/Either.scala b/src/library/scala/util/Either.scala
index b35d8a7c8a..1a2e2d48d5 100644
--- a/src/library/scala/Either.scala
+++ b/src/library/scala/util/Either.scala
@@ -8,7 +8,7 @@
-package scala
+package scala.util
import language.implicitConversions
diff --git a/src/library/scala/util/Try.scala b/src/library/scala/util/Try.scala
index 8faba236f0..988f68bc18 100644
--- a/src/library/scala/util/Try.scala
+++ b/src/library/scala/util/Try.scala
@@ -11,36 +11,77 @@ package scala.util
import collection.Seq
-
+import scala.util.control.NonFatal
/**
- * The `Try` type represents a computation that may either result in an exception,
- * or return a success value. It's analagous to the `Either` type.
+ * The `Try` type represents a computation that may either result in an exception, or return a
+ * successfully computed value. It's similar to, but semantically different from the [[scala.Either]] type.
+ *
+ * Instances of `Try[T]`, are either an instance of [[scala.util.Success]][T] or [[scala.util.Failure]][T].
+ *
+ * For example, `Try` can be used to perform division on a user-defined input, without the need to do explicit
+ * exception-handling in all of the places that an exception might occur.
+ *
+ * Example:
+ * {{{
+ * import scala.util.{Try, Success, Failure}
+ *
+ * def divide: Try[Int] = {
+ * val dividend = Try(Console.readLine("Enter an Int that you'd like to divide:\n").toInt)
+ * val divisor = Try(Console.readLine("Enter an Int that you'd like to divide by:\n").toInt)
+ * val problem = dividend.flatMap(x => divisor.map(y => x/y))
+ * problem match {
+ * case Success(v) =>
+ * println("Result of " + dividend.get + "/"+ divisor.get +" is: " + v)
+ * Success(v)
+ * case Failure(e) =>
+ * println("You must've divided by zero or entered something that's not an Int. Try again!")
+ * println("Info from the exception: " + e.getMessage)
+ * divide
+ * }
+ * }
+ *
+ * }}}
+ *
+ * An important property of `Try` shown in the above example is its ability to ''pipeline'', or chain, operations,
+ * catching exceptions along the way. The `flatMap` and `map` combinators in the above example each essentially
+ * pass off either their successfully completed value, wrapped in the `Success` type for it to be further operated
+ * upon by the next combinator in the chain, or the exception wrapped in the `Failure` type usually to be simply
+ * passed on down the chain. Combinators such as `rescue` and `recover` are designed to provide some type of
+ * default behavior in the case of failure.
+ *
+ * ''Note'': only non-fatal exceptions are caught by the combinators on `Try` (see [[scala.util.control.NonFatal]]).
+ * Serious system errors, on the other hand, will be thrown.
+ *
+ * `Try` comes to the Scala standard library after years of use as an integral part of Twitter's stack.
+ *
+ * @since 2.10
*/
sealed abstract class Try[+T] {
- /**
- * Returns true if the `Try` is a `Failure`, false otherwise.
+
+ /** Returns `true` if the `Try` is a `Failure`, `false` otherwise.
*/
def isFailure: Boolean
- /**
- * Returns true if the `Try` is a `Success`, false otherwise.
+ /** Returns `true` if the `Try` is a `Success`, `false` otherwise.
*/
def isSuccess: Boolean
- /**
- * Returns the value from this `Success` or the given argument if this is a `Failure`.
+ /** Returns the value from this `Success` or the given `default` argument if this is a `Failure`.
*/
def getOrElse[U >: T](default: => U) = if (isSuccess) get else default
- /**
- * Returns the value from this `Success` or throws the exception if this is a `Failure`.
+ /** Returns this `Try` if it's a `Success` or the given `default` argument if this is a `Failure`.
+ */
+ def orElse[U >: T](default: => Try[U]) = if (isSuccess) this else default
+
+ /** Returns the value from this `Success` or throws the exception if this is a `Failure`.
*/
def get: T
/**
- * Applies the given function f if this is a Result.
+ * Applies the given function `f` if this is a `Success`, otherwise returns `Unit` if this is a `Failure`.
*/
def foreach[U](f: T => U): Unit
@@ -54,39 +95,35 @@ sealed abstract class Try[+T] {
*/
def map[U](f: T => U): Try[U]
- def collect[U](pf: PartialFunction[T, U]): Try[U]
-
- def exists(p: T => Boolean): Boolean
-
/**
* Converts this to a `Failure` if the predicate is not satisfied.
*/
def filter(p: T => Boolean): Try[T]
/**
- * Converts this to a `Failure` if the predicate is not satisfied.
- */
- def filterNot(p: T => Boolean): Try[T] = filter(x => !p(x))
-
- /**
- * Calls the exceptionHandler with the exception if this is a `Failure`. This is like `flatMap` for the exception.
+ * Applies the given function `f` if this is a `Failure`, otherwise returns this if this is a `Success`.
+ * This is like `flatMap` for the exception.
*/
- def rescue[U >: T](rescueException: PartialFunction[Throwable, Try[U]]): Try[U]
+ def rescue[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U]
/**
- * Calls the exceptionHandler with the exception if this is a `Failure`. This is like map for the exception.
+ * Applies the given function `f` if this is a `Failure`, otherwise returns this if this is a `Success`.
+ * This is like map for the exception.
*/
- def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U]
+ def recover[U >: T](f: PartialFunction[Throwable, U]): Try[U]
/**
* Returns `None` if this is a `Failure` or a `Some` containing the value if this is a `Success`.
*/
def toOption = if (isSuccess) Some(get) else None
+ /**
+ * Returns an empty `Seq` (usually a `List`) if this is a `Failure` or a `Seq` containing the value if this is a `Success`.
+ */
def toSeq = if (isSuccess) Seq(get) else Seq()
/**
- * Returns the given function applied to the value from this Success or returns this if this is a `Failure`.
+ * Returns the given function applied to the value from this `Success` or returns this if this is a `Failure`.
* Alias for `flatMap`.
*/
def andThen[U](f: T => Try[U]): Try[U] = flatMap(f)
@@ -97,42 +134,76 @@ sealed abstract class Try[+T] {
*/
def flatten[U](implicit ev: T <:< Try[U]): Try[U]
+ /**
+ * Completes this `Try` with an exception wrapped in a `Success`. The exception is either the exception that the
+ * `Try` failed with (if a `Failure`) or an `UnsupportedOperationException`.
+ */
def failed: Try[Throwable]
+
+ /** Completes this `Try` by applying the function `f` to this if this is of type `Failure`, or conversely, by applying
+ * `s` if this is a `Success`.
+ */
+ def transform[U](f: Throwable => Try[U], s: T => Try[U]): Try[U] = this match {
+ case Success(v) => s(v)
+ case Failure(e) => f(e)
+ }
+
}
+object Try {
+
+ implicit def try2either[T](tr: Try[T]): Either[Throwable, T] = {
+ tr match {
+ case Success(v) => Right(v)
+ case Failure(t) => Left(t)
+ }
+ }
-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
- } catch {
- case e2 => Failure(e2)
+ implicit def either2try[T](ei: Either[Throwable, T]): Try[T] = {
+ ei match {
+ case Right(v) => Success(v)
+ case Left(t) => Failure(t)
+ }
+ }
+
+ def apply[T](r: => T): Try[T] = {
+ try { Success(r) } catch {
+ case NonFatal(e) => Failure(e)
}
}
+
+}
+
+final case class Failure[+T](val exception: Throwable) extends Try[T] {
+ def isFailure: Boolean = true
+ def isSuccess: Boolean = false
+ def rescue[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U] =
+ if (f.isDefinedAt(exception)) f(exception) else this
def get: T = throw exception
def flatMap[U](f: T => Try[U]): Try[U] = Failure[U](exception)
def flatten[U](implicit ev: T <:< Try[U]): Try[U] = Failure[U](exception)
def foreach[U](f: T => U): Unit = {}
def map[U](f: T => U): Try[U] = Failure[U](exception)
- def collect[U](pf: PartialFunction[T, U]): Try[U] = Failure[U](exception)
def filter(p: T => Boolean): Try[T] = this
- def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] =
- if (rescueException.isDefinedAt(exception)) {
- Try(rescueException(exception))
- } else {
- this
+ def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = {
+ try {
+ if (rescueException.isDefinedAt(exception)) {
+ Try(rescueException(exception))
+ } else {
+ this
+ }
+ } catch {
+ case NonFatal(e) => Failure(e)
}
- def exists(p: T => Boolean): Boolean = false
+ }
def failed: Try[Throwable] = Success(exception)
}
-final class Success[+T](value: T) extends Try[T] {
+final case 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 rescue[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U] = Success(value)
def get = value
def flatMap[U](f: T => Try[U]): Try[U] =
try f(value)
@@ -142,43 +213,14 @@ final class Success[+T](value: T) extends Try[T] {
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 value) Success(pf(value))
- else Failure[U](new NoSuchElementException("Partial function not defined at " + value))
- def filter(p: T => Boolean): Try[T] =
- 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(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 {
-
- def apply[T](r: => T): Try[T] = {
- try { Success(r) } catch {
- case e => Failure(e)
+ def filter(p: T => Boolean): Try[T] = {
+ try {
+ if (p(value)) this
+ else Failure(new NoSuchElementException("Predicate does not hold for " + value))
+ } catch {
+ case NonFatal(e) => Failure(e)
}
}
-
+ def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = this
+ def failed: Try[Throwable] = Failure(new UnsupportedOperationException("Success.failed"))
}
diff --git a/src/library/scala/concurrent/impl/NonFatal.scala b/src/library/scala/util/control/NonFatal.scala
index bc509e664c..9da2f63307 100644
--- a/src/library/scala/concurrent/impl/NonFatal.scala
+++ b/src/library/scala/util/control/NonFatal.scala
@@ -6,32 +6,33 @@
** |/ **
\* */
-package scala.concurrent
-package impl
+package scala.util.control
/**
- * Extractor of non-fatal Throwables. Will not match fatal errors
- * like VirtualMachineError (OutOfMemoryError)
- * ThreadDeath, LinkageError and InterruptedException.
- * StackOverflowError is matched, i.e. considered non-fatal.
+ * Extractor of non-fatal Throwables. Will not match fatal errors like `VirtualMachineError`
+ * (for example, `OutOfMemoryError`, a subclass of `VirtualMachineError`), `ThreadDeath`,
+ * `LinkageError`, `InterruptedException`, `ControlThrowable`, or `NotImplementedError`.
+ * However, `StackOverflowError` is matched, i.e. considered non-fatal.
*
- * Usage to catch all harmless throwables:
+ * Note that [[scala.util.control.ControlThrowable]], an internal Throwable, is not matched by
+ * `NonFatal` (and would therefore be thrown).
+ *
+ * For example, all harmless Throwables can be caught by:
* {{{
* try {
* // dangerous stuff
* } catch {
- * case NonFatal(e) => log.error(e, "Something not that bad")
+ * case NonFatal(e) => log.error(e, "Something not that bad.")
* }
* }}}
*/
-private[concurrent] object NonFatal {
+object NonFatal {
def unapply(t: Throwable): Option[Throwable] = t match {
case e: StackOverflowError ⇒ Some(e) // StackOverflowError ok even though it is a VirtualMachineError
// VirtualMachineError includes OutOfMemoryError and other fatal errors
- case _: VirtualMachineError | _: ThreadDeath | _: InterruptedException | _: LinkageError ⇒ None
+ case _: VirtualMachineError | _: ThreadDeath | _: InterruptedException | _: LinkageError | _: ControlThrowable | _: NotImplementedError => None
case e ⇒ Some(e)
}
}
-
diff --git a/test/files/run/syncchannel.check b/test/disabled/run/syncchannel.check
index d81cc0710e..d81cc0710e 100644
--- a/test/files/run/syncchannel.check
+++ b/test/disabled/run/syncchannel.check
diff --git a/test/files/run/syncchannel.scala b/test/disabled/run/syncchannel.scala
index 66ae47fd0a..66ae47fd0a 100644
--- a/test/files/run/syncchannel.scala
+++ b/test/disabled/run/syncchannel.scala
diff --git a/test/files/jvm/scala-concurrent-tck.scala b/test/files/jvm/scala-concurrent-tck.scala
index 012460147a..407027f904 100644
--- a/test/files/jvm/scala-concurrent-tck.scala
+++ b/test/files/jvm/scala-concurrent-tck.scala
@@ -138,7 +138,7 @@ trait FutureCallbacks extends TestBase {
testOnSuccessWhenFailed()
testOnFailure()
testOnFailureWhenSpecialThrowable(5, new Error)
- testOnFailureWhenSpecialThrowable(6, new scala.util.control.ControlThrowable { })
+ // testOnFailureWhenSpecialThrowable(6, new scala.util.control.ControlThrowable { })
//TODO: this test is currently problematic, because NonFatal does not match InterruptedException
//testOnFailureWhenSpecialThrowable(7, new InterruptedException)
testOnFailureWhenTimeoutException()
@@ -599,10 +599,10 @@ trait FutureProjections extends TestBase {
throw cause
}
f.failed onComplete {
- case Success(t) =>
+ case Right(t) =>
assert(t == cause)
done()
- case Failure(t) =>
+ case Left(t) =>
assert(false)
}
}
@@ -624,9 +624,9 @@ trait FutureProjections extends TestBase {
done =>
val f = future { 0 }
f.failed onComplete {
- case Success(t) =>
+ case Right(t) =>
assert(false)
- case Failure(t) =>
+ case Left(t) =>
assert(t.isInstanceOf[NoSuchElementException])
done()
}
@@ -733,80 +733,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)
- }
+// 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()
-}
+// testSuccessMatch()
+// testRightMatch()
+// testFailureMatch()
+// testLeftMatch()
+// }
trait CustomExecutionContext extends TestBase {
import scala.concurrent.{ ExecutionContext, Awaitable }
@@ -935,7 +935,7 @@ with FutureCombinators
with FutureProjections
with Promises
with Exceptions
-with TryEitherExtractor
+// with TryEitherExtractor
with CustomExecutionContext
{
System.exit(0)
diff --git a/test/files/jvm/try-type-tests.scala b/test/files/jvm/try-type-tests.scala
new file mode 100644
index 0000000000..eecbb0ae57
--- /dev/null
+++ b/test/files/jvm/try-type-tests.scala
@@ -0,0 +1,250 @@
+import scala.util.{Try, Success, Failure}
+
+// tests the basic combinators on Try
+trait TryStandard {
+
+ def testForeachSuccess(): Unit = {
+ val t = Success(1)
+ var res = 0
+ t.foreach(x => res = x * 10)
+ assert(res == 10)
+ }
+
+ def testForeachFailure(): Unit = {
+ val t = Failure(new Exception("foo"))
+ t.foreach(x => assert(false))
+ }
+
+ def testFlatMapSuccess(): Unit = {
+ val t = Success(1)
+ val n = t.flatMap(x => Try(x * 10))
+ assert(n.get == 10)
+ }
+
+ def testFlatMapFailure(): Unit = {
+ val t = Failure(new Exception("foo"))
+ val n = t.flatMap{ x => assert(false); Try() }
+ }
+
+ def testMapSuccess(): Unit = {
+ val t = Success(1)
+ val n = t.map(x => x * 10)
+ assert(n.get == 10)
+ }
+
+ def testMapFailure(): Unit = {
+ val t = Failure(new Exception("foo"))
+ val n = t.map(x => assert(false))
+ }
+
+ def testFilterSuccessTrue(): Unit = {
+ val t = Success(1)
+ val n = t.filter(x => x > 0)
+ assert(n.get == 1)
+ }
+
+ def testFilterSuccessFalse(): Unit = {
+ val t = Success(1)
+ val n = t.filter(x => x < 0)
+ n match {
+ case Success(v) => assert(false)
+ case Failure(e: NoSuchElementException) => assert(true)
+ }
+ }
+
+ def testFilterFailure(): Unit = {
+ val t = Failure(new Exception("foo"))
+ val n = t.filter{ x => assert(false); true }
+ }
+
+ def testRescueSuccess(): Unit = {
+ val t = Success(1)
+ t.rescue{ case x => assert(false); Try() }
+ }
+
+ def testRescueFailure(): Unit = {
+ val t = Failure(new Exception("foo"))
+ val n = t.rescue{ case x => Try(1) }
+ assert(n.get == 1)
+ }
+
+ def testRecoverSuccess(): Unit = {
+ val t = Success(1)
+ t.recover{ case x => assert(false); 99 }
+ }
+
+ def testRecoverFailure(): Unit = {
+ val t = Failure(new Exception("foo"))
+ val n = t.recover{ case x => 1 }
+ assert(n.get == 1)
+ }
+
+ def testFlattenSuccess(): Unit = {
+ val f = Failure(new Exception("foo"))
+ val t = Success(f)
+ assert(t.flatten == f)
+ }
+
+ def testFailedSuccess(): Unit = {
+ val t = Success(1)
+ val n = t.failed
+ n match {
+ case Failure(e: UnsupportedOperationException) => assert(true)
+ case _ => assert(false)
+ }
+ }
+
+ def testFailedFailure(): Unit = {
+ val t = Failure(new Exception("foo"))
+ val n = t.failed
+ n match {
+ case Success(e: Exception) => assert(true)
+ case _ => assert(false)
+ }
+ }
+
+ testForeachSuccess()
+ testForeachFailure()
+ testFlatMapSuccess()
+ testFlatMapFailure()
+ testMapSuccess()
+ testMapFailure()
+ testFilterSuccessTrue()
+ testFilterSuccessFalse()
+ testFilterFailure()
+ testRescueSuccess()
+ testRescueFailure()
+ testRecoverSuccess()
+ testRecoverFailure()
+ testFlattenSuccess()
+ testFailedSuccess()
+ testFailedFailure()
+}
+
+// tests that implicit conversions from Try to Either behave as expected
+trait TryImplicitConversionTry2Either {
+
+ def testTry2RightMap(): Unit = {
+ val t = Success(1)
+ val n = t.right.map(x => x * 100)
+ assert(n == Right(100))
+ }
+
+ def testTry2LeftMap(): Unit = {
+ val e = new Exception("foo")
+ val t = Failure(e)
+ val n = t.left.map(x => x)
+ assert(n == Left(e))
+ }
+
+ def testTry2FoldSuccess(): Unit = {
+ val t = Success(1)
+ val n = t.fold(x => assert(false), y => y * 200)
+ assert(n == 200)
+ }
+
+ def testTry2FoldFailure(): Unit = {
+ val e = new Exception("foo")
+ val t = Failure(e)
+ val n = t.fold(x => x, y => assert(false))
+ assert(n == e)
+ }
+
+ def testTry2SwapSuccess(): Unit = {
+ val t = Success(1)
+ val n = t.swap
+ assert(n == Left(1))
+ }
+
+ def testTry2SwapFailure(): Unit = {
+ val e = new Exception("foo")
+ val t = Failure(e)
+ val n = t.swap
+ assert(n == Right(e))
+ }
+
+ // def testTry2MergeSucccess(): Unit = {
+ // val t: Try[Int] = Success(1)
+ // val n = (t: Either[Any, Any]).t.merge // connecting two implicit conversions
+ // assert(n == 1)
+ // }
+
+ // def testTry2MergeFailure(): Unit = {
+ // val e = new Exception("foo")
+ // val t = Failure(e)
+ // val n = (t: Either[Any, Any]).merge // connecting two implicit conversions
+ // assert(n == e)
+ // }
+
+ testTry2RightMap()
+ testTry2LeftMap()
+ testTry2FoldSuccess()
+ testTry2FoldFailure()
+ testTry2SwapSuccess()
+ testTry2SwapFailure()
+ // testTry2MergeSucccess()
+ // testTry2MergeFailure()
+}
+
+// tests that implicit conversions from Either to Try behave as expected
+trait TryImplicitConversionEither2Try {
+
+ def testRight2FilterSuccessTrue(): Unit = {
+ def expectsTry[U <% Try[Int]](rght: U): Try[Int] = {
+ val n = rght.filter(x => x > 0) // this should be converted to a Try
+ n
+ }
+ val r = Right(1)
+ val n = expectsTry(r)
+ assert(n == Success(1))
+ }
+
+ def testRight2FilterSuccessFalse(): Unit = {
+ def expectsTry[U <% Try[Int]](rght: U): Try[Int] = {
+ val n = rght.filter(x => x < 0) // this should be converted to a Try
+ n
+ }
+ val r = Right(1)
+ val n = expectsTry(r)
+ n match {
+ case Failure(e: NoSuchElementException) => assert(true)
+ case _ => assert(false)
+ }
+ }
+
+ def testLeft2FilterFailure(): Unit = {
+ def expectsTry[U <% Try[Int]](rght: U): Try[Int] = {
+ val n = rght.filter(x => x > 0) // this should be converted to a Try
+ n
+ }
+ val r = Left(new Exception("foo"))
+ val n = expectsTry(r)
+ n match {
+ case Failure(e: Exception) => assert(true)
+ case _ => assert(false)
+ }
+ }
+
+ def testRight2GetSuccess(): Unit = {
+ def expectsTry[U <% Try[Int]](rght: U): Int = {
+ val n = rght.get // this should be converted to a Try
+ n
+ }
+ val r = Right(1)
+ val n = expectsTry(r)
+ assert(n == 1)
+ }
+
+ testRight2FilterSuccessTrue()
+ testRight2FilterSuccessFalse()
+ testLeft2FilterFailure()
+ testRight2GetSuccess()
+}
+
+object Test
+extends App
+with TryStandard
+with TryImplicitConversionTry2Either
+with TryImplicitConversionEither2Try {
+ System.exit(0)
+} \ No newline at end of file
diff --git a/test/files/neg/t5589neg.check b/test/files/neg/t5589neg.check
index b3ff16d7e4..f1dad94df3 100644
--- a/test/files/neg/t5589neg.check
+++ b/test/files/neg/t5589neg.check
@@ -1,4 +1,4 @@
-t5589neg.scala:2: warning: `withFilter' method does not yet exist on Either.RightProjection[Int,String], using `filter' method instead
+t5589neg.scala:2: warning: `withFilter' method does not yet exist on scala.util.Either.RightProjection[Int,String], using `filter' method instead
def f5(x: Either[Int, String]) = for ((y1, y2: String) <- x.right) yield ((y1, y2))
^
t5589neg.scala:2: error: constructor cannot be instantiated to expected type;
@@ -6,7 +6,7 @@ t5589neg.scala:2: error: constructor cannot be instantiated to expected type;
required: String
def f5(x: Either[Int, String]) = for ((y1, y2: String) <- x.right) yield ((y1, y2))
^
-t5589neg.scala:3: warning: `withFilter' method does not yet exist on Either.RightProjection[Int,String], using `filter' method instead
+t5589neg.scala:3: warning: `withFilter' method does not yet exist on scala.util.Either.RightProjection[Int,String], using `filter' method instead
def f6(x: Either[Int, String]) = for ((y1, y2: Any) <- x.right) yield ((y1, y2))
^
t5589neg.scala:3: error: constructor cannot be instantiated to expected type;