Async macro fixes (#5739)

This commit is contained in:
Yuriy Glukhov 2017-05-16 23:09:19 +03:00 • committed by Andreas Rumpf
commit 6599cae281
3 changed files with 30 additions and 20 deletions

View file

@ -982,6 +982,9 @@ proc semProcAnnotation(c: PContext, prc: PNode;
var x = newNodeI(nkCall, n.info) var x = newNodeI(nkCall, n.info)
x.add(newSymNode(m)) x.add(newSymNode(m))
prc.sons[pragmasPos] = copyExcept(n, i) prc.sons[pragmasPos] = copyExcept(n, i)
if prc[pragmasPos].kind != nkEmpty and prc[pragmasPos].len == 0:
prc.sons[pragmasPos] = emptyNode
if it.kind == nkExprColonExpr: if it.kind == nkExprColonExpr:
# pass pragma argument to the macro too: # pass pragma argument to the macro too:
x.add(it.sons[1]) x.add(it.sons[1])

View file

@ -305,9 +305,10 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
error("Cannot transform this node kind into an async proc." & error("Cannot transform this node kind into an async proc." &
" proc/method definition or lambda node expected.") " proc/method definition or lambda node expected.")
hint("Processing " & prc[0].getName & " as an async proc.") let prcName = prc.name.getName
hint("Processing " & prcName & " as an async proc.")
let returnType = prc[3][0] let returnType = prc.params[0]
var baseType: NimNode var baseType: NimNode
# Verify that the return type is a Future[T] # Verify that the return type is a Future[T]
if returnType.kind == nnkBracketExpr: if returnType.kind == nnkBracketExpr:
@ -326,9 +327,9 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
let subtypeIsVoid = returnType.kind == nnkEmpty or let subtypeIsVoid = returnType.kind == nnkEmpty or
(baseType.kind == nnkIdent and returnType[1].ident == !"void") (baseType.kind == nnkIdent and returnType[1].ident == !"void")
let futureVarIdents = getFutureVarIdents(prc[3]) let futureVarIdents = getFutureVarIdents(prc.params)
var outerProcBody = newNimNode(nnkStmtList, prc[6]) var outerProcBody = newNimNode(nnkStmtList, prc.body)
# -> var retFuture = newFuture[T]() # -> var retFuture = newFuture[T]()
var retFutureSym = genSym(nskVar, "retFuture") var retFutureSym = genSym(nskVar, "retFuture")
@ -338,10 +339,10 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
outerProcBody.add( outerProcBody.add(
newVarStmt(retFutureSym, newVarStmt(retFutureSym,
newCall( newCall(
newNimNode(nnkBracketExpr, prc[6]).add( newNimNode(nnkBracketExpr, prc.body).add(
newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`. newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
subRetType), subRetType),
newLit(prc[0].getName)))) # Get type from return type of this proc newLit(prcName)))) # Get type from return type of this proc
# -> iterator nameIter(): FutureBase {.closure.} = # -> iterator nameIter(): FutureBase {.closure.} =
# -> {.push warning[resultshadowed]: off.} # -> {.push warning[resultshadowed]: off.}
@ -349,8 +350,8 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
# -> {.pop.} # -> {.pop.}
# -> <proc_body> # -> <proc_body>
# -> complete(retFuture, result) # -> complete(retFuture, result)
var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter") var iteratorNameSym = genSym(nskIterator, $prcName & "Iter")
var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid, var procBody = prc.body.processBody(retFutureSym, subtypeIsVoid,
futureVarIdents, nil) futureVarIdents, nil)
# don't do anything with forward bodies (empty) # don't do anything with forward bodies (empty)
if procBody.kind != nnkEmpty: if procBody.kind != nnkEmpty:
@ -362,7 +363,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
newIdentNode("warning"), newIdentNode("resultshadowed")), newIdentNode("warning"), newIdentNode("resultshadowed")),
newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.} newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.}
procBody.insert(1, newNimNode(nnkVarSection, prc[6]).add( procBody.insert(1, newNimNode(nnkVarSection, prc.body).add(
newIdentDefs(newIdentNode("result"), baseType))) # -> var result: T newIdentDefs(newIdentNode("result"), baseType))) # -> var result: T
procBody.insert(2, newNimNode(nnkPragma).add( procBody.insert(2, newNimNode(nnkPragma).add(
@ -377,35 +378,32 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")], var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
procBody, nnkIteratorDef) procBody, nnkIteratorDef)
closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure")) closureIterator.pragma = copyNimTree(prc.pragma)
closureIterator.addPragma(newIdentNode("closure"))
closureIterator.addPragma(newIdentNode("gcsafe"))
outerProcBody.add(closureIterator) outerProcBody.add(closureIterator)
# -> createCb(retFuture) # -> createCb(retFuture)
#var cbName = newIdentNode("cb") #var cbName = newIdentNode("cb")
var procCb = getAst createCb(retFutureSym, iteratorNameSym, var procCb = getAst createCb(retFutureSym, iteratorNameSym,
newStrLitNode(prc[0].getName), newStrLitNode(prcName),
createFutureVarCompletions(futureVarIdents, nil)) createFutureVarCompletions(futureVarIdents, nil))
outerProcBody.add procCb outerProcBody.add procCb
# -> return retFuture # -> return retFuture
outerProcBody.add newNimNode(nnkReturnStmt, prc[6][prc[6].len-1]).add(retFutureSym) outerProcBody.add newNimNode(nnkReturnStmt, prc.body[^1]).add(retFutureSym)
result = prc result = prc
# Remove the 'async' pragma.
for i in 0 .. <result[4].len:
if result[4][i].kind == nnkIdent and result[4][i].ident == !"async":
result[4].del(i)
result[4] = newEmptyNode()
if subtypeIsVoid: if subtypeIsVoid:
# Add discardable pragma. # Add discardable pragma.
if returnType.kind == nnkEmpty: if returnType.kind == nnkEmpty:
# Add Future[void] # Add Future[void]
result[3][0] = parseExpr("Future[void]") result.params[0] = parseExpr("Future[void]")
if procBody.kind != nnkEmpty: if procBody.kind != nnkEmpty:
result[6] = outerProcBody result.body = outerProcBody
#echo(treeRepr(result)) #echo(treeRepr(result))
#if prc[0].getName == "recvLineInto": #if prcName == "recvLineInto":
# echo(toStrLit(result)) # echo(toStrLit(result))
macro async*(prc: untyped): untyped = macro async*(prc: untyped): untyped =

View file

@ -7,3 +7,12 @@ proc foo {.async.}
proc foo {.async.} = proc foo {.async.} =
discard discard
# With additional pragmas:
proc bar {.async, cdecl.}
proc bar {.async.} =
discard
proc verifyCdeclPresent(p: proc : Future[void] {.cdecl.}) = discard
verifyCdeclPresent(bar)