From f7adc8e6018298c3bcd01f91cc3bbccd9410c8f3 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 23 May 2015 15:31:26 +0100 Subject: [PATCH] Rewrote try transformation in asyncdispatch slightly. This seems to be awakening a compiler bug though. --- lib/pure/asyncdispatch.nim | 76 ++++++++++++++++++++------------------ tests/async/tasynctry.nim | 14 +++++++ 2 files changed, 54 insertions(+), 36 deletions(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 8010e9ebc..a2193aa8a 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1216,6 +1216,7 @@ proc generateExceptionCheck(futSym, if tryStmt.kind == nnkNilLit: result = rootReceiver else: + # Create an if statement checking the type of the current exception var exceptionChecks: seq[tuple[cond, body: NimNode]] = @[] let errorNode = newDotExpr(futSym, newIdentNode("error")) for i in 1 .. -> else: raise futSym.error + # This branch is entered when there are not 'except' branches + # specific to the exception. exceptionChecks.add((newIdentNode("true"), newNimNode(nnkRaiseStmt).add(errorNode))) # Read the future if there is no error. @@ -1257,6 +1260,7 @@ proc generateExceptionCheck(futSym, (newDotExpr(futSym, newIdentNode("failed")), ifBody) ) result.add elseNode + echo(treeRepr(result)) template createVar(result: var NimNode, futSymName: string, asyncProc: NimNode, @@ -1336,53 +1340,53 @@ proc processBody(node, retFutureSym: NimNode, of nnkTryStmt: # try: await x; except: ... result = newNimNode(nnkStmtList, node) - template wrapInTry(n, tryBody: expr) = - var temp = n + template wrapInTry(n, tryBody: expr, copyN: bool) = + var temp = if copyN: n.copy else: n n[0] = tryBody tryBody = temp # Transform ``except`` body. # TODO: Could we perform some ``await`` transformation here to get it # working in ``except``? - tryBody[1] = processBody(n[1], retFutureSym, subTypeIsVoid, nil) + #tryBody[1] = processBody(n[1], retFutureSym, subTypeIsVoid, nil) - proc processForTry(n: NimNode, i: var int, - res: NimNode): bool {.compileTime.} = + + proc processForTry(child: NimNode, origNode: NimNode, + ): tuple[res: NimNode, transformed: bool] {.compileTime, nimcall.} + proc processNodes(n: NimNode): NimNode {.compileTime, nimcall.} = + result = newStmtList() + #echo(treeRepr(n)) + var nodes = n.skipStmtList() + for child in nodes.children: + var (res, transformed) = processForTry(child, n) + if not transformed: + # If this line of code hasn't been transformed, we need to wrap + # it in a try statement. + #wrapInTry(node, res, false) + discard + result.add res + + proc processForTry(child: NimNode, origNode: NimNode, + ): tuple[res: NimNode, transformed: bool] = ## Transforms the body of the tryStmt. Does not transform the ## body in ``except``. ## Returns true if the tryStmt node was transformed into an ifStmt. - result = false - var skipped = n.skipStmtList() - while i < skipped.len: - var processed = processBody(skipped[i], retFutureSym, - subTypeIsVoid, n) + var processed: NimNode # = processBody(child, retFutureSym, + # subTypeIsVoid, origNode) + # Check if we transformed the node into an exception check. + # This suggests skipped[i] contains ``await``. + if processed.kind != child.kind or processed.len != child.len: + processed = processed.skipUntilStmtList() + expectKind(processed, nnkStmtList) + expectKind(processed[2][1], nnkElse) - # Check if we transformed the node into an exception check. - # This suggests skipped[i] contains ``await``. - if processed.kind != skipped[i].kind or processed.len != skipped[i].len: - processed = processed.skipUntilStmtList() - expectKind(processed, nnkStmtList) - expectKind(processed[2][1], nnkElse) - i.inc + processed[2][1][0] = processNodes(processed[2][1][0]) - if not processForTry(n, i, processed[2][1][0]): - # We need to wrap the nnkElse nodes back into a tryStmt. - # As they are executed if an exception does not happen - # inside the awaited future. - # The following code will wrap the nodes inside the - # original tryStmt. - wrapInTry(n, processed[2][1][0]) + result = (processed, true) + else: + result = (child, false) - res.add processed - result = true - else: - res.add skipped[i] - i.inc - var i = 0 - if not processForTry(node, i, result): - # If the tryStmt hasn't been transformed we can just put the body - # back into it. - wrapInTry(node, result) + result = processNodes(node) return else: discard @@ -1492,8 +1496,8 @@ macro async*(prc: stmt): stmt {.immediate.} = result[6] = outerProcBody #echo(treeRepr(result)) - #if prc[0].getName == "test": - # echo(toStrLit(result)) + if prc[0].getName == "catch": + echo(toStrLit(result)) proc recvLine*(socket: TAsyncFD): Future[string] {.async.} = ## Reads a line of data from ``socket``. Returned future will complete once diff --git a/tests/async/tasynctry.nim b/tests/async/tasynctry.nim index f77198e2e..5fe5d7921 100644 --- a/tests/async/tasynctry.nim +++ b/tests/async/tasynctry.nim @@ -17,6 +17,9 @@ proc foobar() {.async.} = if 5 == 5: raise newException(EInvalidIndex, "Test") +proc raiseExc() = + raise newException(EInvalidIndex, "Test") + proc catch() {.async.} = # TODO: Create a test for when exceptions are not caught. try: @@ -91,6 +94,14 @@ proc test4(): Future[int] {.async.} = except: result = 2 +proc test2650(): Future[int] {.async.} = + # Test for bug #2650. https://github.com/Araq/Nim/issues/2650 + try: + raiseExc() + discard await foo() + except: + result = 5 + var x = test() assert x.read @@ -102,3 +113,6 @@ assert y.read == 2 y = test4() assert y.read == 2 + +y = test2650() +assert y.read == 5