utils: handle void lambda in ImmediateFuture

Summary:
Lambda returning no values would cause the compiler to try to instantiate an
ImmediateFuture<void>, which doesn't compile. We could try special casing the
void type, but it's easier if we simply consider these lambda to return unit.

Reviewed By: genevievehelsel

Differential Revision: D28372253

fbshipit-source-id: 1368ae5dc5e2d4d6a5c3e31bc87ed7d230027c3a
This commit is contained in:
Xavier Deguillard 2021-05-17 14:05:54 -07:00 committed by Facebook GitHub Bot
parent 3eb9e86b61
commit de6ca0c970
3 changed files with 17 additions and 3 deletions

View File

@ -28,13 +28,21 @@ ImmediateFuture<detail::continuation_result_t<Func, folly::Try<T>>>
ImmediateFuture<T>::thenTry(Func&& func) && {
using NewType = detail::continuation_result_t<Func, folly::Try<T>>;
using RetType = ImmediateFuture<NewType>;
using FuncRetType = std::invoke_result_t<Func, folly::Try<T>>;
return std::visit(
[func = std::forward<Func>(func)](auto&& inner) mutable -> RetType {
using Type = std::decay_t<decltype(inner)>;
if constexpr (std::is_same_v<Type, folly::Try<T>>) {
try {
return func(std::move(inner));
// In the case where Func returns void, force the return value to
// be folly::unit.
if constexpr (std::is_same_v<FuncRetType, void>) {
func(std::move(inner));
return folly::unit;
} else {
return func(std::move(inner));
}
} catch (std::exception& ex) {
return folly::Try<NewType>(
folly::exception_wrapper(std::current_exception(), ex));
@ -44,8 +52,6 @@ ImmediateFuture<T>::thenTry(Func&& func) && {
// transform that return value into a SemiFuture so that the return
// type is a SemiFuture<NewType> and not a
// SemiFuture<ImmediateFuture<NewType>>.
using FuncRetType = std::invoke_result_t<Func, folly::Try<T>>;
auto semiFut = std::move(inner).defer(std::forward<Func>(func));
if constexpr (detail::isImmediateFuture<FuncRetType>::value) {
return std::move(semiFut).deferValue(

View File

@ -48,6 +48,11 @@ struct continuation_result_impl<
using type = typename T::element_type;
};
template <>
struct continuation_result_impl<void> {
using type = folly::Unit;
};
template <
typename Func,
typename Arg,

View File

@ -121,6 +121,9 @@ ImmediateFuture<folly::Unit> unitFunc() {
TEST(ImmediateFuture, unit) {
auto fut = unitFunc();
EXPECT_TRUE(fut.hasImmediate());
auto voidFut = std::move(fut).thenValue([](folly::Unit) {});
EXPECT_TRUE(voidFut.hasImmediate());
}
class Foo {