Commit ec7519ab authored by Kirk Shoop's avatar Kirk Shoop Committed by Facebook Github Bot

improve pushmi compile-time debugging

Summary:
use PUSHMI_TEMPLATE_DEBUG in a few more places
add some additional code to the submit customization point to allow the compiler to emit error info when none of the fallbacks worked.

Reviewed By: yfeldblum

Differential Revision: D15016463

fbshipit-source-id: 1c43c21093d54d662c1d084040608db0e0c029be
parent c43e3f85
......@@ -168,7 +168,7 @@ inline void set_value(std::promise<void>& p) //
//
struct set_done_fn {
PUSHMI_TEMPLATE(class S)
PUSHMI_TEMPLATE_DEBUG(class S)
(requires //
requires(
set_done(std::declval<S&>()),
......@@ -186,7 +186,7 @@ struct set_done_fn {
}
};
struct set_error_fn {
PUSHMI_TEMPLATE(class S, class E)
PUSHMI_TEMPLATE_DEBUG(class S, class E)
(requires //
requires(set_error(std::declval<S&>(), std::declval<E>()))) //
void operator()(S& s, E&& e) const //
......@@ -195,7 +195,7 @@ struct set_error_fn {
}
};
struct set_value_fn {
PUSHMI_TEMPLATE(class S, class... VN)
PUSHMI_TEMPLATE_DEBUG(class S, class... VN)
(requires //
requires(
set_value(std::declval<S&>(), std::declval<VN>()...),
......@@ -214,7 +214,7 @@ struct set_value_fn {
};
struct set_starting_fn {
PUSHMI_TEMPLATE(class S, class Up)
PUSHMI_TEMPLATE_DEBUG(class S, class Up)
(requires //
requires(
set_starting(std::declval<S&>(), std::declval<Up>()),
......
......@@ -50,6 +50,7 @@ class any_flow_sender
vtable const* vptr_ = &noop_;
template <class Wrapped>
any_flow_sender(Wrapped obj, std::false_type) : any_flow_sender() {
static_assert(FlowSenderTo<wrapped_t<Wrapped>&, any_flow_receiver<PE, PV, E, VN...>>, "Wrapped object does not support w.submit(any_flow_receiver) - perhaps std::move(w).submit(any_flow_receiver) is supported");
struct s {
static void op(data& src, data* dst) {
if (dst)
......@@ -66,8 +67,8 @@ class any_flow_sender
vptr_ = &vtbl;
}
template <class Wrapped>
any_flow_sender(Wrapped obj, std::true_type) noexcept
: any_flow_sender() {
any_flow_sender(Wrapped obj, std::true_type) noexcept : any_flow_sender() {
static_assert(FlowSenderTo<wrapped_t<Wrapped>&, any_flow_receiver<PE, PV, E, VN...>>, "Wrapped object does not support w.submit(any_flow_receiver) - perhaps std::move(w).submit(any_flow_receiver) is supported");
struct s {
static void op(data& src, data* dst) {
if (dst)
......@@ -106,8 +107,8 @@ class any_flow_sender
new ((void*)this) any_flow_sender(std::move(that));
return *this;
}
PUSHMI_TEMPLATE(class Out)
(requires ReceiveError<Out, E>&& ReceiveValue<Out, VN...>) //
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires ReceiveError<Out, E>&& ReceiveValue<Out, VN...> && Constructible<any_flow_receiver<PE, PV, E, VN...>, Out>) //
void submit(Out&& out) {
vptr_->submit_(data_, any_flow_receiver<PE, PV, E, VN...>{(Out &&) out});
}
......@@ -129,13 +130,13 @@ class flow_sender<SF> {
constexpr explicit flow_sender(SF sf)
: sf_(std::move(sf)) {}
PUSHMI_TEMPLATE(class Out)
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires FlowReceiver<Out> && Invocable<SF&, Out>)
void submit(Out out) & {
sf_(std::move(out));
}
PUSHMI_TEMPLATE(class Out)
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires FlowReceiver<Out> && Invocable<SF&&, Out>)
void submit(Out out) && {
std::move(sf_)(std::move(out));
......@@ -162,12 +163,12 @@ class flow_sender<Data, DSF> {
constexpr flow_sender(Data data, DSF sf)
: data_(std::move(data)), sf_(std::move(sf)) {}
PUSHMI_TEMPLATE(class Out)
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires FlowReceiver<Out> && Invocable<DSF&, Data&, Out>)
void submit(Out out) & {
sf_(data_, std::move(out));
}
PUSHMI_TEMPLATE(class Out)
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires FlowReceiver<Out> && Invocable<DSF&&, Data&&, Out>)
void submit(Out out) && {
std::move(sf_)(std::move(data_), std::move(out));
......
......@@ -53,6 +53,7 @@ class any_flow_single_sender
template <class Wrapped>
any_flow_single_sender(Wrapped obj, std::false_type)
: any_flow_single_sender() {
static_assert(FlowSenderTo<wrapped_t<Wrapped>&, any_flow_receiver<PE, std::ptrdiff_t, E, VN...>>, "Wrapped object does not support w.submit(any_flow_receiver) - perhaps std::move(w).submit(any_flow_receiver) is supported");
struct s {
static void op(data& src, data* dst) {
if (dst)
......@@ -73,6 +74,7 @@ class any_flow_single_sender
template <class Wrapped>
any_flow_single_sender(Wrapped obj, std::true_type) noexcept
: any_flow_single_sender() {
static_assert(FlowSenderTo<wrapped_t<Wrapped>&, any_flow_receiver<PE, std::ptrdiff_t, E, VN...>>, "Wrapped object does not support w.submit(any_flow_receiver) - perhaps std::move(w).submit(any_flow_receiver) is supported");
struct s {
static void op(data& src, data* dst) {
if (dst)
......@@ -114,8 +116,8 @@ class any_flow_single_sender
new ((void*)this) any_flow_single_sender(std::move(that));
return *this;
}
PUSHMI_TEMPLATE(class Out)
(requires ReceiveError<Out, E>&& ReceiveValue<Out, VN...>) //
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires ReceiveError<Out, E>&& ReceiveValue<Out, VN...> && Constructible<any_flow_receiver<PE, std::ptrdiff_t, E, VN...>, Out>) //
void submit(Out&& out) {
vptr_->submit_(
data_,
......@@ -139,13 +141,13 @@ class flow_single_sender<SF> {
constexpr explicit flow_single_sender(SF sf)
: sf_(std::move(sf)) {}
PUSHMI_TEMPLATE(class Out)
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires Receiver<Out> && Invocable<SF&, Out>)
void submit(Out out) & {
sf_(std::move(out));
}
PUSHMI_TEMPLATE(class Out)
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires Receiver<Out> && Invocable<SF&&, Out>)
void submit(Out out) && {
std::move(sf_)(std::move(out));
......@@ -176,13 +178,13 @@ class flow_single_sender<Data, DSF> {
constexpr flow_single_sender(Data data, DSF sf)
: data_(std::move(data)), sf_(std::move(sf)) {}
PUSHMI_TEMPLATE(class Out)
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires Receiver<Out> && Invocable<DSF&, Data&, Out>)
void submit(Out out) & {
sf_(data_, std::move(out));
}
PUSHMI_TEMPLATE(class Out)
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires Receiver<Out> && Invocable<DSF&&, Data&&, Out>)
void submit(Out out) && {
std::move(sf_)(std::move(data_), std::move(out));
......
......@@ -32,8 +32,9 @@ namespace folly {
namespace pushmi {
namespace _submit_adl {
struct submit_adl_disabled;
template <class S, class R>
void submit(S&&, R&&) = delete;
submit_adl_disabled submit(S&&, R&&);
template <class T>
constexpr typename T::value_type const _v = T::value;
......@@ -77,35 +78,57 @@ namespace _submit_adl {
#endif
struct _impl_ {
PUSHMI_TEMPLATE_DEBUG(class S, class R)
// these pull the line numbers for the different invocations
// out of the IF_CONSTEXPR macros
PUSHMI_TEMPLATE(class S, class R)
(requires Sender<S> && Receiver<R>)
auto operator()(S&& from, R&& to) const
{
auto adl_submit(S&& from, R&& to) const {
return submit((S&&) from, (R&&) to);
}
PUSHMI_TEMPLATE(class S, class R)
(requires Sender<S> && Receiver<R>)
auto member_submit(S&& from, R&& to) const {
return ((S&&) from).submit((R&&) to);
}
PUSHMI_TEMPLATE(class S, class R)
(requires Sender<S> && Receiver<R>)
void debug_submit(S&& from, R&& to) const {
// try to get a useful compile error
PUSHMI_IF_CONSTEXPR((
Same<decltype(submit((S&&) from, (R&&) to)),
submit_adl_disabled>) (
static_assert(std::is_void<decltype(member_submit(id((S&&) from), (R&&) to))>::value, "s.submit(r) failed and adl was disabled");
) else (
static_assert(std::is_void<decltype(adl_submit(id((S&&) from), (R&&) to))>::value, "submit(s, r) via ADL failed");
))
}
PUSHMI_TEMPLATE(class S, class R)
(requires Sender<S> && Receiver<R>)
auto operator()(S&& from, R&& to) const {
// Prefer a .submit() member if it exists:
PUSHMI_IF_CONSTEXPR_RETURN((HasMemberSubmit_<S, R>) (
id((S&&) from).submit((R&&) to);
member_submit(id((S&&) from), (R&&) to);
return std::true_type{};
) else (
// Otherwise, dispatch to a submit() free function if it exists:
PUSHMI_IF_CONSTEXPR_RETURN((HasNonMemberSubmit_<S, R>) (
submit(id((S&&) from), (R&&) to);
adl_submit(id((S&&) from), (R&&) to);
return std::true_type{};
) else (
#if FOLLY_HAS_COROUTINES
// Otherwise, if we support coroutines and S looks like an
// awaitable, dispatch to the
// awaitable, dispatch to the coroutine
PUSHMI_IF_CONSTEXPR_RETURN((IsSubmittableAwaitable_<S, R>) (
_submit_awaitable_(id((S&&) from), (R&&) to);
return std::true_type{};
) else (
debug_submit(id((S&&) from), (R&&) to);
return std::false_type{};
))
#else
// does not work for free functions
id((S&&) from).submit((R&&) to);
debug_submit(id((S&&) from), (R&&) to);
return std::false_type{};
#endif
))
))
......
......@@ -50,6 +50,7 @@ class any_sender
vtable const* vptr_ = &noop_;
template <class Wrapped>
any_sender(Wrapped obj, std::false_type) : any_sender() {
static_assert(SenderTo<wrapped_t<Wrapped>&, any_receiver<E, VN...>>, "Wrapped object does not support w.submit(any_receiver) - perhaps std::move(w).submit(any_receiver) is supported");
struct s {
static void op(data& src, data* dst) {
if (dst)
......@@ -67,6 +68,7 @@ class any_sender
}
template <class Wrapped>
any_sender(Wrapped obj, std::true_type) noexcept : any_sender() {
static_assert(SenderTo<wrapped_t<Wrapped>&, any_receiver<E, VN...>>, "Wrapped object does not support w.submit(any_receiver) - perhaps std::move(w).submit(any_receiver) is supported");
struct s {
static void op(data& src, data* dst) {
if (dst)
......@@ -95,7 +97,7 @@ class any_sender
}
PUSHMI_TEMPLATE(class Wrapped)
(requires SenderTo<wrapped_t<Wrapped>, any_receiver<E, VN...>>) //
(requires Sender<wrapped_t<Wrapped>>) //
explicit any_sender(Wrapped obj) noexcept(insitu<Wrapped>())
: any_sender{std::move(obj), bool_<insitu<Wrapped>()>{}} {}
~any_sender() {
......@@ -106,8 +108,8 @@ class any_sender
new ((void*)this) any_sender(std::move(that));
return *this;
}
PUSHMI_TEMPLATE(class Out)
(requires ReceiveError<Out, E>&& ReceiveValue<Out, VN...>) //
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires ReceiveError<Out, E>&& ReceiveValue<Out, VN...> && Constructible<any_receiver<E, VN...>, Out>) //
void submit(Out&& out) {
vptr_->submit_(data_, any_receiver<E, VN...>{(Out &&) out});
}
......@@ -126,14 +128,14 @@ class sender<SF> : public sender_tag {
constexpr sender() = default;
constexpr explicit sender(SF sf) : sf_(std::move(sf)) {}
PUSHMI_TEMPLATE(class Out)
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires PUSHMI_EXP(
lazy::Receiver<Out> PUSHMI_AND lazy::Invocable<SF&, Out>)) //
void submit(Out out) & {
sf_(std::move(out));
}
PUSHMI_TEMPLATE(class Out)
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires PUSHMI_EXP(
lazy::Receiver<Out> PUSHMI_AND lazy::Invocable<SF&&, Out>)) //
void submit(Out out) && {
......@@ -159,13 +161,13 @@ class sender<Data, DSF> {
constexpr sender(Data data, DSF sf)
: data_(std::move(data)), sf_(std::move(sf)) {}
PUSHMI_TEMPLATE(class Out)
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires PUSHMI_EXP(
lazy::Receiver<Out> PUSHMI_AND lazy::Invocable<DSF&, Data&, Out>)) //
void submit(Out out) & {
sf_(data_, std::move(out));
}
PUSHMI_TEMPLATE(class Out)
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires PUSHMI_EXP(
lazy::Receiver<Out> PUSHMI_AND lazy::Invocable<DSF&&, Data&&, Out>)) //
void submit(Out out) && {
......
......@@ -101,8 +101,7 @@ class any_single_sender
static const vtable vtbl{s::op, s::submit};
new (&data_.buffer_) Wrapped(std::move(obj));
vptr_ = &vtbl;
}
template <class Wrapped>
} template <class Wrapped>
any_single_sender(Wrapped obj, std::false_type, std::true_type) noexcept
: any_single_sender() {
struct s {
......@@ -144,8 +143,8 @@ class any_single_sender
new ((void*)this) any_single_sender(std::move(that));
return *this;
}
PUSHMI_TEMPLATE(class Out)
(requires ReceiveError<Out, E>&& ReceiveValue<Out, VN...>) //
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires ReceiveError<Out, E>&& ReceiveValue<Out, VN...> && Constructible<any_receiver<E, VN...>, Out>) //
void submit(Out&& out) {
vptr_->submit_(data_, any_receiver<E, VN...>{(Out &&) out});
}
......@@ -166,13 +165,13 @@ class single_sender<SF> {
constexpr single_sender() = default;
constexpr explicit single_sender(SF sf) : sf_(std::move(sf)) {}
PUSHMI_TEMPLATE(class Out)
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires Receiver<Out> && Invocable<SF&, Out>) //
void submit(Out&& out) & {
sf_((Out&&)out);
}
PUSHMI_TEMPLATE(class Out)
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires Receiver<Out> && Invocable<SF&&, Out>) //
void submit(Out&& out) && {
std::move(sf_)((Out&&)out);
......@@ -198,12 +197,12 @@ class single_sender<Data, DSF> {
constexpr single_sender(Data data, DSF sf)
: data_(std::move(data)), sf_(std::move(sf)) {}
PUSHMI_TEMPLATE(class Out)
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires Receiver<Out> && Invocable<DSF&, Data&, Out>) //
void submit(Out&& out) & {
sf_(data_, (Out&&)out);
}
PUSHMI_TEMPLATE(class Out)
PUSHMI_TEMPLATE_DEBUG(class Out)
(requires Receiver<Out> && Invocable<DSF&&, Data&&, Out>) //
void submit(Out&& out) && {
std::move(sf_)(std::move(data_), (Out&&)out);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment