Skip to content

Narrow types after 'in' operator. #4071

Closed
@ilevkivskyi

Description

@ilevkivskyi
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.

Activity

self-assigned this
on Oct 8, 2017
elazarg

elazarg commented on Oct 8, 2017

@elazarg
Contributor

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

gvanrossum

gvanrossum commented on Oct 8, 2017

@gvanrossum
Member
ilevkivskyi

ilevkivskyi commented on Oct 8, 2017

@ilevkivskyi
MemberAuthor

@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

ilevkivskyi commented on Oct 8, 2017

@ilevkivskyi
MemberAuthor

@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.

added a commit that references this issue on Oct 13, 2017
b875205
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @gvanrossum@elazarg@ilevkivskyi

      Issue actions

        Narrow types after 'in' operator. · Issue #4071 · python/mypy