Returns a tuple of all alternate types allowed by the `typ` type annotation.

    If typ is a TypeVar,
     * if the typevar is bound, return get_alternate_types_resolving_forwardref_union_and_typevar(bound)
     * if the typevar has constraints, return a tuple containing all the types listed in the constraints (with
     appropriate recursive call to get_alternate_types_resolving_forwardref_union_and_typevar for each of them)
     * otherwise return (object, )

    If typ is a Union, return a tuple containing all the types listed in the union (with
     appropriate recursive call to get_alternate_types_resolving_forwardref_union_and_typevar for each of them)

    If typ is a forward reference, it is evaluated and this method is applied to the results.

    Otherwise (typ, ) is returned

    Note that this function automatically prevent infinite recursion through forward references such as in
    `A = Union[str, 'A']`, by keeping a _memo of already met symbols.

    :param typ: 
    :return:

def get_alternate_types_resolving_forwardref_union_and_typevar(typ, _memo: List[Any] = None) \
        -> Tuple[Any, ...]:
    """
    Returns a tuple of all alternate types allowed by the `typ` type annotation.

    If typ is a TypeVar,
     * if the typevar is bound, return get_alternate_types_resolving_forwardref_union_and_typevar(bound)
     * if the typevar has constraints, return a tuple containing all the types listed in the constraints (with
     appropriate recursive call to get_alternate_types_resolving_forwardref_union_and_typevar for each of them)
     * otherwise return (object, )

    If typ is a Union, return a tuple containing all the types listed in the union (with
     appropriate recursive call to get_alternate_types_resolving_forwardref_union_and_typevar for each of them)

    If typ is a forward reference, it is evaluated and this method is applied to the results.

    Otherwise (typ, ) is returned

    Note that this function automatically prevent infinite recursion through forward references such as in
    `A = Union[str, 'A']`, by keeping a _memo of already met symbols.

    :param typ: 
    :return: 
    """
    # avoid infinite recursion by using a _memo
    _memo = _memo or []
    if typ in _memo:
        return tuple()

    # remember that this was already explored
    _memo.append(typ)
    if is_typevar(typ):
        if hasattr(typ, '__bound__') and typ.__bound__ is not None:
            # TypeVar is 'bound' to a class
            if hasattr(typ, '__contravariant__') and typ.__contravariant__:
                # Contravariant means that only super classes of this type are supported!
                raise Exception('Contravariant TypeVars are not supported')
            else:
                # only subclasses of this are allowed (even if not covariant, because as of today we cant do otherwise)
                return get_alternate_types_resolving_forwardref_union_and_typevar(typ.__bound__, _memo=_memo)

        elif hasattr(typ, '__constraints__') and typ.__constraints__ is not None:
            if hasattr(typ, '__contravariant__') and typ.__contravariant__:
                # Contravariant means that only super classes of this type are supported!
                raise Exception('Contravariant TypeVars are not supported')
            else:
                # TypeVar is 'constrained' to several alternate classes, meaning that subclasses of any of them are
                # allowed (even if not covariant, because as of today we cant do otherwise)
                return tuple(typpp for c in typ.__constraints__
                             for typpp in get_alternate_types_resolving_forwardref_union_and_typevar(c, _memo=_memo))

        else:
            # A non-parametrized TypeVar means 'any'
            return object,

    elif is_union_type(typ):
        # do not use typ.__args__, it may be wrong
        # the solution below works even in typevar+config cases such as u = Union[T, str][Optional[int]]
        return tuple(t for typpp in get_args(typ, evaluate=True)
                     for t in get_alternate_types_resolving_forwardref_union_and_typevar(typpp, _memo=_memo))

    elif is_forward_ref(typ):
        return get_alternate_types_resolving_forwardref_union_and_typevar(resolve_forward_ref(typ), _memo=_memo)

    else:
        return typ,