Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Immediately surface fatal errors in IO.raiseError #3811

Merged
merged 8 commits into from
Nov 23, 2023
3 changes: 3 additions & 0 deletions core/shared/src/main/scala/cats/effect/IOFiber.scala
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,9 @@ private final class IOFiber[A](

case 1 =>
val cur = cur0.asInstanceOf[Error]
if (!NonFatal(cur.t))
onFatalFailure(cur.t)

runLoop(failed(cur.t, 0), nextCancelation, nextAutoCede)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!NonFatal(cur.t))
onFatalFailure(cur.t)
runLoop(failed(cur.t, 0), nextCancelation, nextAutoCede)
val ex = cur.t
if (!NonFatal(ex))
onFatalFailure(ex)
runLoop(failed(ex, 0), nextCancelation, nextAutoCede)


case 2 =>
Expand Down
15 changes: 15 additions & 0 deletions tests/shared/src/test/scala/cats/effect/IOSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,21 @@ class IOSpec extends BaseSpec with Discipline with IOPlatformSpecification {
} yield reported
test must completeAs(true)
}

"immediately surface fatal errors" in ticked { implicit ticker =>
import scala.util.control.NonFatal
val io = IO.raiseError[Unit](new VirtualMachineError {}).voidError

val fatalThrown =
try {
unsafeRun[Unit](io)
false
} catch {
case t if NonFatal(t) => false
case _: Throwable => true
}
IO(fatalThrown) must completeAs(true)
Copy link
Member

@armanbilge armanbilge Sep 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import scala.util.control.NonFatal
val io = IO.raiseError[Unit](new VirtualMachineError {}).voidError
val fatalThrown =
try {
unsafeRun[Unit](io)
false
} catch {
case t if NonFatal(t) => false
case _: Throwable => true
}
IO(fatalThrown) must completeAs(true)
val error = new VirtualMachineError {}
val io = IO.raiseError[Unit](error).voidError
val fatalThrown =
try {
unsafeRun[Unit](io)
false
} catch {
case t: Throwable => t eq error
}
IO.pure(fatalThrown) must completeAs(true)

}
}

"suspension of side effects" should {
Expand Down