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

Union types: Support narrowing to Ellipsis (...) cases of Unions #13157

Merged
merged 1 commit into from
Jul 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions mypy/typeops.py
Original file line number Diff line number Diff line change
Expand Up @@ -732,8 +732,8 @@ def is_singleton_type(typ: Type) -> bool:
'is_singleton_type(t)' returns True if and only if the expression 'a is b' is
always true.

Currently, this returns True when given NoneTypes, enum LiteralTypes and
enum types with a single value.
Currently, this returns True when given NoneTypes, enum LiteralTypes,
enum types with a single value and ... (Ellipses).

Note that other kinds of LiteralTypes cannot count as singleton types. For
example, suppose we do 'a = 100000 + 1' and 'b = 100001'. It is not guaranteed
Expand All @@ -742,12 +742,14 @@ def is_singleton_type(typ: Type) -> bool:
"""
typ = get_proper_type(typ)
# TODO:
# Also make this return True if the type corresponds to ... (ellipsis) or NotImplemented?
# Also make this return True if the type corresponds to NotImplemented?
return (
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 (
vlaci marked this conversation as resolved.
Show resolved Hide resolved
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