Skip to content

Bounded TypeVar inferred as object for nested covariant generic arguments #22331

Open

Description

@ayushin

Bug report

Mypy infers object for a bounded type variable when combining covariant generic arguments, although their common upper bound is valid. This reproduces without Django or plugins.

Reproducer

from typing import Generic, TypeVar
class Model: pass
class Person(Model): pass
class Audit(Model): pass
M = TypeVar("M", bound=Model, covariant=True)
class QuerySet(Generic[M]): pass
Q = TypeVar("Q", bound=QuerySet[Model], covariant=True)
L = TypeVar("L", bound=str, covariant=True)
P = TypeVar("P", bound=Person)
class Prefetch(Generic[L, Q]):
    def __init__(self, lookup: L, queryset: Q) -> None: ...
def accept(*items: Prefetch[L, Q]) -> None: ...
def example(people: QuerySet[P], audits: QuerySet[Audit]) -> None:
    accept(Prefetch("left", queryset=people), Prefetch("audit", queryset=audits))

Expected: the call is accepted; Q = QuerySet[Model] satisfies both arguments and its bound.

Actual:

error: Value of type variable "Q" of "accept" cannot be "object"  [type-var]

Annotating each argument as Prefetch[str, QuerySet[Model]] before the call succeeds. Using concrete QuerySet[Person] instead of QuerySet[P], or removing the L parameter from Prefetch, also succeeds. Merely assigning the arguments to unannotated intermediate variables does not help.

Environment: Python 3.14.6; reproduced on mypy 2.4.1 and unmodified master d8a43fbcf21e30bd7855b5635bdd2f07ffbb5d95, without plugins or project configuration (--no-incremental --cache-dir=/dev/null --config-file=/dev/null).

Originally reported as typeddjango/django-stubs#3770. The draft stubs PR bypasses this inference and is being withdrawn in favor of reporting the checker issue.

Investigation and reproducer prepared with AI assistance.

Activity

  1. Anurag-S1ngh commented on Oct 31, 2026

    @Anurag-S1ngh

    Hi, I'd like to take this issue. Could you assign it to me?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      ⌂ Proxy