// Copyright 2023 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef GRPC_SRC_CORE_LIB_PROMISE_DETAIL_JOIN_STATE_H
#define GRPC_SRC_CORE_LIB_PROMISE_DETAIL_JOIN_STATE_H

// This file is generated by tools/codegen/core/gen_seq.py

#include <grpc/support/port_platform.h>

#include <tuple>
#include <type_traits>
#include <utility>

#include <grpc/support/log.h>

#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/bitset.h"
#include "src/core/lib/gprpp/construct_destruct.h"
#include "src/core/lib/promise/detail/promise_like.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/promise/trace.h"

namespace grpc_core {
namespace promise_detail {
template <class Traits, typename... Ps>
struct JoinState;

template <class Traits, typename P0, typename P1>
struct JoinState<Traits, P0, P1> {
  template <typename T>
  using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>()));
  using Promise0 = PromiseLike<P0>;
  using Result0 = UnwrappedType<typename Promise0::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise0 promise0;
    GPR_NO_UNIQUE_ADDRESS Result0 result0;
  };
  using Promise1 = PromiseLike<P1>;
  using Result1 = UnwrappedType<typename Promise1::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise1 promise1;
    GPR_NO_UNIQUE_ADDRESS Result1 result1;
  };
  GPR_NO_UNIQUE_ADDRESS BitSet<2> ready;
  JoinState(P0&& p0, P1&& p1) {
    Construct(&promise0, std::forward<P0>(p0));
    Construct(&promise1, std::forward<P1>(p1));
  }
  JoinState(const JoinState& other) {
    GPR_ASSERT(other.ready.none());
    Construct(&promise0, other.promise0);
    Construct(&promise1, other.promise1);
  }
  JoinState& operator=(const JoinState& other) = delete;
  JoinState& operator=(JoinState&& other) = delete;
  JoinState(JoinState&& other) noexcept : ready(other.ready) {
    if (ready.is_set(0)) {
      Construct(&result0, std::move(other.result0));
    } else {
      Construct(&promise0, std::move(other.promise0));
    }
    if (ready.is_set(1)) {
      Construct(&result1, std::move(other.result1));
    } else {
      Construct(&promise1, std::move(other.promise1));
    }
  }
  ~JoinState() {
    if (ready.is_set(0)) {
      Destruct(&result0);
    } else {
      Destruct(&promise0);
    }
    if (ready.is_set(1)) {
      Destruct(&result1);
    } else {
      Destruct(&promise1);
    }
  }
  using Result =
      typename Traits::template ResultType<std::tuple<Result0, Result1>>;
  Poll<Result> PollOnce() {
    if (!ready.is_set(0)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 1/2", this);
      }
      auto poll = promise0();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 1/2 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(0);
          Destruct(&promise0);
          Construct(&result0, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 1/2 already ready", this);
    }
    if (!ready.is_set(1)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 2/2", this);
      }
      auto poll = promise1();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 2/2 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(1);
          Destruct(&promise1);
          Construct(&result1, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 2/2 already ready", this);
    }
    if (ready.all()) {
      return Result{std::make_tuple(std::move(result0), std::move(result1))};
    }
    return Pending{};
  }
};

template <class Traits, typename P0, typename P1, typename P2>
struct JoinState<Traits, P0, P1, P2> {
  template <typename T>
  using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>()));
  using Promise0 = PromiseLike<P0>;
  using Result0 = UnwrappedType<typename Promise0::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise0 promise0;
    GPR_NO_UNIQUE_ADDRESS Result0 result0;
  };
  using Promise1 = PromiseLike<P1>;
  using Result1 = UnwrappedType<typename Promise1::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise1 promise1;
    GPR_NO_UNIQUE_ADDRESS Result1 result1;
  };
  using Promise2 = PromiseLike<P2>;
  using Result2 = UnwrappedType<typename Promise2::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise2 promise2;
    GPR_NO_UNIQUE_ADDRESS Result2 result2;
  };
  GPR_NO_UNIQUE_ADDRESS BitSet<3> ready;
  JoinState(P0&& p0, P1&& p1, P2&& p2) {
    Construct(&promise0, std::forward<P0>(p0));
    Construct(&promise1, std::forward<P1>(p1));
    Construct(&promise2, std::forward<P2>(p2));
  }
  JoinState(const JoinState& other) {
    GPR_ASSERT(other.ready.none());
    Construct(&promise0, other.promise0);
    Construct(&promise1, other.promise1);
    Construct(&promise2, other.promise2);
  }
  JoinState& operator=(const JoinState& other) = delete;
  JoinState& operator=(JoinState&& other) = delete;
  JoinState(JoinState&& other) noexcept : ready(other.ready) {
    if (ready.is_set(0)) {
      Construct(&result0, std::move(other.result0));
    } else {
      Construct(&promise0, std::move(other.promise0));
    }
    if (ready.is_set(1)) {
      Construct(&result1, std::move(other.result1));
    } else {
      Construct(&promise1, std::move(other.promise1));
    }
    if (ready.is_set(2)) {
      Construct(&result2, std::move(other.result2));
    } else {
      Construct(&promise2, std::move(other.promise2));
    }
  }
  ~JoinState() {
    if (ready.is_set(0)) {
      Destruct(&result0);
    } else {
      Destruct(&promise0);
    }
    if (ready.is_set(1)) {
      Destruct(&result1);
    } else {
      Destruct(&promise1);
    }
    if (ready.is_set(2)) {
      Destruct(&result2);
    } else {
      Destruct(&promise2);
    }
  }
  using Result = typename Traits::template ResultType<
      std::tuple<Result0, Result1, Result2>>;
  Poll<Result> PollOnce() {
    if (!ready.is_set(0)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 1/3", this);
      }
      auto poll = promise0();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 1/3 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(0);
          Destruct(&promise0);
          Construct(&result0, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 1/3 already ready", this);
    }
    if (!ready.is_set(1)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 2/3", this);
      }
      auto poll = promise1();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 2/3 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(1);
          Destruct(&promise1);
          Construct(&result1, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 2/3 already ready", this);
    }
    if (!ready.is_set(2)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 3/3", this);
      }
      auto poll = promise2();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 3/3 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(2);
          Destruct(&promise2);
          Construct(&result2, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 3/3 already ready", this);
    }
    if (ready.all()) {
      return Result{std::make_tuple(std::move(result0), std::move(result1),
                                    std::move(result2))};
    }
    return Pending{};
  }
};

