diff --git a/src/library/scala/util/Using.scala b/src/library/scala/util/Using.scala index 6e37277a6cd7..ebec5e7007ec 100644 --- a/src/library/scala/util/Using.scala +++ b/src/library/scala/util/Using.scala @@ -125,8 +125,8 @@ import scala.util.control.{ControlThrowable, NonFatal} * - `java.lang.LinkageError` * - `java.lang.InterruptedException` and `java.lang.ThreadDeath` * - [[scala.util.control.NonFatal fatal exceptions]], excluding `scala.util.control.ControlThrowable` + * - all other exceptions, excluding `scala.util.control.ControlThrowable` * - `scala.util.control.ControlThrowable` - * - all other exceptions * * When more than two exceptions are thrown, the first two are combined and * re-thrown as described above, and each successive exception thrown is combined @@ -265,9 +265,9 @@ object Using { case _: VirtualMachineError => 4 case _: LinkageError => 3 case _: InterruptedException | _: ThreadDeath => 2 - case _: ControlThrowable => 0 + case _: ControlThrowable => -1 // below everything case e if !NonFatal(e) => 1 // in case this method gets out of sync with NonFatal - case _ => -1 + case _ => 0 } @inline def suppress(t: Throwable, suppressed: Throwable): Throwable = { t.addSuppressed(suppressed); t } diff --git a/test/junit/scala/util/UsingTest.scala b/test/junit/scala/util/UsingTest.scala index eb7350159cdc..cba73c15a42d 100644 --- a/test/junit/scala/util/UsingTest.scala +++ b/test/junit/scala/util/UsingTest.scala @@ -15,29 +15,29 @@ class UsingTest { private def genericResourceThrowing[CloseT <: Throwable: ClassTag]( resource: => CustomResource[CloseT], - onLinkage: SuppressionBehavior, - onInterruption: SuppressionBehavior, - onControl: SuppressionBehavior, - onException: SuppressionBehavior + onLinkage: ThrowBehavior, + onInterruption: ThrowBehavior, + onControl: ThrowBehavior, + onException: ThrowBehavior ): Unit = { def check[UseT <: Throwable: ClassTag]( t: String => UseT, - behavior: SuppressionBehavior, + behavior: ThrowBehavior, allowsSuppression: Boolean ): Unit = { val ex = use(resource, t) - if (behavior == IsSuppressed) { + if (behavior == UseIsThrown) { assertThrowableClass[UseT](ex) if (allowsSuppression) assertSingleSuppressed[CloseT](ex) else assertNoSuppressed(ex) } else { assertThrowableClass[CloseT](ex) - if (behavior == AcceptsSuppressed) assertSingleSuppressed[UseT](ex) + if (behavior == CloseIsThrown) assertSingleSuppressed[UseT](ex) else assertNoSuppressed(ex) } } - check(new UsingVMError(_), behavior = IsSuppressed, allowsSuppression = true) + check(new UsingVMError(_), behavior = UseIsThrown, allowsSuppression = true) check(new UsingLinkageError(_), onLinkage, allowsSuppression = true) check(_ => new UsingInterruption, onInterruption, allowsSuppression = true) check(new UsingControl(_), onControl, allowsSuppression = false) @@ -49,250 +49,248 @@ class UsingTest { def resourceThrowingVMError(): Unit = { genericResourceThrowing( new VMErrorResource, - onLinkage = AcceptsSuppressed, - onInterruption = AcceptsSuppressed, - onControl = AcceptsSuppressed, - onException = AcceptsSuppressed) + onLinkage = CloseIsThrown, + onInterruption = CloseIsThrown, + onControl = CloseIsThrown, + onException = CloseIsThrown) } @Test def resourceThrowingLinkageError(): Unit = { genericResourceThrowing( new LinkageResource, - onLinkage = IsSuppressed, - onInterruption = AcceptsSuppressed, - onControl = AcceptsSuppressed, - onException = AcceptsSuppressed) + onLinkage = UseIsThrown, + onInterruption = CloseIsThrown, + onControl = CloseIsThrown, + onException = CloseIsThrown) } @Test def resourceThrowingInterruption(): Unit = { genericResourceThrowing( new InterruptionResource, - onLinkage = IsSuppressed, - onInterruption = IsSuppressed, - onControl = AcceptsSuppressed, - onException = AcceptsSuppressed) + onLinkage = UseIsThrown, + onInterruption = UseIsThrown, + onControl = CloseIsThrown, + onException = CloseIsThrown) } @Test def resourceThrowingControl(): Unit = { genericResourceThrowing( new ControlResource, - onLinkage = IsSuppressed, - onInterruption = IsSuppressed, - onControl = IsSuppressed, - onException = IgnoresSuppressed) + onLinkage = UseIsThrown, + onInterruption = UseIsThrown, + onControl = UseIsThrown, + onException = UseIsThrown) } @Test def resourceThrowingError(): Unit = { genericResourceThrowing( new ErrorResource, - onLinkage = IsSuppressed, - onInterruption = IsSuppressed, - onControl = IsSuppressed, - onException = IsSuppressed) + onLinkage = UseIsThrown, + onInterruption = UseIsThrown, + onControl = CloseIsThrown, + onException = UseIsThrown) } @Test def resourceThrowingException(): Unit = { genericResourceThrowing( new ExceptionResource, - onLinkage = IsSuppressed, - onInterruption = IsSuppressed, - onControl = IsSuppressed, - onException = IsSuppressed) + onLinkage = UseIsThrown, + onInterruption = UseIsThrown, + onControl = CloseIsThrown, + onException = UseIsThrown) } /* `Using.apply` exception preference */ private def genericUsingThrowing[CloseT <: Throwable: ClassTag]( resource: => CustomResource[CloseT], - onLinkage: SuppressionBehavior, - onInterruption: SuppressionBehavior, - onControl: SuppressionBehavior, - onException: SuppressionBehavior + onLinkage: ThrowBehavior, + onInterruption: ThrowBehavior, + onControl: ThrowBehavior, + onException: ThrowBehavior ): Unit = { def check[UseT <: Throwable: ClassTag]( t: String => UseT, - behavior: SuppressionBehavior, + behavior: ThrowBehavior, allowsSuppression: Boolean, - yieldsTry: Boolean ): Unit = { - val ex = if (yieldsTry) UseWrapped(resource, t) else UseWrapped.catching(resource, t) - if (behavior == IsSuppressed) { + val ex = useWrapped(resource, t) + if (behavior == UseIsThrown) { assertThrowableClass[UseT](ex) if (allowsSuppression) assertSingleSuppressed[CloseT](ex) else assertNoSuppressed(ex) } else { assertThrowableClass[CloseT](ex) - if (behavior == AcceptsSuppressed) assertSingleSuppressed[UseT](ex) + if (behavior == CloseIsThrown) assertSingleSuppressed[UseT](ex) else assertNoSuppressed(ex) } } - check(new UsingVMError(_), behavior = IsSuppressed, allowsSuppression = true, yieldsTry = false) - check(new UsingLinkageError(_), onLinkage, allowsSuppression = true, yieldsTry = false) - check(_ => new UsingInterruption, onInterruption, allowsSuppression = true, yieldsTry = false) - check(new UsingControl(_), onControl, allowsSuppression = false, yieldsTry = false) - check(new UsingError(_), onException, allowsSuppression = true, yieldsTry = onException == IsSuppressed) - check(new UsingException(_), onException, allowsSuppression = true, yieldsTry = onException == IsSuppressed) + check(new UsingVMError(_), behavior = UseIsThrown, allowsSuppression = true) + check(new UsingLinkageError(_), onLinkage, allowsSuppression = true) + check(_ => new UsingInterruption, onInterruption, allowsSuppression = true) + check(new UsingControl(_), onControl, allowsSuppression = false) + check(new UsingError(_), onException, allowsSuppression = true) + check(new UsingException(_), onException, allowsSuppression = true) } @Test def usingThrowingVMError(): Unit = { genericUsingThrowing( new VMErrorResource, - onLinkage = AcceptsSuppressed, - onInterruption = AcceptsSuppressed, - onControl = AcceptsSuppressed, - onException = AcceptsSuppressed) + onLinkage = CloseIsThrown, + onInterruption = CloseIsThrown, + onControl = CloseIsThrown, + onException = CloseIsThrown) } @Test def usingThrowingLinkageError(): Unit = { genericUsingThrowing( new LinkageResource, - onLinkage = IsSuppressed, - onInterruption = AcceptsSuppressed, - onControl = AcceptsSuppressed, - onException = AcceptsSuppressed) + onLinkage = UseIsThrown, + onInterruption = CloseIsThrown, + onControl = CloseIsThrown, + onException = CloseIsThrown) } @Test def usingThrowingInterruption(): Unit = { genericUsingThrowing( new InterruptionResource, - onLinkage = IsSuppressed, - onInterruption = IsSuppressed, - onControl = AcceptsSuppressed, - onException = AcceptsSuppressed) + onLinkage = UseIsThrown, + onInterruption = UseIsThrown, + onControl = CloseIsThrown, + onException = CloseIsThrown) } @Test def usingThrowingControl(): Unit = { genericUsingThrowing( new ControlResource, - onLinkage = IsSuppressed, - onInterruption = IsSuppressed, - onControl = IsSuppressed, - onException = IgnoresSuppressed) + onLinkage = UseIsThrown, + onInterruption = UseIsThrown, + onControl = UseIsThrown, + onException = UseIsThrown) } @Test def usingThrowingError(): Unit = { genericUsingThrowing( new ErrorResource, - onLinkage = IsSuppressed, - onInterruption = IsSuppressed, - onControl = IsSuppressed, - onException = IsSuppressed) + onLinkage = UseIsThrown, + onInterruption = UseIsThrown, + onControl = CloseIsThrown, + onException = UseIsThrown) } @Test def usingThrowingException(): Unit = { genericUsingThrowing( new ExceptionResource, - onLinkage = IsSuppressed, - onInterruption = IsSuppressed, - onControl = IsSuppressed, - onException = IsSuppressed) + onLinkage = UseIsThrown, + onInterruption = UseIsThrown, + onControl = CloseIsThrown, + onException = UseIsThrown) } /* `Using.Manager.apply` exception preference */ private def genericManagerThrowing[CloseT <: Throwable: ClassTag]( resource: => CustomResource[CloseT], - onLinkage: SuppressionBehavior, - onInterruption: SuppressionBehavior, - onControl: SuppressionBehavior, - onException: SuppressionBehavior + onLinkage: ThrowBehavior, + onInterruption: ThrowBehavior, + onControl: ThrowBehavior, + onException: ThrowBehavior ): Unit = { def check[UseT <: Throwable: ClassTag]( t: String => UseT, - behavior: SuppressionBehavior, + behavior: ThrowBehavior, allowsSuppression: Boolean, - yieldsTry: Boolean ): Unit = { - val ex = if (yieldsTry) UseManager(resource, t) else UseManager.catching(resource, t) - if (behavior == IsSuppressed) { + val ex = useManager(resource, t) + if (behavior == UseIsThrown) { assertThrowableClass[UseT](ex) if (allowsSuppression) assertSingleSuppressed[CloseT](ex) else assertNoSuppressed(ex) } else { assertThrowableClass[CloseT](ex) - if (behavior == AcceptsSuppressed) assertSingleSuppressed[UseT](ex) + if (behavior == CloseIsThrown) assertSingleSuppressed[UseT](ex) else assertNoSuppressed(ex) } } - check(new UsingVMError(_), behavior = IsSuppressed, allowsSuppression = true, yieldsTry = false) - check(new UsingLinkageError(_), onLinkage, allowsSuppression = true, yieldsTry = false) - check(_ => new UsingInterruption, onInterruption, allowsSuppression = true, yieldsTry = false) - check(new UsingControl(_), onControl, allowsSuppression = false, yieldsTry = false) - check(new UsingError(_), onException, allowsSuppression = true, yieldsTry = onException == IsSuppressed) - check(new UsingException(_), onException, allowsSuppression = true, yieldsTry = onException == IsSuppressed) + check(new UsingVMError(_), behavior = UseIsThrown, allowsSuppression = true) + check(new UsingLinkageError(_), onLinkage, allowsSuppression = true) + check(_ => new UsingInterruption, onInterruption, allowsSuppression = true) + check(new UsingControl(_), onControl, allowsSuppression = false) + check(new UsingError(_), onException, allowsSuppression = true) + check(new UsingException(_), onException, allowsSuppression = true) } @Test def managerThrowingVMError(): Unit = { genericManagerThrowing( new VMErrorResource, - onLinkage = AcceptsSuppressed, - onInterruption = AcceptsSuppressed, - onControl = AcceptsSuppressed, - onException = AcceptsSuppressed) + onLinkage = CloseIsThrown, + onInterruption = CloseIsThrown, + onControl = CloseIsThrown, + onException = CloseIsThrown) } @Test def managerThrowingLinkageError(): Unit = { genericManagerThrowing( new LinkageResource, - onLinkage = IsSuppressed, - onInterruption = AcceptsSuppressed, - onControl = AcceptsSuppressed, - onException = AcceptsSuppressed) + onLinkage = UseIsThrown, + onInterruption = CloseIsThrown, + onControl = CloseIsThrown, + onException = CloseIsThrown) } @Test def managerThrowingInterruption(): Unit = { genericManagerThrowing( new InterruptionResource, - onLinkage = IsSuppressed, - onInterruption = IsSuppressed, - onControl = AcceptsSuppressed, - onException = AcceptsSuppressed) + onLinkage = UseIsThrown, + onInterruption = UseIsThrown, + onControl = CloseIsThrown, + onException = CloseIsThrown) } @Test def managerThrowingControl(): Unit = { genericManagerThrowing( new ControlResource, - onLinkage = IsSuppressed, - onInterruption = IsSuppressed, - onControl = IsSuppressed, - onException = IgnoresSuppressed) + onLinkage = UseIsThrown, + onInterruption = UseIsThrown, + onControl = UseIsThrown, + onException = UseIsThrown) } @Test def managerThrowingError(): Unit = { genericManagerThrowing( new ErrorResource, - onLinkage = IsSuppressed, - onInterruption = IsSuppressed, - onControl = IsSuppressed, - onException = IsSuppressed) + onLinkage = UseIsThrown, + onInterruption = UseIsThrown, + onControl = CloseIsThrown, + onException = UseIsThrown) } @Test def managerThrowingException(): Unit = { genericManagerThrowing( new ExceptionResource, - onLinkage = IsSuppressed, - onInterruption = IsSuppressed, - onControl = IsSuppressed, - onException = IsSuppressed) + onLinkage = UseIsThrown, + onInterruption = UseIsThrown, + onControl = CloseIsThrown, + onException = UseIsThrown) } /* nested resource usage returns the correct exception */ @@ -579,13 +577,13 @@ class UsingTest { @Test def usingOpThrow(): Unit = { - val ex = UseWrapped(new NoOpResource, new UsingException(_)) + val ex = useWrapped(new NoOpResource, new UsingException(_)) assertThrowableClass[UsingException](ex) } @Test def managerOpThrow(): Unit = { - val ex = UseManager(new NoOpResource, new UsingException(_)) + val ex = useManager(new NoOpResource, new UsingException(_)) assertThrowableClass[UsingException](ex) } @@ -779,13 +777,11 @@ object UsingTest { final class ErrorResource extends CustomResource(new ClosingError(_)) final class ExceptionResource extends CustomResource(new ClosingException(_)) - sealed trait SuppressionBehavior - /** is added as a suppressed exception to the other exception, and the other exception is thrown */ - case object IsSuppressed extends SuppressionBehavior - /** is thrown, and the other exception is added to this as suppressed */ - case object AcceptsSuppressed extends SuppressionBehavior - /** is thrown, and the other exception is ignored */ - case object IgnoresSuppressed extends SuppressionBehavior + sealed trait ThrowBehavior + /** resource use exception is thrown */ + case object UseIsThrown extends ThrowBehavior + /** resource closing exception is thrown */ + case object CloseIsThrown extends ThrowBehavior def assertThrowableClass[T <: Throwable: ClassTag](t: Throwable): Unit = { assertEquals(s"Caught [${t.getMessage}]", implicitly[ClassTag[T]].runtimeClass, t.getClass) @@ -810,31 +806,24 @@ object UsingTest { } } - object UseWrapped { - def apply(resource: => BaseResource, t: String => Throwable): Throwable = - Using(resource)(opThrowing(t)).failed.get + def use(resource: BaseResource, t: String => Throwable): Throwable = + catchThrowable(Using.resource(resource)(opThrowing(t))) - def catching(resource: => BaseResource, t: String => Throwable): Throwable = - catchThrowable(Using(resource)(opThrowing(t))) - } + def useWrapped(resource: => BaseResource, t: String => Throwable): Throwable = + try Using(resource)(opThrowing(t)).failed.get + catch { + case t: Throwable => t + } - object UseManager { - def apply(resource: => BaseResource, t: String => Throwable): Throwable = + def useManager(resource: => BaseResource, t: String => Throwable): Throwable = + try { Using.Manager { m => val r = m(resource) opThrowing(t)(r) }.failed.get - def catching(resource: => BaseResource, t: String => Throwable): Throwable = - catchThrowable { - Using.Manager { m => - val r = m(resource) - opThrowing(t)(r) - } - } - } - - def use(resource: BaseResource, t: String => Throwable): Throwable = - catchThrowable(Using.resource(resource)(opThrowing(t))) + } catch { + case t: Throwable => t // this is awful + } private def opThrowing(t: String => Throwable): BaseResource => Nothing = r => {