Skip to content

SI-8689 Avoid internal error in Promise after sequence of completions #4289

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

Merged
merged 1 commit into from
Feb 15, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions src/library/scala/concurrent/Promise.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,8 @@ trait Promise[T] {
*
* @return This promise
*/
final def completeWith(other: Future[T]): this.type = {
other onComplete { this complete _ }
this
}

final def completeWith(other: Future[T]): this.type = tryCompleteWith(other)

/** Attempts to complete this promise with the specified future, once that future is completed.
*
* @return This promise
Expand Down
77 changes: 68 additions & 9 deletions test/files/jvm/future-spec/PromiseTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,80 @@ object PromiseTests extends MinimalScalaTest {
Await.result(failure fallbackTo otherFailure, defaultTimeout)
}.getMessage mustBe ("br0ken")
}


"be completable with a completed Promise" in {
{
val p = Promise[String]()
p.tryCompleteWith(Promise[String]().success("foo").future)
Await.result(p.future, defaultTimeout) mustBe ("foo")
}
{
val p = Promise[String]()
p.completeWith(Promise[String]().success("foo").future)
Await.result(p.future, defaultTimeout) mustBe ("foo")
}
{
val p = Promise[String]()
p.tryCompleteWith(Promise[String]().failure(new RuntimeException("br0ken")).future)
intercept[RuntimeException] {
Await.result(p.future, defaultTimeout)
}.getMessage mustBe ("br0ken")
}
{
val p = Promise[String]()
p.tryCompleteWith(Promise[String]().failure(new RuntimeException("br0ken")).future)
intercept[RuntimeException] {
Await.result(p.future, defaultTimeout)
}.getMessage mustBe ("br0ken")
}
}
}

"A successful Promise" should {
val result = "test value"
val promise = Promise[String]().complete(Success(result))
promise.isCompleted mustBe (true)
futureWithResult(_(promise.future, result))
"be completed" in {
val result = "test value"
val promise = Promise[String]().complete(Success(result))
promise.isCompleted mustBe (true)
futureWithResult(_(promise.future, result))
}

"not be completable with a completed Promise" in {
{
val p = Promise.successful("bar")
p.tryCompleteWith(Promise[String]().success("foo").future)
Await.result(p.future, defaultTimeout) mustBe ("bar")
}
{
val p = Promise.successful("bar")
p.completeWith(Promise[String]().success("foo").future)
Await.result(p.future, defaultTimeout) mustBe ("bar")
}
}
}

"A failed Promise" should {
val message = "Expected Exception"
val promise = Promise[String]().complete(Failure(new RuntimeException(message)))
promise.isCompleted mustBe (true)
futureWithException[RuntimeException](_(promise.future, message))
"be completed" in {
val message = "Expected Exception"
val promise = Promise[String]().complete(Failure(new RuntimeException(message)))
promise.isCompleted mustBe (true)
futureWithException[RuntimeException](_(promise.future, message))
}
"not be completable with a completed Promise" in {
{
val p = Promise[String]().failure(new RuntimeException("unbr0ken"))
p.tryCompleteWith(Promise[String].failure(new Exception("br0ken")).future)
intercept[RuntimeException] {
Await.result(p.future, defaultTimeout)
}.getMessage mustBe ("unbr0ken")
}
{
val p = Promise[String]().failure(new RuntimeException("unbr0ken"))
p.completeWith(Promise[String]().failure(new Exception("br0ken")).future)
intercept[RuntimeException] {
Await.result(p.future, defaultTimeout)
}.getMessage mustBe ("unbr0ken")
}
}
}

"An interrupted Promise" should {
Expand Down
1 change: 1 addition & 0 deletions test/files/jvm/t8689.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
success
13 changes: 13 additions & 0 deletions test/files/jvm/t8689.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
object Test {
def main(args: Array[String]): Unit = {
import scala.concurrent._
import ExecutionContext.Implicits.global
val source1 = Promise[Int]()
val source2 = Promise[Int]()
source2.completeWith(source1.future).future.onComplete {
case _ => print("success")
}
source2.tryFailure(new TimeoutException)
source1.success(123)
}
}