Fix `async` `proc` types & small cleanups (#347)

* Fix `async` `proc` types & small cleanups

* review comments
This commit is contained in:
Tanguy 2023-01-19 07:52:11 +01:00 committed by GitHub
parent 4ada7fc0e1
commit f3b77d8661
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 26 additions and 17 deletions

View File

@ -72,6 +72,13 @@ proc verifyReturnType(typeName: string) {.compileTime.} =
macro unsupported(s: static[string]): untyped = macro unsupported(s: static[string]): untyped =
error s error s
proc params2(someProc: NimNode): NimNode =
# until https://github.com/nim-lang/Nim/pull/19563 is available
if someProc.kind == nnkProcTy:
someProc[0]
else:
params(someProc)
proc cleanupOpenSymChoice(node: NimNode): NimNode {.compileTime.} = proc cleanupOpenSymChoice(node: NimNode): NimNode {.compileTime.} =
# Replace every Call -> OpenSymChoice by a Bracket expr # Replace every Call -> OpenSymChoice by a Bracket expr
# ref https://github.com/nim-lang/Nim/issues/11091 # ref https://github.com/nim-lang/Nim/issues/11091
@ -92,21 +99,20 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
error("Cannot transform " & $prc.kind & " into an async proc." & error("Cannot transform " & $prc.kind & " into an async proc." &
" proc/method definition or lambda node expected.") " proc/method definition or lambda node expected.")
let returnType = let returnType = cleanupOpenSymChoice(prc.params2[0])
cleanupOpenSymChoice(if prc.kind == nnkProcTy: prc[0][0] else: prc.params[0])
var baseType: NimNode
# Verify that the return type is a Future[T]
if returnType.kind == nnkBracketExpr:
let fut = repr(returnType[0])
verifyReturnType(fut)
baseType = returnType[1]
elif returnType.kind == nnkEmpty:
baseType = returnType
else:
verifyReturnType(repr(returnType))
let subtypeIsVoid = returnType.kind == nnkEmpty or # Verify that the return type is a Future[T]
(baseType.kind == nnkIdent and returnType[1].eqIdent("void")) let baseType =
if returnType.kind == nnkBracketExpr:
let fut = repr(returnType[0])
verifyReturnType(fut)
returnType[1]
elif returnType.kind == nnkEmpty:
ident("void")
else:
raiseAssert("Unhandled async return type: " & $prc.kind)
let subtypeIsVoid = baseType.eqIdent("void")
if prc.kind in {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}: if prc.kind in {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}:
let let
@ -260,13 +266,12 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
# Add discardable pragma. # Add discardable pragma.
if returnType.kind == nnkEmpty: if returnType.kind == nnkEmpty:
# Add Future[void] # Add Future[void]
prc.params[0] = prc.params2[0] =
newNimNode(nnkBracketExpr, prc) newNimNode(nnkBracketExpr, prc)
.add(newIdentNode("Future")) .add(newIdentNode("Future"))
.add(newIdentNode("void")) .add(newIdentNode("void"))
prc prc
#echo(treeRepr(result))
template await*[T](f: Future[T]): untyped = template await*[T](f: Future[T]): untyped =
when declared(chronosInternalRetFuture): when declared(chronosInternalRetFuture):
@ -318,8 +323,8 @@ macro async*(prc: untyped): untyped =
## Macro which processes async procedures into the appropriate ## Macro which processes async procedures into the appropriate
## iterators and yield statements. ## iterators and yield statements.
if prc.kind == nnkStmtList: if prc.kind == nnkStmtList:
result = newStmtList()
for oneProc in prc: for oneProc in prc:
result = newStmtList()
result.add asyncSingleProc(oneProc) result.add asyncSingleProc(oneProc)
else: else:
result = asyncSingleProc(prc) result = asyncSingleProc(prc)

View File

@ -13,6 +13,7 @@ when defined(nimHasUsed): {.used.}
type type
RetValueType = proc(n: int): Future[int] {.async.} RetValueType = proc(n: int): Future[int] {.async.}
RetImplicitVoidType = proc(n: int) {.async.}
RetVoidType = proc(n: int): Future[void] {.async.} RetVoidType = proc(n: int): Future[void] {.async.}
proc asyncRetValue(n: int): Future[int] {.async.} = proc asyncRetValue(n: int): Future[int] {.async.} =
@ -59,6 +60,9 @@ proc testAwait(): Future[bool] {.async.} =
block: block:
let fn: RetVoidType = asyncRetVoid let fn: RetVoidType = asyncRetVoid
await fn(100) await fn(100)
block:
let fn: RetImplicitVoidType = asyncRetVoid
await fn(100)
block: block:
let fn: RetValueType = asyncRetValue let fn: RetValueType = asyncRetValue
if (await fn(100)) != 1000: if (await fn(100)) != 1000: