Skip to content

Commit e2dfe3a

Browse files
committed
Add example of withUnsafeContinuation lowering to SIL
1 parent 29587ac commit e2dfe3a

File tree

1 file changed

+45
-5
lines changed

1 file changed

+45
-5
lines changed

docs/SIL.rst

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,8 @@ tasks, and can have explicit *suspend points* where they suspend execution.
640640
otherwise can be invoked with the normal ``apply`` and ``try_apply``
641641
instructions (or ``begin_apply`` if they are coroutines).
642642

643-
``@async`` functions may express primitive suspend points by using the
643+
In Swift, the ``withUnsafeContinuation`` primitive is used to implement
644+
primitive suspend points. In SIL, ``@async`` functions represent this abstraction
644645
``begin_async_continuation[_addr]`` and ``await_async_continuation``
645646
instructions. ``begin_async_continuation[_addr]`` creates a *continuation*
646647
value that can be used to resume the coroutine when it suspends, feeding a
@@ -649,10 +650,49 @@ error when it resumes. The resulting continuation value can then be passed
649650
into a completion handler, registered with an event loop, or scheduled by
650651
some other mechanism. The ``await_async_continuation`` instruction suspends
651652
execution of the coroutine until the continuation is invoked to resume it.
652-
All continuation values must be used to resume the async coroutine exactly
653-
once. It is undefined behavior to attempt to resume the same continuation
654-
more than once. Failing to resume a continuation will leave the coroutine
655-
stuck in the suspended state, leaking any memory or other resources it owns.
653+
A use of ``withUnsafeContinuation`` in Swift::
654+
655+
func waitForCallback() async -> Int {
656+
return await withUnsafeContinuation { cc in
657+
registerCallback { cc.resume($0) }
658+
}
659+
}
660+
661+
might lower to the following SIL::
662+
663+
sil @waitForCallback : $@convention(thin) @async () -> Int {
664+
entry:
665+
%cc = begin_async_continuation $Int
666+
%closure = function_ref @waitForCallback_closure
667+
: $@convention(thin) (UnsafeContinuation<Int>) -> ()
668+
apply %closure(%cc)
669+
await_async_continuation %cc, resume resume_cc
670+
671+
resume_cc(%result : $Int):
672+
return %result
673+
}
674+
675+
The closure may then be inlined into the ``waitForCallback`` function::
676+
677+
sil @waitForCallback : $@convention(thin) @async () -> Int {
678+
entry:
679+
%cc = begin_async_continuation $Int
680+
%registerCallback = function_ref @registerCallback
681+
: $@convention(thin) (@convention(thick) () -> ()) -> ()
682+
%callback_fn = function_ref @waitForCallback_callback
683+
%callback = partial_apply %callback_fn(%cc)
684+
apply %registerCallback(%callback)
685+
await_async_continuation %cc, resume resume_cc
686+
687+
resume_cc(%result : $Int):
688+
return %result
689+
}
690+
691+
Every continuation value must be used exactly once to resume its associated
692+
async coroutine once. It is undefined behavior to attempt to resume the same
693+
continuation more than once. On the flip side, failing to resume a continuation
694+
will leave the async task stuck in the suspended state, leaking any memory or
695+
other resources it owns.
656696

657697
Coroutine Types
658698
```````````````

0 commit comments

Comments
 (0)