[fit] Always pass results to continuations by reference.

The API previously supported passing copyable results by value whereas movable
results had to be passed by reference.  This behavior was frequently confusing
to developers and had hidden costs such as unintended copying.

Now results are always passed by reference.  Amended the examples, documentation,
tests, and existing code accordingly.

Test: fit-test
Change-Id: I4865f6f701d5c859c350798789f0ed366ab228fb
diff --git a/garnet/bin/guest/vmm/device/virtio_net.cc b/garnet/bin/guest/vmm/device/virtio_net.cc
index a402458..067cc73 100644
--- a/garnet/bin/guest/vmm/device/virtio_net.cc
+++ b/garnet/bin/guest/vmm/device/virtio_net.cc
@@ -193,10 +193,10 @@
 
     executor_.schedule_task(
         AddEthernetDevice(kInterfacePath, std::move(config))
-            .and_then([this, addr = std::move(addr)](uint32_t nic_id) mutable {
+            .and_then([this, addr = std::move(addr)](const uint32_t& nic_id) mutable {
               return SetInterfaceAddress(nic_id, std::move(addr));
             })
-            .and_then([this](uint32_t nic_id) mutable {
+            .and_then([this](const uint32_t& nic_id) mutable {
               netstack_->SetInterfaceStatus(nic_id, true);
             })
             .or_else([]() mutable {
diff --git a/garnet/public/lib/inspect/reader.cc b/garnet/public/lib/inspect/reader.cc
index de611e9..2982ab4 100644
--- a/garnet/public/lib/inspect/reader.cc
+++ b/garnet/public/lib/inspect/reader.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "lib/inspect/reader.h"
-
 #include <lib/inspect-vmo/block.h>
 #include <lib/inspect-vmo/scanner.h>
 #include <lib/inspect-vmo/snapshot.h>
@@ -15,6 +13,7 @@
 #include "fuchsia/inspect/cpp/fidl.h"
 #include "lib/fit/bridge.h"
 #include "lib/inspect/hierarchy.h"
+#include "lib/inspect/reader.h"
 
 namespace inspect {
 
@@ -110,7 +109,7 @@
   ObjectReader reader(child_ptr.Unbind());
   return bridge.consumer.promise_or(fit::error())
       .and_then([ret = std::move(reader)](
-                    bool success) mutable -> fit::result<ObjectReader> {
+                    const bool& success) mutable -> fit::result<ObjectReader> {
         if (success) {
           return fit::ok(ObjectReader(std::move(ret)));
         } else {
diff --git a/garnet/tests/zircon/libdriver-integration-test/integration-test.cc b/garnet/tests/zircon/libdriver-integration-test/integration-test.cc
index 07647b7..485fa09 100644
--- a/garnet/tests/zircon/libdriver-integration-test/integration-test.cc
+++ b/garnet/tests/zircon/libdriver-integration-test/integration-test.cc
@@ -76,7 +76,7 @@
 void IntegrationTest::RunPromise(Promise<void> promise, zx::time deadline) {
     async::Executor executor(loop_.dispatcher());
 
-    auto new_promise = promise.then([&](Promise<void>::result_type result) {
+    auto new_promise = promise.then([&](Promise<void>::result_type& result) {
         if (result.is_error()) {
             ADD_FAILURE() << result.error();
         }
diff --git a/garnet/tests/zircon/libdriver-integration-test/integration-test.h b/garnet/tests/zircon/libdriver-integration-test/integration-test.h
index d5eb899..68a6463 100644
--- a/garnet/tests/zircon/libdriver-integration-test/integration-test.h
+++ b/garnet/tests/zircon/libdriver-integration-test/integration-test.h
@@ -105,7 +105,7 @@
     // the returned promise fails.
     auto JoinPromises(Promise<void> promise1, Promise<void> promise2) {
         return join_promises(std::move(promise1), std::move(promise2))
-            .then([](fit::result<std::tuple<Result<void>, Result<void>>> wrapped_results)
+            .then([](fit::result<std::tuple<Result<void>, Result<void>>>& wrapped_results)
                   -> Result<void> {
                 // join_promises() can't fail, so just extract the value
                 auto results = wrapped_results.value();
diff --git a/peridot/bin/sessionmgr/story/model/ledger_story_model_storage.cc b/peridot/bin/sessionmgr/story/model/ledger_story_model_storage.cc
index ac439c3..a08cf8c 100644
--- a/peridot/bin/sessionmgr/story/model/ledger_story_model_storage.cc
+++ b/peridot/bin/sessionmgr/story/model/ledger_story_model_storage.cc
@@ -364,7 +364,7 @@
            // result in an error.
            return fit::join_promises(std::move(update_device_state_promise),
                                      std::move(update_shared_state_promise))
-               .and_then([](std::tuple<fit::result<>, fit::result<>> results)
+               .and_then([](std::tuple<fit::result<>, fit::result<>>& results)
                              -> fit::result<> {
                  auto [device_result, shared_result] = results;
                  if (device_result.is_error() || shared_result.is_error()) {
diff --git a/src/connectivity/network/testing/netemul/runner/helpers/netstack_intermediary/netstack_intermediary.cc b/src/connectivity/network/testing/netemul/runner/helpers/netstack_intermediary/netstack_intermediary.cc
index 6cae26d..36da938 100644
--- a/src/connectivity/network/testing/netemul/runner/helpers/netstack_intermediary/netstack_intermediary.cc
+++ b/src/connectivity/network/testing/netemul/runner/helpers/netstack_intermediary/netstack_intermediary.cc
@@ -60,7 +60,7 @@
                 return SetupEthClient(std::move(net));
               })
           .and_then([this, callback = std::move(callback)](
-                        zx_status_t status) mutable {
+                        const zx_status_t& status) mutable {
             // The FakeEndpoint's OnData method fires when new data is observed
             // on the netemul virtual network.
             fake_ep_.events().OnData = [this](std::vector<uint8_t> data) {
diff --git a/src/connectivity/network/testing/netemul/runner/sandbox.cc b/src/connectivity/network/testing/netemul/runner/sandbox.cc
index 935cf64..5fd998f 100644
--- a/src/connectivity/network/testing/netemul/runner/sandbox.cc
+++ b/src/connectivity/network/testing/netemul/runner/sandbox.cc
@@ -360,7 +360,7 @@
 
                return fit::ok(std::move(child_env));
              })
-      .and_then([this, config](ConfiguringEnvironmentPtr child_env) {
+      .and_then([this, config](ConfiguringEnvironmentPtr& child_env) {
         return ConfigureEnvironment(std::move(child_env), config);
       });
 }
@@ -452,7 +452,7 @@
   }
 
   return fit::join_promise_vector(std::move(promises))
-      .and_then([](std::vector<fit::result<>> results) -> fit::result<> {
+      .and_then([](std::vector<fit::result<>>& results) -> fit::result<> {
         for (const auto& r : results) {
           if (r.is_error()) {
             return fit::error();
diff --git a/zircon/docs/fit_promise_guide.md b/zircon/docs/fit_promise_guide.md
index 58ac355..b714a48 100644
--- a/zircon/docs/fit_promise_guide.md
+++ b/zircon/docs/fit_promise_guide.md
@@ -56,10 +56,10 @@
 As mentioned above, the template arguments for `fit::promise<>` represent the return and error types:
 
 ```cpp
-fit::promise<ReturnType, ErrorType>
+fit::promise<ValueType, ErrorType>
 ```
 
-The error type can be omitted and it will take the default error type of `void` (e.g. `fit::promise<MyReturnType>` is equivalent to `fit::promise<MyReturnType, void>`).
+The error type can be omitted and it will take the default error type of `void` (e.g. `fit::promise<MyValueType>` is equivalent to `fit::promise<MyValueType, void>`).
 
 During execution, a promise must eventually reach one of the following states:
 
@@ -71,11 +71,11 @@
 
 Often complex tasks can be decomposed into smaller more granular tasks. Each of these tasks needs to be asynchronously executed, but if there is some dependency between the tasks, there is a need to preserve them. This can be achieved through different combinators, such as:
 
-* `fit::promise::then()` becomes useful for defining task dependency, as execute task 1 then task 2, regardless of task 1's status.
+* `fit::promise::then()` becomes useful for defining task dependency, as execute task 1 then task 2, regardless of task 1's status.  The prior task's result is received through an argument of type `fit::result<ValueType, ErrorType>&` or `const fit::result<ValueType, ErrorType>&`.
 ```cpp
-auto execute_task_1_then_task_2 = fit::make_promise([] () -> fit::result<ReturnType, ErrorType> {
-     …..;
-}).then([] (fit::result<ReturnType, ErrorType>& result) {
+auto execute_task_1_then_task_2 = fit::make_promise([] () -> fit::result<ValueType, ErrorType> {
+  ...
+}).then([] (fit::result<ValueType, ErrorType>& result) {
     if (result.is_ok()) {
       ...
     } else {  // result.is_error()
@@ -84,21 +84,21 @@
 });
 ```
 
-* `fit::promise::and_then()` becomes useful for defining task dependency only in the case of task 1's success.
+* `fit::promise::and_then()` becomes useful for defining task dependency only in the case of task 1's success.  The prior task's result is received through an argument of type `ValueType&` or `ValueType&`.
 ```cpp
 auto execute_task_1_then_task_2 = fit::make_promise([] () {
   ...
-}).and_then([] (ReturnType& success_value) {
+}).and_then([] (ValueType& success_value) {
   ...
 });
 ```
 
-* `fit::promise::or_else()` becomes useful for defining task dependency only in the case of task 1's failure.
+* `fit::promise::or_else()` becomes useful for defining task dependency only in the case of task 1's failure.  The prior task's result is received through an argument of type `ErrorType&` or `const ErrorType&`.
 ```cpp
 auto execute_task_1_then_task_2 = fit::make_promise([] () {
-  ...;
+  ...
 }).or_else([] (ErrorType& failure_value) {
-  ...;
+  ...
 });
 ```
 
@@ -106,27 +106,40 @@
 
 Sometimes, multiple promises can be executed with no dependencies between them, but the aggregate result is a dependency of the next asynchronous step. In this case, `fit::join_promises()` and `fit::join_promise_vector()` are used to join on the results of multiple promises.
 
-`fit::join_promises()` is used when each promise is referenced by a variable. `fit::join_promises()` supports heterogeneous promise types.
+`fit::join_promises()` is used when each promise is referenced by a variable. `fit::join_promises()` supports heterogeneous promise types.  The prior tasks' results are received through an argument of type `std::tuple<...>&` or `const std::tuple<...>&`.
 ```cpp
 auto DoImportantThingsInParallel() {
   auto promise1 = FetchStringFromDbAsync("foo");
   auto promise2 = InitializeFrobinatorAsync();
   return fit::join_promises(std::move(promise1), std::move(promise2))
-      .and_then([] (std::tuple<fit::result<std::string>, fit::result<Frobinator>> results) {
+      .and_then([] (std::tuple<fit::result<std::string>, fit::result<Frobinator>>& results) {
         return fit::ok(std::get<0>(results).value() + std::get<1>(results).value().GetFrobinatorSummary());
       });
 }
 ```
 
-`fit::join_promise_vector()` is used when the promises are stored in `std::vector<>`. This has the added constraint that all promises must be homogeneous (be of the same type).
+`fit::join_promise_vector()` is used when the promises are stored in `std::vector<>`. This has the added constraint that all promises must be homogeneous (be of the same type).  The prior tasks' results are received through an argument of type `std::vector<fit::result<ValueType, ErrorType>>&` or `const std::vector<fit::result<ValueType, ErrorType>>&`.
+```cpp
+auto ConcatenateImportantThingsDoneInParallel() {
+  std::vector<fit::promise<std::string>> promises;
+  promises.push_back(FetchStringFromDbAsync("foo"));
+  promises.push_back(FetchStringFromDbAsync("bar"));
+  return fit::join_promise_vector(std::move(promises))
+      .and_then([] (std::vector<fit::result<std::string>>& results) {
+        return fit::ok(results[0].value() + "," + results[1].value());
+      });
+}
+```
 
 ### `return fit::make_promise()`: Chaining or branching by returning new promises
 
 It may become useful to defer the decision of which promises to chain together until runtime. This method is in contrast with chaining that is performed syntactically (through the use of consecutive `.then()`, `.and_then()` and `.or_else()` calls).
 
+Instead of returning a `fit::result<...>` (using `fit::ok` or `fit::error`), the handler function may return a new promise which will be evaluated after the handler function returns.
+
 ```cpp
 fit::make_promise(...)
-  .then([] (fit::result<> result) {
+  .then([] (fit::result<>& result) {
     if (result.is_ok()) {
       return fit::make_promise(...); // Do work in success case.
     } else {
@@ -163,7 +176,7 @@
     state->i++;
   }).and_then([state = state.get()] {
     state->i--;
-  }).inspect([state = std::move(state)] {});
+  }).inspect([state = std::move(state)] (const fit::result<>&) {});
 }
 ```
 
@@ -242,11 +255,42 @@
 
 ## Common gotchas
 
-### It is not possible to change ErrorType mid-promise
+### Sequences of `and_then` or `or_else` must have compatible types
 
-A promise's handler and all of its continuations may have different *ResultTypes*, but they must all share the same *ErrorType*.
+When building promises using `and_then`, each successive continuation may have a different *ValueType* but must have the same *ErrorType* because `and_then` forwards prior errors without consuming them.
 
-TODO: write more and how to get around this problem
+When building promises using `or_else`, each successive continuation may have a different *ErrorType* but must have the same *ValueType* because `or_else` forwards prior values without consuming them.
+
+To change types in the middle of the sequence, use `then` to consume the prior result and produce a new result of the desired type.
+
+The following example does not compile because the error type returned by the the last `and_then` handler is incompatible with the prior handler's result.
+```cpp
+auto a = fit::make_promise([] {
+  // returns fit::result<int, void>
+  return fit::ok(4);
+}).and_then([] (const int& value) {
+  // returns fit::result<float, void>
+  return fit::ok(value * 2.2f);
+}).and_then([] (const float& value) {
+  // ERROR!  Prior result had "void" error type but this handler returns const char*.
+  if (value >= 0)
+    return fit::ok(value);
+  return fit::error("bad value");
+}
+
+Use `then` to consume the result and change its type:
+```cpp
+auto a = fit::make_promise([] {
+  // returns fit::result<int, void>
+  return fit::ok(4);
+}).and_then([] (const int& value) {
+  // returns fit::result<float, void>
+  return fit::ok(value * 2.2f);
+}).then([] (const fit::result<float>& result) -> fit::result<float, const char*> {
+  if (result.is_ok() && result.value() >= 0)
+    return fit::ok(value);
+  return fit::error("bad value");
+}
 
 ### Handlers / continuation functions can return fit::result<> or a new fit::promise<>, not both
 
@@ -262,20 +306,20 @@
   return fit::make_promise([] { return fit::ok(); });
 });
 ```
+
 ### Continuation signatures
 
 Have you seen an error message like this?
 
 ```
-../../zircon/system/ulib/fit/include/lib/fit/promise_internal.h:342:5: error: static_assert failed "The provided handler's last argument was expected to be of type V&, const V&, or V (if the value is copy-constructible).  Please refer to the combinator's documentation for
+../../zircon/system/ulib/fit/include/lib/fit/promise_internal.h:342:5: error: static_assert failed "The provided handler's last argument was expected to be of type V& or const V& where V is the prior result's value type and E is the prior result's error type.  Please refer to the combinator's documentation for
  a list of supported handler function signatures."
 ```
 
 or:
 
 ```
-../../zircon/system/ulib/fit/include/lib/fit/promise.h:288:5: error: static_assert failed due to requirement '::fit::internal::is_continuation<fit::internal::and_then_continuation<fit::promise_impl<fit::function_impl<16, false, fit::result<fuchsia::modular::storymodel::St
-oryModel, void> (fit::context &)> >, (lambda at ../../peridot/bin/sessionmgr/story/model/ledger_story_model_storage.cc:222:17)>, void>::value' "Continuation type is invalid.  A continuation is a callable object with this signature: fit::result<V, E>(fit::context&)."
+../../zircon/system/ulib/fit/include/lib/fit/promise.h:288:5: error: static_assert failed due to requirement '::fit::internal::is_continuation<fit::internal::and_then_continuation<fit::promise_impl<fit::function_impl<16, false, fit::result<fuchsia::modular::storymodel::StoryModel, void> (fit::context &)> >, (lambda at ../../peridot/bin/sessionmgr/story/model/ledger_story_model_storage.cc:222:17)>, void>::value' "Continuation type is invalid.  A continuation is a callable object with this signature: fit::result<V, E>(fit::context&)."
 ```
 
 This most likely means that one of the continuation functions has a signature that isn't valid. The valid signatures for different continuation functions are shown below:
@@ -285,10 +329,8 @@
 ```cpp
 .then([] (fit::result<V, E>& result) {});
 .then([] (const fit::result<V, E>& result) {});
-.then([] (fit::result<V, E> result) {});  // Only if V and E are copyable
 .then([] (fit::context& c, fit::result<V, E>& result) {});
 .then([] (fit::context& c, const fit::result<V, E>& result) {});
-.then([] (fit::context& c, fit::result<V, E> result) {});  // Only if V and E are copyable
 ```
 
 For `.and_then()`:
@@ -296,10 +338,8 @@
 ```cpp
 .and_then([] (V& success_value) {});
 .and_then([] (const V& success_value) {});
-.and_then([] (V success_value) {});  // Only if V is copyable
 .and_then([] (fit::context& c, V& success_value) {});
 .and_then([] (fit::context& c, const V& success_value) {});
-.and_then([] (fit::context& c, V& success_value) {});  // Only if V is copyable
 ```
 
 For `.or_else()`:
@@ -307,17 +347,17 @@
 ```cpp
 .or_else([] (E& error_value) {});
 .or_else([] (const E& error_value) {});
-.or_else([] (E error_value) {});  // Only if E is copyable
 .or_else([] (fit::context& c, E& error_value) {});
 .or_else([] (fit::context& c, const E& error_value) {});
-.or_else([] (fit::context& c, E& error_value) {});  // Only if E is copyable
 ```
 
 For `.inspect()`:
 
 ```cpp
-// TODO
+.inspect([] (fit::result<V, E>& result) {});
+.inspect([] (const fit::result<V, E>& result) {});
 ```
+
 ### Captures and Argument Lifecycle
 
 Promises are composed of handler and continuation functions that are usually
@@ -361,4 +401,3 @@
 * fit::bridge
 * common gotchas:
 captured state lifecycle
-
diff --git a/zircon/system/ulib/fit/include/lib/fit/bridge.h b/zircon/system/ulib/fit/include/lib/fit/bridge.h
index 7030f81..7b09ffe 100644
--- a/zircon/system/ulib/fit/include/lib/fit/bridge.h
+++ b/zircon/system/ulib/fit/include/lib/fit/bridge.h
@@ -89,7 +89,7 @@
 //     uint8_t buffer[4096];
 //     void my_program(fit::executor* executor) {
 //         auto promise = promise_read(buffer, sizeof(buffer))
-//             .and_then([] (size_t bytes_read) {
+//             .and_then([] (const size_t& bytes_read) {
 //                 // consume contents of buffer
 //             })
 //             .or_else() {
@@ -122,10 +122,10 @@
 //     uint8_t buffer[4096];
 //     void my_program(fit::executor* executor) {
 //         auto promise = promise_write(buffer, sizeof(buffer))
-//             .and_then([] (size_t bytes_written) {
+//             .and_then([] (const size_t& bytes_written) {
 //                 // consume contents of buffer
 //             })
-//             .or_else(int error) {
+//             .or_else(const int& error) {
 //                 // handle error case
 //             });
 //         executor->schedule_task(std::move(promise));
@@ -453,7 +453,7 @@
 //         executor->schedule_task(
 //             m->perform_calculation(16)
 //                 .promise_or(fit::error())
-//                 .and_then([] (int result) { printf("done: %d\n", result); })
+//                 .and_then([] (const int& result) { printf("done: %d\n", result); })
 //                 .or_else([] { puts("failed or abandoned"); }));
 //     }
 //
diff --git a/zircon/system/ulib/fit/include/lib/fit/promise.h b/zircon/system/ulib/fit/include/lib/fit/promise.h
index 783a80c..5cf3e7a 100644
--- a/zircon/system/ulib/fit/include/lib/fit/promise.h
+++ b/zircon/system/ulib/fit/include/lib/fit/promise.h
@@ -63,8 +63,12 @@
 //                        fit::result<> when prior promise completes
 //    |wrap_with()|: applies a wrapper to the promise
 //    |box()|: wraps the promise's continuation into a |fit::function|
-//    |fit::join_promises()|: await multiple promises, once they all complete
-//                            return a tuple of their results
+//    |fit::join_promises()|: await multiple promises in an argument list,
+//                            once they all complete return a tuple of
+//                            their results
+//    |fit::join_promise_vector()|: await multiple promises in a vector,
+//                                  once they all complete return a vector
+//                                  of their results
 //
 // You can also create your own custom combinators by crafting new
 // types of continuations.
@@ -175,20 +179,20 @@
 // Do this: (chaining as a single expression performs at most one heap allocation)
 //
 //     fit::promise<> f = fit::make_promise([] { ... });
-//         .then([](fit::result<> result) { ... });
+//         .then([](fit::result<>& result) { ... });
 //         .and_then([] { ... });
 //
 // Or this: (still only performs at most one heap allocation)
 //
 //     auto f = fit::make_promise([] { ... });
-//     auto g = f.then([](fit::result<> result) { ... });
+//     auto g = f.then([](fit::result<>& result) { ... });
 //     auto h = g.and_then([] { ... });
 //     fit::promise<> boxed_h = h;
 //
 // But don't do this: (incurs up to three heap allocations due to eager boxing)
 //
 //     fit::promise<> f = fit::make_promise([] { ... });
-//     fit::promise<> g = f.then([](fit::result<> result) { ... });
+//     fit::promise<> g = f.then([](fit::result<>& result) { ... });
 //     fit::promise<> h = g.and_then([] { ... });
 //
 // SINGLE OWNERSHIP MODEL
@@ -428,10 +432,8 @@
     //   fit::result<new_value_type, new_error_type>(fit::context&)
     //
     // The handler must accept one of the following argument lists:
-    // - (result_type)
     // - (result_type&)
     // - (const result_type&)
-    // - (fit::context&, result_type)
     // - (fit::context&, result_type&)
     // - (fit::context&, const result_type&)
     //
@@ -441,7 +443,7 @@
     // EXAMPLE
     //
     //     auto f = fit::make_promise(...)
-    //         .then([] (fit::result<int, std::string> result)
+    //         .then([] (fit::result<int, std::string>& result)
     //                   -> fit::result<std::string, void> {
     //             if (result.is_ok()) {
     //                 printf("received value: %d\n", result.value());
@@ -491,10 +493,8 @@
     //   fit::result<new_value_type, error_type>(fit::context&)
     //
     // The handler must accept one of the following argument lists:
-    // - (value_type)
     // - (value_type&)
     // - (const value_type&)
-    // - (fit::context&, value_type)
     // - (fit::context&, value_type&)
     // - (fit::context&, const value_type&)
     //
@@ -504,7 +504,7 @@
     // EXAMPLE
     //
     //     auto f = fit::make_promise(...)
-    //         .and_then([] (int value) {
+    //         .and_then([] (const int& value) {
     //             printf("received value: %d\n", value);
     //             if (value % 15 == 0)
     //                 return ::fit::ok("fizzbuzz");
@@ -548,10 +548,8 @@
     //   fit::result<value_type, new_error_type>(fit::context&)
     //
     // The handler must accept one of the following argument lists:
-    // - (error_type)
     // - (error_type&)
     // - (const error_type&)
-    // - (fit::context&, error_type)
     // - (fit::context&, error_type&)
     // - (fit::context&, const error_type&)
     //
@@ -561,7 +559,7 @@
     // EXAMPLE
     //
     //     auto f = fit::make_promise(...)
-    //         .or_else([] (std::string error) {
+    //         .or_else([] (const std::string& error) {
     //             printf("received error: %s\n", error.c_str());
     //             return ::fit::error();
     //         })
@@ -585,10 +583,10 @@
     // passing it the promise's result then delivering the result onwards
     // to the next promise once the handler returns.
     //
-    // The handler receive a copy, const reference, or non-const reference
+    // The handler receives a const reference, or non-const reference
     // depending on the signature of the handler's last argument.
     //
-    // - Copies and const references are especially useful for inspecting a
+    // - Const references are especially useful for inspecting a
     //   result mid-stream without modification, such as printing it for
     //   debugging.
     // - Non-const references are especially useful for synchronously
@@ -603,10 +601,8 @@
     // - void
     //
     // The handler must accept one of the following argument lists:
-    // - (result_type)
     // - (result_type&)
     // - (const result_type&)
-    // - (fit::context&, result_type)
     // - (fit::context&, result_type&)
     // - (fit::context&, const result_type&)
     //
@@ -846,8 +842,8 @@
 //     }
 //
 //     auto f = wait_for_good_weather(7)
-//         .and_then([] (weather_type weather) { ... })
-//         .or_else([] (std::string error) { ... });
+//         .and_then([] (const weather_type& weather) { ... })
+//         .or_else([] (const std::string& error) { ... });
 //
 template <typename PromiseHandler>
 inline promise_impl<::fit::internal::context_handler_invoker<PromiseHandler>>
@@ -875,7 +871,7 @@
 //         auto f = get_random_number();
 //         auto g = get_random_number();
 //         return fit::join_promises(std::move(f), std::move(g))
-//             .and_then([] (std::tuple<fit::result<int>, fit::result<int>> results) {
+//             .and_then([] (std::tuple<fit::result<int>, fit::result<int>>& results) {
 //                 return fit::ok(results.get<0>.value() + results.get<1>.value());
 //             });
 //     }
@@ -902,7 +898,7 @@
 //         promises.push_back(get_random_number());
 //         promises.push_back(get_random_number());
 //         return fit::join_promise_vector(std::move(promises))
-//             .and_then([] (std::vector<fit::result<int>> results) {
+//             .and_then([] (std::vector<fit::result<int>>& results) {
 //                 return fit::ok(results[0].value() + results[1].value());
 //             });
 //     }
diff --git a/zircon/system/ulib/fit/include/lib/fit/promise_internal.h b/zircon/system/ulib/fit/include/lib/fit/promise_internal.h
index 30e7085..0b2f28a6 100644
--- a/zircon/system/ulib/fit/include/lib/fit/promise_internal.h
+++ b/zircon/system/ulib/fit/include/lib/fit/promise_internal.h
@@ -306,13 +306,11 @@
         typename ::fit::callable_traits<Handler>::args::template at<
             base_type::next_arg_index>;
     static_assert(
-        (std::is_same<result_arg_type, PriorResult>::value &&
-         std::is_copy_constructible<result_arg_type>::value) ||
-            std::is_same<result_arg_type, PriorResult&>::value ||
+        std::is_same<result_arg_type, PriorResult&>::value ||
             std::is_same<result_arg_type, const PriorResult&>::value,
         "The provided handler's last argument was expected to be of type "
-        "fit::result<V, E>&, const fit::result<V, E>&, or fit::result<V, E> "
-        "(if the result is copy-constructible).  "
+        "fit::result<V, E>& or const fit::result<V, E>& where V is the prior "
+        "result's value type and E is the prior result's error type.  "
         "Please refer to the combinator's documentation for a list of "
         "supported handler function signatures.");
 
@@ -340,12 +338,10 @@
         typename ::fit::callable_traits<Handler>::args::template at<
             base_type::next_arg_index>;
     static_assert(
-        (std::is_same<value_arg_type, V>::value &&
-         std::is_copy_constructible<value_arg_type>::value) ||
-            std::is_same<value_arg_type, V&>::value ||
+        std::is_same<value_arg_type, V&>::value ||
             std::is_same<value_arg_type, const V&>::value,
         "The provided handler's last argument was expected to be of type "
-        "V&, const V&, or V (if the value is copy-constructible).  "
+        "V& or const V& where V is the prior result's value type.  "
         "Please refer to the combinator's documentation for a list of "
         "supported handler function signatures.");
 
@@ -393,12 +389,10 @@
         typename ::fit::callable_traits<Handler>::args::template at<
             base_type::next_arg_index>;
     static_assert(
-        (std::is_same<error_arg_type, E>::value &&
-         std::is_copy_constructible<error_arg_type>::value) ||
-            std::is_same<error_arg_type, E&>::value ||
+        std::is_same<error_arg_type, E&>::value ||
             std::is_same<error_arg_type, const E&>::value,
         "The provided handler's last argument was expected to be of type "
-        "E&, const E&, or E (if the error is copy-constructible).  "
+        "E& or const E& where E is the prior result's error type.  "
         "Please refer to the combinator's documentation for a list of "
         "supported handler function signatures.");
 
diff --git a/zircon/system/ulib/fit/include/lib/fit/sequencer.h b/zircon/system/ulib/fit/include/lib/fit/sequencer.h
index 996bc68..bc6dbff 100644
--- a/zircon/system/ulib/fit/include/lib/fit/sequencer.h
+++ b/zircon/system/ulib/fit/include/lib/fit/sequencer.h
@@ -33,9 +33,9 @@
 //     // sequential work with the sequencer.
 //     fit::promise<> perform_complex_task() {
 //         return fit::make_promise([] { /* do sequential work */ })
-//             .then([] (fit::result<> result) { /* this will also be wrapped */ })
+//             .then([] (fit::result<>& result) { /* this will also be wrapped */ })
 //             .wrap_with(seq)
-//             .then([] (fit::result<> result) { /* do more work */ });
+//             .then([] (fit::result<>& result) { /* do more work */ });
 //     }
 //
 class sequencer final {
@@ -56,7 +56,7 @@
         return prior.promise_or(fit::ok())
             .then([promise = std::move(promise),
                    completer = std::move(bridge.completer)](
-                      fit::context& context, fit::result<>) mutable {
+                      fit::context& context, const fit::result<>&) mutable {
                 // This handler will run once the completer associated
                 // with the |prior| promise is abandoned.  Once the promise
                 // has finished, both the promise and completer will be
diff --git a/zircon/system/utest/fit/bridge_tests.cpp b/zircon/system/utest/fit/bridge_tests.cpp
index c783a87..7f28d3c 100644
--- a/zircon/system/utest/fit/bridge_tests.cpp
+++ b/zircon/system/utest/fit/bridge_tests.cpp
@@ -547,7 +547,7 @@
         auto t = std::thread([&] { executor.run(); });
         fit::run_single_threaded(
             consumer.promise()
-                .then([&](fit::context& context, fit::result<int> result) {
+                .then([&](fit::context& context, const fit::result<int>& result) {
                     ASSERT_CRITICAL(context.executor() != &executor);
                     ASSERT_CRITICAL(result.value() == 42);
                     run_count[1]++;
@@ -576,7 +576,7 @@
         auto t = std::thread([&] { executor.run(); });
         fit::run_single_threaded(
             consumer.promise()
-                .then([&](fit::context& context, fit::result<int> result) {
+                .then([&](fit::context& context, const fit::result<int>& result) {
                     // This should not run because the promise was abandoned.
                     run_count[1]++;
                 }));
@@ -605,7 +605,7 @@
         auto t = std::thread([&] { executor.run(); });
         fit::run_single_threaded(
             consumer.promise_or(fit::error())
-                .then([&](fit::context& context, fit::result<int> result) {
+                .then([&](fit::context& context, const fit::result<int>& result) {
                     ASSERT_CRITICAL(context.executor() != &executor);
                     ASSERT_CRITICAL(result.is_error());
                     run_count[1]++;
diff --git a/zircon/system/utest/fit/examples/promise_example1.cpp b/zircon/system/utest/fit/examples/promise_example1.cpp
index ad38d1d..eea30d58 100644
--- a/zircon/system/utest/fit/examples/promise_example1.cpp
+++ b/zircon/system/utest/fit/examples/promise_example1.cpp
@@ -63,19 +63,19 @@
 fit::promise<> prepare_simulation() {
     int hours = random() % 8;
     return pick_bananas(hours)
-        .and_then([](int harvest) -> fit::result<int, std::string> {
+        .and_then([](const int& harvest) -> fit::result<int, std::string> {
             printf("We picked %d bananas today!\n", harvest);
             if (harvest == 0)
                 return fit::error("What will we eat now?");
             return fit::ok(harvest);
         })
-        .and_then([](int harvest) {
+        .and_then([](const int& harvest) {
             int appetite = random() % 7;
             if (appetite > harvest)
                 appetite = harvest;
             return eat_bananas(appetite);
         })
-        .or_else([](std::string error) {
+        .or_else([](const std::string& error) {
             printf("Oh no!  %s\n", error.c_str());
             return fit::error();
         })
diff --git a/zircon/system/utest/fit/examples/promise_example2.cpp b/zircon/system/utest/fit/examples/promise_example2.cpp
index 00818eb..dba678e 100644
--- a/zircon/system/utest/fit/examples/promise_example2.cpp
+++ b/zircon/system/utest/fit/examples/promise_example2.cpp
@@ -151,7 +151,7 @@
 auto play_round(const std::shared_ptr<game_state>& state) {
     return fit::join_promises(roll_for_damage("Red"), roll_for_damage("Blue"))
         .and_then(
-            [state](std::tuple<fit::result<int>, fit::result<int>> damages) {
+            [state](const std::tuple<fit::result<int>, fit::result<int>>& damages) {
                 // Damage tallies are ready, apply them to the game state.
                 state->blue_hp = std::max(state->blue_hp - std::get<0>(damages).value(), 0);
                 state->red_hp = std::max(state->red_hp - std::get<1>(damages).value(), 0);
diff --git a/zircon/system/utest/fit/promise_tests.cpp b/zircon/system/utest/fit/promise_tests.cpp
index aee22eaa..e6f71ce 100644
--- a/zircon/system/utest/fit/promise_tests.cpp
+++ b/zircon/system/utest/fit/promise_tests.cpp
@@ -59,10 +59,10 @@
                 // Pretend that squaring numbers is hard and takes time
                 // to finish...
                 return utils::sleep_for_a_little_while()
-                    .then([i](fit::result<>) {
+                    .then([i](const fit::result<>&) {
                         return fit::ok(i * i);
                     });
-            }).then([](fit::result<int> square) -> fit::result<int, const char*> {
+            }).then([](const fit::result<int>& square) -> fit::result<int, const char*> {
                 if (square.value() % 2 == 0)
                     return fit::ok(square.value() / 2);
                 return fit::error("square is odd");
@@ -451,12 +451,12 @@
     fake_context fake_context;
 
     // Chaining on OK.
-    // Handler signature: fit::result<>(fit::result<int, char>).
+    // Handler signature: fit::result<>(const fit::result<int, char>&).
     {
         uint64_t run_count = 0;
         auto p =
             make_delayed_ok_promise(42)
-                .then([&](fit::result<int, char> result) -> fit::result<> {
+                .then([&](const fit::result<int, char>& result) -> fit::result<> {
                     ASSERT_CRITICAL(result.value() == 42);
                     if (++run_count == 2)
                         return fit::ok();
@@ -480,12 +480,12 @@
     }
 
     // Chaining on ERROR.
-    // Handler signature: fit::result<>(fit::result<int, char>).
+    // Handler signature: fit::result<>(const fit::result<int, char>&).
     {
         uint64_t run_count = 0;
         auto p =
             make_delayed_error_promise('x')
-                .then([&](fit::result<int, char> result) -> fit::result<> {
+                .then([&](const fit::result<int, char>& result) -> fit::result<> {
                     ASSERT_CRITICAL(result.error() == 'x');
                     if (++run_count == 2)
                         return fit::ok();
@@ -513,11 +513,6 @@
         uint64_t run_count = 0;
         auto p =
             make_ok_promise(42)
-                .then([&](fit::result<int, char> result)
-                          -> fit::result<int, char> {
-                    run_count++;
-                    return fit::ok(result.value() + 1);
-                })
                 .then([&](fit::result<int, char>& result)
                           -> fit::result<int, char> {
                     run_count++;
@@ -528,12 +523,6 @@
                     run_count++;
                     return fit::ok(result.value() + 1);
                 })
-                .then([&](fit::context& context, fit::result<int, char> result)
-                          -> fit::result<int, char> {
-                    ASSERT_CRITICAL(&context == &fake_context);
-                    run_count++;
-                    return fit::ok(result.value() + 1);
-                })
                 .then([&](fit::context& context, fit::result<int, char>& result)
                           -> fit::result<int, char> {
                     ASSERT_CRITICAL(&context == &fake_context);
@@ -549,9 +538,9 @@
 
         fit::result<int, char> result = p(fake_context);
         EXPECT_FALSE(p);
-        EXPECT_EQ(6, run_count);
+        EXPECT_EQ(4, run_count);
         EXPECT_EQ(fit::result_state::ok, result.state());
-        EXPECT_EQ(48, result.value());
+        EXPECT_EQ(46, result.value());
     }
 
     END_TEST;
@@ -563,12 +552,12 @@
     fake_context fake_context;
 
     // Chaining on OK.
-    // Handler signature: fit::result<>(int).
+    // Handler signature: fit::result<>(const int&).
     {
         uint64_t run_count = 0;
         auto p =
             make_delayed_ok_promise(42)
-                .and_then([&](int value) -> fit::result<void, char> {
+                .and_then([&](const int& value) -> fit::result<void, char> {
                     ASSERT_CRITICAL(value == 42);
                     if (++run_count == 2)
                         return fit::error('y');
@@ -593,12 +582,12 @@
     }
 
     // Chaining on ERROR.
-    // Handler signature: fit::result<>(int).
+    // Handler signature: fit::result<>(const int&).
     {
         uint64_t run_count = 0;
         auto p =
             make_delayed_error_promise('x')
-                .and_then([&](int value) -> fit::result<void, char> {
+                .and_then([&](const int& value) -> fit::result<void, char> {
                     run_count++;
                     return fit::pending();
                 });
@@ -620,11 +609,6 @@
         uint64_t run_count = 0;
         auto p =
             make_ok_promise(42)
-                .and_then([&](int value)
-                              -> fit::result<int, char> {
-                    run_count++;
-                    return fit::ok(value + 1);
-                })
                 .and_then([&](int& value)
                               -> fit::result<int, char> {
                     run_count++;
@@ -635,12 +619,6 @@
                     run_count++;
                     return fit::ok(value + 1);
                 })
-                .and_then([&](fit::context& context, int value)
-                              -> fit::result<int, char> {
-                    ASSERT_CRITICAL(&context == &fake_context);
-                    run_count++;
-                    return fit::ok(value + 1);
-                })
                 .and_then([&](fit::context& context, int& value)
                               -> fit::result<int, char> {
                     ASSERT_CRITICAL(&context == &fake_context);
@@ -655,9 +633,9 @@
                 });
 
         fit::result<int, char> result = p(fake_context);
-        EXPECT_EQ(6, run_count);
+        EXPECT_EQ(4, run_count);
         EXPECT_EQ(fit::result_state::ok, result.state());
-        EXPECT_EQ(48, result.value());
+        EXPECT_EQ(46, result.value());
         EXPECT_FALSE(p);
     }
 
@@ -670,12 +648,12 @@
     fake_context fake_context;
 
     // Chaining on OK.
-    // Handler signature: fit::result<>(char).
+    // Handler signature: fit::result<>(const char&).
     {
         uint64_t run_count = 0;
         auto p =
             make_delayed_ok_promise(42)
-                .or_else([&](char error) -> fit::result<int> {
+                .or_else([&](const char& error) -> fit::result<int> {
                     run_count++;
                     return fit::pending();
                 });
@@ -693,12 +671,12 @@
     }
 
     // Chaining on ERROR.
-    // Handler signature: fit::result<>(char).
+    // Handler signature: fit::result<>(const char&).
     {
         uint64_t run_count = 0;
         auto p =
             make_delayed_error_promise('x')
-                .or_else([&](char error) -> fit::result<int> {
+                .or_else([&](const char& error) -> fit::result<int> {
                     ASSERT_CRITICAL(error == 'x');
                     if (++run_count == 2)
                         return fit::ok(43);
@@ -727,11 +705,6 @@
         uint64_t run_count = 0;
         auto p =
             make_error_promise('a')
-                .or_else([&](char error)
-                             -> fit::result<int, char> {
-                    run_count++;
-                    return fit::error(static_cast<char>(error + 1));
-                })
                 .or_else([&](char& error)
                              -> fit::result<int, char> {
                     run_count++;
@@ -742,12 +715,6 @@
                     run_count++;
                     return fit::error(static_cast<char>(error + 1));
                 })
-                .or_else([&](fit::context& context, char error)
-                             -> fit::result<int, char> {
-                    ASSERT_CRITICAL(&context == &fake_context);
-                    run_count++;
-                    return fit::error(static_cast<char>(error + 1));
-                })
                 .or_else([&](fit::context& context, char& error)
                              -> fit::result<int, char> {
                     ASSERT_CRITICAL(&context == &fake_context);
@@ -762,9 +729,9 @@
                 });
 
         fit::result<int, char> result = p(fake_context);
-        EXPECT_EQ(6, run_count);
+        EXPECT_EQ(4, run_count);
         EXPECT_EQ(fit::result_state::error, result.state());
-        EXPECT_EQ('g', result.error());
+        EXPECT_EQ('e', result.error());
         EXPECT_FALSE(p);
     }
 
@@ -777,12 +744,12 @@
     fake_context fake_context;
 
     // Chaining on OK.
-    // Handler signature: void(fit::result<int, char>).
+    // Handler signature: void(const fit::result<int, char>&).
     {
         uint64_t run_count = 0;
         auto p =
             make_delayed_ok_promise(42)
-                .inspect([&](fit::result<int, char> result) {
+                .inspect([&](const fit::result<int, char>& result) {
                     ASSERT_CRITICAL(result.value() == 42);
                     run_count++;
                 });
@@ -800,12 +767,12 @@
     }
 
     // Chaining on ERROR.
-    // Handler signature: void(fit::result<int, char>).
+    // Handler signature: void(const fit::result<int, char>&).
     {
         uint64_t run_count = 0;
         auto p =
             make_delayed_error_promise('x')
-                .inspect([&](fit::result<int, char> result) {
+                .inspect([&](const fit::result<int, char>& result) {
                     ASSERT_CRITICAL(result.error() == 'x');
                     run_count++;
                 });
@@ -827,10 +794,6 @@
         uint64_t run_count = 0;
         auto p =
             make_ok_promise(42)
-                .inspect([&](fit::result<int, char> result) {
-                    ASSERT_CRITICAL(result.value() == 42);
-                    run_count++;
-                })
                 .inspect([&](fit::result<int, char>& result) {
                     ASSERT_CRITICAL(result.value() == 42);
                     run_count++;
@@ -840,11 +803,6 @@
                     ASSERT_CRITICAL(result.value() == 43);
                     run_count++;
                 })
-                .inspect([&](fit::context& context, fit::result<int, char> result) {
-                    ASSERT_CRITICAL(result.value() == 43);
-                    ASSERT_CRITICAL(&context == &fake_context);
-                    run_count++;
-                })
                 .inspect([&](fit::context& context, fit::result<int, char>& result) {
                     ASSERT_CRITICAL(result.value() == 43);
                     ASSERT_CRITICAL(&context == &fake_context);
@@ -859,7 +817,7 @@
 
         fit::result<int, char> result = p(fake_context);
         EXPECT_FALSE(p);
-        EXPECT_EQ(6, run_count);
+        EXPECT_EQ(4, run_count);
         EXPECT_EQ(fit::result_state::ok, result.state());
         EXPECT_EQ(44, result.value());
     }
@@ -915,7 +873,7 @@
     // Apply a wrapper which steals a promise's result th
     auto p = make_delayed_ok_promise(42)
                  .wrap_with(wrapper)
-                 .then([&](fit::result<>) { successor_run_count++; });
+                 .then([&](const fit::result<>&) { successor_run_count++; });
     static_assert(std::is_same<void, decltype(p)::value_type>::value, "");
     static_assert(std::is_same<void, decltype(p)::error_type>::value, "");
 
@@ -965,7 +923,7 @@
 
     auto p = fit::join_promises(
         make_ok_promise(42),
-        make_error_promise('x').or_else([](char error) {
+        make_error_promise('x').or_else([](const char& error) {
             return fit::error('y');
         }),
         make_delayed_ok_promise(55));
@@ -1024,7 +982,7 @@
 
     std::vector<fit::promise<int, char>> promises;
     promises.push_back(make_ok_promise(42));
-    promises.push_back(make_error_promise('x').or_else([](char error) {
+    promises.push_back(make_error_promise('x').or_else([](const char& error) {
         return fit::error('y');
     }));
     promises.push_back(make_delayed_ok_promise(55));
@@ -1255,56 +1213,35 @@
 void diagnose_handler_with_too_many_arguments() {
     // Expected between 1 and 2 arguments, got 3.
     fit::make_promise([] {})
-        .then([](fit::context&, fit::result<>, int excess) {});
+        .then([](fit::context&, const fit::result<>&, int excess) {});
 }
 #endif
 #if 0
 void diagnose_handler_with_invalid_context_arg() {
     // When there are two argument, the first must be fit::context&.
     fit::make_promise([] {})
-        .then([](fit::result<>, int excess) {});
+        .then([](const fit::result<>&, int excess) {});
 }
 #endif
 #if 0
 void diagnose_handler_with_invalid_result_arg() {
     // The result type must match that produced by the prior.
     fit::make_promise([] {})
-        .then([](fit::result<int>& result) {});
-}
-#endif
-#if 0
-void diagnose_handler_with_invalid_move_only_result_arg() {
-    // Move-only types must be passed by reference not by value.
-    fit::make_promise([] { return fit::ok(move_only{}); })
-        .then([](fit::result<move_only> result) {});
+        .then([](const fit::result<int>& result) {});
 }
 #endif
 #if 0
 void diagnose_handler_with_invalid_value_arg() {
     // The value type must match that produced by the prior.
     fit::make_promise([] { return fit::ok(3.2f); })
-        .and_then([](int value) {});
-}
-#endif
-#if 0
-void diagnose_handler_with_invalid_move_only_value_arg() {
-    // The value type must match that produced by the prior.
-    fit::make_promise([] { return fit::ok(move_only{}); })
-        .and_then([](move_only value) {});
+        .and_then([](const int& value) {});
 }
 #endif
 #if 0
 void diagnose_handler_with_invalid_error_arg() {
     // The error type must match that produced by the prior.
     fit::make_promise([] { return fit::error(3.2f); })
-        .or_else([](int error) {});
-}
-#endif
-#if 0
-void diagnose_handler_with_invalid_move_only_error_arg() {
-    // The error type must match that produced by the prior.
-    fit::make_promise([] { return fit::error(move_only{}); })
-        .or_else([](move_only error) {});
+        .or_else([](const int& error) {});
 }
 #endif
 
diff --git a/zircon/system/utest/fit/scope_tests.cpp b/zircon/system/utest/fit/scope_tests.cpp
index aa41cdf..6517fd1 100644
--- a/zircon/system/utest/fit/scope_tests.cpp
+++ b/zircon/system/utest/fit/scope_tests.cpp
@@ -65,17 +65,17 @@
 
     // Schedule some tasks which accumulate values asynchronously.
     executor.schedule_task(acc->add(2).and_then(
-        [&](uint32_t value) { sums[0] = value; }));
+        [&](const uint32_t& value) { sums[0] = value; }));
     executor.schedule_task(acc->add(1).and_then(
-        [&](uint32_t value) { sums[1] = value; }));
+        [&](const uint32_t& value) { sums[1] = value; }));
     executor.schedule_task(acc->add(5).and_then(
-        [&](uint32_t value) { sums[2] = value; }));
+        [&](const uint32_t& value) { sums[2] = value; }));
 
     // Schedule a task which accumulates and then destroys the accumulator
     // so that the scope is exited.  Any remaining promises will be aborted.
     uint32_t last_count = 0;
     executor.schedule_task(acc->add(3).and_then(
-        [&](uint32_t value) {
+        [&](const uint32_t& value) {
             sums[3] = value;
             // Schedule destruction in another task to avoid re-entrance.
             executor.schedule_task(fit::make_promise([&] {
diff --git a/zircon/system/utest/fit/sequencer_tests.cpp b/zircon/system/utest/fit/sequencer_tests.cpp
index 8c836838..7f6b362 100644
--- a/zircon/system/utest/fit/sequencer_tests.cpp
+++ b/zircon/system/utest/fit/sequencer_tests.cpp
@@ -23,7 +23,7 @@
     // This promise writes ":a" sequentially then writes ":a2" later.
     auto a = fit::make_promise([&] { str += ":a"; })
                  .wrap_with(seq)
-                 .then([&](fit::result<>) { str += ":a2"; });
+                 .then([&](const fit::result<>&) { str += ":a2"; });
 
     // This promise writes ":b" sequentially then writes ":b2" and ":b3" later.
     // Also schedules another sequential task that writes ":e".
@@ -34,7 +34,7 @@
                          .wrap_with(seq));
              })
                  .wrap_with(seq)
-                 .then([&, count = 0](fit::context& context, fit::result<>) mutable
+                 .then([&, count = 0](fit::context& context, const fit::result<>&) mutable
                        -> fit::result<> {
                      if (++count == 5) {
                          str += ":b3";
@@ -52,7 +52,7 @@
                  return fit::pending();
              })
                  .wrap_with(seq)
-                 .then([&](fit::result<>) { str += ":c2"; });
+                 .then([&](const fit::result<>&) { str += ":c2"; });
 
     // This promise writes ":d" sequentially.
     auto d = fit::make_promise([&] { str += ":d"; })