Skip to content

Commit 6d35485

Browse files
authored
a new implementation of get_completion_signatures that improves diagnostics (#1811)
1 parent 6d56871 commit 6d35485

10 files changed

Lines changed: 216 additions & 162 deletions

include/exec/sequence_senders.hpp

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -322,40 +322,40 @@ namespace exec {
322322
return __result_t();
323323
} else if constexpr (sizeof...(_Env) == 0) {
324324
return STDEXEC::__dependent_sender<_Sequence>();
325-
} else if constexpr ((__is_debug_env<_Env> || ...)) {
326-
// This ought to cause a hard error that indicates where the problem is.
327-
using __item_types_t [[maybe_unused]] = STDEXEC::__mconstant<STDEXEC_REMOVE_REFERENCE(
328-
_Sequence)::template get_item_types<_Sequence, _Env...>()>;
329-
return __debug::__item_types();
330325
} else {
331326
return __unrecognized_sequence_error_t<_Sequence, _Env...>();
332327
}
333328
}
334329

335330
struct get_item_types_t {
336-
template <class _Sequence, class... _Env>
337-
constexpr auto operator()(_Sequence&&, const _Env&...) const noexcept {
338-
using _NewSequence = STDEXEC::__maybe_transform_sender_t<_Sequence, _Env...>;
339-
if constexpr (STDEXEC::__merror<_NewSequence>) {
340-
return exec::__invalid_item_types(_NewSequence());
341-
} else {
342-
return __sequence_sndr::__get_item_types_helper<_NewSequence, _Env...>();
343-
}
331+
template <class _Sequence>
332+
constexpr auto operator()(_Sequence&&) const noexcept {
333+
return __sequence_sndr::__get_item_types_helper<_Sequence>();
334+
}
335+
336+
template <class _Sequence, class _Env>
337+
constexpr auto operator()(_Sequence&&, const _Env&) const noexcept {
338+
using __new_sequence_t = transform_sender_result_t<_Sequence, _Env>;
339+
static_assert(!STDEXEC::__merror<__new_sequence_t>);
340+
return __sequence_sndr::__get_item_types_helper<__new_sequence_t, _Env>();
344341
}
345342
};
346343
} // namespace __sequence_sndr
347344

348345
using __sequence_sndr::get_item_types_t; // for backwards compatibility
349346

350-
template <class _Sequence, class... _Env>
347+
template <class _Sequence>
351348
[[nodiscard]]
352349
consteval auto get_item_types() {
353-
using _NewSequence = STDEXEC::__maybe_transform_sender_t<_Sequence, _Env...>;
354-
if constexpr (STDEXEC::__merror<_NewSequence>) {
355-
return exec::__invalid_item_types(_NewSequence());
356-
} else {
357-
return __sequence_sndr::__get_item_types_helper<_NewSequence, _Env...>();
358-
}
350+
return __sequence_sndr::__get_item_types_helper<_Sequence>();
351+
}
352+
353+
template <class _Sequence, class _Env>
354+
[[nodiscard]]
355+
consteval auto get_item_types() {
356+
using __new_sequence_t = STDEXEC::transform_sender_result_t<_Sequence, _Env>;
357+
static_assert(!STDEXEC::__merror<__new_sequence_t>);
358+
return __sequence_sndr::__get_item_types_helper<__new_sequence_t, _Env>();
359359
}
360360

