Skip to content

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

Closed
@thesketh

Description

@thesketh

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrong

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions