diff --git a/README.md b/README.md index b57c6e02..97a9b395 100644 --- a/README.md +++ b/README.md @@ -412,10 +412,6 @@ yet demonstrates different exploits of `cps`. See [this list of open Nim issues surfaced by CPS development](https://github.com/nim-lang/Nim/issues?q=is%3Aopen+is%3Aissue+label%3ACPS); some repercussions include the following: -- You can overload `cpsVoodoo` procedures with `cpsVoodoo`, and `cpsMagic` - with `cpsMagic`, but other overloads run the risk of clashing with the - shim produced by these procedure macros. - - Exceptions are evaluated differently under `panics:on` and `panics:off`, so you may need to use `panics:on` in order to produce correct code. diff --git a/cps/spec.nim b/cps/spec.nim index e4d989bb..8f3c695c 100644 --- a/cps/spec.nim +++ b/cps/spec.nim @@ -363,18 +363,7 @@ type Dismissed ## The continuation is currently somewhere else Finished ## The continuation is finished and can no longer be resumed -proc wrapErrorShim(n: NimNode): NimNode = - ## Wrap a proc definition in a guard to avoid symbol redefinition errors. - expectKind(n, nnkProcDef) - # when not declaredInScope(fn): - result = - nnkWhenStmt.newTree: - nnkElifBranch.newTree: - prefix(newCall(bindSym"declaredInScope", n.name), "not") - # proc fn() = error "you can only do this in cps" - result.last.add n - -proc makeErrorShim(n: NimNode): NimNode = +proc makeErrorShim*(n: NimNode): NimNode = ## Upgrades a procedure to serve as a CPS primitive, generating ## errors out of `.cps.` context and taking continuations as input. expectKind(n, nnkProcDef) @@ -383,7 +372,6 @@ proc makeErrorShim(n: NimNode): NimNode = # value. While this version will throw an exception at runtime, it # may be used inside CPS as magic(); for better programmer ergonomics. var shim = copyNimTree n - shim.addPragma ident"used" del(shim.params, 1) # delete the 1st Continuation argument let msg = newLit($n.name & "() is only valid in {.cps.} context") shim.body = # raise a defect when invoked directly @@ -401,12 +389,8 @@ macro cpsMagic*(n: untyped): untyped = ## The target procedure of a cpsMagic pragma returns the `Continuation` ## to which control-flow should return; this is _usually_ the same value ## passed into the procedure, but this is not required nor is it checked! - ## - ## You can overload `cpsVoodoo` procedures with `cpsVoodoo`, and `cpsMagic` - ## with `cpsMagic`, but you cannot mix the two. expectKind(n, nnkProcDef) - let n = copyNimTree n - n.addPragma ident"used" + result = newStmtList NormNode n # preserve the original proc var shim = makeErrorShim n # create the shim shim.params[0] = newEmptyNode() # wipe out the return value @@ -415,25 +399,19 @@ macro cpsMagic*(n: untyped): untyped = # continuation. shim.addPragma ident"cpsMustJump" shim.addPragma ident"cpsMagicCall" - shim = wrapErrorShim shim # `when not declaredInScope(fn): shim` - result = newStmtList(shim, n) # preserve the original proc + result.add shim macro cpsVoodoo*(n: untyped): untyped = ## Similar to a `cpsMagic` where the first argument is concerned, but ## may specify a return value which is usable inside the CPS procedure. - ## - ## You can overload `cpsVoodoo` procedures with `cpsVoodoo`, and `cpsMagic` - ## with `cpsMagic`, but you cannot mix the two. expectKind(n, nnkProcDef) - let n = copyNimTree n - n.addPragma ident"used" + result = newStmtList n # preserve the original proc var shim = makeErrorShim n # create the shim # we use this pragma to identify the primitive and rewrite it inside # CPS so that it again binds to the version that takes a continuation. shim.addPragma ident"cpsVoodooCall" - shim = wrapErrorShim shim # `when not declaredInScope(fn): shim` - result = newStmtList(shim, n) # preserve the original proc + result.add shim when cpsTraceDeque or cpsStackFrames: from std/strformat import `&` diff --git a/cps/transform.nim b/cps/transform.nim index 6312c71e..41485487 100644 --- a/cps/transform.nim +++ b/cps/transform.nim @@ -1077,21 +1077,19 @@ macro cpsHandleUnhandledException(contType: typed; n: typed): untyped = # Rewrite continuations within this continuation body as well fnDef.body = fnDef.body.filter(handle) # Put the body in a try-except to capture the unhandled exception - fnDef.body = - genAstOpt({}, contType, cont = NimNode cont, - unwind = ident"unwind", # just a desym of the unwind() - body = NimNode fnDef.body): - bind getCurrentException - try: - body - except: - cont.ex = getCurrentException() - # A continuation body created with makeContProc (which is all of - # them) will have a terminator in the body, thus this part can - # only be reached iff the except branch happened to deter the jump - # - # Workaround for https://github.com/nim-lang/Nim/issues/18411 - return Continuation unwind(contType(cont), cont.ex) + fnDef.body = genAstOpt({}, contType, cont = NimNode cont, + body = NimNode fnDef.body): + bind getCurrentException + try: + body + except: + cont.ex = getCurrentException() + # A continuation body created with makeContProc (which is all of + # them) will have a terminator in the body, thus this part can + # only be reached iff the except branch happened to deter the jump + # + # Workaround for https://github.com/nim-lang/Nim/issues/18411 + return Continuation: unwind(contType(cont), cont.ex) result = fnDef debugAnnotation cpsHandleUnhandledException, n: diff --git a/tests/tapi.nim b/tests/tapi.nim index cf443ae1..fac12a14 100644 --- a/tests/tapi.nim +++ b/tests/tapi.nim @@ -210,14 +210,3 @@ suite "cps api": return 3 check foo() == 3 - - block: - ## magic/voodoo can be overloaded - type - C = ref object of Continuation - O = ref object of C - - proc sayYourNameV(c: C): string {.cpsVoodoo.} = return "I am C" - proc sayYourNameV(c: O): string {.cpsVoodoo.} = return "I am O" - proc sayYourNameM(c: C): C {.cpsMagic.} = discard "I am C" - proc sayYourNameM(c: O): O {.cpsMagic.} = discard "I am O" diff --git a/tests/thooks.nim b/tests/thooks.nim index 593e1da8..ba24d19a 100644 --- a/tests/thooks.nim +++ b/tests/thooks.nim @@ -256,7 +256,7 @@ suite "hooks": block: ## custom continuation exception handling works var k = newKiller 4 - proc unwind(c: Cont; ex: ref Exception): Continuation {.cpsMagic.} = + proc unwind(c: Cont; ex: ref Exception): Continuation {.cpsMagic, used.} = inc k result = cps.unwind(c, ex)