template <class Traits, typename P0, typename P1, typename P2, typename P3>
struct JoinState<Traits, P0, P1, P2, P3> {
  template <typename T>
  using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>()));
  using Promise0 = PromiseLike<P0>;
  using Result0 = UnwrappedType<typename Promise0::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise0 promise0;
    GPR_NO_UNIQUE_ADDRESS Result0 result0;
  };
  using Promise1 = PromiseLike<P1>;
  using Result1 = UnwrappedType<typename Promise1::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise1 promise1;
    GPR_NO_UNIQUE_ADDRESS Result1 result1;
  };
  using Promise2 = PromiseLike<P2>;
  using Result2 = UnwrappedType<typename Promise2::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise2 promise2;
    GPR_NO_UNIQUE_ADDRESS Result2 result2;
  };
  using Promise3 = PromiseLike<P3>;
  using Result3 = UnwrappedType<typename Promise3::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise3 promise3;
    GPR_NO_UNIQUE_ADDRESS Result3 result3;
  };
  GPR_NO_UNIQUE_ADDRESS BitSet<4> ready;
  JoinState(P0&& p0, P1&& p1, P2&& p2, P3&& p3) {
    Construct(&promise0, std::forward<P0>(p0));
    Construct(&promise1, std::forward<P1>(p1));
    Construct(&promise2, std::forward<P2>(p2));
    Construct(&promise3, std::forward<P3>(p3));
  }
  JoinState(const JoinState& other) {
    GPR_ASSERT(other.ready.none());
    Construct(&promise0, other.promise0);
    Construct(&promise1, other.promise1);
    Construct(&promise2, other.promise2);
    Construct(&promise3, other.promise3);
  }
  JoinState& operator=(const JoinState& other) = delete;
  JoinState& operator=(JoinState&& other) = delete;
  JoinState(JoinState&& other) noexcept : ready(other.ready) {
    if (ready.is_set(0)) {
      Construct(&result0, std::move(other.result0));
    } else {
      Construct(&promise0, std::move(other.promise0));
    }
    if (ready.is_set(1)) {
      Construct(&result1, std::move(other.result1));
    } else {
      Construct(&promise1, std::move(other.promise1));
    }
    if (ready.is_set(2)) {
      Construct(&result2, std::move(other.result2));
    } else {
      Construct(&promise2, std::move(other.promise2));
    }
    if (ready.is_set(3)) {
      Construct(&result3, std::move(other.result3));
    } else {
      Construct(&promise3, std::move(other.promise3));
    }
  }
  ~JoinState() {
    if (ready.is_set(0)) {
      Destruct(&result0);
    } else {
      Destruct(&promise0);
    }
    if (ready.is_set(1)) {
      Destruct(&result1);
    } else {
      Destruct(&promise1);
    }
    if (ready.is_set(2)) {
      Destruct(&result2);
    } else {
      Destruct(&promise2);
    }
    if (ready.is_set(3)) {
      Destruct(&result3);
    } else {
      Destruct(&promise3);
    }
  }
  using Result = typename Traits::template ResultType<
      std::tuple<Result0, Result1, Result2, Result3>>;
  Poll<Result> PollOnce() {
    if (!ready.is_set(0)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 1/4", this);
      }
      auto poll = promise0();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 1/4 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(0);
          Destruct(&promise0);
          Construct(&result0, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 1/4 already ready", this);
    }
    if (!ready.is_set(1)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 2/4", this);
      }
      auto poll = promise1();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 2/4 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(1);
          Destruct(&promise1);
          Construct(&result1, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 2/4 already ready", this);
    }
    if (!ready.is_set(2)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 3/4", this);
      }
      auto poll = promise2();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 3/4 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(2);
          Destruct(&promise2);
          Construct(&result2, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 3/4 already ready", this);
    }
    if (!ready.is_set(3)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 4/4", this);
      }
      auto poll = promise3();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 4/4 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(3);
          Destruct(&promise3);
          Construct(&result3, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 4/4 already ready", this);
    }
    if (ready.all()) {
      return Result{std::make_tuple(std::move(result0), std::move(result1),
                                    std::move(result2), std::move(result3))};
    }
    return Pending{};
  }
};

template <class Traits, typename P0, typename P1, typename P2, typename P3,
          typename P4>
