Precursor changes to minimize diff for optional support.

* Comment tweaks
* A few appropriate-seeming constraints
* Better way of invoking invoke()
* More test cases
* Be consistent about (actual, expected) order

Bug: none
Change-Id: I4725dcc647f8727952f997c6b334d1476656be75
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6192027
Auto-Submit: Peter Kasting <pkasting@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1409958}
diff --git a/base/types/expected_macros.h b/base/types/expected_macros.h
index eea12b2c..50c6ac5 100644
--- a/base/types/expected_macros.h
+++ b/base/types/expected_macros.h
@@ -12,18 +12,20 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros/concat.h"
+#include "base/macros/if.h"
+#include "base/macros/is_empty.h"
 #include "base/macros/remove_parens.h"
 #include "base/macros/uniquify.h"
 #include "base/memory/raw_ptr_exclusion.h"
 #include "base/types/expected.h"
 
-// Executes an expression `rexpr` that returns a `base::expected<T, E>`. If the
+// Executes an expression `rexpr` that returns an `expected<T, E>`. If the
 // result is an error, causes the calling function to return. If no additional
 // arguments are given, the function return value is the `E` returned by
 // `rexpr`. Otherwise, the additional arguments are treated as an invocable that
 // expects an E as its last argument and returns some type (including `void`)
 // convertible to the function's return type; that is, the function returns the
-// result of `std::invoke(..., E)`.
+// result of `std::invoke(..., E)` on the additional arguments.
 //
 // This works with move-only types and can be used in functions that return
 // either an `E` directly or a `base::expected<U, E>`, without needing to
@@ -96,10 +98,10 @@
                                    BASE_UNIQUIFY(_expected_value), rexpr,  \
                                    __VA_ARGS__)
 
-// Executes an expression `rexpr` that returns a `base::expected<T, E>`. If the
-// result is an expected value, moves the `T` into whatever `lhs` defines/refers
-// to; otherwise, behaves like RETURN_IF_ERROR() above. Avoid side effects in
-// `lhs`, as it will not be evaluated in the error case.
+// Executes an expression `rexpr` that returns an `expected<T, E>`. If the
+// result is not an error, moves the `T` into whatever `lhs` defines/refers to;
+// otherwise, behaves like RETURN_IF_ERROR() above. Avoid side effects in `lhs`,
+// as it will not be evaluated in the error case.
 //
 // # Interface
 //
@@ -209,7 +211,7 @@
 // the error of an `expected<T, E>`. Supports move-only `E`, as well as `void`.
 //
 // In order to support `void` return types, `UnexpectedDeducer` is not
-// constructed directly from an `E`, but from a lambda that returns `E`; and
+// constructed directly with an `E`, but with a lambda that returns `E`; and
 // callers must return `Ret()` rather than returning the deducer itself. Using
 // both these indirections allows consistent invocation from macros.
 template <typename Lambda, typename E = std::invoke_result_t<Lambda&&>>
@@ -230,11 +232,17 @@
   // arbitrary `T`) or `E`.
   template <typename T>
   // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr operator expected<T, E>() && noexcept {
+  constexpr operator expected<T, E>() && noexcept
+    requires(!std::is_void_v<E>)
+  {
     return expected<T, E>(unexpect, std::move(lambda_)());
   }
   // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr operator E() && noexcept { return std::move(lambda_)(); }
+  constexpr operator E() && noexcept
+    requires(!std::is_void_v<E>)
+  {
+    return std::move(lambda_)();
+  }
 
  private:
   // RAW_PTR_EXCLUSION: Not intended to handle &&-qualified members.
@@ -253,23 +261,19 @@
 
 #define BASE_INTERNAL_EXPECTED_PASS_ARGS(func, ...) func(__VA_ARGS__)
 
