docs: private static void complete(AbstractFuture<?> future) {
      boolean maskExecutorExceptions = future.maskExecutorExceptions;
      Listener next = null;
      outer: while (true) {
        future.releaseWaiters();
        // We call this before the listeners in order to avoid needing to manage a separate stack data
        // structure for them.
        // afterDone() should be generally fast and only used for cleanup work... but in theory can
        // also be recursive and create StackOverflowErrors
        future.afterDone();
        // push the current set of listeners onto next
        next = future.clearListeners(next);
        future = null;
        while (next != null) {
          Listener curr = next;
          next = next.next;
          Runnable task = curr.task;
          if (task instanceof AbstractFuture.SetFuture) {
            AbstractFuture.SetFuture<?> setFuture = (AbstractFuture.SetFuture) task;
            // We unwind setFuture specifically to avoid StackOverflowErrors in the case of long
            // chains of SetFutures
            // Handling this special case is important because there is no way to pass an executor to
            // setFuture, so a user couldn't break the chain by doing this themselves.  It is also
            // potentially common if someone writes a recursive Futures.transformAsync transformer.
            future = setFuture.owner;
            if (future.value == setFuture) {
              Object valueToSet = getFutureValue(setFuture.future);
              if (ATOMIC_HELPER.casValue(future, setFuture, valueToSet)) {
                continue outer;
              }
            }
            // other wise the future we were trying to set is already done.
          } else {
            executeListener(task, curr.executor, maskExecutorExceptions);
          }
        }
        break;
      }
    }