struct JoinState<Traits, P0, P1, P2, P3, P4> {
  template <typename T>
  using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>()));
  using Promise0 = PromiseLike<P0>;
  using Result0 = UnwrappedType<typename Promise0::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise0 promise0;
    GPR_NO_UNIQUE_ADDRESS Result0 result0;
  };
  using Promise1 = PromiseLike<P1>;
  using Result1 = UnwrappedType<typename Promise1::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise1 promise1;
    GPR_NO_UNIQUE_ADDRESS Result1 result1;
  };
  using Promise2 = PromiseLike<P2>;
  using Result2 = UnwrappedType<typename Promise2::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise2 promise2;
    GPR_NO_UNIQUE_ADDRESS Result2 result2;
  };
  using Promise3 = PromiseLike<P3>;
  using Result3 = UnwrappedType<typename Promise3::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise3 promise3;
    GPR_NO_UNIQUE_ADDRESS Result3 result3;
  };
  using Promise4 = PromiseLike<P4>;
  using Result4 = UnwrappedType<typename Promise4::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise4 promise4;
    GPR_NO_UNIQUE_ADDRESS Result4 result4;
  };
  GPR_NO_UNIQUE_ADDRESS BitSet<5> ready;
  JoinState(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4) {
    Construct(&promise0, std::forward<P0>(p0));
    Construct(&promise1, std::forward<P1>(p1));
    Construct(&promise2, std::forward<P2>(p2));
    Construct(&promise3, std::forward<P3>(p3));
    Construct(&promise4, std::forward<P4>(p4));
  }
  JoinState(const JoinState& other) {
    GPR_ASSERT(other.ready.none());
    Construct(&promise0, other.promise0);
    Construct(&promise1, other.promise1);
    Construct(&promise2, other.promise2);
    Construct(&promise3, other.promise3);
    Construct(&promise4, other.promise4);
  }
  JoinState& operator=(const JoinState& other) = delete;
  JoinState& operator=(JoinState&& other) = delete;
  JoinState(JoinState&& other) noexcept : ready(other.ready) {
    if (ready.is_set(0)) {
      Construct(&result0, std::move(other.result0));
    } else {
      Construct(&promise0, std::move(other.promise0));
    }
    if (ready.is_set(1)) {
      Construct(&result1, std::move(other.result1));
    } else {
      Construct(&promise1, std::move(other.promise1));
    }
    if (ready.is_set(2)) {
      Construct(&result2, std::move(other.result2));
    } else {
      Construct(&promise2, std::move(other.promise2));
    }
    if (ready.is_set(3)) {
      Construct(&result3, std::move(other.result3));
    } else {
      Construct(&promise3, std::move(other.promise3));
    }
    if (ready.is_set(4)) {
      Construct(&result4, std::move(other.result4));
    } else {
      Construct(&promise4, std::move(other.promise4));
    }
  }
  ~JoinState() {
    if (ready.is_set(0)) {
      Destruct(&result0);
    } else {
      Destruct(&promise0);
    }
    if (ready.is_set(1)) {
      Destruct(&result1);
    } else {
      Destruct(&promise1);
    }
    if (ready.is_set(2)) {
      Destruct(&result2);
    } else {
      Destruct(&promise2);
    }
    if (ready.is_set(3)) {
      Destruct(&result3);
    } else {
      Destruct(&promise3);
    }
    if (ready.is_set(4)) {
      Destruct(&result4);
    } else {
      Destruct(&promise4);
    }
  }
  using Result = typename Traits::template ResultType<
      std::tuple<Result0, Result1, Result2, Result3, Result4>>;
  Poll<Result> PollOnce() {
    if (!ready.is_set(0)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 1/5", this);
      }
      auto poll = promise0();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 1/5 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(0);
          Destruct(&promise0);
          Construct(&result0, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 1/5 already ready", this);
    }
    if (!ready.is_set(1)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 2/5", this);
      }
      auto poll = promise1();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 2/5 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(1);
          Destruct(&promise1);
          Construct(&result1, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 2/5 already ready", this);
    }
    if (!ready.is_set(2)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 3/5", this);
      }
      auto poll = promise2();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 3/5 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(2);
          Destruct(&promise2);
          Construct(&result2, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 3/5 already ready", this);
    }
    if (!ready.is_set(3)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 4/5", this);
      }
      auto poll = promise3();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 4/5 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(3);
          Destruct(&promise3);
          Construct(&result3, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 4/5 already ready", this);
    }
    if (!ready.is_set(4)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 5/5", this);
      }
      auto poll = promise4();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 5/5 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(4);
          Destruct(&promise4);
          Construct(&result4, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 5/5 already ready", this);
    }
    if (ready.all()) {
      return Result{std::make_tuple(std::move(result0), std::move(result1),
                                    std::move(result2), std::move(result3),
                                    std::move(result4))};
    }
    return Pending{};
  }
};

template <class Traits, typename P0, typename P1, typename P2, typename P3,
          typename P4, typename P5>
