Skip to content

Commit 62db095

Browse files
Avinash Singhmeta-codesync[bot]
authored andcommitted
Revert D92590863: result no longer implemented via Expected
Differential Revision: D92590863 Original commit changeset: cb03bf8cb184 Original Phabricator Diff: D92590863 fbshipit-source-id: a133dc05c95c40d9c0afd19e62863bfdd63e104f
1 parent a5d9981 commit 62db095

File tree

6 files changed

+224
-360
lines changed

6 files changed

+224
-360
lines changed

folly/result/detail/result_or_unwind.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,13 @@ class result_or_unwind_crtp : public result_or_unwind_base<Derived, Storage> {
183183
void await_suspend(result_promise_handle<U> h) noexcept {
184184
auto toResult = [&](auto&& eos) {
185185
auto& v = *h.promise().value_;
186+
expected_detail::ExpectedHelper::assume_empty(v.exp_);
186187
// For lvalue `Storage` (e.g. `result<T>&`), `storage()` returns a ref,
187188
// and `result::error_or_stopped() const&` returns `const
188-
// error_or_stopped&`, which gets copied into `eos_` -- preserving the
189-
// original result. This is intentional: users don't expect `co_await
189+
// error_or_stopped&`, which gets copied into `Unexpected` -- preserving
190+
// the original result. This is intentional: users don't expect `co_await
190191
// or_unwind(r)` to mutate `r`, since `r` might outlive the current coro.
191-
v.eos_ = static_cast<decltype(eos)>(eos);
192+
v.exp_ = Unexpected{static_cast<decltype(eos)>(eos)};
192193
h.destroy(); // Abort the rest of the coroutine, resume() won't be called
193194
};
194195
if constexpr (Base::kIsErrorOrStopped) {

folly/result/detail/result_promise.h

Lines changed: 16 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
#pragma once
1818

19-
#include <folly/Utility.h>
2019
#include <folly/coro/Coroutine.h> // delete with clang-15 support
2120
#include <folly/result/result.h>
2221

@@ -31,15 +30,13 @@ template <typename>
3130
struct result_promise_base;
3231

3332
template <typename T>
34-
class result_promise_return {
35-
private:
36-
result<T> storage_{typename result<T>::has_value_sigil_t{}};
37-
result<T>*& ptr_;
33+
struct result_promise_return {
34+
result<T> storage_{expected_detail::EmptyTag{}};
35+
result<T>*& pointer_;
3836

39-
public:
4037
/* implicit */ result_promise_return(result_promise_base<T>& p) noexcept
41-
: ptr_{p.value_} {
42-
ptr_ = &storage_;
38+
: pointer_{p.value_} {
39+
pointer_ = &storage_;
4340
}
4441
result_promise_return(result_promise_return const&) = delete;
4542
void operator=(result_promise_return const&) = delete;
@@ -52,15 +49,14 @@ class result_promise_return {
5249
/* implicit */ operator result<T>() {
5350
// Simplify this once clang 15 is well-forgotten, and remove the dep on
5451
// `Coroutine.h`. From D42260201: handle both deferred and eager
55-
// return-object conversion behaviors; see docs for
52+
// return-object conversion behaviors see docs for
5653
// detect_promise_return_object_eager_conversion
57-
//
58-
// Storage is in "has value" sigil state with uninitialized `value_`;
59-
// `return_value` / `unhandled_exception` will initialize it.
60-
if (coro::detect_promise_return_object_eager_conversion()) { // eager
61-
return result<T>{typename result<T>::has_value_sigil_t{}, ptr_};
62-
} else { // deferred
63-
return std::move(storage_);
54+
if (coro::detect_promise_return_object_eager_conversion()) {
55+
assert(storage_.is_expected_empty());
56+
return result<T>{expected_detail::EmptyTag{}, pointer_}; // eager
57+
} else {
58+
assert(!storage_.is_expected_empty());
59+
return std::move(storage_); // deferred
6460
}
6561
}
6662
};
@@ -79,9 +75,7 @@ struct result_promise_base {
7975
std::suspend_never initial_suspend() const noexcept { return {}; }
8076
std::suspend_never final_suspend() const noexcept { return {}; }
8177
void unhandled_exception() noexcept {
82-
// Directly set `eos_` -- using `result` assignment would try to destroy
83-
// uninitialized `value_` (UB since we start in "has value" sigil state).
84-
value_->eos_ = error_or_stopped::from_current_exception();
78+
*value_ = result<T>{error_or_stopped::from_current_exception()};
8579
}
8680

8781
result_promise_return<T> get_return_object() noexcept { return *this; }
@@ -96,35 +90,17 @@ struct result_promise<T, typename std::enable_if<!std::is_void_v<T>>::type>
9690
// The default for `U` is tested in `returnImplicitCtor`.
9791
template <typename U = T>
9892
void return_value(U&& u) {
99-
// We're in "has value" sigil state with uninitialized `value_`. Use
100-
// placement `new` -- NEVER assignment, which would call `operator=(T&)` on
101-
// garbage (UB!). This supports non-default-constructible `T`, helps perf.
10293
auto& v = *this->value_;
103-
if constexpr (std::is_same_v<std::remove_cvref_t<U>, error_or_stopped>) {
104-
v.eos_ = static_cast<U&&>(u);
105-
} else if constexpr (std::is_same_v<std::remove_cvref_t<U>, result<T>>) {
106-
// Returning `result<T>` (with `T` matching ours) acts like `or_unwind()`:
107-
if (static_cast<U&&>(u).has_value()) {
108-
return_value(static_cast<U&&>(u).value_or_throw());
109-
} else {
110-
// NOLINTNEXTLINE(facebook-hte-MissingStdForward): false positive
111-
return_value(forward_like<U>(u.eos_));
112-
}
113-
} else {
114-
// Returning a value; `eos_` already says "has value"
115-
new (&v.value_)
116-
typename std::remove_reference_t<decltype(v)>::storage_type(
117-
static_cast<U&&>(u));
118-
}
94+
expected_detail::ExpectedHelper::assume_empty(v.exp_);
95+
v = static_cast<U&&>(u);
11996
}
12097
};
12198

12299
template <typename T>
123100
struct result_promise<T, typename std::enable_if<std::is_void_v<T>>::type>
124101
: public result_promise_base<T> {
125102
// You can fail via `co_await err` since void coros only allow `co_return;`.
126-
// NB: `has_value_sigil_t` sets `eos_` to "has value", nothing to do.
127-
void return_void() {}
103+
void return_void() { this->value_->exp_.emplace(unit); }
128104
};
129105

130106
template <typename T> // Need an alias since nested types cannot be deduced.

folly/result/result.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
namespace folly {
2727
namespace detail {
2828

29+
const error_or_stopped& dfatal_get_empty_result_error() {
30+
static const folly::Indestructible<error_or_stopped> r{empty_result_error{}};
31+
LOG(DFATAL) << "`folly::result` had an empty underlying `folly::Expected`";
32+
return *r;
33+
}
34+
2935
const error_or_stopped& dfatal_get_bad_result_access_error() {
3036
static const folly::Indestructible<error_or_stopped> r{
3137
bad_result_access_error{}};

0 commit comments

Comments
 (0)