diff --git a/chronos.nimble b/chronos.nimble index 6b4ac58a8..14293c744 100644 --- a/chronos.nimble +++ b/chronos.nimble @@ -8,7 +8,7 @@ license = "MIT or Apache License 2.0" skipDirs = @["tests"] requires "nim >= 1.2.0", - "stew", + "stew#assign-result", "bearssl", "httputils", "unittest2" diff --git a/chronos/asyncmacro2.nim b/chronos/asyncmacro2.nim index a7fc3ba72..36fd0b80e 100644 --- a/chronos/asyncmacro2.nim +++ b/chronos/asyncmacro2.nim @@ -156,6 +156,13 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = procBody = prc.body.processBody(castFutureSym, baseType) + # Support `let x = ? await ...` + assignResultSym = ident "assignResult?" + assignResult = quote do: + when declared(Result): + template `assignResultSym`(v: Result) = + `castFutureSym`.complete(v) + # don't do anything with forward bodies (empty) if procBody.kind != nnkEmpty: let @@ -185,7 +192,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = completeDecl = completeWithNode(castFutureSym, baseType, procBodyBlck) - closureBody = newStmtList(resultDecl, completeDecl) + closureBody = newStmtList(assignResult, resultDecl, completeDecl) internalFutureParameter = nnkIdentDefs.newTree( internalFutureSym, newIdentNode("FutureBase"), newEmptyNode()) diff --git a/tests/testmacro.nim b/tests/testmacro.nim index 2526c5dea..b4e0fa9d7 100644 --- a/tests/testmacro.nim +++ b/tests/testmacro.nim @@ -94,6 +94,20 @@ proc testAwaitne(): Future[bool] {.async.} = return true +proc resultOk(): Future[Result[int, string]] {.async.} = + return ok(42) + +proc resultErr(): Future[Result[int, string]] {.async.} = + return err("string") + +proc testResult: Future[Result[int, string]] {.async.} = + let + x = ? await resultOk() + + if x == 42: + let _ = ? await resultErr() + return err("not this one") + suite "Macro transformations test suite": test "`await` command test": check waitFor(testAwait()) == true @@ -226,3 +240,18 @@ suite "Closure iterator's exception transformation issues": waitFor(x()) +suite "Result integration": + test "question mark": + # generics are tricky and buggy, test them more! + proc someFunc2[T](v: T): Future[Result[T, string]] {.async.} = + return ok(v) + proc someFunc[T](v: T): Future[Result[T, string]] {.async.} = + let tmp = ? await someFunc2(v) + return ok(tmp + 2) + + proc caller(v: int): Future[Result[int, string]] {.async.} = + return ok(3 + ? await someFunc(v)) + + check waitFor(testResult()).error() == "string" + + check waitFor(caller(42))[] == 42 + 2 + 3