Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

async raises of #327

Draft
wants to merge 37 commits into
base: master
Choose a base branch
from
Draft

async raises of #327

wants to merge 37 commits into from

Conversation

Menduist
Copy link
Contributor

@Menduist Menduist commented Nov 8, 2022

Note: this PR targets #251

While working on #298, I quickly realized that we need such a system, for instance for wait:

proc wait*[T](fut: Future[T], timeout = InfiniteDuration): Future[T] {.asyncraisesof: [fut].}

This PR adds the possibility to do "async raises of" (similar to "effectsOf"):

    proc test44 {.asyncraises: [ValueError], async.} = discard
    proc testOther {.asyncraises: [IOError], async.} = discard

    proc wrapper1(fut: Future[void]) {.asyncraises: [CancelledError], async, asyncraisesof: [fut].} =
      await fut

    proc test55 {.asyncraises: [ValueError, CancelledError], async.} =
      await wrapper1(test44())
    waitFor(test55())

    checkNotCompiles:
      proc wrapper2(fut: Future[void]) {.asyncraises: [CancelledError], async, asyncraisesof: [fut].} =
        await testOther()
      waitFor wrapper2(test44())

(this also works with "manual async", see tests)

This is a bit complex, but essentially relies on two things:


wrapper1 will become a generic taking the error types as generic parameters:

proc wrapper1[Err1_469768925](fut: RaiseTrackingFuture[void, Err1_469768925]): auto {.
    stackTrace: off, raises: [], gcsafe.} =

The return type will then be rewritten using a typed macro (that will have the generic types instantiated):

  result = RaiseTrackingFuture[void,
                               combineAsyncExceptions(CancelledError, Err1)](nil)

(note that instead of auto & result =, a typed macro could directly rewrite the return type, but did this here for simplicity)

This will give the correct return type to the procedure once instantiated.


For .async. procedures, a second type macro will make sure that the iterator can only raise the correct exceptions:

  asyncinternalraises(iterator wrapper1_469768926(
      chronosInternalRetFuture: Future[void]): FutureBase {.closure, gcsafe,
      gcsafe.} =
        [...]
          , [CancelledError, Err1])

At instantiation, will rewrite to:

iterator wrapper1_469769166(chronosInternalRetFuture: Future[void]): FutureBase {.
    closure, gcsafe, gcsafe, raises: [CancelledError, ValueError].} =

I'm not very happy with the code ATM hence the draft, but it works in basic cases at least

Base automatically changed from raisetracking to master October 17, 2023 12:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant