Skip to content
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

Inconsistent behavior when narrowing bounded generics. #13426

Open
denballakh opened this issue Aug 15, 2022 · 2 comments
Open

Inconsistent behavior when narrowing bounded generics. #13426

denballakh opened this issue Aug 15, 2022 · 2 comments
Labels
bug mypy got something wrong topic-type-narrowing Conditional type narrowing / binder

Comments

@denballakh
Copy link
Contributor

Consider this example:

from typing import Generic, TypeVar

T = TypeVar('T')
G = TypeVar('G', bound='Y')

class X(Generic[T]): pass
class Y: pass

# Consider this function:
def f(a: X[T] | G) -> X[T] | G:
    if isinstance(a, X):
        reveal_type(a) # X[T`-1]
        return a
    if isinstance(a, Y):
        reveal_type(a) # G`-2
        return a

    print() # error: unreachable. It is ok, because all possibilities checked.

# The same function, but if's swapped
def g(a: X[T] | G) -> X[T] | G: # error: Missing return statement
    if isinstance(a, Y):
        reveal_type(a) # Y
        return a # error: Incompatible return value type (got "Y", expected "Union[X[T], G]")
    if isinstance(a, X):
        reveal_type(a) # X[T`-1]
        return a

    print() # no "error: unreachable", because it is reachable and mypy complains about "missing return"
    # I expect to get no errors here, because it isnt reachable

Expected Behavior
First function is fine. I expect to get no errors in second function. Also first reveal_type in second function is IMO invalid, it should be G.

Your Environment

  • Mypy version used: mypy 0.971 (compiled: yes)
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files):
disallow_any_unimported = True
disallow_any_generics = True
disallow_subclassing_any = True
disallow_untyped_defs = True
disallow_incomplete_defs = True
disallow_untyped_decorators = True
warn_unreachable = True
warn_redundant_casts = True
warn_unused_ignores = True
# warn_return_any = True
strict_equality = True
show_column_numbers = True
  • Python version used: 3.10.6
  • Operating system and version: Win10

PS: pls give better title to this issue, idk how to properly describe this issue.

@denballakh denballakh added the bug mypy got something wrong label Aug 15, 2022
@denballakh
Copy link
Contributor Author

May be related: #9023 #7913 #7362

@brianschubert
Copy link
Collaborator

This incorrect reachability analysis in the second function was fixed in #14923.

The narrowing issue in the isinstance(a, Y) branch is still present in mypy v1.13.0. Here's a simplified reproducer:

from typing import TypeVar, assert_never

class A: pass

T = TypeVar("T", bound=A)

def foo(x: T | int) -> T | int:
    if isinstance(x, A):
        reveal_type(x)  # N: Revealed type is "__main__.A"
        return x  # E: Incompatible return value type (got "A", expected "T | int")

@brianschubert brianschubert added the topic-type-narrowing Conditional type narrowing / binder label Dec 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-type-narrowing Conditional type narrowing / binder
Projects
None yet
Development

No branches or pull requests

2 participants