struct JoinState<Traits, P0, P1, P2, P3, P4, P5> {
  template <typename T>
  using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>()));
  using Promise0 = PromiseLike<P0>;
  using Result0 = UnwrappedType<typename Promise0::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise0 promise0;
    GPR_NO_UNIQUE_ADDRESS Result0 result0;
  };
  using Promise1 = PromiseLike<P1>;
  using Result1 = UnwrappedType<typename Promise1::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise1 promise1;
    GPR_NO_UNIQUE_ADDRESS Result1 result1;
  };
  using Promise2 = PromiseLike<P2>;
  using Result2 = UnwrappedType<typename Promise2::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise2 promise2;
    GPR_NO_UNIQUE_ADDRESS Result2 result2;
  };
  using Promise3 = PromiseLike<P3>;
  using Result3 = UnwrappedType<typename Promise3::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise3 promise3;
    GPR_NO_UNIQUE_ADDRESS Result3 result3;
  };
  using Promise4 = PromiseLike<P4>;
  using Result4 = UnwrappedType<typename Promise4::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise4 promise4;
    GPR_NO_UNIQUE_ADDRESS Result4 result4;
  };
  using Promise5 = PromiseLike<P5>;
  using Result5 = UnwrappedType<typename Promise5::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise5 promise5;
    GPR_NO_UNIQUE_ADDRESS Result5 result5;
  };
  GPR_NO_UNIQUE_ADDRESS BitSet<6> ready;
  JoinState(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5) {
    Construct(&promise0, std::forward<P0>(p0));
    Construct(&promise1, std::forward<P1>(p1));
    Construct(&promise2, std::forward<P2>(p2));
    Construct(&promise3, std::forward<P3>(p3));
    Construct(&promise4, std::forward<P4>(p4));
    Construct(&promise5, std::forward<P5>(p5));
  }
  JoinState(const JoinState& other) {
    GPR_ASSERT(other.ready.none());
    Construct(&promise0, other.promise0);
    Construct(&promise1, other.promise1);
    Construct(&promise2, other.promise2);
    Construct(&promise3, other.promise3);
    Construct(&promise4, other.promise4);
    Construct(&promise5, other.promise5);
  }
  JoinState& operator=(const JoinState& other) = delete;
  JoinState& operator=(JoinState&& other) = delete;
  JoinState(JoinState&& other) noexcept : ready(other.ready) {
    if (ready.is_set(0)) {
      Construct(&result0, std::move(other.result0));
    } else {
      Construct(&promise0, std::move(other.promise0));
    }
    if (ready.is_set(1)) {
      Construct(&result1, std::move(other.result1));
    } else {
      Construct(&promise1, std::move(other.promise1));
    }
    if (ready.is_set(2)) {
      Construct(&result2, std::move(other.result2));
    } else {
      Construct(&promise2, std::move(other.promise2));
    }
    if (ready.is_set(3)) {
      Construct(&result3, std::move(other.result3));
    } else {
      Construct(&promise3, std::move(other.promise3));
    }
    if (ready.is_set(4)) {
      Construct(&result4, std::move(other.result4));
    } else {
      Construct(&promise4, std::move(other.promise4));
    }
    if (ready.is_set(5)) {
      Construct(&result5, std::move(other.result5));
    } else {
      Construct(&promise5, std::move(other.promise5));
    }
  }
  ~JoinState() {
    if (ready.is_set(0)) {
      Destruct(&result0);
    } else {
      Destruct(&promise0);
    }
    if (ready.is_set(1)) {
      Destruct(&result1);
    } else {
      Destruct(&promise1);
    }
    if (ready.is_set(2)) {
      Destruct(&result2);
    } else {
      Destruct(&promise2);
    }
    if (ready.is_set(3)) {
      Destruct(&result3);
    } else {
      Destruct(&promise3);
    }
    if (ready.is_set(4)) {
      Destruct(&result4);
    } else {
      Destruct(&promise4);
    }
    if (ready.is_set(5)) {
      Destruct(&result5);
    } else {
      Destruct(&promise5);
    }
  }
  using Result = typename Traits::template ResultType<
      std::tuple<Result0, Result1, Result2, Result3, Result4, Result5>>;
  Poll<Result> PollOnce() {
    if (!ready.is_set(0)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 1/6", this);
      }
      auto poll = promise0();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 1/6 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(0);
          Destruct(&promise0);
          Construct(&result0, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 1/6 already ready", this);
    }
    if (!ready.is_set(1)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 2/6", this);
      }
      auto poll = promise1();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 2/6 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(1);
          Destruct(&promise1);
          Construct(&result1, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 2/6 already ready", this);
    }
    if (!ready.is_set(2)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 3/6", this);
      }
      auto poll = promise2();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 3/6 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(2);
          Destruct(&promise2);
          Construct(&result2, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 3/6 already ready", this);
    }
    if (!ready.is_set(3)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 4/6", this);
      }
      auto poll = promise3();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 4/6 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(3);
          Destruct(&promise3);
          Construct(&result3, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 4/6 already ready", this);
    }
    if (!ready.is_set(4)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 5/6", this);
      }
      auto poll = promise4();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 5/6 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(4);
          Destruct(&promise4);
          Construct(&result4, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 5/6 already ready", this);
    }
    if (!ready.is_set(5)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 6/6", this);
      }
      auto poll = promise5();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 6/6 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(5);
          Destruct(&promise5);
          Construct(&result5, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 6/6 already ready", this);
    }
    if (ready.all()) {
      return Result{std::make_tuple(std::move(result0), std::move(result1),
                                    std::move(result2), std::move(result3),
                                    std::move(result4), std::move(result5))};
    }
    return Pending{};
  }
};

template <class Traits, typename P0, typename P1, typename P2, typename P3,
          typename P4, typename P5, typename P6>
