diff --git a/execution.bs b/execution.bs index 3515da1..b8ca442 100644 --- a/execution.bs +++ b/execution.bs @@ -5521,7 +5521,9 @@ template<class C> sender with a receiver that has an environment of type `Env`. The type of the receiver does not affect an asychronous operation's completion signatures, only the type of the receiver's - environment. + environment. A sender type whose completion signatures are knowable + independent of an execution environment is known as a non-dependent sender. 14. A sender algorithm is a function that takes and/or returns a sender. There are three categories of sender algorithms: @@ -5641,7 +5643,7 @@ namespace std::execution { template<class Sndr> concept sender = see below; - template<class Sndr, class Env = empty_env> + template<class Sndr, class... Env> concept sender_in = see below; template<class Sndr, class Rcvr> @@ -5660,9 +5662,9 @@ namespace std::execution { struct get_completion_signatures_t; inline constexpr get_completion_signatures_t get_completion_signatures {}; - template<class Sndr, class Env = empty_env> - requires sender_in<Sndr, Env> - using completion_signatures_of_t = call-result-t<get_completion_signatures_t, Sndr, Env>; + template<class Sndr, class... Env> + requires sender_in<Sndr, Env...> + using completion_signatures_of_t = call-result-t<get_completion_signatures_t, Sndr, Env...>; template<class... Ts> using decayed-tuple = tuple<decay_t<Ts>...>; // exposition only @@ -6762,12 +6764,13 @@ namespace std::execution { move_constructible<remove_cvref_t<Sndr>> && // rvalues are movable, and constructible_from<remove_cvref_t<Sndr>, Sndr>; // lvalues are copyable - template<class Sndr, class Env = empty_env> + template<class Sndr, class... Env> concept sender_in = sender<Sndr> && - queryable<Env> && - requires (Sndr&& sndr, Env&& env) { - { get_completion_signatures(std::forward<Sndr>(sndr), std::forward<Env>(env)) } + (sizeof...(Env) <= 1) + (queryable<Env> &&...) && + requires (Sndr&& sndr, Env&&... env) { + { get_completion_signatures(std::forward<Sndr>(sndr), std::forward<Env>(env)...) } -> valid-completion-signatures; }; @@ -6871,8 +6874,13 @@ namespace std::execution { is an lvalue referring to the coroutine's promise type, `Promise`. This includes the invocation of the promise type's `await_transform` member if any, the invocation of the `operator co_await` - picked by overload resolution if any, and any necessary implicit - conversions and materializations. + picked by overload resolution if any, and any necessary implicit conversions + and materializations. Let GET-AWAITER(c) be + expression-equivalent to GET-AWAITER(c, q) where `q` is + an lvalue of an unspecified empty class type `none-such` that lacks + an `await_transform` member, and where + coroutine_handle<none-such> behaves as + `coroutine_handle`. I have opened [cwg#250](https://github.com/cplusplus/CWG/issues/250) to give these @@ -6886,18 +6894,18 @@ namespace std::execution { template<class T> concept await-suspend-result = see below; - template<class A, class Promise> + template<class A, class... Promise> concept is-awaiter = // exposition only - requires (A& a, coroutine_handle<Promise> h) { + requires (A& a, coroutine_handle<Promise...> h) { a.await_ready() ? 1 : 0; { a.await_suspend(h) } -> await-suspend-result; a.await_resume(); }; - template<class C, class Promise> + template<class C, class... Promise> concept is-awaitable = - requires (C (*fc)() noexcept, Promise& p) { - { GET-AWAITER(fc(), p) } -> is-awaiter<Promise>; + requires (C (*fc)() noexcept, Promise&... p) { + { GET-AWAITER(fc(), p...) } -> is-awaiter<Promise...>; }; } @@ -6911,7 +6919,9 @@ namespace std::execution { 4. For a subexpression `c` such that `decltype((c))` is type `C`, and an lvalue `p` of type `Promise`, await-result-type<C, Promise> - denotes the type decltype(GET-AWAITER(c, p).await_resume()). + denotes the type decltype(GET-AWAITER(c, p).await_resume()), + and await-result-type<C> denotes the type + decltype(GET-AWAITER(c).await_resume()). 5. Let `with-await-transform` be the exposition-only class template: @@ -7098,30 +7108,64 @@ namespace std::execution { ### `execution::get_completion_signatures` [exec.getcomplsigs] ### {#spec-execution.getcomplsigs} -1. `get_completion_signatures` is a customization point object. Let `sndr` be an - expression such that `decltype((sndr))` is `Sndr`, and let `env` be an - expression such that `decltype((env))` is `Env`. Then - `get_completion_signatures(sndr, env)` is expression-equivalent to: +1. `get_completion_signatures` is a customization point object. For a + subexpression `sndr`, let `Sndr` be `decltype((sndr))`. Then + `get_completion_signatures(sndr)` is expression-equivalent to: - 1. `decltype(sndr.get_completion_signatures(env)){}` if that - expression is well-formed, + 1. `remove_cvref_t::completion_signatures()` if that expression is + well-formed, - 2. Otherwise, `remove_cvref_t::completion_signatures{}` if that expression is well-formed, + 2. Otherwise, `decltype(sndr.get_completion_signatures())()` if that + expression is well-formed, - 3. Otherwise, if is-awaitable<Sndr, env-promise<Env>> + 3. Otherwise, if is-awaitable<Sndr> is `true`, then: -
-            completion_signatures<
-              SET-VALUE-SIG(await-result-type<Sndr,
-                            env-promise<Env>>), // see [exec.snd.concepts]
-              set_error_t(exception_ptr),
-              set_stopped_t()>{}
-            
+
+        completion_signatures<
+          SET-VALUE-SIG(await-result-type<Sndr>), // see [exec.snd.concepts]
+          set_error_t(exception_ptr),
+          set_stopped_t()>()
+        
+ + 4. Otherwise, `get_completion_signatures(sndr)` is ill-formed. + +2. For a subexpression `env`, let `Env` be `decltype((env))`. Then + `get_completion_signatures(sndr, env)` is expression-equivalent to: + + 1. `remove_cvref_t::completion_signatures()` if that expression is + well-formed, + + 2. Otherwise, `decltype(sndr.get_completion_signatures(env))()` if that + expression is well-formed, + + 3. Otherwise, if is-awaitable<Sndr, + env-promise<Env>> is `true`, then: + +
+        completion_signatures<
+          SET-VALUE-SIG(await-result-type<Sndr,
+                        env-promise<Env>>), // see [exec.snd.concepts]
+          set_error_t(exception_ptr),
+          set_stopped_t()>()
+        
4. Otherwise, `get_completion_signatures(sndr, env)` is ill-formed. -2. Let `rcvr` be an rvalue receiver of type `Rcvr`, and let `Sndr` be the type of a +3. If `get_completion_signatures(sndr)` is well-formed and its type denotes a + specialization of the `completion_signatures` class template, then `Sndr` is + a non-dependent sender type ([async.ops]). + +4. Given a pack of subexpressions `se`, the expression + `get_completion_signatures(se...)` is ill-formed if `sizeof...(se)` is less + than `1` or greater than `2`. + +5. If `completion_signatures_of_t` and `completion_signatures_of_t` are both well-formed, they shall denote the same set of completion + signatures, disregarding the order of signatures and rvalue reference + qualification of arguments. + +6. Let `rcvr` be an rvalue receiver of type `Rcvr`, and let `Sndr` be the type of a sender such that `sender_in>` is `true`. Let `Sigs...` be the template arguments of the `completion_signatures` specialization named by `completion_signatures_of_t>`. Let `CSO` be @@ -7157,7 +7201,7 @@ namespace std::execution { [[noreturn]] void return_void() noexcept { terminate(); } coroutine_handle<> unhandled_stopped() noexcept { - set_stopped((DR&&) rcvr); + set_stopped(std::move(rcvr)); return noop_coroutine(); } @@ -7376,6 +7420,10 @@ namespace std::execution { `exception_ptr` argument, the implementation is allowed to omit the `exception_ptr` error completion signature from the set. +7. Unless otherwise specified, an adaptor whose child senders are all + non-dependent ([async.ops]) is itself non-dependent. This requirement applies + to any function that is selected by the implementation of the sender adaptor. + #### Sender adaptor closure objects [exec.adapt.objects] #### {#spec-execution.senders.adaptor.objects} 1. A pipeable sender adaptor closure object is a function object that @@ -7722,13 +7770,22 @@ namespace std::execution { of the invocable as a value completion. 2. The names `then`, `upon_error`, and `upon_stopped` denote customization point - objects. Let the expression `then-cpo` be one of `then`, - `upon_error`, or `upon_stopped`. For subexpressions `sndr` and `f`, let `Sndr` be - `decltype((sndr))` and let `F` be the decayed type of `f`. If `Sndr` does not - satisfy `sender`, or `F` does not satisfy `movable-value`, + objects. For `then`, `upon_error`, and `upon_stopped`, let `set-cpo` + be `set_value`, `set_error`, and `set_stopped` respectively. Let the + expression `then-cpo` be one of `then`, `upon_error`, or + `upon_stopped`. For subexpressions `sndr` and `f`, let `Sndr` be + `decltype((sndr))` and let `F` be the decayed type of `f`. If `Sndr` does + not satisfy `sender`, or `F` does not satisfy `movable-value`, then-cpo(sndr, f) is ill-formed. -3. Otherwise, the expression then-cpo(sndr, f) is +3. Let `invoke-result` be an alias template such that + invoke-result<Ts...> denotes the type + `invoke_result_t`. If `sender_in` is `true` and + gather-signatures<tag_t<set-cpo>, + completion_signatures_of_t<Sndr>, invoke-result, + type-list> is ill-formed, the program is ill-formed. + +4. Otherwise, the expression then-cpo(sndr, f) is expression-equivalent to:
@@ -7737,10 +7794,8 @@ namespace std::execution {
           make-sender(then-cpo, f, sndr));
         
-4. For `then`, `upon_error`, and `upon_stopped`, let `set-cpo` - be `set_value`, `set_error`, and `set_stopped` respectively. The - exposition-only class template `impls-for` - ([exec.snd.general]) is specialized for `then-cpo` as follows: +5. The exposition-only class template `impls-for` ([exec.snd.general]) is + specialized for `then-cpo` as follows:
         namespace std::execution {
@@ -7806,9 +7861,15 @@ namespace std::execution {
         make-sender(let-cpo, f, sndr));
       
-5. The exposition-only class template `impls-for` - ([exec.snd.general]) is specialized for `let-cpo` as - follows: +5. Let `invoke-result` be an alias template such that + invoke-result<Ts...> denotes the type + `invoke_result_t`. If `sender_in` is `true` and + gather-signatures<tag_t<set-cpo>, + completion_signatures_of_t<Sndr>, invoke-result, + type-list> is ill-formed, the program is ill-formed. + +6. The exposition-only class template `impls-for` ([exec.snd.general]) is + specialized for `let-cpo` as follows:
         namespace std::execution {
@@ -7917,7 +7978,7 @@ namespace std::execution {
     env) is ill-formed. Otherwise, it is equal to
     JOIN-ENV(let-env(sndr), FWD-ENV(env)).
 
-7. Let the subexpression `out_sndr` denote the result of the invocation
+8. Let the subexpression `out_sndr` denote the result of the invocation
     let-cpo(sndr, f) or an object copied or moved from such,
     and let the subexpression `rcvr` denote a receiver such that the expression
     `connect(out_sndr, rcvr)` is well-formed. The expression `connect(out_sndr,
@@ -7952,8 +8013,15 @@ namespace std::execution {
           make-sender(bulk, product-type{shape, f}, sndr));
         
-4. The exposition-only class template `impls-for` - ([exec.snd.general]) is specialized for `bulk_t` as follows: +4. Let `invoke-result` be an alias template such that + invoke-result<Ts...> denotes the type + `invoke_result_t`. If `sender_in` is `true` and + gather-signatures<tag_t<set-cpo>, + completion_signatures_of_t<Sndr>, invoke-result, + type-list> is ill-formed, the program is ill-formed. + +5. The exposition-only class template `impls-for` ([exec.snd.general]) is + specialized for `bulk_t` as follows:
         namespace std::execution {
@@ -7989,7 +8057,7 @@ namespace std::execution {
               `true` if and only if `Tag` denotes a type other than `set_value_t`
               or if the expression `f(auto(shape), args...)` is well-formed.
 
-5. Let the subexpression `out_sndr` denote the result of the invocation
+6. Let the subexpression `out_sndr` denote the result of the invocation
     bulk(sndr, shape, f) or an object copied or moved from such,
     and let the subexpression `rcvr` denote a receiver such that the expression
     `connect(out_sndr, rcvr)` is well-formed. The expression `connect(out_sndr,