Skip to content

Commit 29587ac

Browse files
committed
Revise with feedback from John and Andy
1 parent 57215cb commit 29587ac

File tree

1 file changed

+73
-90
lines changed

1 file changed

+73
-90
lines changed

docs/SIL.rst

Lines changed: 73 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -631,98 +631,80 @@ autorelease in the callee.
631631
type behaves like a non-generic type, as if the substitutions were
632632
actually applied to the underlying function type.
633633

634+
Async Functions
635+
```````````````
636+
637+
SIL function types may be ``@async``. ``@async`` functions run inside async
638+
tasks, and can have explicit *suspend points* where they suspend execution.
639+
``@async`` functions can only be called from other ``@async`` functions, but
640+
otherwise can be invoked with the normal ``apply`` and ``try_apply``
641+
instructions (or ``begin_apply`` if they are coroutines).
642+
643+
``@async`` functions may express primitive suspend points by using the
644+
``begin_async_continuation[_addr]`` and ``await_async_continuation``
645+
instructions. ``begin_async_continuation[_addr]`` creates a *continuation*
646+
value that can be used to resume the coroutine when it suspends, feeding a
647+
value back into the currently-running function or causing it to fail with an
648+
error when it resumes. The resulting continuation value can then be passed
649+
into a completion handler, registered with an event loop, or scheduled by
650+
some other mechanism. The ``await_async_continuation`` instruction suspends
651+
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.
656+
634657
Coroutine Types
635658
```````````````
636659

637660
A coroutine is a function which can suspend itself and return control to
638661
its caller without terminating the function. That is, it does not need to
639-
obey a strict stack discipline. Different kinds of coroutines in SIL have
640-
different representations, reflecting the different capabilities and
641-
structural constraints of different language-level features:
642-
643-
Yielding Coroutines
644-
...................
645-
646-
Some kinds of coroutine have control flow that is tightly integrated with
647-
their callers, and pass information back and forth between caller and callee
648-
in a structured way. *Generalized accessors* and generators in Swift fit this
649-
description: a ``read`` or ``modify`` accessor coroutine projects a single
650-
value, yields ownership of that one value temporarily to the caller, and then
651-
takes ownership back when resumed, allowing the coroutine to clean up resources
652-
or otherwise react to mutations done by the caller. *Generators* similarly
653-
yield a stream of values one at a time to their caller, temporarily yielding
654-
ownership of each value in turn to the caller. The tight coupling of the
655-
caller's control flow with these coroutines allows the caller to *borrow*
656-
values produced by the coroutine, where a normal function return would need to
657-
transfer ownership of its return value, since a normal function's context
658-
ceases to exist and be able to maintain ownership of the value after it
659-
returns.
660-
661-
To support these concepts, SIL supports two kinds of *yielding coroutine*:
662+
obey a strict stack discipline. SIL coroutines have control flow that is
663+
tightly integrated with their callers, and they pass information back and forth
664+
between caller and callee in a structured way through yield points.
665+
*Generalized accessors* and *generators* in Swift fit this description: a
666+
``read`` or ``modify`` accessor coroutine projects a single value, yields
667+
ownership of that one value temporarily to the caller, and then takes ownership
668+
back when resumed, allowing the coroutine to clean up resources or otherwise
669+
react to mutations done by the caller. *Generators* similarly yield a stream of
670+
values one at a time to their caller, temporarily yielding ownership of each
671+
value in turn to the caller. The tight coupling of the caller's control flow
672+
with these coroutines allows the caller to *borrow* values produced by the
673+
coroutine, where a normal function return would need to transfer ownership of
674+
its return value, since a normal function's context ceases to exist and be able
675+
to maintain ownership of the value after it returns.
676+
677+
To support these concepts, SIL supports two kinds of coroutine:
662678
``@yield_many`` and ``@yield_once``. Either of these attributes may be
663-
written before a function type to indicate that it is a yielding coroutine type.
679+
written before a function type to indicate that it is a coroutine type.
680+
``@yield_many`` and ``@yield_once`` coroutines are allowed to also be
681+
``@async``. (Note that ``@async`` functions are not themselves modeled
682+
explicitly as coroutines in SIL, although the implementation may use a coroutine
683+
lowering strategy.)
664684