struct JoinState<Traits, P0, P1, P2, P3, P4, P5, P6> {
  template <typename T>
  using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>()));
  using Promise0 = PromiseLike<P0>;
  using Result0 = UnwrappedType<typename Promise0::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise0 promise0;
    GPR_NO_UNIQUE_ADDRESS Result0 result0;
  };
  using Promise1 = PromiseLike<P1>;
  using Result1 = UnwrappedType<typename Promise1::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise1 promise1;
    GPR_NO_UNIQUE_ADDRESS Result1 result1;
  };
  using Promise2 = PromiseLike<P2>;
  using Result2 = UnwrappedType<typename Promise2::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise2 promise2;
    GPR_NO_UNIQUE_ADDRESS Result2 result2;
  };
  using Promise3 = PromiseLike<P3>;
  using Result3 = UnwrappedType<typename Promise3::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise3 promise3;
    GPR_NO_UNIQUE_ADDRESS Result3 result3;
  };
  using Promise4 = PromiseLike<P4>;
  using Result4 = UnwrappedType<typename Promise4::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise4 promise4;
    GPR_NO_UNIQUE_ADDRESS Result4 result4;
  };
  using Promise5 = PromiseLike<P5>;
  using Result5 = UnwrappedType<typename Promise5::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise5 promise5;
    GPR_NO_UNIQUE_ADDRESS Result5 result5;
  };
  using Promise6 = PromiseLike<P6>;
  using Result6 = UnwrappedType<typename Promise6::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise6 promise6;
    GPR_NO_UNIQUE_ADDRESS Result6 result6;
  };
  GPR_NO_UNIQUE_ADDRESS BitSet<7> ready;
  JoinState(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5, P6&& p6) {
    Construct(&promise0, std::forward<P0>(p0));
    Construct(&promise1, std::forward<P1>(p1));
    Construct(&promise2, std::forward<P2>(p2));
    Construct(&promise3, std::forward<P3>(p3));
    Construct(&promise4, std::forward<P4>(p4));
    Construct(&promise5, std::forward<P5>(p5));
    Construct(&promise6, std::forward<P6>(p6));
  }
  JoinState(const JoinState& other) {
    GPR_ASSERT(other.ready.none());
    Construct(&promise0, other.promise0);
    Construct(&promise1, other.promise1);
    Construct(&promise2, other.promise2);
    Construct(&promise3, other.promise3);
    Construct(&promise4, other.promise4);
    Construct(&promise5, other.promise5);
    Construct(&promise6, other.promise6);
  }
  JoinState& operator=(const JoinState& other) = delete;
  JoinState& operator=(JoinState&& other) = delete;
  JoinState(JoinState&& other) noexcept : ready(other.ready) {
    if (ready.is_set(0)) {
      Construct(&result0, std::move(other.result0));
    } else {
      Construct(&promise0, std::move(other.promise0));
    }
    if (ready.is_set(1)) {
      Construct(&result1, std::move(other.result1));
    } else {
      Construct(&promise1, std::move(other.promise1));
    }
    if (ready.is_set(2)) {
      Construct(&result2, std::move(other.result2));
    } else {
      Construct(&promise2, std::move(other.promise2));
    }
    if (ready.is_set(3)) {
      Construct(&result3, std::move(other.result3));
    } else {
      Construct(&promise3, std::move(other.promise3));
    }
    if (ready.is_set(4)) {
      Construct(&result4, std::move(other.result4));
    } else {
      Construct(&promise4, std::move(other.promise4));
    }
    if (ready.is_set(5)) {
      Construct(&result5, std::move(other.result5));
    } else {
      Construct(&promise5, std::move(other.promise5));
    }
    if (ready.is_set(6)) {
      Construct(&result6, std::move(other.result6));
    } else {
      Construct(&promise6, std::move(other.promise6));
    }
  }
  ~JoinState() {
    if (ready.is_set(0)) {
      Destruct(&result0);
    } else {
      Destruct(&promise0);
    }
    if (ready.is_set(1)) {
      Destruct(&result1);
    } else {
      Destruct(&promise1);
    }
    if (ready.is_set(2)) {
      Destruct(&result2);
    } else {
      Destruct(&promise2);
    }
    if (ready.is_set(3)) {
      Destruct(&result3);
    } else {
      Destruct(&promise3);
    }
    if (ready.is_set(4)) {
      Destruct(&result4);
    } else {
      Destruct(&promise4);
    }
    if (ready.is_set(5)) {
      Destruct(&result5);
    } else {
      Destruct(&promise5);
    }
    if (ready.is_set(6)) {
      Destruct(&result6);
    } else {
      Destruct(&promise6);
    }
  }
  using Result = typename Traits::template ResultType<std::tuple<
      Result0, Result1, Result2, Result3, Result4, Result5, Result6>>;
  Poll<Result> PollOnce() {
    if (!ready.is_set(0)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 1/7", this);
      }
      auto poll = promise0();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 1/7 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(0);
          Destruct(&promise0);
          Construct(&result0, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 1/7 already ready", this);
    }
    if (!ready.is_set(1)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 2/7", this);
      }
      auto poll = promise1();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 2/7 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(1);
          Destruct(&promise1);
          Construct(&result1, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 2/7 already ready", this);
    }
    if (!ready.is_set(2)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 3/7", this);
      }
      auto poll = promise2();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 3/7 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(2);
          Destruct(&promise2);
          Construct(&result2, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 3/7 already ready", this);
    }
    if (!ready.is_set(3)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 4/7", this);
      }
      auto poll = promise3();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 4/7 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(3);
          Destruct(&promise3);
          Construct(&result3, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 4/7 already ready", this);
    }
    if (!ready.is_set(4)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 5/7", this);
      }
      auto poll = promise4();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 5/7 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(4);
          Destruct(&promise4);
          Construct(&result4, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 5/7 already ready", this);
    }
    if (!ready.is_set(5)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 6/7", this);
      }
      auto poll = promise5();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 6/7 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(5);
          Destruct(&promise5);
          Construct(&result5, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 6/7 already ready", this);
    }
    if (!ready.is_set(6)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 7/7", this);
      }
      auto poll = promise6();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 7/7 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(6);
          Destruct(&promise6);
          Construct(&result6, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 7/7 already ready", this);
    }
    if (ready.all()) {
      return Result{std::make_tuple(std::move(result0), std::move(result1),
                                    std::move(result2), std::move(result3),
                                    std::move(result4), std::move(result5),
                                    std::move(result6))};
    }
    return Pending{};
  }
};

