From ddd5f3aa8f080328e98f656fd5f5d2946b5aa77f Mon Sep 17 00:00:00 2001 From: phaller Date: Fri, 20 Jul 2012 16:29:37 +0200 Subject: SIP-14 - Fix critical Java compatibility issue in scala.concurrent.Await Patch contributed by @viktorklang --- src/library/scala/concurrent/package.scala | 78 ++++++++++++++++-------------- test/files/jvm/scala-concurrent-tck.scala | 11 ++++- 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala index a6488b602f..a2ef42fac8 100644 --- a/src/library/scala/concurrent/package.scala +++ b/src/library/scala/concurrent/package.scala @@ -18,41 +18,6 @@ package object concurrent { type CancellationException = java.util.concurrent.CancellationException type TimeoutException = java.util.concurrent.TimeoutException - @implicitNotFound("Don't call `Awaitable` methods directly, use the `Await` object.") - sealed trait CanAwait - private implicit object AwaitPermission extends CanAwait - - /** - * `Await` is what is used to ensure proper handling of blocking for `Awaitable` instances. - */ - object Await { - /** - * Invokes ready() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`. - * ready() blocks until the awaitable has completed or the timeout expires. - * - * Throws a TimeoutException if the timeout expires, as that is in the contract of `Awaitable.ready`. - * @param awaitable the `Awaitable` on which `ready` is to be called - * @param atMost the maximum timeout for which to wait - * @return the result of `awaitable.ready` which is defined to be the awaitable itself. - */ - @throws(classOf[TimeoutException]) - def ready[T](awaitable: Awaitable[T], atMost: Duration): awaitable.type = - blocking(awaitable.ready(atMost)) - - /** - * Invokes result() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`. - * result() blocks until the awaitable has completed or the timeout expires. - * - * Throws a TimeoutException if the timeout expires, or any exception thrown by `Awaitable.result`. - * @param awaitable the `Awaitable` on which `result` is to be called - * @param atMost the maximum timeout for which to wait - * @return the result of `awaitable.result` - */ - @throws(classOf[Exception]) - def result[T](awaitable: Awaitable[T], atMost: Duration): T = - blocking(awaitable.result(atMost)) - } - /** Starts an asynchronous computation and returns a `Future` object with the result of that computation. * * The result becomes available once the asynchronous computation is completed. @@ -85,5 +50,46 @@ package object concurrent { * - TimeoutException - in the case that the blockable object timed out */ @throws(classOf[Exception]) - def blocking[T](body: =>T): T = BlockContext.current.blockOn(body) + def blocking[T](body: =>T): T = BlockContext.current.blockOn(body)(scala.concurrent.AwaitPermission) +} + +package concurrent { + @implicitNotFound("Don't call `Awaitable` methods directly, use the `Await` object.") + sealed trait CanAwait + + /** + * Internal usage only, implementation detail. + */ + private[concurrent] object AwaitPermission extends CanAwait + + /** + * `Await` is what is used to ensure proper handling of blocking for `Awaitable` instances. + */ + object Await { + /** + * Invokes ready() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`. + * ready() blocks until the awaitable has completed or the timeout expires. + * + * Throws a TimeoutException if the timeout expires, as that is in the contract of `Awaitable.ready`. + * @param awaitable the `Awaitable` on which `ready` is to be called + * @param atMost the maximum timeout for which to wait + * @return the result of `awaitable.ready` which is defined to be the awaitable itself. + */ + @throws(classOf[TimeoutException]) + def ready[T](awaitable: Awaitable[T], atMost: Duration): awaitable.type = + blocking(awaitable.ready(atMost)(AwaitPermission)) + + /** + * Invokes result() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`. + * result() blocks until the awaitable has completed or the timeout expires. + * + * Throws a TimeoutException if the timeout expires, or any exception thrown by `Awaitable.result`. + * @param awaitable the `Awaitable` on which `result` is to be called + * @param atMost the maximum timeout for which to wait + * @return the result of `awaitable.result` + */ + @throws(classOf[Exception]) + def result[T](awaitable: Awaitable[T], atMost: Duration): T = + blocking(awaitable.result(atMost)(AwaitPermission)) + } } diff --git a/test/files/jvm/scala-concurrent-tck.scala b/test/files/jvm/scala-concurrent-tck.scala index 1209b710b0..43d4c9dc71 100644 --- a/test/files/jvm/scala-concurrent-tck.scala +++ b/test/files/jvm/scala-concurrent-tck.scala @@ -700,9 +700,18 @@ trait Blocking extends TestBase { } } + def testFQCNForAwaitAPI(): Unit = once { + done => + + assert(classOf[CanAwait].getName == "scala.concurrent.CanAwait") + assert(Await.getClass.getName == "scala.concurrent.Await") + + done() + } + testAwaitSuccess() testAwaitFailure() - + testFQCNForAwaitAPI() } trait BlockContexts extends TestBase { -- cgit v1.2.3