diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index e850744b5c710..7de28e4b1170e 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -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) diff --git a/mypy/semanal.py b/mypy/semanal.py index 1a99a4837cee1..90b95525693cb 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -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() alias_tvars, depends_on, qualified_tvars = \ [], set(), [] # type: List[str], Set[str], List[str] diff --git a/test-data/unit/check-type-aliases.test b/test-data/unit/check-type-aliases.test index a697c32d7c49b..2e587c95cd4d0 100644 --- a/test-data/unit/check-type-aliases.test +++ b/test-data/unit/check-type-aliases.test @@ -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 diff --git a/test-data/unit/fixtures/bool.pyi b/test-data/unit/fixtures/bool.pyi index ca2564dabafd9..9b985b1c5580e 100644 --- a/test-data/unit/fixtures/bool.pyi +++ b/test-data/unit/fixtures/bool.pyi @@ -1,5 +1,5 @@ # builtins stub used in boolean-related test cases. -from typing import Generic, TypeVar +from typing import Generic, TypeVar, Union T = TypeVar('T') class object: @@ -7,7 +7,8 @@ class object: 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