summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorMiran <narimiran@disroot.org>2018-11-09 23:45:17 +0100
committerDominik Picheta <dominikpicheta@googlemail.com>2018-11-09 22:45:17 +0000
commit964b5dac7cbfe04a8d015fe9d6c1020143bc51d2 (patch)
treeaa11f5b2339b37233111cb77ac6f9caf31623ca3
parent8d850f7a69d473360c5b1a9db9fd998ab9b5dff4 (diff)
downloadNim-964b5dac7cbfe04a8d015fe9d6c1020143bc51d2.tar.gz
complete future only once in `or` (fixes #8982) (#9632)
* complete future only once in `or`

Analogous to `and`.
Credits to @k0zmo for proposing the solution.

* add test
-rw-r--r--lib/pure/asyncfutures.nim5
-rw-r--r--tests/async/t8982.nim33
2 files changed, 36 insertions, 2 deletions
diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim
index aa8314632..5037c8a24 100644
--- a/lib/pure/asyncfutures.nim
+++ b/lib/pure/asyncfutures.nim
@@ -375,8 +375,9 @@ proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =
   ## complete.
   var retFuture = newFuture[void]("asyncdispatch.`or`")
   proc cb[X](fut: Future[X]) =
-    if fut.failed: retFuture.fail(fut.error)
-    if not retFuture.finished: retFuture.complete()
+    if not retFuture.finished:
+      if fut.failed: retFuture.fail(fut.error)
+      else: retFuture.complete()
   fut1.callback = cb[T]
   fut2.callback = cb[Y]
   return retFuture
diff --git a/tests/async/t8982.nim b/tests/async/t8982.nim
new file mode 100644
index 000000000..5face7edf
--- /dev/null
+++ b/tests/async/t8982.nim
@@ -0,0 +1,33 @@
+discard """
+output: '''
+timeout
+runForever should throw ValueError, this is expected
+'''
+"""
+
+
+import asyncdispatch
+
+proc failingAwaitable(p: int) {.async.} =
+  await sleepAsync(500)
+  if p > 0:
+    raise newException(Exception, "my exception")
+
+proc main() {.async.} =
+  let fut = failingAwaitable(1)
+  try:
+    await fut or sleepAsync(100)
+    if fut.finished:
+      echo "finished"
+    else:
+      echo "timeout"
+  except:
+    echo "failed"
+
+
+# Previously this would raise "An attempt was made to complete a Future more than once."
+try:
+  asyncCheck main()
+  runForever()
+except ValueError:
+  echo "runForever should throw ValueError, this is expected"