1+ import scala .util .control .NonFatal
2+ import scala .util .control .NonLocalReturns ._
3+
14object lib {
25 inline def (op : => T ) rescue[T ] (fallback : => T ) =
36 try op
47 catch {
5- case _ : Throwable => fallback
8+ case NonFatal (_) => fallback // ReturnThrowable is fatal error, thus ignored
69 }
710
811 inline def (op : => T ) rescue[T , E <: Throwable ] (fallback : PartialFunction [E , T ]) =
912 try op
1013 catch {
14+ // case ex: ReturnThrowable[_] => throw ex // bug #7041
1115 case ex : E =>
12- if (fallback.isDefinedAt(ex)) fallback(ex) else throw ex
16+ // user should never match `ReturnThrowable`, which breaks semantics of non-local return
17+ if (fallback.isDefinedAt(ex) && ! ex.isInstanceOf [ReturnThrowable [_]]) fallback(ex) else throw ex
1318 }
1419}
1520
@@ -30,6 +35,8 @@ import lib._
3035 } == 3
3136 )
3237
38+ (9 / 0 ) rescue { case ex : ArithmeticException => 4 }
39+
3340 assert(
3441 {
3542 {
@@ -42,4 +49,30 @@ import lib._
4249 }
4350 } == 3
4451 )
52+
53+ assert(foo(10 ) == 40 )
54+ assert(bar(10 ) == 40 )
55+
56+ // should not catch fatal errors
57+ assert(
58+ try { { throw new OutOfMemoryError (); true } rescue false }
59+ catch { case _ : OutOfMemoryError => true }
60+ )
61+
62+ // should catch any errors specified, including fatal errors
63+ assert(
64+ try { { throw new OutOfMemoryError (); true } rescue { case _ : OutOfMemoryError => true } }
65+ catch { case _ : OutOfMemoryError => false }
66+ )
67+
68+ // should not catch NonLocalReturns
69+ def foo (x : Int ): Int = returning[Int ] {
70+ { throwReturn[Int ](4 * x) : Int } rescue 10
71+ }
72+
73+ // should catch specified exceptions, but not NonLocalReturn
74+ def bar (x : Int ): Int = returning[Int ] {
75+ { throwReturn[Int ](4 * x) : Int } rescue { case _ => 10 }
76+ }
77+
4578}
0 commit comments