diff --git a/chronos/asyncmacro2.nim b/chronos/asyncmacro2.nim index 04fda6a..0d3e634 100644 --- a/chronos/asyncmacro2.nim +++ b/chronos/asyncmacro2.nim @@ -72,6 +72,20 @@ proc verifyReturnType(typeName: string) {.compileTime.} = macro unsupported(s: static[string]): untyped = error s +proc cleanupOpenSymChoice(node: NimNode): NimNode {.compileTime.} = + # Replace every Call -> OpenSymChoice by a Bracket expr + # ref https://github.com/nim-lang/Nim/issues/11091 + if node.kind in nnkCallKinds and + node[0].kind == nnkOpenSymChoice and node[0].eqIdent("[]"): + result = newNimNode(nnkBracketExpr).add( + cleanupOpenSymChoice(node[1]), + cleanupOpenSymChoice(node[2]) + ) + else: + result = node.copyNimNode() + for child in node: + result.add(cleanupOpenSymChoice(child)) + proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = ## This macro transforms a single procedure into a closure iterator. ## The ``async`` macro supports a stmtList holding multiple async procedures. @@ -81,17 +95,13 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = let prcName = prc.name.getName - let returnType = prc.params[0] + let returnType = cleanupOpenSymChoice(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 in nnkCallKinds and returnType[0].eqIdent("[]"): - let fut = repr(returnType[1]) - verifyReturnType(fut) - baseType = returnType[2] elif returnType.kind == nnkEmpty: baseType = returnType else: diff --git a/tests/testmacro.nim b/tests/testmacro.nim index c18b37e..fadda82 100644 --- a/tests/testmacro.nim +++ b/tests/testmacro.nim @@ -6,6 +6,7 @@ # Apache License, version 2.0, (LICENSE-APACHEv2) # MIT license (LICENSE-MIT) import unittest2 +import macros import ../chronos when defined(nimHasUsed): {.used.} @@ -80,3 +81,19 @@ suite "Macro transformations test suite": check waitFor(testAwait()) == true test "`awaitne` command test": check waitFor(testAwaitne()) == true + + + test "template async macro transformation": + template templatedAsync(name, restype: untyped): untyped = + proc name(): Future[restype] {.async.} = return @[4] + + templatedAsync(testTemplate, seq[int]) + check waitFor(testTemplate()) == @[4] + + macro macroAsync(name, restype, innerrestype: untyped): untyped = + quote do: + proc `name`(): Future[`restype`[`innerrestype`]] {.async.} = return + + type OpenObject = object + macroAsync(testMacro, seq, OpenObject) + check waitFor(testMacro()).len == 0