Skip to content

Fix crash on contravariant base that refers back to the subclass - #22365

Closed
kushwahaamar-dev wants to merge 1 commit into
python:masterfrom
kushwahaamar-dev:contravariant-recursive-base
Closed

kushwahaamar-dev wants to merge 1 commit into
python:masterfrom
kushwahaamar-dev:contravariant-recursive-base

Conversation

@kushwahaamar-dev

Copy link
Copy Markdown

Fixes #22360

With a contravariant N and

class C(N[N["C"]]): ...

checking C <: N[C] maps C up to N[N[C]], and since N is contravariant the argument check becomes C <: N[C] again. mypy kept going around that loop until it hit the recursion limit (segfault on compiled builds).

is_subtype already checks the assumption stack at the top, which is how recursive aliases avoid this. So in visit_instance I push (left, right) while checking the type args, but only when left was mapped to a base class and the target has a contravariant (or not yet inferred) type var. That's the only shape that can loop back, and it keeps the extra work off the common path.

C is now accepted as an N[C], which matches pyright and ty. A real mismatch like returning C as N[int] still errors.

Added tests for the plain and generic versions from the issue, plus a PEP 695 one where the variance is inferred.

With class C(N[N[C]]) and a contravariant N, checking C <: N[C] maps C
to N[N[C]], and the contravariant argument flips the check back to
C <: N[C], so mypy recursed until it crashed.

Assume the pair holds while checking type arguments when left was
mapped to a base and the target has a contravariant (or not yet
inferred) type variable. That reuses the existing assumption stack
that recursive type aliases already rely on.

Fixes python#22360
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

@ilevkivskyi ilevkivskyi closed this Nov 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

contravariant generic with a self-referential base

2 participants