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

Narrow types after 'in' operator. #4071

Closed
ilevkivskyi opened this issue Oct 8, 2017 · 4 comments
Closed

Narrow types after 'in' operator. #4071

ilevkivskyi opened this issue Oct 8, 2017 · 4 comments
Assignees

Comments

@ilevkivskyi
Copy link
Member

Sometimes it is useful to narrow down a type after an in/not in comparison. For example:

class Option:
    ...
opt: Union[Option, str]
if opt in ('verbose', 'silent'):
    reveal_type(opt)  # we know this is 'str'
else:
    ...  # still a union here

presets: List[Option]
if opt not in presets:
    ...  # still a union
else:
    reveal_type(opt)  # we know this can be only 'Option'

This seems to be especially useful for --strict-optional, for example:

class Node:
    fullname: Optional[str]
n: Node

reverse_aliases: Dict[str, str]
if n.fullname in reverse_aliases:
    reveal_type(n.fullname)  # This should be 'str'

(related #2980)

A similar idea was discussed in #1749, but emitting an error on if 'a' in [1, 2, 3]: ... would require a larger change: emitting errors on unreachable code in binder.

@ilevkivskyi ilevkivskyi self-assigned this Oct 8, 2017
@elazarg
Copy link
Contributor

elazarg commented Oct 8, 2017

I think this can also fall out of #4063 (just as a note; of course a dedicated PR is more practical)

@gvanrossum
Copy link
Member

gvanrossum commented Oct 8, 2017 via email

@ilevkivskyi
Copy link
Member Author

@gvanrossum

Careful. For unconstrained x, after x in (1, 2), x may still be a float. (Or a fraction or decimal?)

OK, makes sense, we should not narrow down if we start from Any and should not use promotions (this is actually default in is_overlapping_types). I will update the PR now.

@ilevkivskyi
Copy link
Member Author

ilevkivskyi commented Oct 8, 2017

@gvanrossum OK, I updated PR #4072
Now it does not narrow type from Any and does not use promotions:

x: Any
if x in [1, 2, 3]:
    reveal_type(x)  # Revealed type is 'Any'
y: float
if y in [1, 2, 3]:
    reveal_type(x)  # Revealed type is 'builtins.float'

It is however not easy to prohibit this:

z: object
if z in [1, 2, 3]:
    reveal_type(z)  # Revealed type is 'builtins.int'

This is still formally speaking unsafe, but I think it is a reasonable price to pay.

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

No branches or pull requests

3 participants