diff --git a/include/exec/repeat_until.hpp b/include/exec/repeat_until.hpp index 4fdc31423..3e5c970d1 100644 --- a/include/exec/repeat_until.hpp +++ b/include/exec/repeat_until.hpp @@ -304,4 +304,15 @@ namespace STDEXEC { return STDEXEC::get_completion_signatures<__sndr_t, _Env...>(); } }; + + template <> + struct __sexpr_impl : __sexpr_defaults { + template + static consteval auto get_completion_signatures() { + static_assert(sender_expr_for<_Sender, exec::repeat_t>); + using __sndr_t = + __detail::__transform_sender_result_t>; + return STDEXEC::get_completion_signatures<__sndr_t, _Env...>(); + } + }; } // namespace STDEXEC diff --git a/test/exec/test_repeat_until.cpp b/test/exec/test_repeat_until.cpp index ff864a790..3cc6b86ef 100644 --- a/test/exec/test_repeat_until.cpp +++ b/test/exec/test_repeat_until.cpp @@ -17,6 +17,7 @@ #include "exec/repeat_until.hpp" #include "exec/static_thread_pool.hpp" +#include "stdexec/__detail/__sync_wait.hpp" #include "stdexec/execution.hpp" #include @@ -269,6 +270,47 @@ namespace { } while (!done); } + TEST_CASE("repeat composes with completion signatures") { + ex::sender auto only_stopped = ex::just_stopped() | exec::repeat(); + static_assert( + std::same_as, ex::__detail::__not_a_variant>, + "Expect no value completions"); + static_assert( + std::same_as, std::variant>, + "Missing added set_error_t(std::exception_ptr)"); + static_assert( + ex::sender_of, + "Missing set_stopped_t() from upstream"); + + // operator| and sync_wait require valid completion signatures + ex::sync_wait(only_stopped | ex::upon_stopped([]() noexcept { return -1; })); + + + ex::sender auto only_error = ex::just_error(-1) | exec::repeat(); + static_assert( + std::same_as, ex::__detail::__not_a_variant>, + "Expect no value completions"); + static_assert( + std::same_as< + ex::error_types_of_t, + std::variant + >, + "Missing added set_error_t(std::exception_ptr)"); + + // set_stopped_t is always added as a consequence of the internal trampoline_scheduler + using SC = ex::completion_signatures_of_t>; + static_assert( + !ex::sender_of + || ex::sender_of, + "Missing added set_error_t(std::exception_ptr)"); + + // operator| and sync_wait require valid completion signatures + ex::sync_wait( + only_error // + | ex::upon_stopped([]() { return -1; }) + | ex::upon_error([](const auto) { return -1; })); + } + TEST_CASE( "repeat_until works correctly when the child operation sends type which throws when " "decay-copied, and when converted to bool, and which is only rvalue convertible to bool",