template <class Traits, typename P0, typename P1, typename P2, typename P3,
          typename P4, typename P5, typename P6, typename P7>
struct JoinState<Traits, P0, P1, P2, P3, P4, P5, P6, P7> {
  template <typename T>
  using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>()));
  using Promise0 = PromiseLike<P0>;
  using Result0 = UnwrappedType<typename Promise0::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise0 promise0;
    GPR_NO_UNIQUE_ADDRESS Result0 result0;
  };
  using Promise1 = PromiseLike<P1>;
  using Result1 = UnwrappedType<typename Promise1::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise1 promise1;
    GPR_NO_UNIQUE_ADDRESS Result1 result1;
  };
  using Promise2 = PromiseLike<P2>;
  using Result2 = UnwrappedType<typename Promise2::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise2 promise2;
    GPR_NO_UNIQUE_ADDRESS Result2 result2;
  };
  using Promise3 = PromiseLike<P3>;
  using Result3 = UnwrappedType<typename Promise3::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise3 promise3;
    GPR_NO_UNIQUE_ADDRESS Result3 result3;
  };
  using Promise4 = PromiseLike<P4>;
  using Result4 = UnwrappedType<typename Promise4::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise4 promise4;
    GPR_NO_UNIQUE_ADDRESS Result4 result4;
  };
  using Promise5 = PromiseLike<P5>;
  using Result5 = UnwrappedType<typename Promise5::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise5 promise5;
    GPR_NO_UNIQUE_ADDRESS Result5 result5;
  };
  using Promise6 = PromiseLike<P6>;
  using Result6 = UnwrappedType<typename Promise6::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise6 promise6;
    GPR_NO_UNIQUE_ADDRESS Result6 result6;
  };
  using Promise7 = PromiseLike<P7>;
  using Result7 = UnwrappedType<typename Promise7::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise7 promise7;
    GPR_NO_UNIQUE_ADDRESS Result7 result7;
  };
  GPR_NO_UNIQUE_ADDRESS BitSet<8> ready;
  JoinState(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5, P6&& p6,
            P7&& p7) {
    Construct(&promise0, std::forward<P0>(p0));
    Construct(&promise1, std::forward<P1>(p1));
    Construct(&promise2, std::forward<P2>(p2));
    Construct(&promise3, std::forward<P3>(p3));
    Construct(&promise4, std::forward<P4>(p4));
    Construct(&promise5, std::forward<P5>(p5));
    Construct(&promise6, std::forward<P6>(p6));
    Construct(&promise7, std::forward<P7>(p7));
  }
  JoinState(const JoinState& other) {
    GPR_ASSERT(other.ready.none());
    Construct(&promise0, other.promise0);
    Construct(&promise1, other.promise1);
    Construct(&promise2, other.promise2);
    Construct(&promise3, other.promise3);
    Construct(&promise4, other.promise4);
    Construct(&promise5, other.promise5);
    Construct(&promise6, other.promise6);
    Construct(&promise7, other.promise7);
  }
  JoinState& operator=(const JoinState& other) = delete;
  JoinState& operator=(JoinState&& other) = delete;
  JoinState(JoinState&& other) noexcept : ready(other.ready) {
    if (ready.is_set(0)) {
      Construct(&result0, std::move(other.result0));
    } else {
      Construct(&promise0, std::move(other.promise0));
    }
    if (ready.is_set(1)) {
      Construct(&result1, std::move(other.result1));
    } else {
      Construct(&promise1, std::move(other.promise1));
    }
    if (ready.is_set(2)) {
      Construct(&result2, std::move(other.result2));
    } else {
      Construct(&promise2, std::move(other.promise2));
    }
    if (ready.is_set(3)) {
      Construct(&result3, std::move(other.result3));
    } else {
      Construct(&promise3, std::move(other.promise3));
    }
    if (ready.is_set(4)) {
      Construct(&result4, std::move(other.result4));
    } else {
      Construct(&promise4, std::move(other.promise4));
    }
    if (ready.is_set(5)) {
      Construct(&result5, std::move(other.result5));
    } else {
      Construct(&promise5, std::move(other.promise5));
    }
    if (ready.is_set(6)) {
      Construct(&result6, std::move(other.result6));
    } else {
      Construct(&promise6, std::move(other.promise6));
    }
    if (ready.is_set(7)) {
      Construct(&result7, std::move(other.result7));
    } else {
      Construct(&promise7, std::move(other.promise7));
    }
  }
  ~JoinState() {
    if (ready.is_set(0)) {
      Destruct(&result0);
    } else {
      Destruct(&promise0);
    }
    if (ready.is_set(1)) {
      Destruct(&result1);
    } else {
      Destruct(&promise1);
    }
    if (ready.is_set(2)) {
      Destruct(&result2);
    } else {
      Destruct(&promise2);
    }
    if (ready.is_set(3)) {
      Destruct(&result3);
    } else {
      Destruct(&promise3);
    }
    if (ready.is_set(4)) {
      Destruct(&result4);
    } else {
      Destruct(&promise4);
    }
    if (ready.is_set(5)) {
      Destruct(&result5);
    } else {
      Destruct(&promise5);
    }
    if (ready.is_set(6)) {
      Destruct(&result6);
    } else {
      Destruct(&promise6);
    }
    if (ready.is_set(7)) {
      Destruct(&result7);
    } else {
      Destruct(&promise7);
    }
  }
  using Result = typename Traits::template ResultType<std::tuple<
      Result0, Result1, Result2, Result3, Result4, Result5, Result6, Result7>>;
  Poll<Result> PollOnce() {
    if (!ready.is_set(0)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 1/8", this);
      }
      auto poll = promise0();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 1/8 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(0);
          Destruct(&promise0);
          Construct(&result0, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 1/8 already ready", this);
    }
    if (!ready.is_set(1)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 2/8", this);
      }
      auto poll = promise1();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 2/8 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(1);
          Destruct(&promise1);
          Construct(&result1, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 2/8 already ready", this);
    }
    if (!ready.is_set(2)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 3/8", this);
      }
      auto poll = promise2();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 3/8 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(2);
          Destruct(&promise2);
          Construct(&result2, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 3/8 already ready", this);
    }
    if (!ready.is_set(3)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 4/8", this);
      }
      auto poll = promise3();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 4/8 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(3);
          Destruct(&promise3);
          Construct(&result3, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 4/8 already ready", this);
    }
    if (!ready.is_set(4)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 5/8", this);
      }
      auto poll = promise4();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 5/8 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(4);
          Destruct(&promise4);
          Construct(&result4, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 5/8 already ready", this);
    }
    if (!ready.is_set(5)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 6/8", this);
      }
      auto poll = promise5();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 6/8 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(5);
          Destruct(&promise5);
          Construct(&result5, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 6/8 already ready", this);
    }
    if (!ready.is_set(6)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 7/8", this);
      }
      auto poll = promise6();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 7/8 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(6);
          Destruct(&promise6);
          Construct(&result6, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 7/8 already ready", this);
    }
    if (!ready.is_set(7)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 8/8", this);
      }
      auto poll = promise7();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 8/8 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(7);
          Destruct(&promise7);
          Construct(&result7, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 8/8 already ready", this);
    }
    if (ready.all()) {
      return Result{std::make_tuple(std::move(result0), std::move(result1),
                                    std::move(result2), std::move(result3),
                                    std::move(result4), std::move(result5),
                                    std::move(result6), std::move(result7))};
    }
    return Pending{};
  }
};

