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

Now type(None) is more consistent, refs #11550 #11552

Closed
wants to merge 2 commits into from
Closed
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
5 changes: 5 additions & 0 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -3220,6 +3220,11 @@ class LongName(Generic[T]): ...
return type_object_type(tuple_fallback(item).type, self.named_type)
elif isinstance(item, AnyType):
return AnyType(TypeOfAny.from_another_any, source_any=item)
elif isinstance(item, NoneType):
# This is a special case, `x = type(None)` turns into
# `x = TypeAliasType(None)` during semantic analysis.
# So, we need to show the real type here. Which is `Type[None]`.
return TypeType(item)
else:
if alias_definition:
return AnyType(TypeOfAny.special_form)
Expand Down
2 changes: 2 additions & 0 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -2686,6 +2686,8 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool:

res: Optional[Type] = None
if self.is_none_alias(rvalue):
# This is really `Type[None]`, not just `None`, but we use
# this as a backwards compatible solution. See #11550
res = NoneType()
Copy link
Member Author

@sobolevn sobolevn Nov 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can still cause issues, for example:

none = type(None)

print(none())  # E: error: Cannot instantiate type "Type[None]"

But, I've decided to keep this as-is (and do not change this to res = TypeType(NoneType())), because I'm affraid this can cause issues to our old users, who use type(None) for annotations.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we decide to change this, we can try to make Type[None] and None compatible. So, this will work:

n = type(None)
var: n = None  # will still be ok!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think types that are none should be annotated None. If someone tries to annotate something that is none as type(None) we should give an error and tell them to annotate it as : None (though I also expect this to be rather rare).

alias_tvars, depends_on, qualified_tvars = \
[], set(), [] # type: List[str], Set[str], List[str]
Expand Down
39 changes: 39 additions & 0 deletions test-data/unit/check-type-aliases.test
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,45 @@ x = y # E: Incompatible types in assignment (expression has type "Optional[int]
y = z
[builtins fixtures/bool.pyi]

[case testTypeNoneAliases]
from typing import Type

a = type(None)
b: Type[None]
c: Type[None] = type(None)
d: None
e = None

reveal_type(a) # N: Revealed type is "Type[None]"
reveal_type(b) # N: Revealed type is "Type[None]"
reveal_type(c) # N: Revealed type is "Type[None]"
reveal_type(d) # N: Revealed type is "None"
reveal_type(e) # N: Revealed type is "None"

reveal_type(type(None)) # N: Revealed type is "Type[None]"
reveal_type(None) # N: Revealed type is "None"
[builtins fixtures/bool.pyi]

[case testTypeNoneAliasesStrict]
# flags: --strict-optional
from typing import Type

a = type(None)
b: Type[None]
c: Type[None] = type(None)
d: None
e = None

reveal_type(a) # N: Revealed type is "Type[None]"
reveal_type(b) # N: Revealed type is "Type[None]"
reveal_type(c) # N: Revealed type is "Type[None]"
reveal_type(d) # N: Revealed type is "None"
reveal_type(e) # N: Revealed type is "None"

reveal_type(type(None)) # N: Revealed type is "Type[None]"
reveal_type(None) # N: Revealed type is "None"
[builtins fixtures/bool.pyi]

[case testAliasToTupleAndCallable]
from typing import Callable, Tuple
C = Callable
Expand Down
5 changes: 3 additions & 2 deletions test-data/unit/fixtures/bool.pyi
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# builtins stub used in boolean-related test cases.
from typing import Generic, TypeVar
from typing import Generic, TypeVar, Union
T = TypeVar('T')

class object:
def __init__(self) -> None: pass
def __eq__(self, other: object) -> bool: pass
def __ne__(self, other: object) -> bool: pass

class type: pass
class type:
def __init__(self, obj: Union[object, None]) -> None: pass
class tuple(Generic[T]): pass
class function: pass
class int: pass
Expand Down