Skip to content

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