665-
A yielding coroutine type may declare any number of *yielded values*, which is to
685+
A coroutine type may declare any number of *yielded values*, which is to
666686
say, values which are provided to the caller at a yield point. Yielded
667687
values are written in the result list of a function type, prefixed by
668688
the ``@yields`` attribute. A yielded value may have a convention attribute,
669689
taken from the set of parameter attributes and interpreted as if the yield
670690
site were calling back to the calling function.
671691

672-
Currently, a yielding coroutine may not have normal results.
692+
Currently, a coroutine may not have normal results.
673693

674-
Yielding coroutine functions may be used in many of the same ways as normal
694+
Coroutine functions may be used in many of the same ways as normal
675695
function values. However, they cannot be called with the standard
676696
``apply`` or ``try_apply`` instructions. A non-throwing yield-once
677697
coroutine can be called with the ``begin_apply`` instruction. There
678698
is no support yet for calling a throwing yield-once coroutine or for
679699
calling a yield-many coroutine of any kind.
680700

681-
Yielding coroutines may contain the special ``yield`` and ``unwind``
701+
Coroutines may contain the special ``yield`` and ``unwind``
682702
instructions.
683703

684704
A ``@yield_many`` coroutine may yield as many times as it desires.
685705
A ``@yield_once`` coroutine may yield exactly once before returning,
686706
although it may also ``throw`` before reaching that point.
687707