361361
// Legacy interface:
@@ -429,7 +429,8 @@ namespace exec {
429429
struct _THE_CALL_TO_GET_ITEM_TYPES_IS_ILL_FORMED_ { };
430430

431431
template <class _Sequence>
432-
requires(!STDEXEC::__merror<_Sequence>) && (!STDEXEC::__minvocable_q<__item_types_of_t, _Sequence>)
432+
requires(!STDEXEC::__merror<_Sequence>)
433+
&& (!STDEXEC::__minvocable_q<__item_types_of_t, _Sequence>)
433434
auto __check_sequence(_Sequence*) -> STDEXEC::__mexception<
434435
STDEXEC::_WHAT_(_ERROR_WHILE_COMPUTING_THE_SEQUENCE_ITEM_TYPES_),
435436
STDEXEC::_WHY_(_THE_CALL_TO_GET_ITEM_TYPES_IS_ILL_FORMED_),

include/stdexec/__detail/__as_awaitable.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ namespace STDEXEC {
189189
struct as_awaitable_t {
190190
template <class _Tp, class _Promise>
191191
static consteval auto __get_declfn() noexcept {
192-
if constexpr (__detail::__has_as_awaitable_member<_Tp, _Promise>) {
192+
if constexpr (__connect_await::__has_as_awaitable_member<_Tp, _Promise>) {
193193
using __result_t = decltype(__declval<_Tp>().as_awaitable(__declval<_Promise&>()));
194194
constexpr bool __is_nothrow = noexcept(__declval<_Tp>()
195195
.as_awaitable(__declval<_Promise&>()));
@@ -211,7 +211,7 @@ namespace STDEXEC {
211211
requires __callable<__mtypeof<_DeclFn>>
212212
auto operator()(_Tp&& __t, _Promise& __promise) const noexcept(noexcept(_DeclFn()))
213213
-> decltype(_DeclFn()) {
214-
if constexpr (__detail::__has_as_awaitable_member<_Tp, _Promise>) {
214+
if constexpr (__connect_await::__has_as_awaitable_member<_Tp, _Promise>) {
215215
using __result_t = decltype(static_cast<_Tp&&>(__t).as_awaitable(__promise));
216216
static_assert(__awaitable<__result_t, _Promise>);
217217
return static_cast<_Tp&&>(__t).as_awaitable(__promise);

include/stdexec/__detail/__awaitable.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
#include "__concepts.hpp"
1919
#include "__config.hpp"
20-
#include "__utility.hpp"
20+
#include "__meta.hpp"
2121

2222
namespace STDEXEC {
2323
#if !STDEXEC_NO_STD_COROUTINES()

include/stdexec/__detail/__basic_sender.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ namespace STDEXEC {
193193
};
194194

195195
template <class _Tag, class _Self, class... _Env>
196-
concept __has_get_completion_signatures = requires {
196+
concept __has_get_completion_signatures_impl = requires {
197197
__sexpr_impl<_Tag>::template get_completion_signatures<_Self, _Env...>();
198198
};
199199
} // namespace __detail
@@ -305,9 +305,9 @@ namespace STDEXEC {
305305
using namespace __detail;
306306
static_assert(STDEXEC_IS_BASE_OF(__sexpr, __decay_t<_Self>));
307307
using __self_t = __copy_cvref_t<_Self, __sexpr>;
308-
if constexpr (__has_get_completion_signatures<__tag_t, __self_t, _Env...>) {
308+
if constexpr (__has_get_completion_signatures_impl<__tag_t, __self_t, _Env...>) {
309309
return __sexpr_impl<__tag_t>::template get_completion_signatures<__self_t, _Env...>();
310-
} else if constexpr (__has_get_completion_signatures<__tag_t, __self_t>) {
310+
} else if constexpr (__has_get_completion_signatures_impl<__tag_t, __self_t>) {
311311
return __sexpr_impl<__tag_t>::template get_completion_signatures<__self_t>();
312312
} else if constexpr (sizeof...(_Env) == 0) {
313313
return __dependent_sender<_Self>();

include/stdexec/__detail/__connect_awaitable.hpp

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
#include "__concepts.hpp"
2222
#include "__config.hpp"
2323
#include "__env.hpp"
24-
#include "__get_completion_signatures.hpp"
2524
#include "__meta.hpp"
2625
#include "__receivers.hpp"
2726

@@ -36,6 +35,40 @@ namespace STDEXEC {
3635
/////////////////////////////////////////////////////////////////////////////
3736
// __connect_await
3837
namespace __connect_await {
38+
template <class _Tp, class _Promise>
39+
concept __has_as_awaitable_member = requires(_Tp&& __t, _Promise& __promise) {
40+
static_cast<_Tp&&>(__t).as_awaitable(__promise);
41+
};
42+
43+
// A partial duplicate of with_awaitable_senders to avoid circular type dependencies
44+
template <class _Promise>
45+
struct __with_await_transform {
46+
template <class _Ty>
47+
STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
48+
constexpr auto await_transform(_Ty&& __value) noexcept -> _Ty&& {
49+
return static_cast<_Ty&&>(__value);
50+
}
51+
52+
template <class _Ty>
53+
requires __has_as_awaitable_member<_Ty, _Promise&>
54+
STDEXEC_ATTRIBUTE(nodiscard, host, device)
55+
auto await_transform(_Ty&& __value)
56+
noexcept(noexcept(__declval<_Ty>().as_awaitable(__declval<_Promise&>())))
57+
-> decltype(__declval<_Ty>().as_awaitable(__declval<_Promise&>())) {
58+
return static_cast<_Ty&&>(__value).as_awaitable(static_cast<_Promise&>(*this));
59+
}
60+
61+
template <class _Ty>
62+
requires __has_as_awaitable_member<_Ty, _Promise&>
63+
|| tag_invocable<as_awaitable_t, _Ty, _Promise&>
64+
STDEXEC_ATTRIBUTE(nodiscard, host, device)
65+
auto await_transform(_Ty&& __value)
66+
noexcept(nothrow_tag_invocable<as_awaitable_t, _Ty, _Promise&>)
67+
-> tag_invoke_result_t<as_awaitable_t, _Ty, _Promise&> {
68+
return tag_invoke(as_awaitable, static_cast<_Ty&&>(__value), static_cast<_Promise&>(*this));
69+
}
70+
};
71+
3972
struct __promise_base {
4073
constexpr auto initial_suspend() noexcept -> __std::suspend_always {
4174
return {};
@@ -101,7 +134,7 @@ namespace STDEXEC {
101134
template <class _Receiver>
102135
struct __promise
103136
: __promise_base
104-
, __detail::__with_await_transform<__promise<_Receiver>> {
137+
, __with_await_transform<__promise<_Receiver>> {
105138
# if STDEXEC_EDG()
106139
constexpr __promise(auto&&, _Receiver&& __rcvr) noexcept
107140
: __rcvr_(__rcvr) {
@@ -207,8 +240,12 @@ namespace STDEXEC {
207240
#else
208241
namespace __connect_await {
209242
template <class>
210-
using __promise = void;
243+
struct __promise { };
244+
245+
template <class>
246+
struct __with_await_transform { };
211247
} // namespace __connect_await
248+
212249
struct __connect_awaitable_t { };
213250
#endif
214251
inline constexpr __connect_awaitable_t __connect_awaitable{};

include/stdexec/__detail/__execution_fwd.hpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -225,17 +225,16 @@ namespace STDEXEC {
225225
concept __well_formed_completions = bool(
226226
__cmplsigs::__well_formed_completions_helper<_Completions>);
227227

228-
template <class _Sender, class... _Env>
229-
requires(sizeof...(_Env) <= 1)
230-
[[nodiscard]]
231-
consteval auto get_completion_signatures() -> __well_formed_completions auto;
228+
// template <class _Sender>
229+
// consteval auto get_completion_signatures();
232230

233-
// Legacy interface:
234-
template <class _Sender, class... _Env>
235-
requires(sizeof...(_Env) <= 1)
236-
[[nodiscard]]
237-
constexpr auto get_completion_signatures(_Sender&&, const _Env&...) noexcept //
238-
-> __well_formed_completions auto;
231+
// template <class _Sender, class _Env>
232+
// consteval auto get_completion_signatures();
233+
234+
// // Legacy interface:
235+
// template <class _Sender, class... _Env>
236+
// requires(sizeof...(_Env) <= 1)
237+
// constexpr auto get_completion_signatures(_Sender&&, const _Env&...) noexcept;
239238

240239
#if STDEXEC_NO_STD_CONSTEXPR_EXCEPTIONS()
241240

0 commit comments

Comments
 (0)