Skip to content

scala.util.Failure.recoverWith broken in Scala 2.13.0-M5 #11242

Closed
@sjrd

Description

@sjrd

See scala-js/scala-js#3480 (comment)

On 2.13.0-M5:

C:\Users\Sepi>scala
Welcome to Scala 2.13.0-M5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_60).
Type in expressions for evaluation. Or try :help.

scala> import scala.util._
import scala.util._

scala> :paste
// Entering paste mode (ctrl-D to finish)

    val e: Try[Int] = Failure(new Exception("dfd"))
    val pf: PartialFunction[Throwable, Int] = {
      case _: RuntimeException => 1
    }
    val e2 = e.recoverWith(pf.andThen(Try(_)))
    println(e2)

// Exiting paste mode, now interpreting.

Failure(java.lang.ClassCastException: java.lang.Object cannot be cast to scala.util.Try)
e: scala.util.Try[Int] = Failure(java.lang.Exception: dfd)
pf: PartialFunction[Throwable,Int] = <function1>
e2: scala.util.Try[Int] = Failure(java.lang.ClassCastException: java.lang.Object cannot be cast to scala.util.Try)

On 2.12.6:

C:\Users\Sepi>scala
Welcome to Scala 2.12.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_60).
Type in expressions for evaluation. Or try :help.

scala> import scala.util._
import scala.util._

scala> :paste
// Entering paste mode (ctrl-D to finish)

    val e: Try[Int] = Failure(new Exception("dfd"))
    val pf: PartialFunction[Throwable, Int] = {
      case _: RuntimeException => 1
    }
    val e2 = e.recoverWith(pf.andThen(Try(_)))
    println(e2)

// Exiting paste mode, now interpreting.

Failure(java.lang.Exception: dfd)
e: scala.util.Try[Int] = Failure(java.lang.Exception: dfd)
pf: PartialFunction[Throwable,Int] = <function1>
e2: scala.util.Try[Int] = Failure(java.lang.Exception: dfd)

Note that 2.13.0-M5 has thrown a ClassCastException, and it has been swallowed by the Try as Failure(ClassCastException). 2.12.6 correctly reports a Failure(Exception).

That's because Failure.recoverWith is broken. It should be something like:

  override def recoverWith[U >: T](pf: PartialFunction[Throwable, Try[U]]): Try[U] = {
    val marker = Statics.pfMarker
    try {
      val v: Any = pf.applyOrElse(exception, ((x: Throwable) => marker))
      if (marker ne v.asInstanceOf[AnyRef]) v.asInstanceOf[Try[U]] else this
    } catch { case NonFatal(e) => Failure(e) }
  }

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions