python / python/mypy

Having a function that takes `Optional[T]` as an input and returns `T` (A type var) works incorrectly if T is an union

Open
#17,383 2 comments 6 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug priority-0-high topic-join-v-union
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Bug Report

Having a function that takes Optional[T] as an input and returns T (A type var) works incorrectly if T is an union.

To Reproduce

from typing import TypeVar


class A:
    pass


class B:
    pass


T = TypeVar("T")


def make_non_optional(value: T | None) -> T:
    if value is None:
        raise ValueError("Value is None")
    return value


def make_non_optimal_simple_example() -> A:
    my_value: A | None = None
    return make_non_optional(my_value)  # This works as expected


def make_non_optimal_complex_example_broken() -> A | B:
    my_value: A | B | None = None
    return make_non_optional(my_value)  # error: Incompatible return value type (got "object", expected "A | B")  [return-value]

Expected Behavior

When calling make_non_optional(my_value) with A | B | None the returned type should be A | B

Actual Behavior

It has object type as the return type

Your Environment

Mypy version used:

 $ mypy --version
mypy 1.10.0 (compiled: yes)

Python version used:

 $ python --version
Python 3.12.2

Mypy command-line flags: none

Mypy configuration options from mypy.ini (and other config files): none

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the provided example with mypy 1.10.0, then trace the type inference handling for TypeVar inputs whose type is a union. Add a regression test for the example and consider the issue done when the call is inferred as A | B without an incompatible return-value error.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
compilers, devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.