template <class Traits, typename P0, typename P1, typename P2, typename P3,
          typename P4, typename P5, typename P6, typename P7, typename P8>
struct JoinState<Traits, P0, P1, P2, P3, P4, P5, P6, P7, P8> {
  template <typename T>
  using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>()));
  using Promise0 = PromiseLike<P0>;
  using Result0 = UnwrappedType<typename Promise0::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise0 promise0;
    GPR_NO_UNIQUE_ADDRESS Result0 result0;
  };
  using Promise1 = PromiseLike<P1>;
  using Result1 = UnwrappedType<typename Promise1::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise1 promise1;
    GPR_NO_UNIQUE_ADDRESS Result1 result1;
  };
  using Promise2 = PromiseLike<P2>;
  using Result2 = UnwrappedType<typename Promise2::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise2 promise2;
    GPR_NO_UNIQUE_ADDRESS Result2 result2;
  };
  using Promise3 = PromiseLike<P3>;
  using Result3 = UnwrappedType<typename Promise3::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise3 promise3;
    GPR_NO_UNIQUE_ADDRESS Result3 result3;
  };
  using Promise4 = PromiseLike<P4>;
  using Result4 = UnwrappedType<typename Promise4::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise4 promise4;
    GPR_NO_UNIQUE_ADDRESS Result4 result4;
  };
  using Promise5 = PromiseLike<P5>;
  using Result5 = UnwrappedType<typename Promise5::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise5 promise5;
    GPR_NO_UNIQUE_ADDRESS Result5 result5;
  };
  using Promise6 = PromiseLike<P6>;
  using Result6 = UnwrappedType<typename Promise6::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise6 promise6;
    GPR_NO_UNIQUE_ADDRESS Result6 result6;
  };
  using Promise7 = PromiseLike<P7>;
  using Result7 = UnwrappedType<typename Promise7::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise7 promise7;
    GPR_NO_UNIQUE_ADDRESS Result7 result7;
  };
  using Promise8 = PromiseLike<P8>;
  using Result8 = UnwrappedType<typename Promise8::Result>;
  union {
    GPR_NO_UNIQUE_ADDRESS Promise8 promise8;
    GPR_NO_UNIQUE_ADDRESS Result8 result8;
  };
  GPR_NO_UNIQUE_ADDRESS BitSet<9> ready;
  JoinState(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5, P6&& p6,
            P7&& p7, P8&& p8) {
    Construct(&promise0, std::forward<P0>(p0));
    Construct(&promise1, std::forward<P1>(p1));
    Construct(&promise2, std::forward<P2>(p2));
    Construct(&promise3, std::forward<P3>(p3));
    Construct(&promise4, std::forward<P4>(p4));
    Construct(&promise5, std::forward<P5>(p5));
    Construct(&promise6, std::forward<P6>(p6));
    Construct(&promise7, std::forward<P7>(p7));
    Construct(&promise8, std::forward<P8>(p8));
  }
  JoinState(const JoinState& other) {
    GPR_ASSERT(other.ready.none());
    Construct(&promise0, other.promise0);
    Construct(&promise1, other.promise1);
    Construct(&promise2, other.promise2);
    Construct(&promise3, other.promise3);
    Construct(&promise4, other.promise4);
    Construct(&promise5, other.promise5);
    Construct(&promise6, other.promise6);
    Construct(&promise7, other.promise7);
    Construct(&promise8, other.promise8);
  }
  JoinState& operator=(const JoinState& other) = delete;
  JoinState& operator=(JoinState&& other) = delete;
  JoinState(JoinState&& other) noexcept : ready(other.ready) {
    if (ready.is_set(0)) {
      Construct(&result0, std::move(other.result0));
    } else {
      Construct(&promise0, std::move(other.promise0));
    }
    if (ready.is_set(1)) {
      Construct(&result1, std::move(other.result1));
    } else {
      Construct(&promise1, std::move(other.promise1));
    }
    if (ready.is_set(2)) {
      Construct(&result2, std::move(other.result2));
    } else {
      Construct(&promise2, std::move(other.promise2));
    }
    if (ready.is_set(3)) {
      Construct(&result3, std::move(other.result3));
    } else {
      Construct(&promise3, std::move(other.promise3));
    }
    if (ready.is_set(4)) {
      Construct(&result4, std::move(other.result4));
    } else {
      Construct(&promise4, std::move(other.promise4));
    }
    if (ready.is_set(5)) {
      Construct(&result5, std::move(other.result5));
    } else {
      Construct(&promise5, std::move(other.promise5));
    }
    if (ready.is_set(6)) {
      Construct(&result6, std::move(other.result6));
    } else {
      Construct(&promise6, std::move(other.promise6));
    }
    if (ready.is_set(7)) {
      Construct(&result7, std::move(other.result7));
    } else {
      Construct(&promise7, std::move(other.promise7));
    }
    if (ready.is_set(8)) {
      Construct(&result8, std::move(other.result8));
    } else {
      Construct(&promise8, std::move(other.promise8));
    }
  }
  ~JoinState() {
    if (ready.is_set(0)) {
      Destruct(&result0);
    } else {
      Destruct(&promise0);
    }
    if (ready.is_set(1)) {
      Destruct(&result1);
    } else {
      Destruct(&promise1);
    }
    if (ready.is_set(2)) {
      Destruct(&result2);
    } else {
      Destruct(&promise2);
    }
    if (ready.is_set(3)) {
      Destruct(&result3);
    } else {
      Destruct(&promise3);
    }
    if (ready.is_set(4)) {
      Destruct(&result4);
    } else {
      Destruct(&promise4);
    }
    if (ready.is_set(5)) {
      Destruct(&result5);
    } else {
      Destruct(&promise5);
    }
    if (ready.is_set(6)) {
      Destruct(&result6);
    } else {
      Destruct(&promise6);
    }
    if (ready.is_set(7)) {
      Destruct(&result7);
    } else {
      Destruct(&promise7);
    }
    if (ready.is_set(8)) {
      Destruct(&result8);
    } else {
      Destruct(&promise8);
    }
  }
  using Result = typename Traits::template ResultType<
      std::tuple<Result0, Result1, Result2, Result3, Result4, Result5, Result6,
                 Result7, Result8>>;
  Poll<Result> PollOnce() {
    if (!ready.is_set(0)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 1/9", this);
      }
      auto poll = promise0();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 1/9 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(0);
          Destruct(&promise0);
          Construct(&result0, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 1/9 already ready", this);
    }
    if (!ready.is_set(1)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 2/9", this);
      }
      auto poll = promise1();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 2/9 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(1);
          Destruct(&promise1);
          Construct(&result1, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 2/9 already ready", this);
    }
    if (!ready.is_set(2)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 3/9", this);
      }
      auto poll = promise2();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 3/9 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(2);
          Destruct(&promise2);
          Construct(&result2, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 3/9 already ready", this);
    }
    if (!ready.is_set(3)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 4/9", this);
      }
      auto poll = promise3();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 4/9 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(3);
          Destruct(&promise3);
          Construct(&result3, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 4/9 already ready", this);
    }
    if (!ready.is_set(4)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 5/9", this);
      }
      auto poll = promise4();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 5/9 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(4);
          Destruct(&promise4);
          Construct(&result4, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 5/9 already ready", this);
    }
    if (!ready.is_set(5)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 6/9", this);
      }
      auto poll = promise5();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 6/9 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(5);
          Destruct(&promise5);
          Construct(&result5, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 6/9 already ready", this);
    }
    if (!ready.is_set(6)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 7/9", this);
      }
      auto poll = promise6();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 7/9 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(6);
          Destruct(&promise6);
          Construct(&result6, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 7/9 already ready", this);
    }
    if (!ready.is_set(7)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 8/9", this);
      }
      auto poll = promise7();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 8/9 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(7);
          Destruct(&promise7);
          Construct(&result7, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 8/9 already ready", this);
    }
    if (!ready.is_set(8)) {
      if (grpc_trace_promise_primitives.enabled()) {
        gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 9/9", this);
      }
      auto poll = promise8();
      if (grpc_trace_promise_primitives.enabled()) {
        auto* p = poll.value_if_ready();
        gpr_log(GPR_DEBUG, "join[%p]: joint 9/9 %s", this,
                p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
                             : "pending");
      }
      if (auto* p = poll.value_if_ready()) {
        if (Traits::IsOk(*p)) {
          ready.set(8);
          Destruct(&promise8);
          Construct(&result8, Traits::Unwrapped(std::move(*p)));
        } else {
          return Traits::template EarlyReturn<Result>(std::move(*p));
        }
      }
    } else if (grpc_trace_promise_primitives.enabled()) {
      gpr_log(GPR_DEBUG, "join[%p]: joint 9/9 already ready", this);
    }
    if (ready.all()) {
      return Result{std::make_tuple(
          std::move(result0), std::move(result1), std::move(result2),
          std::move(result3), std::move(result4), std::move(result5),
          std::move(result6), std::move(result7), std::move(result8))};
    }
    return Pending{};
  }
};

}  // namespace promise_detail
}  // namespace grpc_core

#endif  // GRPC_SRC_CORE_LIB_PROMISE_DETAIL_JOIN_STATE_H