688-
Async Coroutines
689-
................
690-
691-
``async`` coroutines are quite different from yielding coroutines.
692-
Async coroutines are almost like threads in that they
693-
have largely independent execution contexts, and do not generally directly
694-
transfer values between each other without going through synchronization
695-
abstractions. Unlike ``@yield_once`` or ``@yield_many`` coroutine functions, an
696-
individual async function does not represent an entire coroutine unto itself,
697-
but is an individual unit of code that may run inside an async coroutine.
698-
Unlike preemptive threads, async functions have explicit *suspend points* where
699-
they allow their coroutine's execution to be suspended so that a different
700-
coroutine may run.
701-
702-
In SIL, a function type has the ``@async`` attribute to
703-
indicate it may contain suspend points. Being ``@async`` is orthogonal to being
704-
a yielding coroutine--the ``@async`` attribute can be applied
705-
both to functions and to both kinds of yielding coroutine. ``@async`` functions
706-
can only be called from other ``@async`` functions, but otherwise can be
707-
invoked with the normal ``apply`` and ``try_apply`` instructions (or
708-
``begin_apply`` if they are yielding coroutines). An ``@async`` function may
709-
only use the special ``yield`` and ``unwind`` instructions if it is
710-
a yielding coroutine in addition to being async.
711-
712-
``@async`` functions may
713-
express primitive suspend points by using the ``begin_async_continuation[_addr]`` and
714-
``await_async_continuation`` instructions. ``begin_async_continuation[_addr]``
715-
creates a *continuation* value that can be used to resume the coroutine when it
716-
suspends, feeding a value back into the currently-running function or causing
717-
it to fail with an error when it resumes. The resulting continuation value can
718-
then be passed into a completion handler, registered with an event loop, or
719-
scheduled by some other mechanism. The ``await_continuation`` instruction
720-
suspends execution of the coroutine until the continuation is invoked to resume
721-
it. All continuation values must be used to resume the async coroutine exactly
722-
once. It is undefined behavior to attempt to resume the same continuation more
723-
than once. Failing to resume a continuation will leave the coroutine stuck in
724-
the suspended state, leaking any memory or other resources it owns.
725-
726708
Properties of Types
727709
```````````````````
728710

@@ -5992,7 +5974,7 @@ yield
59925974
sil-yield-values ::= '(' (sil-operand (',' sil-operand)*)? ')'
59935975

59945976
Temporarily suspends the current function and provides the given
5995-
values to the calling function. The current function must be a yielding coroutine,
5977+
values to the calling function. The current function must be a coroutine,
59965978
and the yield values must match the yield types of the coroutine.
59975979
If the calling function resumes the coroutine normally, control passes to
59985980
the ``resume`` destination. If the calling function aborts the coroutine,
@@ -6020,7 +6002,7 @@ unwind
60206002

60216003
Exits the current function and returns control to the calling function,
60226004
completing an unwind from a ``yield``. The current function must be a
6023-
yielding coroutine.
6005+
coroutine.
60246006

60256007
``unwind`` is only permitted in blocks reachable from the ``unwind`` edges
60266008
of ``yield`` instructions.
@@ -6367,7 +6349,7 @@ await_async_continuation
63676349
bb1(%1 : $T):
63686350
bb2(%2 : $Error):
63696351

6370-
Suspends execution of an ``@async`` function until the continuation operation
6352+
Suspends execution of an ``@async`` function until the continuation
63716353
is resumed. The continuation must be the result of a
63726354
``begin_async_continuation`` or ``begin_async_continuation_addr``
63736355
instruction within the same function; see the documentation for
@@ -6378,27 +6360,28 @@ instruction must always have a ``resume`` successor, but must have an
63786360
``error`` successor if and only if the operand is an
63796361
``UnsafeThrowingContinuation<T>``.
63806362

6381-
If the operand is the result of a
6382-
``begin_async_continuation`` instruction, then the ``resume`` successor block
6383-
must take an argument whose type is the maximally-abstracted lowered type
6384-
of ``T``, matching the type argument of the ``Unsafe[Throwing]Continuation<T>``
6385-
operand. The value of the ``resume`` argument is owned by the current
6386-
function. If the operand is the result of a ``begin_async_continuation_addr``
6387-
instruction, then the ``resume`` successor block must *not* take an argument;
6388-
the resume value will be written to the memory referenced by the operand to the
6389-
``begin_async_continuation_addr`` instruction, after which point the value in
6390-
that memory becomes owned by the current function. With either variant,
6391-
if the ``await_async_continuation`` instruction has an ``error`` successor block,
6392-
the ``error`` block must take a single ``Error`` argument, and that argument
6393-
is owned by the enclosing function. The memory referenced by a
6394-
``begin_async_continuation_addr`` instruction remains uninitialized when
6395-
``await_async_continuation`` resumes on the ``error`` successor.
6396-
6397-
It is possible for a continuation to be resumed before ``await_async_continuation``.
6398-
In this case, the resume operation returns immediately, and
6399-
``await_async_continuation`` immediately transfers control to its ``resume``
6400-
or ``error`` successor block, with the resume or error value that the
6401-
continuation was resumed with.
6363+
If the operand is the result of a ``begin_async_continuation`` instruction,
6364+
then the ``resume`` successor block must take an argument whose type is the
6365+
maximally-abstracted lowered type of ``T``, matching the type argument of the
6366+
``Unsafe[Throwing]Continuation<T>`` operand. The value of the ``resume``
6367+
argument is owned by the current function. If the operand is the result of a
6368+
``begin_async_continuation_addr`` instruction, then the ``resume`` successor
6369+
block must *not* take an argument; the resume value will be written to the
6370+
memory referenced by the operand to the ``begin_async_continuation_addr``
6371+
instruction, after which point the value in that memory becomes owned by the
6372+
current function. With either variant, if the ``await_async_continuation``
6373+
instruction has an ``error`` successor block, the ``error`` block must take a
6374+
single ``Error`` argument, and that argument is owned by the enclosing
6375+
function. The memory referenced by a ``begin_async_continuation_addr``
6376+
instruction remains uninitialized when ``await_async_continuation`` resumes on
6377+
the ``error`` successor.
6378+
6379+
It is possible for a continuation to be resumed before
6380+
``await_async_continuation``. In this case, the resume operation returns
6381+
immediately to its caller. When the ``await_async_continuation`` instruction
6382+
later executes, it then immediately transfers control to
6383+
its ``resume`` or ``error`` successor block, using the resume or error value
6384+
that the continuation was already resumed with.
64026385

64036386
Differentiable Programming
64046387
~~~~~~~~~~~~~~~~~~~~~~~~~~

0 commit comments

Comments
 (0)