Skip to content

Commit

Permalink
Union types: Support narrowing to Ellipsis (...) cases of Unions
Browse files Browse the repository at this point in the history
After this change, narrowing to `Ellipsis` works similarly with
regards to narrowing as `None` in `Optional`s

It would be a good followup refactor to delegate some of the logic
from `is_singleton_type` to the actual mypy types so they could decide
for themselves if they are representing singleton objects

Fixes: python#13117
Co-authored-by: Zsolt Cserna <cserna.zsolt@gmail.com>
  • Loading branch information
László Vaskó and csernazs committed Jul 16, 2022
1 parent b13a450 commit 1bc831a
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 2 deletions.
4 changes: 3 additions & 1 deletion mypy/typeops.py
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,9 @@ def is_singleton_type(typ: Type) -> bool:
isinstance(typ, NoneType)
or (isinstance(typ, LiteralType)
and (typ.is_enum_literal() or isinstance(typ.value, bool)))
or (isinstance(typ, Instance) and typ.type.is_enum and len(get_enum_values(typ)) == 1)
or (isinstance(typ, Instance) and (
typ.type.is_enum and len(get_enum_values(typ)) == 1
or typ.type.fullname == 'builtins.ellipsis'))
)


Expand Down
10 changes: 10 additions & 0 deletions test-data/unit/check-unions.test
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,16 @@ def f() -> Union[int, None]: pass
x = 1
x = f()

[case testUnionWithEllipsis]
from typing import Union
def f(x: Union[int, EllipsisType]) -> int:
if x is Ellipsis:
reveal_type(x) # N: Revealed type is "builtins.ellipsis"
x = 1
reveal_type(x) # N: Revealed type is "builtins.int"
return x
[builtins fixtures/isinstancelist.pyi]

[case testOptional]
from typing import Optional
def f(x: Optional[int]) -> None: pass
Expand Down
5 changes: 4 additions & 1 deletion test-data/unit/fixtures/isinstancelist.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ class type:
def __init__(self, x) -> None: pass

class function: pass
class ellipsis: pass
class classmethod: pass

class ellipsis: pass
EllipsisType = ellipsis
Ellipsis = ellipsis()

def isinstance(x: object, t: Union[type, Tuple]) -> bool: pass
def issubclass(x: object, t: Union[type, Tuple]) -> bool: pass

Expand Down

0 comments on commit 1bc831a

Please sign in to comment.