diff --git a/synapse/util/async_helpers.py b/synapse/util/async_helpers.py
index 20ce294209..bde99ea878 100644
--- a/synapse/util/async_helpers.py
+++ b/synapse/util/async_helpers.py
@@ -30,9 +30,11 @@ from typing import (
Iterator,
Optional,
Set,
+ Tuple,
TypeVar,
Union,
cast,
+ overload,
)
import attr
@@ -234,6 +236,59 @@ def yieldable_gather_results(
).addErrback(unwrapFirstError)
+T1 = TypeVar("T1")
+T2 = TypeVar("T2")
+T3 = TypeVar("T3")
+
+
+@overload
+def gather_results(
+ deferredList: Tuple[()], consumeErrors: bool = ...
+) -> "defer.Deferred[Tuple[()]]":
+ ...
+
+
+@overload
+def gather_results(
+ deferredList: Tuple["defer.Deferred[T1]"],
+ consumeErrors: bool = ...,
+) -> "defer.Deferred[Tuple[T1]]":
+ ...
+
+
+@overload
+def gather_results(
+ deferredList: Tuple["defer.Deferred[T1]", "defer.Deferred[T2]"],
+ consumeErrors: bool = ...,
+) -> "defer.Deferred[Tuple[T1, T2]]":
+ ...
+
+
+@overload
+def gather_results(
+ deferredList: Tuple[
+ "defer.Deferred[T1]", "defer.Deferred[T2]", "defer.Deferred[T3]"
+ ],
+ consumeErrors: bool = ...,
+) -> "defer.Deferred[Tuple[T1, T2, T3]]":
+ ...
+
+
+def gather_results( # type: ignore[misc]
+ deferredList: Tuple["defer.Deferred[T1]", ...],
+ consumeErrors: bool = False,
+) -> "defer.Deferred[Tuple[T1, ...]]":
+ """Combines a tuple of `Deferred`s into a single `Deferred`.
+
+ Wraps `defer.gatherResults` to provide type annotations that support heterogenous
+ lists of `Deferred`s.
+ """
+ # The `type: ignore[misc]` above suppresses
+ # "Overloaded function implementation cannot produce return type of signature 1/2/3"
+ deferred = defer.gatherResults(deferredList, consumeErrors=consumeErrors)
+ return deferred.addCallback(tuple)
+
+
@attr.s(slots=True)
class _LinearizerEntry:
# The number of things executing.
@@ -352,7 +407,7 @@ class Linearizer:
logger.debug("Waiting to acquire linearizer lock %r for key %r", self.name, key)
- new_defer = make_deferred_yieldable(defer.Deferred())
+ new_defer: "defer.Deferred[None]" = make_deferred_yieldable(defer.Deferred())
entry.deferreds[new_defer] = 1
def cb(_r: None) -> "defer.Deferred[None]":
|