@@ -640,7 +640,8 @@ tasks, and can have explicit *suspend points* where they suspend execution.
640640otherwise can be invoked with the normal ``apply `` and ``try_apply ``
641641instructions (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 ``
645646instructions. ``begin_async_continuation[_addr] `` creates a *continuation *
646647value 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
649650into a completion handler, registered with an event loop, or scheduled by
650651some other mechanism. The ``await_async_continuation `` instruction suspends
651652execution 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
657697Coroutine Types
658698```````````````
0 commit comments