Skip to content

Commit d481b20

Browse files
authored
Add suppressed exceptions when one is thrown during releasing in use (#337)
1 parent c98e048 commit d481b20

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

core/src/main/scala/ox/resource.scala

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,20 @@ inline def use[R, T](inline acquire: R, inline release: R => Unit)(inline f: R =
3838
*/
3939
inline def useInterruptible[R, T](inline acquire: R, inline release: R => Unit)(inline f: R => T): T =
4040
val r = acquire
41+
var caught: Throwable = null
4142
try f(r)
42-
finally release(r)
43+
catch
44+
case e: Throwable =>
45+
caught = e
46+
null.asInstanceOf[T]
47+
finally
48+
if caught == null then release(r)
49+
else
50+
try release(r)
51+
catch case e: Throwable => caught.addSuppressed(e)
52+
finally throw caught
53+
end try
54+
end useInterruptible
4355

4456
/** Use the given [[AutoCloseable]] resource, acquired using `acquire` in the given `f` code block. Releasing is [[uninterruptible]]. To use
4557
* multiple resources, consider creating a [[supervised]] scope and [[useCloseableInScope]] method.

core/src/test/scala/ox/ResourceTest.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,23 @@ class ResourceTest extends AnyFlatSpec with Matchers:
143143

144144
trail.get shouldBe Vector("allocate", "in scope", "release")
145145
}
146+
147+
it should "add suppressed exception when there's an exception during releasing" in {
148+
val trail = Trail()
149+
150+
class TestResource:
151+
trail.add("allocate")
152+
def release(): Unit =
153+
trail.add("release")
154+
throw new RuntimeException("e1")
155+
156+
try
157+
use(new TestResource, _.release()) { r =>
158+
trail.add("in scope")
159+
throw new RuntimeException("e2")
160+
}
161+
catch case e => trail.add(s"exception ${e.getMessage} (${e.getSuppressed.map(_.getMessage).mkString(", ")})")
162+
163+
trail.get shouldBe Vector("allocate", "in scope", "release", "exception e2 (e1)")
164+
}
146165
end ResourceTest

0 commit comments

Comments
 (0)