Commit e2fcfa38 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

No longer allow continuations taking non-const lvalue-ref

Summary: [Folly] No longer allow continuations taking non-const lvalue-ref, since that is not really necessary - callers can get all the same results using continuations taking non-const rvalue-ref instead.

Reviewed By: Orvid

Differential Revision: D8166011

fbshipit-source-id: 468d049c6034339f3caf1a82fbc8c755ec2f51e6
parent 51a23742
......@@ -981,7 +981,6 @@ template <class T>
template <class F>
typename std::enable_if<
!futures::detail::callableWith<F, exception_wrapper>::value &&
!futures::detail::callableWith<F, exception_wrapper&>::value &&
!futures::detail::Extract<F>::ReturnsFuture::value,
Future<T>>::type
Future<T>::onError(F&& func) {
......@@ -1017,7 +1016,6 @@ template <class T>
template <class F>
typename std::enable_if<
!futures::detail::callableWith<F, exception_wrapper>::value &&
!futures::detail::callableWith<F, exception_wrapper&>::value &&
futures::detail::Extract<F>::ReturnsFuture::value,
Future<T>>::type
Future<T>::onError(F&& func) {
......
......@@ -120,13 +120,7 @@ struct callableResult {
typename std::conditional<
callableWith<F, T&&>::value,
detail::argResult<false, F, T&&>,
typename std::conditional<
callableWith<F, T&>::value,
detail::argResult<false, F, T&>,
typename std::conditional<
callableWith<F, Try<T>&&>::value,
detail::argResult<true, F, Try<T>&&>,
detail::argResult<true, F, Try<T>&>>::type>::type>::type>::type Arg;
detail::argResult<true, F, Try<T>&&>>::type>::type Arg;
typedef isFutureOrSemiFuture<typename Arg::Result> ReturnsFuture;
typedef Future<typename ReturnsFuture::Inner> Return;
};
......@@ -136,10 +130,7 @@ struct tryCallableResult {
typedef typename std::conditional<
callableWith<F>::value,
detail::argResult<false, F>,
typename std::conditional<
callableWith<F, Try<T>&&>::value,
detail::argResult<true, F, Try<T>&&>,
detail::argResult<true, F, Try<T>&>>::type>::type Arg;
detail::argResult<true, F, Try<T>&&>>::type Arg;
typedef isFutureOrSemiFuture<typename Arg::Result> ReturnsFuture;
typedef typename ReturnsFuture::Inner value_type;
};
......@@ -149,10 +140,7 @@ struct valueCallableResult {
typedef typename std::conditional<
callableWith<F>::value,
detail::argResult<false, F>,
typename std::conditional<
callableWith<F, T&&>::value,
detail::argResult<false, F, T&&>,
detail::argResult<false, F, T&>>::type>::type Arg;
detail::argResult<false, F, T&&>>::type Arg;
typedef isFutureOrSemiFuture<typename Arg::Result> ReturnsFuture;
typedef typename ReturnsFuture::Inner value_type;
typedef typename Arg::ArgList::FirstArg FirstArg;
......
......@@ -872,7 +872,6 @@ class Future : private futures::detail::FutureBase<T> {
template <class F>
typename std::enable_if<
!futures::detail::callableWith<F, exception_wrapper>::value &&
!futures::detail::callableWith<F, exception_wrapper&>::value &&
!futures::detail::Extract<F>::ReturnsFuture::value,
Future<T>>::type
onError(F&& func);
......@@ -881,7 +880,6 @@ class Future : private futures::detail::FutureBase<T> {
template <class F>
typename std::enable_if<
!futures::detail::callableWith<F, exception_wrapper>::value &&
!futures::detail::callableWith<F, exception_wrapper&>::value &&
futures::detail::Extract<F>::ReturnsFuture::value,
Future<T>>::type
onError(F&& func);
......
......@@ -879,39 +879,31 @@ TEST(Future, special) {
}
TEST(Future, then) {
auto f = makeFuture<std::string>("0")
.then([](){
return makeFuture<std::string>("1"); })
.then([](Try<std::string>&& t) {
return makeFuture(t.value() + ";2"); })
auto f =
makeFuture<std::string>("0")
.then([]() { return makeFuture<std::string>("1"); })
.then(
[](Try<std::string>&& t) { return makeFuture(t.value() + ";2"); })
.then([](const Try<std::string>&& t) {
return makeFuture(t.value() + ";3"); })
.then([](Try<std::string>& t) {
return makeFuture(t.value() + ";4"); })
return makeFuture(t.value() + ";3");
})
.then([](const Try<std::string>& t) {
return makeFuture(t.value() + ";5"); })
.then([](Try<std::string> t) {
return makeFuture(t.value() + ";6"); })
return makeFuture(t.value() + ";4");
})
.then([](Try<std::string> t) { return makeFuture(t.value() + ";5"); })
.then([](const Try<std::string> t) {
return makeFuture(t.value() + ";7"); })
.then([](std::string&& s) {
return makeFuture(s + ";8"); })
.then([](const std::string&& s) {
return makeFuture(s + ";9"); })
.then([](std::string& s) {
return makeFuture(s + ";10"); })
.then([](const std::string& s) {
return makeFuture(s + ";11"); })
.then([](std::string s) {
return makeFuture(s + ";12"); })
.then([](const std::string s) {
return makeFuture(s + ";13"); })
;
EXPECT_EQ(f.value(), "1;2;3;4;5;6;7;8;9;10;11;12;13");
return makeFuture(t.value() + ";6");
})
.then([](std::string&& s) { return makeFuture(s + ";7"); })
.then([](const std::string&& s) { return makeFuture(s + ";8"); })
.then([](const std::string& s) { return makeFuture(s + ";9"); })
.then([](std::string s) { return makeFuture(s + ";10"); })
.then([](const std::string s) { return makeFuture(s + ";11"); });
EXPECT_EQ(f.value(), "1;2;3;4;5;6;7;8;9;10;11");
}
static folly::Future<std::string> doWorkStaticTry(Try<std::string>&& t) {
return makeFuture(t.value() + ";8");
return makeFuture(t.value() + ";7");
}
TEST(Future, thenTrythenValue) {
......@@ -923,25 +915,21 @@ TEST(Future, thenTrythenValue) {
.thenTry([](const Try<std::string>&& t) {
return makeFuture(t.value() + ";3");
})
.thenTry(
[](Try<std::string>& t) { return makeFuture(t.value() + ";4"); })
.thenTry([](const Try<std::string>& t) {
return makeFuture(t.value() + ";5");
return makeFuture(t.value() + ";4");
})
.thenTry(
[](Try<std::string> t) { return makeFuture(t.value() + ";6"); })
[](Try<std::string> t) { return makeFuture(t.value() + ";5"); })
.thenTry([](const Try<std::string> t) {
return makeFuture(t.value() + ";7");
return makeFuture(t.value() + ";6");
})
.thenTry(doWorkStaticTry)
.thenValue([](std::string&& s) { return makeFuture(s + ";9"); })
.thenValue(
[](const std::string&& s) { return makeFuture(s + ";10"); })
.thenValue([](std::string& s) { return makeFuture(s + ";11"); })
.thenValue([](const std::string& s) { return makeFuture(s + ";12"); })
.thenValue([](std::string s) { return makeFuture(s + ";13"); })
.thenValue([](const std::string s) { return makeFuture(s + ";14"); });
EXPECT_EQ(f.value(), "1;2;3;4;5;6;7;8;9;10;11;12;13;14");
.thenValue([](std::string&& s) { return makeFuture(s + ";8"); })
.thenValue([](const std::string&& s) { return makeFuture(s + ";9"); })
.thenValue([](const std::string& s) { return makeFuture(s + ";10"); })
.thenValue([](std::string s) { return makeFuture(s + ";11"); })
.thenValue([](const std::string s) { return makeFuture(s + ";12"); });
EXPECT_EQ(f.value(), "1;2;3;4;5;6;7;8;9;10;11;12");
}
TEST(Future, thenTry) {
......@@ -1075,7 +1063,7 @@ TEST(Future, thenStdFunction) {
EXPECT_EQ(f.value(), 42);
}
{
std::function<int(Try<int>&)> fn = [](Try<int>& t){ return t.value() + 2; };
std::function<int(Try<int>)> fn = [](Try<int> t) { return t.value() + 2; };
auto f = makeFuture(1).then(std::move(fn));
EXPECT_EQ(f.value(), 3);
}
......
......@@ -22,11 +22,7 @@ TEST(Basic, thenVariants) {
{Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, Try<A>>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>>());}
{Future<B> f = someFuture<A>().then([&](Try<A>){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A>&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A>&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, Try<A>&>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>&>());}
{Future<B> f = someFuture<A>().then([&](Try<A>&){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A&&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A&&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, A&&>, &anObject);}
......@@ -42,11 +38,7 @@ TEST(Basic, thenVariants) {
{Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, A>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A>());}
{Future<B> f = someFuture<A>().then([&](A){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, A&>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A&>());}
{Future<B> f = someFuture<A>().then([&](A&){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then([&](){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, Try<A>&&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>&&>);}
......@@ -63,11 +55,7 @@ TEST(Basic, thenVariants) {
{Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, Try<A>>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>>());}
{Future<B> f = someFuture<A>().then([&](Try<A>){return B();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, Try<A>&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, Try<A>&>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>&>());}
{Future<B> f = someFuture<A>().then([&](Try<A>&){return B();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, A&&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A&&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, A&&>, &anObject);}
......@@ -83,10 +71,6 @@ TEST(Basic, thenVariants) {
{Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, A>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, A>());}
{Future<B> f = someFuture<A>().then([&](A){return B();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, A&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, A&>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, A&>());}
{Future<B> f = someFuture<A>().then([&](A&){return B();});}
{Future<B> f = someFuture<A>().then([&](){return B();});}
}
......@@ -106,16 +106,6 @@ TEST(Then, tryRValueReference) {
EXPECT_EQ(future.value(), 23);
}
TEST(Then, tryLValueReference) {
auto future = makeFuture<Widget>(23).then(
[](Try<Widget>& t) {
EXPECT_EQ(t.value().copied_, 0);
EXPECT_EQ(t.value().moved_, 2);
return t.value().v_;
});
EXPECT_EQ(future.value(), 23);
}
TEST(Then, tryConstLValueReference) {
auto future = makeFuture<Widget>(23).then(
[](const Try<Widget>& t) {
......@@ -166,16 +156,6 @@ TEST(Then, rValueReference) {
EXPECT_EQ(future.value(), 23);
}
TEST(Then, lValueReference) {
auto future = makeFuture<Widget>(23).then(
[](Widget& w) {
EXPECT_EQ(w.copied_, 0);
EXPECT_EQ(w.moved_, 2);
return w.v_;
});
EXPECT_EQ(future.value(), 23);
}
TEST(Then, constLValueReference) {
auto future = makeFuture<Widget>(23).then(
[](const Widget& w) {
......
......@@ -332,7 +332,7 @@ TEST(Wait, WaitPlusThen) {
EXPECT_EQ(f.value(), 42);
f.wait();
auto continuation = 0;
EXPECT_NO_THROW(f.then([&](auto& v) { continuation = v; }));
EXPECT_NO_THROW(f.then([&](auto&& v) { continuation = v; }));
EXPECT_EQ(continuation, 42);
}
......@@ -352,7 +352,7 @@ TEST(Wait, WaitPlusThen) {
EXPECT_FALSE(f.isReady()); // deterministically passes in practice
f.wait();
EXPECT_THROW(f.then([](auto&) {}), std::logic_error);
EXPECT_THROW(f.then([](auto&&) {}), std::logic_error);
t.join();
}
......@@ -366,7 +366,7 @@ TEST(Wait, WaitPlusThen) {
EXPECT_EQ(f.value(), 42);
f.wait(std::chrono::seconds(10));
auto continuation = 0;
EXPECT_NO_THROW(f.then([&](auto& v) { continuation = v; }));
EXPECT_NO_THROW(f.then([&](auto&& v) { continuation = v; }));
EXPECT_EQ(continuation, 42);
}
......@@ -388,7 +388,7 @@ TEST(Wait, WaitPlusThen) {
f.wait(std::chrono::seconds(10));
EXPECT_TRUE(f.isReady()); // deterministically passes in practice
auto continuation = 0;
EXPECT_NO_THROW(f.then([&](auto& v) { continuation = v; }));
EXPECT_NO_THROW(f.then([&](auto&& v) { continuation = v; }));
EXPECT_EQ(continuation, 42);
t.join();
}
......@@ -400,7 +400,7 @@ TEST(Wait, WaitPlusThen) {
auto f = p.getFuture();
f.wait(milliseconds(1));
auto continuation = 0;
EXPECT_NO_THROW(f.then([&](auto& v) { continuation = v; }));
EXPECT_NO_THROW(f.then([&](auto&& v) { continuation = v; }));
EXPECT_EQ(continuation, 0);
}
......@@ -416,7 +416,7 @@ TEST(Wait, WaitPlusThen) {
auto continuation = 0;
InlineExecutor e;
auto f2 = std::move(f).via(&e);
EXPECT_NO_THROW(f2.then([&](auto& v) { continuation = v; }));
EXPECT_NO_THROW(f2.then([&](auto&& v) { continuation = v; }));
EXPECT_EQ(continuation, 42);
}
......@@ -438,7 +438,7 @@ TEST(Wait, WaitPlusThen) {
f.wait();
InlineExecutor e;
auto f2 = std::move(f).via(&e);
EXPECT_THROW(f2.then([](auto&) {}), std::logic_error);
EXPECT_THROW(f2.then([](auto&&) {}), std::logic_error);
t.join();
}
......@@ -454,7 +454,7 @@ TEST(Wait, WaitPlusThen) {
auto continuation = 0;
InlineExecutor e;
auto f2 = std::move(f).via(&e);
EXPECT_NO_THROW(f2.then([&](auto& v) { continuation = v; }));
EXPECT_NO_THROW(f2.then([&](auto&& v) { continuation = v; }));
EXPECT_EQ(continuation, 42);
}
......@@ -478,7 +478,7 @@ TEST(Wait, WaitPlusThen) {
auto continuation = 0;
InlineExecutor e;
auto f2 = std::move(f).via(&e);
EXPECT_NO_THROW(f2.then([&](auto& v) { continuation = v; }));
EXPECT_NO_THROW(f2.then([&](auto&& v) { continuation = v; }));
EXPECT_EQ(continuation, 42);
t.join();
}
......@@ -492,7 +492,7 @@ TEST(Wait, WaitPlusThen) {
auto continuation = 0;
InlineExecutor e;
auto f2 = std::move(f).via(&e);
EXPECT_NO_THROW(f2.then([&](auto& v) { continuation = v; }));
EXPECT_NO_THROW(f2.then([&](auto&& v) { continuation = v; }));
EXPECT_EQ(continuation, 0);
p.setValue(42);
EXPECT_EQ(continuation, 42);
......
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