15cee9157SPatrick Williams /*
25cee9157SPatrick Williams  * Copyright (c) 2021-2024 NVIDIA Corporation
35cee9157SPatrick Williams  *
45cee9157SPatrick Williams  * Licensed under the Apache License Version 2.0 with LLVM Exceptions
55cee9157SPatrick Williams  * (the "License"); you may not use this file except in compliance with
65cee9157SPatrick Williams  * the License. You may obtain a copy of the License at
75cee9157SPatrick Williams  *
85cee9157SPatrick Williams  *   https://llvm.org/LICENSE.txt
95cee9157SPatrick Williams  *
105cee9157SPatrick Williams  * Unless required by applicable law or agreed to in writing, software
115cee9157SPatrick Williams  * distributed under the License is distributed on an "AS IS" BASIS,
125cee9157SPatrick Williams  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135cee9157SPatrick Williams  * See the License for the specific language governing permissions and
145cee9157SPatrick Williams  * limitations under the License.
155cee9157SPatrick Williams  */
165cee9157SPatrick Williams #pragma once
175cee9157SPatrick Williams 
185cee9157SPatrick Williams #include "__execution_fwd.hpp"
195cee9157SPatrick Williams 
205cee9157SPatrick Williams // include these after __execution_fwd.hpp
215cee9157SPatrick Williams #include "__awaitable.hpp"
225cee9157SPatrick Williams #include "__completion_signatures.hpp"
235cee9157SPatrick Williams #include "__concepts.hpp"
245cee9157SPatrick Williams #include "__connect_awaitable.hpp"
255cee9157SPatrick Williams #include "__debug.hpp"
265cee9157SPatrick Williams #include "__env.hpp"
275cee9157SPatrick Williams #include "__operation_states.hpp"
285cee9157SPatrick Williams #include "__receivers.hpp"
295cee9157SPatrick Williams #include "__senders_core.hpp"
305cee9157SPatrick Williams #include "__transform_completion_signatures.hpp"
315cee9157SPatrick Williams #include "__transform_sender.hpp"
325cee9157SPatrick Williams #include "__type_traits.hpp"
335cee9157SPatrick Williams 
345cee9157SPatrick Williams namespace stdexec
355cee9157SPatrick Williams {
365cee9157SPatrick Williams /////////////////////////////////////////////////////////////////////////////
375cee9157SPatrick Williams // [execution.get_completion_signatures]
385cee9157SPatrick Williams namespace __detail
395cee9157SPatrick Williams {
405cee9157SPatrick Williams struct __dependent_completions
415cee9157SPatrick Williams {};
425cee9157SPatrick Williams 
435cee9157SPatrick Williams template <class _Completions>
445cee9157SPatrick Williams concept __well_formed_sender =
455cee9157SPatrick Williams     __valid_completion_signatures<_Completions> ||
465cee9157SPatrick Williams     __same_as<_Completions, _ERROR_<__dependent_completions>>;
475cee9157SPatrick Williams } // namespace __detail
485cee9157SPatrick Williams 
495cee9157SPatrick Williams using dependent_completions = _ERROR_<__detail::__dependent_completions>;
505cee9157SPatrick Williams 
515cee9157SPatrick Williams namespace __sigs
525cee9157SPatrick Williams {
535cee9157SPatrick Williams template <class _Sender, class _Env>
545cee9157SPatrick Williams using __tfx_sender =
555cee9157SPatrick Williams     transform_sender_result_t<__late_domain_of_t<_Sender, _Env>, _Sender, _Env>;
565cee9157SPatrick Williams 
575cee9157SPatrick Williams template <class _Sender, class... _Env>
585cee9157SPatrick Williams using __member_result_t =
595cee9157SPatrick Williams     decltype(__declval<_Sender>().get_completion_signatures(
605cee9157SPatrick Williams         __declval<_Env>()...));
615cee9157SPatrick Williams 
625cee9157SPatrick Williams template <class _Sender, class... _Env>
635cee9157SPatrick Williams using __static_member_result_t =               //
645cee9157SPatrick Williams     decltype(STDEXEC_REMOVE_REFERENCE(_Sender) //
655cee9157SPatrick Williams              ::get_completion_signatures(__declval<_Sender>(),
665cee9157SPatrick Williams                                          __declval<_Env>()...));
675cee9157SPatrick Williams 
685cee9157SPatrick Williams template <class _Sender, class... _Env>
695cee9157SPatrick Williams concept __with_member = __mvalid<__member_result_t, _Sender, _Env...>;
705cee9157SPatrick Williams 
715cee9157SPatrick Williams template <class _Sender, class... _Env>
725cee9157SPatrick Williams concept __with_static_member =
735cee9157SPatrick Williams     __mvalid<__static_member_result_t, _Sender, _Env...>;
745cee9157SPatrick Williams 
755cee9157SPatrick Williams template <class _Sender, class... _Env>
765cee9157SPatrick Williams concept __with_tag_invoke = //
775cee9157SPatrick Williams     tag_invocable<get_completion_signatures_t, _Sender, _Env...>;
785cee9157SPatrick Williams 
795cee9157SPatrick Williams template <class _Sender, class... _Env>
805cee9157SPatrick Williams concept __with_legacy_tag_invoke = //
815cee9157SPatrick Williams     (sizeof...(_Env) == 0) &&
825cee9157SPatrick Williams     tag_invocable<get_completion_signatures_t, _Sender, empty_env>;
835cee9157SPatrick Williams 
845cee9157SPatrick Williams template <class _Sender>
855cee9157SPatrick Williams using __member_alias_t = //
865cee9157SPatrick Williams     typename __decay_t<_Sender>::completion_signatures;
875cee9157SPatrick Williams 
885cee9157SPatrick Williams template <class _Sender>
895cee9157SPatrick Williams concept __with_member_alias = __mvalid<__member_alias_t, _Sender>;
905cee9157SPatrick Williams 
915cee9157SPatrick Williams struct get_completion_signatures_t
925cee9157SPatrick Williams {
935cee9157SPatrick Williams     template <class _Sender, class... _Env>
__implstdexec::__sigs::get_completion_signatures_t945cee9157SPatrick Williams     static auto __impl()
955cee9157SPatrick Williams     {
965cee9157SPatrick Williams         // Compute the type of the transformed sender:
975cee9157SPatrick Williams         using __tfx_fn =
985cee9157SPatrick Williams             __if_c<sizeof...(_Env) == 0, __mconst<_Sender>, __q<__tfx_sender>>;
995cee9157SPatrick Williams         using _TfxSender = __minvoke<__tfx_fn, _Sender, _Env...>;
1005cee9157SPatrick Williams 
1015cee9157SPatrick Williams         if constexpr (__merror<_TfxSender>)
1025cee9157SPatrick Williams         {
1035cee9157SPatrick Williams             // Computing the type of the transformed sender returned an error
1045cee9157SPatrick Williams             // type. Propagate it.
1055cee9157SPatrick Williams             return static_cast<_TfxSender (*)()>(nullptr);
1065cee9157SPatrick Williams         }
1075cee9157SPatrick Williams         else if constexpr (__with_member_alias<_TfxSender>)
1085cee9157SPatrick Williams         {
1095cee9157SPatrick Williams             using _Result = __member_alias_t<_TfxSender>;
1105cee9157SPatrick Williams             return static_cast<_Result (*)()>(nullptr);
1115cee9157SPatrick Williams         }
1125cee9157SPatrick Williams         else if constexpr (__with_static_member<_TfxSender, _Env...>)
1135cee9157SPatrick Williams         {
1145cee9157SPatrick Williams             using _Result = __static_member_result_t<_TfxSender, _Env...>;
1155cee9157SPatrick Williams             return static_cast<_Result (*)()>(nullptr);
1165cee9157SPatrick Williams         }
1175cee9157SPatrick Williams         else if constexpr (__with_member<_TfxSender, _Env...>)
1185cee9157SPatrick Williams         {
1195cee9157SPatrick Williams             using _Result = __member_result_t<_TfxSender, _Env...>;
1205cee9157SPatrick Williams             return static_cast<_Result (*)()>(nullptr);
1215cee9157SPatrick Williams         }
1225cee9157SPatrick Williams         else if constexpr (__with_tag_invoke<_TfxSender, _Env...>)
1235cee9157SPatrick Williams         {
1245cee9157SPatrick Williams             using _Result = tag_invoke_result_t<get_completion_signatures_t,
1255cee9157SPatrick Williams                                                 _TfxSender, _Env...>;
1265cee9157SPatrick Williams             return static_cast<_Result (*)()>(nullptr);
1275cee9157SPatrick Williams         }
1285cee9157SPatrick Williams         else if constexpr (__with_legacy_tag_invoke<_TfxSender, _Env...>)
1295cee9157SPatrick Williams         {
1305cee9157SPatrick Williams             // This branch is strictly for backwards compatibility
1315cee9157SPatrick Williams             using _Result = tag_invoke_result_t<get_completion_signatures_t,
1325cee9157SPatrick Williams                                                 _Sender, empty_env>;
1335cee9157SPatrick Williams             return static_cast<_Result (*)()>(nullptr);
1345cee9157SPatrick Williams             // [WAR] The explicit cast to bool below is to work around a bug in
1355cee9157SPatrick Williams             // nvc++ (nvbug#4707793)
1365cee9157SPatrick Williams         }
1375cee9157SPatrick Williams         else if constexpr (bool(__awaitable<_TfxSender,
1385cee9157SPatrick Williams                                             __env::__promise<_Env>...>))
1395cee9157SPatrick Williams         {
1405cee9157SPatrick Williams             using _AwaitResult =
1415cee9157SPatrick Williams                 __await_result_t<_TfxSender, __env::__promise<_Env>...>;
1425cee9157SPatrick Williams             using _Result = completion_signatures<
1435cee9157SPatrick Williams                 // set_value_t() or set_value_t(T)
1445cee9157SPatrick Williams                 __minvoke<__mremove<void, __qf<set_value_t>>, _AwaitResult>,
1455cee9157SPatrick Williams                 set_error_t(std::exception_ptr), set_stopped_t()>;
1465cee9157SPatrick Williams             return static_cast<_Result (*)()>(nullptr);
1475cee9157SPatrick Williams         }
1485cee9157SPatrick Williams         else if constexpr (sizeof...(_Env) == 0)
1495cee9157SPatrick Williams         {
1505cee9157SPatrick Williams             // It's possible this is a dependent sender.
1515cee9157SPatrick Williams             return static_cast<dependent_completions (*)()>(nullptr);
1525cee9157SPatrick Williams         }
1535cee9157SPatrick Williams         else if constexpr ((__is_debug_env<_Env> || ...))
1545cee9157SPatrick Williams         {
1555cee9157SPatrick Williams             using __tag_invoke::tag_invoke;
1565cee9157SPatrick Williams             // This ought to cause a hard error that indicates where the problem
1575cee9157SPatrick Williams             // is.
1585cee9157SPatrick Williams             using _Completions [[maybe_unused]] =
1595cee9157SPatrick Williams                 tag_invoke_result_t<get_completion_signatures_t, _Sender,
1605cee9157SPatrick Williams                                     _Env...>;
1615cee9157SPatrick Williams             return static_cast<__debug::__completion_signatures (*)()>(nullptr);
1625cee9157SPatrick Williams         }
1635cee9157SPatrick Williams         else
1645cee9157SPatrick Williams         {
1655cee9157SPatrick Williams             using _Result = __mexception<_UNRECOGNIZED_SENDER_TYPE_<>,
1665cee9157SPatrick Williams                                          _WITH_SENDER_<_Sender>,
1675cee9157SPatrick Williams                                          _WITH_ENVIRONMENT_<_Env>...>;
1685cee9157SPatrick Williams             return static_cast<_Result (*)()>(nullptr);
1695cee9157SPatrick Williams         }
1705cee9157SPatrick Williams     }
1715cee9157SPatrick Williams 
1725cee9157SPatrick Williams     // NOT TO SPEC: if we're unable to compute the completion signatures,
1735cee9157SPatrick Williams     // return an error type instead of SFINAE.
1745cee9157SPatrick Williams     template <class _Sender, class... _Env>
1755cee9157SPatrick Williams         requires(sizeof...(_Env) <= 1)
operator ()stdexec::__sigs::get_completion_signatures_t1765cee9157SPatrick Williams     constexpr auto operator()(_Sender&&, _Env&&...) const noexcept //
1775cee9157SPatrick Williams         -> decltype(__impl<_Sender, _Env...>()())
1785cee9157SPatrick Williams     {
1795cee9157SPatrick Williams         return {};
1805cee9157SPatrick Williams     }
1815cee9157SPatrick Williams };
1825cee9157SPatrick Williams } // namespace __sigs
1835cee9157SPatrick Williams 
1845cee9157SPatrick Williams using __sigs::get_completion_signatures_t;
1855cee9157SPatrick Williams inline constexpr get_completion_signatures_t get_completion_signatures{};
1865cee9157SPatrick Williams 
1875cee9157SPatrick Williams /////////////////////////////////////////////////////////////////////////////
1885cee9157SPatrick Williams // [execution.senders.connect]
1895cee9157SPatrick Williams namespace __connect
1905cee9157SPatrick Williams {
1915cee9157SPatrick Williams template <class _Sender, class _Receiver>
1925cee9157SPatrick Williams using __tfx_sender = //
1935cee9157SPatrick Williams     transform_sender_result_t<__late_domain_of_t<_Sender, env_of_t<_Receiver>>,
1945cee9157SPatrick Williams                               _Sender, env_of_t<_Receiver>>;
1955cee9157SPatrick Williams 
1965cee9157SPatrick Williams template <class _Sender, class _Receiver>
1975cee9157SPatrick Williams using __member_result_t =
1985cee9157SPatrick Williams     decltype(__declval<_Sender>().connect(__declval<_Receiver>()));
1995cee9157SPatrick Williams 
2005cee9157SPatrick Williams template <class _Sender, class _Receiver>
2015cee9157SPatrick Williams using __static_member_result_t =
2025cee9157SPatrick Williams     decltype(STDEXEC_REMOVE_REFERENCE(_Sender) //
2035cee9157SPatrick Williams              ::connect(__declval<_Sender>(), __declval<_Receiver>()));
2045cee9157SPatrick Williams 
2055cee9157SPatrick Williams template <class _Sender, class _Receiver>
2065cee9157SPatrick Williams concept __with_member = __mvalid<__member_result_t, _Sender, _Receiver>;
2075cee9157SPatrick Williams 
2085cee9157SPatrick Williams template <class _Sender, class _Receiver>
2095cee9157SPatrick Williams concept __with_static_member =
2105cee9157SPatrick Williams     __mvalid<__static_member_result_t, _Sender, _Receiver>;
2115cee9157SPatrick Williams 
2125cee9157SPatrick Williams template <class _Sender, class _Receiver>
2135cee9157SPatrick Williams concept __with_tag_invoke = tag_invocable<connect_t, _Sender, _Receiver>;
2145cee9157SPatrick Williams 
2155cee9157SPatrick Williams template <class _Sender, class _Receiver>
2165cee9157SPatrick Williams concept __with_co_await = __callable<__connect_awaitable_t, _Sender, _Receiver>;
2175cee9157SPatrick Williams 
2185cee9157SPatrick Williams struct connect_t
2195cee9157SPatrick Williams {
2205cee9157SPatrick Williams     template <class _Sender, class _Env>
__check_signaturesstdexec::__connect::connect_t2215cee9157SPatrick Williams     static constexpr auto __check_signatures() -> bool
2225cee9157SPatrick Williams     {
2235cee9157SPatrick Williams         if constexpr (sender_in<_Sender, _Env>)
2245cee9157SPatrick Williams         {
2255cee9157SPatrick Williams             // Instantiate __debug_sender via completion_signatures_of_t to
2265cee9157SPatrick Williams             // check that the actual completions match the expected completions.
2275cee9157SPatrick Williams             //
2285cee9157SPatrick Williams             // Instantiate completion_signatures_of_t only if sender_in is true
2295cee9157SPatrick Williams             // to workaround Clang not implementing CWG#2369 yet (connect() does
2305cee9157SPatrick Williams             // not have a constraint for _Sender satisfying sender_in).
2315cee9157SPatrick Williams             using __checked_signatures
2325cee9157SPatrick Williams                 [[maybe_unused]] = completion_signatures_of_t<_Sender, _Env>;
2335cee9157SPatrick Williams         }
2345cee9157SPatrick Williams         return true;
2355cee9157SPatrick Williams     }
2365cee9157SPatrick Williams 
2375cee9157SPatrick Williams     template <class _Sender, class _Receiver>
__select_implstdexec::__connect::connect_t2385cee9157SPatrick Williams     static constexpr auto __select_impl() noexcept
2395cee9157SPatrick Williams     {
2405cee9157SPatrick Williams         using _Domain = __late_domain_of_t<_Sender, env_of_t<_Receiver>>;
2415cee9157SPatrick Williams         using _TfxSender = __tfx_sender<_Sender, _Receiver>;
2425cee9157SPatrick Williams         constexpr bool _NothrowTfxSender =
2435cee9157SPatrick Williams             __nothrow_callable<transform_sender_t, _Domain, _Sender,
2445cee9157SPatrick Williams                                env_of_t<_Receiver>>;
2455cee9157SPatrick Williams 
2465cee9157SPatrick Williams #if STDEXEC_ENABLE_EXTRA_TYPE_CHECKING()
2475cee9157SPatrick Williams         static_assert(__check_signatures<_TfxSender, env_of_t<_Receiver>>());
2485cee9157SPatrick Williams #endif
2495cee9157SPatrick Williams 
2505cee9157SPatrick Williams         if constexpr (__with_static_member<_TfxSender, _Receiver>)
2515cee9157SPatrick Williams         {
2525cee9157SPatrick Williams             using _Result = __static_member_result_t<_TfxSender, _Receiver>;
2535cee9157SPatrick Williams             constexpr bool _Nothrow = //
254*06f265f6SPatrick Williams                 _NothrowTfxSender &&
255*06f265f6SPatrick Williams                 noexcept(__declval<_TfxSender>().connect(
2565cee9157SPatrick Williams                     __declval<_TfxSender>(), __declval<_Receiver>()));
2575cee9157SPatrick Williams             return static_cast<_Result (*)() noexcept(_Nothrow)>(nullptr);
2585cee9157SPatrick Williams         }
2595cee9157SPatrick Williams         else if constexpr (__with_member<_TfxSender, _Receiver>)
2605cee9157SPatrick Williams         {
2615cee9157SPatrick Williams             using _Result = __member_result_t<_TfxSender, _Receiver>;
2625cee9157SPatrick Williams             constexpr bool _Nothrow = //
263*06f265f6SPatrick Williams                 _NothrowTfxSender && noexcept(__declval<_TfxSender>().connect(
264*06f265f6SPatrick Williams                                          __declval<_Receiver>()));
2655cee9157SPatrick Williams             return static_cast<_Result (*)() noexcept(_Nothrow)>(nullptr);
2665cee9157SPatrick Williams         }
2675cee9157SPatrick Williams         else if constexpr (__with_tag_invoke<_TfxSender, _Receiver>)
2685cee9157SPatrick Williams         {
2695cee9157SPatrick Williams             using _Result =
2705cee9157SPatrick Williams                 tag_invoke_result_t<connect_t, _TfxSender, _Receiver>;
2715cee9157SPatrick Williams             constexpr bool _Nothrow = //
2725cee9157SPatrick Williams                 _NothrowTfxSender &&
2735cee9157SPatrick Williams                 nothrow_tag_invocable<connect_t, _TfxSender, _Receiver>;
2745cee9157SPatrick Williams             return static_cast<_Result (*)() noexcept(_Nothrow)>(nullptr);
2755cee9157SPatrick Williams         }
2765cee9157SPatrick Williams         else if constexpr (__with_co_await<_TfxSender, _Receiver>)
2775cee9157SPatrick Williams         {
2785cee9157SPatrick Williams             using _Result =
2795cee9157SPatrick Williams                 __call_result_t<__connect_awaitable_t, _TfxSender, _Receiver>;
2805cee9157SPatrick Williams             return static_cast<_Result (*)()>(nullptr);
2815cee9157SPatrick Williams         }
2825cee9157SPatrick Williams         else
2835cee9157SPatrick Williams         {
2845cee9157SPatrick Williams             using _Result = __debug::__debug_operation;
2855cee9157SPatrick Williams             return static_cast<_Result (*)() noexcept(_NothrowTfxSender)>(
2865cee9157SPatrick Williams                 nullptr);
2875cee9157SPatrick Williams         }
2885cee9157SPatrick Williams     }
2895cee9157SPatrick Williams 
2905cee9157SPatrick Williams     template <class _Sender, class _Receiver>
2915cee9157SPatrick Williams     using __select_impl_t = decltype(__select_impl<_Sender, _Receiver>());
2925cee9157SPatrick Williams 
2935cee9157SPatrick Williams     template <sender _Sender, receiver _Receiver>
2945cee9157SPatrick Williams         requires __with_static_member<__tfx_sender<_Sender, _Receiver>,
2955cee9157SPatrick Williams                                       _Receiver> ||
296*06f265f6SPatrick Williams                      __with_member<__tfx_sender<_Sender, _Receiver>,
297*06f265f6SPatrick Williams                                    _Receiver> ||
2985cee9157SPatrick Williams                      __with_tag_invoke<__tfx_sender<_Sender, _Receiver>,
2995cee9157SPatrick Williams                                        _Receiver> ||
300*06f265f6SPatrick Williams                      __with_co_await<__tfx_sender<_Sender, _Receiver>,
301*06f265f6SPatrick Williams                                      _Receiver> ||
3025cee9157SPatrick Williams                      __is_debug_env<env_of_t<_Receiver>>
3035cee9157SPatrick Williams     auto operator()(_Sender&& __sndr, _Receiver&& __rcvr) const
3045cee9157SPatrick Williams         noexcept(__nothrow_callable<__select_impl_t<_Sender, _Receiver>>)
3055cee9157SPatrick Williams             -> __call_result_t<__select_impl_t<_Sender, _Receiver>>
3065cee9157SPatrick Williams     {
3075cee9157SPatrick Williams         using _TfxSender = __tfx_sender<_Sender, _Receiver>;
3085cee9157SPatrick Williams         auto&& __env = get_env(__rcvr);
3095cee9157SPatrick Williams         auto __domain = __get_late_domain(__sndr, __env);
3105cee9157SPatrick Williams 
3115cee9157SPatrick Williams         if constexpr (__with_static_member<_TfxSender, _Receiver>)
3125cee9157SPatrick Williams         {
3135cee9157SPatrick Williams             static_assert(
3145cee9157SPatrick Williams                 operation_state<
3155cee9157SPatrick Williams                     __static_member_result_t<_TfxSender, _Receiver>>,
3165cee9157SPatrick Williams                 "Sender::connect(sender, receiver) must return a type that "
3175cee9157SPatrick Williams                 "satisfies the operation_state concept");
3185cee9157SPatrick Williams             auto&& __tfx_sndr = transform_sender(
3195cee9157SPatrick Williams                 __domain, static_cast<_Sender&&>(__sndr), __env);
3205cee9157SPatrick Williams             return __tfx_sndr.connect(static_cast<_TfxSender&&>(__tfx_sndr),
3215cee9157SPatrick Williams                                       static_cast<_Receiver&&>(__rcvr));
3225cee9157SPatrick Williams         }
3235cee9157SPatrick Williams         else if constexpr (__with_member<_TfxSender, _Receiver>)
3245cee9157SPatrick Williams         {
3255cee9157SPatrick Williams             static_assert(
3265cee9157SPatrick Williams                 operation_state<__member_result_t<_TfxSender, _Receiver>>,
3275cee9157SPatrick Williams                 "sender.connect(receiver) must return a type that "
3285cee9157SPatrick Williams                 "satisfies the operation_state concept");
3295cee9157SPatrick Williams             return transform_sender(__domain, static_cast<_Sender&&>(__sndr),
3305cee9157SPatrick Williams                                     __env)
3315cee9157SPatrick Williams                 .connect(static_cast<_Receiver&&>(__rcvr));
3325cee9157SPatrick Williams         }
3335cee9157SPatrick Williams         else if constexpr (__with_tag_invoke<_TfxSender, _Receiver>)
3345cee9157SPatrick Williams         {
3355cee9157SPatrick Williams             static_assert(
3365cee9157SPatrick Williams                 operation_state<
3375cee9157SPatrick Williams                     tag_invoke_result_t<connect_t, _TfxSender, _Receiver>>,
3385cee9157SPatrick Williams                 "stdexec::connect(sender, receiver) must return a type that "
3395cee9157SPatrick Williams                 "satisfies the operation_state concept");
340*06f265f6SPatrick Williams             return tag_invoke(
341*06f265f6SPatrick Williams                 connect_t(),
342*06f265f6SPatrick Williams                 transform_sender(__domain, static_cast<_Sender&&>(__sndr),
3435cee9157SPatrick Williams                                  __env),
3445cee9157SPatrick Williams                 static_cast<_Receiver&&>(__rcvr));
3455cee9157SPatrick Williams         }
3465cee9157SPatrick Williams         else if constexpr (__with_co_await<_TfxSender, _Receiver>)
3475cee9157SPatrick Williams         {
3485cee9157SPatrick Williams             return __connect_awaitable( //
3495cee9157SPatrick Williams                 transform_sender(__domain, static_cast<_Sender&&>(__sndr),
3505cee9157SPatrick Williams                                  __env),
3515cee9157SPatrick Williams                 static_cast<_Receiver&&>(__rcvr));
3525cee9157SPatrick Williams         }
3535cee9157SPatrick Williams         else
3545cee9157SPatrick Williams         {
3555cee9157SPatrick Williams             // This should generate an instantiation backtrace that contains
3565cee9157SPatrick Williams             // useful debugging information.
3575cee9157SPatrick Williams             using __tag_invoke::tag_invoke;
3585cee9157SPatrick Williams             tag_invoke(*this,
3595cee9157SPatrick Williams                        transform_sender(__domain,
3605cee9157SPatrick Williams                                         static_cast<_Sender&&>(__sndr), __env),
3615cee9157SPatrick Williams                        static_cast<_Receiver&&>(__rcvr));
3625cee9157SPatrick Williams         }
3635cee9157SPatrick Williams     }
3645cee9157SPatrick Williams 
querystdexec::__connect::connect_t3655cee9157SPatrick Williams     static constexpr auto query(forwarding_query_t) noexcept -> bool
3665cee9157SPatrick Williams     {
3675cee9157SPatrick Williams         return false;
3685cee9157SPatrick Williams     }
3695cee9157SPatrick Williams };
3705cee9157SPatrick Williams } // namespace __connect
3715cee9157SPatrick Williams 
3725cee9157SPatrick Williams using __connect::connect_t;
3735cee9157SPatrick Williams inline constexpr __connect::connect_t connect{};
3745cee9157SPatrick Williams 
3755cee9157SPatrick Williams /////////////////////////////////////////////////////////////////////////////
3765cee9157SPatrick Williams // [exec.snd]
3775cee9157SPatrick Williams template <class _Sender, class _Receiver>
3785cee9157SPatrick Williams concept sender_to =                            //
3795cee9157SPatrick Williams     receiver<_Receiver>                        //
3805cee9157SPatrick Williams     && sender_in<_Sender, env_of_t<_Receiver>> //
3815cee9157SPatrick Williams     && __receiver_from<_Receiver, _Sender>     //
3825cee9157SPatrick Williams     && requires(_Sender&& __sndr, _Receiver&& __rcvr) {
3835cee9157SPatrick Williams            connect(static_cast<_Sender&&>(__sndr),
3845cee9157SPatrick Williams                    static_cast<_Receiver&&>(__rcvr));
3855cee9157SPatrick Williams        };
3865cee9157SPatrick Williams 
3875cee9157SPatrick Williams template <class _Tag, class... _Args>
3885cee9157SPatrick Williams auto __tag_of_sig_(_Tag (*)(_Args...)) -> _Tag;
3895cee9157SPatrick Williams template <class _Sig>
3905cee9157SPatrick Williams using __tag_of_sig_t =
3915cee9157SPatrick Williams     decltype(stdexec::__tag_of_sig_(static_cast<_Sig*>(nullptr)));
3925cee9157SPatrick Williams 
3935cee9157SPatrick Williams template <class _Sender, class _SetSig, class _Env = empty_env>
3945cee9157SPatrick Williams concept sender_of =          //
3955cee9157SPatrick Williams     sender_in<_Sender, _Env> //
3965cee9157SPatrick Williams     &&
3975cee9157SPatrick Williams     same_as<
3985cee9157SPatrick Williams         __types<_SetSig>,
3995cee9157SPatrick Williams         __gather_completions_of<
4005cee9157SPatrick Williams             __tag_of_sig_t<_SetSig>, _Sender, _Env,
4015cee9157SPatrick Williams             __mcompose_q<__types, __qf<__tag_of_sig_t<_SetSig>>::template __f>,
4025cee9157SPatrick Williams             __mconcat<__qq<__types>>>>;
4035cee9157SPatrick Williams 
4045cee9157SPatrick Williams template <class _Error>
4055cee9157SPatrick Williams     requires false
4065cee9157SPatrick Williams using __nofail_t = _Error;
4075cee9157SPatrick Williams 
4085cee9157SPatrick Williams template <class _Sender, class _Env = empty_env>
4095cee9157SPatrick Williams concept __nofail_sender =
4105cee9157SPatrick Williams     sender_in<_Sender, _Env> &&
4115cee9157SPatrick Williams     requires {
4125cee9157SPatrick Williams         typename __gather_completion_signatures<
4135cee9157SPatrick Williams             __completion_signatures_of_t<_Sender, _Env>, set_error_t,
4145cee9157SPatrick Williams             __nofail_t, __sigs::__default_completion, __types>;
4155cee9157SPatrick Williams     };
4165cee9157SPatrick Williams 
4175cee9157SPatrick Williams /////////////////////////////////////////////////////////////////////////////
4185cee9157SPatrick Williams // early sender type-checking
4195cee9157SPatrick Williams template <class _Sender>
4205cee9157SPatrick Williams concept __well_formed_sender = __detail::__well_formed_sender<__minvoke<
4215cee9157SPatrick Williams     __with_default_q<__completion_signatures_of_t, dependent_completions>,
4225cee9157SPatrick Williams     _Sender>>;
4235cee9157SPatrick Williams } // namespace stdexec
424