Skip to content

Support type narrowing based on in (__contains__()) #17101

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
allisonkarlitskaya opened this issue Apr 5, 2024 · 1 comment
Closed

Support type narrowing based on in (__contains__()) #17101

allisonkarlitskaya opened this issue Apr 5, 2024 · 1 comment
Labels

Comments

@allisonkarlitskaya
Copy link

I recently tried and failed to get some code like this working:

from typing import Collection, TypeVar
T = TypeVar('T')
  
def check_contained(x: object, y: Collection[T]) -> T:
    if x not in y:
        raise RuntimeError
    return x    # Incompatible return value type (got "object", expected "T")

At first, I thought that this is definitely wrong, but then I realized: okay, in theory in is implemented based on __eq__ and we could be in a situation where x compares equal to a T-typed value in y without being T itself (for example, if T is bool, y is [True] and x is 1). The error message could definitely be more helpful in this case, of course...

But consider this case:

def check_str_contained(x: object, y: Collection[str]) -> str:
    if x not in y:
        raise RuntimeError
    return x    # Incompatible return value type (got "object", expected "str")

I really can't figure out a reasonable counterexample here. The only way we're going to have x in y is if x is either a str or a subclass of str. I suppose we might imagine that y contains str subclasses which implement strange __eq__ rules that return true on comparison to non-str values...

And indeed, this also fails:

def check_eq(x: object, y: str) -> str:
    if x != y:
        raise RuntimeError
    return x    # Incompatible return value type (got "object", expected "str")

and, taken to the extreme, this too:

def check_boolstr(x: object, y: Collection[Literal["yes"] | Literal["no"]]) -> str:
    if x not in y:
        raise RuntimeError
    return x    # Incompatible return value type (got "object", expected "str")

That's a shame. This would be a very useful feature, particularly on generics. Maybe we can figure out a way forward here...

@sterliakov
Copy link
Collaborator

Duplicates #3229?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants