Skip to content

Commit 4592abd

Browse files
committed
results.? compatibity
This PR uses the facilities provided in status-im/nim-stew#134 to support `?` in `async` proc's.
1 parent 2c7774d commit 4592abd

File tree

3 files changed

+43
-3
lines changed

3 files changed

+43
-3
lines changed

chronos.nimble

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ license = "MIT or Apache License 2.0"
88
skipDirs = @["tests"]
99

1010
requires "nim >= 1.2.0",
11-
"stew",
11+
"stew#assign-result",
1212
"bearssl",
1313
"httputils",
1414
"unittest2"

chronos/asyncmacro2.nim

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
# distribution, for details about the copyright.
88
#
99

10-
import std/[macros]
10+
import
11+
std/[macros]
1112

1213
proc skipUntilStmtList(node: NimNode): NimNode {.compileTime.} =
1314
# Skips a nest of StmtList's.
@@ -131,6 +132,13 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
131132
cast[`internalFutureType`](`internalFutureSym`)
132133
procBody = prc.body.processBody(castFutureSym, baseTypeIsVoid)
133134

135+
# Support `let x = ? await ...`
136+
assignResultSym = ident "assignResult?"
137+
assignResult = quote do:
138+
when declared(Result):
139+
template `assignResultSym`(v: Result) =
140+
`castFutureSym`.complete(v)
141+
134142
# don't do anything with forward bodies (empty)
135143
if procBody.kind != nnkEmpty:
136144
# fix #13899, `defer` should not escape its original scope
@@ -143,11 +151,12 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
143151
template result: auto {.used.} =
144152
{.fatal: "You should not reference the `result` variable inside" &
145153
" a void async proc".}
154+
146155
# -> complete(chronosInternalRetFuture)
147156
let complete =
148157
newCall(newIdentNode("complete"), castFutureSym)
149158

150-
newStmtList(resultTemplate, procBodyBlck, complete)
159+
newStmtList(resultTemplate, assignResult, procBodyBlck, complete)
151160
else:
152161
# -> iterator nameIter(chronosInternalRetFuture: Future[T]): FutureBase {.closure.} =
153162
# -> {.push warning[resultshadowed]: off.}
@@ -170,6 +179,8 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
170179
newNimNode(nnkPragma).add(
171180
newIdentNode("pop")),
172181

182+
assignResult,
183+
173184
procBodyBlck,
174185

175186
# -> complete(chronosInternalRetFuture, result)

tests/testmacro.nim

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,20 @@ proc testAwaitne(): Future[bool] {.async.} =
9494

9595
return true
9696

97+
proc resultOk(): Future[Result[int, string]] {.async.} =
98+
return ok(42)
99+
100+
proc resultErr(): Future[Result[int, string]] {.async.} =
101+
return err("string")
102+
103+
proc testResult: Future[Result[int, string]] {.async.} =
104+
let
105+
x = ? await resultOk()
106+
107+
if x == 42:
108+
let _ = ? await resultErr()
109+
return err("not this one")
110+
97111
suite "Macro transformations test suite":
98112
test "`await` command test":
99113
check waitFor(testAwait()) == true
@@ -156,3 +170,18 @@ suite "Closure iterator's exception transformation issues":
156170

157171
waitFor(x())
158172

173+
suite "Result integration":
174+
test "question mark":
175+
# generics are tricky and buggy, test them more!
176+
proc someFunc2[T](v: T): Future[Result[T, string]] {.async.} =
177+
return ok(v)
178+
proc someFunc[T](v: T): Future[Result[T, string]] {.async.} =
179+
let tmp = ? await someFunc2(v)
180+
return ok(tmp + 2)
181+
182+
proc caller(v: int): Future[Result[int, string]] {.async.} =
183+
return ok(3 + ? await someFunc(v))
184+
185+
check waitFor(testResult()).error() == "string"
186+
187+
check waitFor(caller(42))[] == 42 + 2 + 3

0 commit comments

Comments
 (0)