-// These are necessary to avoid mismatched parens inside __VA_OPT__() below.
-#define BASE_INTERNAL_EXPECTED_BEGIN_INVOKE std::invoke(
-#define BASE_INTERNAL_EXPECTED_END_INVOKE )
-
-#define BASE_INTERNAL_EXPECTED_BODY(expected, rexpr, name, ...)              \
-  decltype(auto) expected = (rexpr);                                         \
-  {                                                                          \
-    static_assert(base::internal::IsExpected<decltype(expected)>,            \
-                  #name " should only be used with base::expected<>");       \
-  }                                                                          \
-  if (!expected.has_value()) [[unlikely]] {                                  \
-    return base::internal::UnexpectedDeducer([&] {                           \
-             return __VA_OPT__(BASE_INTERNAL_EXPECTED_BEGIN_INVOKE)          \
-                 __VA_ARGS__ __VA_OPT__(, ) std::move(expected)              \
-                     .error() __VA_OPT__(BASE_INTERNAL_EXPECTED_END_INVOKE); \
-           })                                                                \
-        .Ret();                                                              \
+#define BASE_INTERNAL_EXPECTED_BODY(expected, rexpr, name, ...)           \
+  decltype(auto) expected = (rexpr);                                      \
+  {                                                                       \
+    static_assert(base::internal::IsExpected<decltype(expected)>,         \
+                  #name " should only be used with base::expected<>");    \
+  }                                                                       \
+  if (!expected.has_value()) [[unlikely]] {                               \
+    return base::internal::UnexpectedDeducer([&] {                        \
+             return BASE_IF(                                              \
+                 BASE_IS_EMPTY(__VA_ARGS__), std::move(expected).error(), \
+                 std::invoke(__VA_ARGS__, std::move(expected).error()));  \
+           })                                                             \
+        .Ret();                                                           \
   }
 
 #define BASE_INTERNAL_EXPECTED_RETURN_IF_ERROR(expected, rexpr, ...) \
@@ -279,7 +283,6 @@
   } while (false)
 
 #define BASE_INTERNAL_EXPECTED_ASSIGN_OR_RETURN(lhs, expected, rexpr, ...)     \
-  BASE_INTERNAL_EXPECTED_BODY(expected, rexpr, ASSIGN_OR_RETURN, __VA_ARGS__); \
   {                                                                            \
     constexpr auto lhs_v = std::string_view(#lhs);                             \
     static_assert(!(lhs_v.front() == '(' && lhs_v.back() == ')' &&             \
@@ -288,6 +291,7 @@
                   "parenthesized expressions containing '?' to the first "     \
                   "argument of ASSIGN_OR_RETURN()");                           \
   }                                                                            \
+  BASE_INTERNAL_EXPECTED_BODY(expected, rexpr, ASSIGN_OR_RETURN, __VA_ARGS__); \
   BASE_REMOVE_PARENS(lhs) = std::move(expected).value();
 
 #endif  // BASE_TYPES_EXPECTED_MACROS_H_
diff --git a/base/types/expected_macros_unittest.cc b/base/types/expected_macros_unittest.cc
index 695f84d0..70fc026 100644
--- a/base/types/expected_macros_unittest.cc
+++ b/base/types/expected_macros_unittest.cc
@@ -57,12 +57,15 @@
 TEST(ReturnIfError, Works) {
   const auto func = []() -> std::string {
     RETURN_IF_ERROR(ReturnOk());
-    RETURN_IF_ERROR(ReturnOk());
+    expected<int, std::string> e_int1 = 1;
+    RETURN_IF_ERROR(e_int1);
+    const expected<int, std::string> e_int2 = 2;
+    RETURN_IF_ERROR(e_int2);
     RETURN_IF_ERROR(ReturnError("EXPECTED"));
     return "ERROR";
   };
 
-  EXPECT_EQ("EXPECTED", func());
+  EXPECT_EQ(func(), "EXPECTED");
 }
 
 TEST(ReturnIfError, WorksWithExpectedReturn) {
@@ -83,7 +86,7 @@
     return "ERROR";
   };
 
-  EXPECT_EQ("EXPECTED", func());
+  EXPECT_EQ(func(), "EXPECTED");
 }
 
 TEST(ReturnIfError, WorksWithMoveOnlyType) {
@@ -116,7 +119,7 @@
     return "ERROR";
   };
 
-  EXPECT_EQ("EXPECTED A EXPECTED B", func());
+  EXPECT_EQ(func(), "EXPECTED A EXPECTED B");
 }
 
 TEST(ReturnIfError, WorksWithAdaptorFuncAndExpectedReturn) {
@@ -173,27 +176,33 @@
 TEST(AssignOrReturn, Works) {
   const auto func = []() -> std::string {
     ASSIGN_OR_RETURN(int value1, ReturnValue(1));
-    EXPECT_EQ(1, value1);
+    EXPECT_EQ(value1, 1);
     ASSIGN_OR_RETURN(const int value2, ReturnValue(2));
-    EXPECT_EQ(2, value2);
+    EXPECT_EQ(value2, 2);
     ASSIGN_OR_RETURN(const int& value3, ReturnValue(3));
-    EXPECT_EQ(3, value3);
-    ASSIGN_OR_RETURN([[maybe_unused]] const int value4,
+    EXPECT_EQ(value3, 3);
+    expected<int, std::string> e_int4 = 4;
+    ASSIGN_OR_RETURN(int value4, e_int4);
+    EXPECT_EQ(value4, 4);
+    const expected<int, std::string> e_int5 = 5;
+    ASSIGN_OR_RETURN(int value5, e_int5);
+    EXPECT_EQ(value5, 5);
+    ASSIGN_OR_RETURN([[maybe_unused]] const int value6,
                      ReturnError("EXPECTED"));
     return "ERROR";
   };
 
-  EXPECT_EQ("EXPECTED", func());
+  EXPECT_EQ(func(), "EXPECTED");
 }
 
 TEST(AssignOrReturn, WorksWithExpectedReturn) {
   const auto func = []() -> expected<void, std::string> {
     ASSIGN_OR_RETURN(int value1, ReturnValue(1));
-    EXPECT_EQ(1, value1);
+    EXPECT_EQ(value1, 1);
     ASSIGN_OR_RETURN(const int value2, ReturnValue(2));
-    EXPECT_EQ(2, value2);
+    EXPECT_EQ(value2, 2);
     ASSIGN_OR_RETURN(const int& value3, ReturnValue(3));
-    EXPECT_EQ(3, value3);
+    EXPECT_EQ(value3, 3);
     ASSIGN_OR_RETURN([[maybe_unused]] const int value4,
                      ReturnError("EXPECTED"));
     return ok();
@@ -205,13 +214,13 @@
 TEST(AssignOrReturn, WorksWithLambda) {
   const auto func = []() -> std::string {
     ASSIGN_OR_RETURN(const int value1, [] { return ReturnValue(1); }());
-    EXPECT_EQ(1, value1);
+    EXPECT_EQ(value1, 1);
     ASSIGN_OR_RETURN([[maybe_unused]] const int value2,
                      [] { return ReturnError("EXPECTED"); }());
     return "ERROR";
   };
 
-  EXPECT_EQ("EXPECTED", func());
+  EXPECT_EQ(func(), "EXPECTED");
 }
 
 TEST(AssignOrReturn, WorksWithMoveOnlyType) {
@@ -237,33 +246,33 @@
 TEST(AssignOrReturn, WorksWithCommasInType) {
   const auto func = []() -> std::string {
     ASSIGN_OR_RETURN((const std::tuple<int, int> t1), ReturnTupleValue(1, 1));
-    EXPECT_EQ((std::tuple(1, 1)), t1);
+    EXPECT_EQ(t1, (std::tuple(1, 1)));
     ASSIGN_OR_RETURN((const std::tuple<int, std::tuple<int, int>, int> t2),
                      ReturnTupleValue(1, std::tuple(1, 1), 1));
-    EXPECT_EQ((std::tuple(1, std::tuple(1, 1), 1)), t2);
+    EXPECT_EQ(t2, (std::tuple(1, std::tuple(1, 1), 1)));
     ASSIGN_OR_RETURN(
         ([[maybe_unused]] const std::tuple<int, std::tuple<int, int>, int> t3),
         (ReturnTupleError<int, std::tuple<int, int>, int>("EXPECTED")));
     return "ERROR";
   };
 
-  EXPECT_EQ("EXPECTED", func());
+  EXPECT_EQ(func(), "EXPECTED");
 }
 
 TEST(AssignOrReturn, WorksWithStructuredBindings) {
   const auto func = []() -> std::string {
     ASSIGN_OR_RETURN((const auto& [t1, t2, t3, t4, t5]),
                      ReturnTupleValue(std::tuple(1, 1), 1, 2, 3, 4));
-    EXPECT_EQ((std::tuple(1, 1)), t1);
-    EXPECT_EQ(1, t2);
-    EXPECT_EQ(2, t3);
-    EXPECT_EQ(3, t4);
-    EXPECT_EQ(4, t5);
+    EXPECT_EQ(t1, (std::tuple(1, 1)));
+    EXPECT_EQ(t2, 1);
+    EXPECT_EQ(t3, 2);
+    EXPECT_EQ(t4, 3);
+    EXPECT_EQ(t5, 4);
     ASSIGN_OR_RETURN([[maybe_unused]] int t6, ReturnError("EXPECTED"));
     return "ERROR";
   };
 
-  EXPECT_EQ("EXPECTED", func());
+  EXPECT_EQ(func(), "EXPECTED");
 }
 
 TEST(AssignOrReturn, WorksWithParenthesesAndDereference) {
@@ -271,19 +280,19 @@
     int integer;
     int* pointer_to_integer = &integer;
     ASSIGN_OR_RETURN((*pointer_to_integer), ReturnValue(1));
-    EXPECT_EQ(1, integer);
+    EXPECT_EQ(integer, 1);
     ASSIGN_OR_RETURN(*pointer_to_integer, ReturnValue(2));
-    EXPECT_EQ(2, integer);
+    EXPECT_EQ(integer, 2);
     // Test where the order of dereference matters.
-    pointer_to_integer--;
+    --pointer_to_integer;
     int* const* const pointer_to_pointer_to_integer = &pointer_to_integer;
     ASSIGN_OR_RETURN((*pointer_to_pointer_to_integer)[1], ReturnValue(3));
-    EXPECT_EQ(3, integer);
+    EXPECT_EQ(integer, 3);
     ASSIGN_OR_RETURN([[maybe_unused]] const int t1, ReturnError("EXPECTED"));
     return "ERROR";
   };
 
-  EXPECT_EQ("EXPECTED", func());
+  EXPECT_EQ(func(), "EXPECTED");
 }
 
 TEST(AssignOrReturn, WorksWithAdaptorFunc) {
@@ -293,13 +302,13 @@
   };
   const auto adaptor = [](std::string error) { return error + " EXPECTED B"; };
   const auto func = [&]() -> std::string {
-    ASSIGN_OR_RETURN([[maybe_unused]] int value, ReturnValue(1),
-                     fail_test_if_called);
+    ASSIGN_OR_RETURN(int value, ReturnValue(1), fail_test_if_called);
+    EXPECT_EQ(value, 1);
     ASSIGN_OR_RETURN(value, ReturnError("EXPECTED A"), adaptor);
     return "ERROR";
   };
 
-  EXPECT_EQ("EXPECTED A EXPECTED B", func());
+  EXPECT_EQ(func(), "EXPECTED A EXPECTED B");
 }
 
 TEST(AssignOrReturn, WorksWithAdaptorFuncAndExpectedReturn) {
@@ -372,7 +381,7 @@
     return "ERROR";
   };
 
-  EXPECT_EQ("EXPECTED A EXPECTED B", func());
+  EXPECT_EQ(func(), "EXPECTED A EXPECTED B");
 }
 
 TEST(AssignOrReturn, WorksWithAppendIncludingLocals) {
@@ -383,21 +392,21 @@
     return "ERROR";
   };
 
-  EXPECT_EQ("EXPECTED A EXPECTED B", func(" EXPECTED B"));
+  EXPECT_EQ(func(" EXPECTED B"), "EXPECTED A EXPECTED B");
 }
 
 TEST(AssignOrReturn, WorksForExistingVariable) {
   const auto func = []() -> std::string {
     int value = 1;
     ASSIGN_OR_RETURN(value, ReturnValue(2));
-    EXPECT_EQ(2, value);
+    EXPECT_EQ(value, 2);
     ASSIGN_OR_RETURN(value, ReturnValue(3));
-    EXPECT_EQ(3, value);
+    EXPECT_EQ(value, 3);
     ASSIGN_OR_RETURN(value, ReturnError("EXPECTED"));
     return "ERROR";
   };
 
-  EXPECT_EQ("EXPECTED", func());
+  EXPECT_EQ(func(), "EXPECTED");
 }
 
 TEST(AssignOrReturn, UniquePtrWorks) {
@@ -407,7 +416,7 @@
     return "EXPECTED";
   };
 
-  EXPECT_EQ("EXPECTED", func());
+  EXPECT_EQ(func(), "EXPECTED");
 }
 
 TEST(AssignOrReturn, UniquePtrWorksForExistingVariable) {
@@ -421,7 +430,7 @@
     return "EXPECTED";
   };
 
-  EXPECT_EQ("EXPECTED", func());
+  EXPECT_EQ(func(), "EXPECTED");
 }
 
 }  // namespace