Skip to content

mypy too strict in enforcing generic return types when they are unions #19239

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
thesketh opened this issue Jun 5, 2025 · 3 comments
Closed
Labels
bug mypy got something wrong

Comments

@thesketh
Copy link

thesketh commented Jun 5, 2025

Bug Report

mypy is overly strict in enforcing union return types from generic functions.

If a function both takes and returns a value of type T, which is a union of two types, and does any guarding to check which of the possible types the value is before returning it, mypy emits an "Incompatible return type" error.

To Reproduce

This happens with checks using isinstance or with is None e.g.:

def generic_function[T: str | int](value: T) -> T:
    if isinstance(value, int):
        return value
    return value

https://mypy-play.net/?mypy=latest&python=3.12&gist=470d29ce79af159a1950e5f47aac2798

and

def generic_function[T: str | None](value: T) -> T:
    if value is None:
        return value
    return value

https://mypy-play.net/?mypy=latest&python=3.12&gist=16f08fc7cc619fa2797d12d6c50e2103

Expected Behavior

mypy should not emit an error, because the input and output types are still correct, the guard just leads to an early return.

I suppose more specifically I would expect that guards on the input type for a generic which takes and returns the same type should also be guards on the output type.

Actual Behavior

error: Incompatible return value type (got "int", expected "T") [return-value]
and
error: Incompatible return value type (got "None", expected "T") [return-value]

Your Environment

  • Mypy version used: 1.16.0
  • Mypy command-line flags:
  • Mypy configuration options from mypy.ini (and other config files):
[tool.mypy]
strict = true
python_version = "3.12"
plugins = ['pydantic.mypy']
  • Python version used: Python 3.12
@thesketh thesketh added the bug mypy got something wrong label Jun 5, 2025
@thesketh thesketh changed the title [1.16 regression] mypy too strict in enforcing generic return types when they are unions mypy too strict in enforcing generic return types when they are unions Jun 5, 2025
@thesketh
Copy link
Author

thesketh commented Jun 5, 2025

I've changed the title - the None case is a 1.16 regression and has been fixed on master, but the int/isinstance case still emits an error and I don't think it should.

@A5rocks
Copy link
Collaborator

A5rocks commented Jun 5, 2025

I assume this is fixed by #19183

@thesketh
Copy link
Author

thesketh commented Jun 5, 2025

Looks like it has been - I must have accidentally clicked "mypy latest" when I tried the isinstance(value, int) case, whoops. Nice spot @A5rocks

@thesketh thesketh closed this as completed Jun 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

No branches or pull requests

2 participants