Skip to content

Represent bottom type as Never #15996

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

Merged
merged 1 commit into from
Aug 31, 2023
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
12 changes: 6 additions & 6 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -3934,7 +3934,7 @@ def is_valid_defaultdict_partial_value_type(self, t: ProperType) -> bool:
Examples:

* t is 'int' --> True
* t is 'list[<nothing>]' --> True
* t is 'list[Never]' --> True
* t is 'dict[...]' --> False (only generic types with a single type
argument supported)
"""
Expand Down Expand Up @@ -3980,7 +3980,7 @@ def set_inference_error_fallback_type(self, var: Var, lvalue: Lvalue, type: Type
x = [] # type: ignore
x.append(1) # Should be ok!

We implement this here by giving x a valid type (replacing inferred <nothing> with Any).
We implement this here by giving x a valid type (replacing inferred Never with Any).
"""
fallback = self.inference_error_fallback_type(type)
self.set_inferred_type(var, lvalue, fallback)
Expand Down Expand Up @@ -7403,7 +7403,7 @@ def is_valid_inferred_type(typ: Type, is_lvalue_final: bool = False) -> bool:
class InvalidInferredTypes(BoolTypeQuery):
"""Find type components that are not valid for an inferred type.

These include <Erased> type, and any <nothing> types resulting from failed
These include <Erased> type, and any uninhabited types resulting from failed
(ambiguous) type inference.
"""

Expand All @@ -7424,15 +7424,15 @@ def visit_type_var(self, t: TypeVarType) -> bool:


class SetNothingToAny(TypeTranslator):
"""Replace all ambiguous <nothing> types with Any (to avoid spurious extra errors)."""
"""Replace all ambiguous Uninhabited types with Any (to avoid spurious extra errors)."""

def visit_uninhabited_type(self, t: UninhabitedType) -> Type:
if t.ambiguous:
return AnyType(TypeOfAny.from_error)
return t

def visit_type_alias_type(self, t: TypeAliasType) -> Type:
# Target of the alias cannot be an ambiguous <nothing>, so we just
# Target of the alias cannot be an ambiguous UninhabitedType, so we just
# replace the arguments.
return t.copy_modified(args=[a.accept(self) for a in t.args])

Expand Down Expand Up @@ -7774,7 +7774,7 @@ def is_subtype_no_promote(left: Type, right: Type) -> bool:


def is_overlapping_types_no_promote_no_uninhabited_no_none(left: Type, right: Type) -> bool:
# For the purpose of unsafe overload checks we consider list[<nothing>] and list[int]
# For the purpose of unsafe overload checks we consider list[Never] and list[int]
# non-overlapping. This is consistent with how we treat list[int] and list[str] as
# non-overlapping, despite [] belongs to both. Also this will prevent false positives
# for failed type inference during unification.
Expand Down
4 changes: 2 additions & 2 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -2080,7 +2080,7 @@ def infer_function_type_arguments(
):
freeze_all_type_vars(applied)
return applied
# If it didn't work, erase free variables as <nothing>, to avoid confusing errors.
# If it didn't work, erase free variables as uninhabited, to avoid confusing errors.
unknown = UninhabitedType()
unknown.ambiguous = True
inferred_args = [
Expand Down Expand Up @@ -2440,7 +2440,7 @@ def check_argument_types(
callee_arg_types = [orig_callee_arg_type]
callee_arg_kinds = [ARG_STAR]
else:
# TODO: Any and <nothing> can appear in Unpack (as a result of user error),
# TODO: Any and Never can appear in Unpack (as a result of user error),
# fail gracefully here and elsewhere (and/or normalize them away).
assert isinstance(unpacked_type, Instance)
assert unpacked_type.type.fullname == "builtins.tuple"
Expand Down
2 changes: 1 addition & 1 deletion mypy/expandtype.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ def expand_unpack(self, t: UnpackType) -> list[Type]:
):
return [UnpackType(typ=repl)]
elif isinstance(repl, (AnyType, UninhabitedType)):
# Replace *Ts = Any with *Ts = *tuple[Any, ...] and some for <nothing>.
# Replace *Ts = Any with *Ts = *tuple[Any, ...] and some for Never.
# These types may appear here as a result of user error or failed inference.
return [UnpackType(t.type.tuple_fallback.copy_modified(args=[repl]))]
else:
Expand Down
4 changes: 2 additions & 2 deletions mypy/meet.py
Original file line number Diff line number Diff line change
Expand Up @@ -968,11 +968,11 @@ def typed_dict_mapping_overlap(

As usual empty, dictionaries lie in a gray area. In general, List[str] and List[str]
are considered non-overlapping despite empty list belongs to both. However, List[int]
and List[<nothing>] are considered overlapping.
and List[Never] are considered overlapping.

So here we follow the same logic: a TypedDict with no required keys is considered
non-overlapping with Mapping[str, <some type>], but is considered overlapping with
Mapping[<nothing>, <nothing>]. This way we avoid false positives for overloads, and also
Mapping[Never, Never]. This way we avoid false positives for overloads, and also
avoid false positives for comparisons like SomeTypedDict == {} under --strict-equality.
"""
left, right = get_proper_types((left, right))
Expand Down
6 changes: 3 additions & 3 deletions mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -2052,7 +2052,7 @@ def report_protocol_problems(
if supertype.type.fullname in exclusions.get(type(subtype), []):
return
if any(isinstance(tp, UninhabitedType) for tp in get_proper_types(supertype.args)):
# We don't want to add notes for failed inference (e.g. Iterable[<nothing>]).
# We don't want to add notes for failed inference (e.g. Iterable[Never]).
# This will be only confusing a user even more.
return

Expand Down Expand Up @@ -2379,7 +2379,7 @@ def quote_type_string(type_string: str) -> str:
"""Quotes a type representation for use in messages."""
no_quote_regex = r"^<(tuple|union): \d+ items>$"
if (
type_string in ["Module", "overloaded function", "<nothing>", "<deleted>"]
type_string in ["Module", "overloaded function", "Never", "<deleted>"]
or type_string.startswith("Module ")
or re.match(no_quote_regex, type_string) is not None
or type_string.endswith("?")
Expand Down Expand Up @@ -2581,7 +2581,7 @@ def format_literal_value(typ: LiteralType) -> str:
if typ.is_noreturn:
return "NoReturn"
else:
return "<nothing>"
return "Never"
elif isinstance(typ, TypeType):
type_name = "type" if options.use_lowercase_names() else "Type"
return f"{type_name}[{format(typ.item)}]"
Expand Down
4 changes: 2 additions & 2 deletions mypy/solve.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,8 @@ def test(x: U) -> U: ...
common_upper_bound_p = get_proper_type(common_upper_bound)
# We include None for when strict-optional is disabled.
if isinstance(common_upper_bound_p, (UninhabitedType, NoneType)):
# This will cause to infer <nothing>, which is better than a free TypeVar
# that has an upper bound <nothing>.
# This will cause to infer Never, which is better than a free TypeVar
# that has an upper bound Never.
return None

values: list[Type] = []
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeops.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ class B(A): pass
)

# Update the method signature with the solutions found.
# Technically, some constraints might be unsolvable, make them <nothing>.
# Technically, some constraints might be unsolvable, make them Never.
to_apply = [t if t is not None else UninhabitedType() for t in typeargs]
func = expand_type(func, {tv.id: arg for tv, arg in zip(self_vars, to_apply)})
variables = [v for v in func.variables if v not in self_vars]
Expand Down
2 changes: 1 addition & 1 deletion mypy/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3103,7 +3103,7 @@ def visit_none_type(self, t: NoneType) -> str:
return "None"

def visit_uninhabited_type(self, t: UninhabitedType) -> str:
return "<nothing>"
return "Never"

def visit_erased_type(self, t: ErasedType) -> str:
return "<Erased>"
Expand Down
16 changes: 8 additions & 8 deletions test-data/unit/check-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -7718,13 +7718,13 @@ class D:
def __init__(self) -> NoReturn: ...

if object():
reveal_type(A()) # N: Revealed type is "<nothing>"
reveal_type(A()) # N: Revealed type is "Never"
if object():
reveal_type(B()) # N: Revealed type is "<nothing>"
reveal_type(B()) # N: Revealed type is "Never"
if object():
reveal_type(C()) # N: Revealed type is "<nothing>"
reveal_type(C()) # N: Revealed type is "Never"
if object():
reveal_type(D()) # N: Revealed type is "<nothing>"
reveal_type(D()) # N: Revealed type is "Never"

[case testOverloadedNewAndInitNoReturn]
from typing import NoReturn, overload
Expand Down Expand Up @@ -7764,19 +7764,19 @@ class D:
def __init__(self, a: int = ...) -> None: ...

if object():
reveal_type(A()) # N: Revealed type is "<nothing>"
reveal_type(A()) # N: Revealed type is "Never"
reveal_type(A(1)) # N: Revealed type is "__main__.A"

if object():
reveal_type(B()) # N: Revealed type is "<nothing>"
reveal_type(B()) # N: Revealed type is "Never"
reveal_type(B(1)) # N: Revealed type is "__main__.B"

if object():
reveal_type(C()) # N: Revealed type is "<nothing>"
reveal_type(C()) # N: Revealed type is "Never"
reveal_type(C(1)) # N: Revealed type is "__main__.C"

if object():
reveal_type(D()) # N: Revealed type is "<nothing>"
reveal_type(D()) # N: Revealed type is "Never"
reveal_type(D(1)) # N: Revealed type is "__main__.D"

[case testClassScopeImportWithWrapperAndError]
Expand Down
12 changes: 6 additions & 6 deletions test-data/unit/check-dataclass-transform.test
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ class FunctionModel:
integer_: tuple

FunctionModel(string_="abc", integer_=1)
FunctionModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "FunctionModel" has incompatible type "Tuple[<nothing>, ...]"; expected "int"
FunctionModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "FunctionModel" has incompatible type "Tuple[Never, ...]"; expected "int"

[typing fixtures/typing-full.pyi]
[builtins fixtures/dataclasses.pyi]
Expand All @@ -529,7 +529,7 @@ class FunctionModel:
integer_: int

FunctionModel(string_="abc", integer_=1)
FunctionModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "FunctionModel" has incompatible type "Tuple[<nothing>, ...]"; expected "int"
FunctionModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "FunctionModel" has incompatible type "Tuple[Never, ...]"; expected "int"

[typing fixtures/typing-full.pyi]
[builtins fixtures/dataclasses.pyi]
Expand All @@ -552,7 +552,7 @@ class BaseClassModel(ModelBase):
integer_: tuple

BaseClassModel(string_="abc", integer_=1)
BaseClassModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "BaseClassModel" has incompatible type "Tuple[<nothing>, ...]"; expected "int"
BaseClassModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "BaseClassModel" has incompatible type "Tuple[Never, ...]"; expected "int"

[typing fixtures/typing-full.pyi]
[builtins fixtures/dataclasses.pyi]
Expand All @@ -574,7 +574,7 @@ class BaseClassModel(ModelBase):
integer_: int

BaseClassModel(string_="abc", integer_=1)
BaseClassModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "BaseClassModel" has incompatible type "Tuple[<nothing>, ...]"; expected "int"
BaseClassModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "BaseClassModel" has incompatible type "Tuple[Never, ...]"; expected "int"

[typing fixtures/typing-full.pyi]
[builtins fixtures/dataclasses.pyi]
Expand All @@ -599,7 +599,7 @@ class MetaClassModel(ModelBaseWithMeta):
integer_: tuple

MetaClassModel(string_="abc", integer_=1)
MetaClassModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "MetaClassModel" has incompatible type "Tuple[<nothing>, ...]"; expected "int"
MetaClassModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "MetaClassModel" has incompatible type "Tuple[Never, ...]"; expected "int"

[typing fixtures/typing-full.pyi]
[builtins fixtures/dataclasses.pyi]
Expand All @@ -624,7 +624,7 @@ class MetaClassModel(ModelBaseWithMeta):
integer_: int

MetaClassModel(string_="abc", integer_=1)
MetaClassModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "MetaClassModel" has incompatible type "Tuple[<nothing>, ...]"; expected "int"
MetaClassModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "MetaClassModel" has incompatible type "Tuple[Never, ...]"; expected "int"

[typing fixtures/typing-full.pyi]
[builtins fixtures/dataclasses.pyi]
Expand Down
8 changes: 4 additions & 4 deletions test-data/unit/check-dataclasses.test
Original file line number Diff line number Diff line change
Expand Up @@ -2134,8 +2134,8 @@ T = TypeVar('T')
class A(Generic[T]):
x: T # exercises meet(T=int, int) = int
y: bool # exercises meet(bool, int) = bool
z: str # exercises meet(str, bytes) = <nothing>
w: dict # exercises meet(dict, <nothing>) = <nothing>
z: str # exercises meet(str, bytes) = Never
w: dict # exercises meet(dict, Never) = Never
init_var: InitVar[int] # exercises (non-optional, optional) = non-optional

@dataclass
Expand All @@ -2149,8 +2149,8 @@ class B:
a_or_b: Union[A[int], B]
_ = replace(a_or_b, x=42, y=True, init_var=42)
_ = replace(a_or_b, x=42, y=True) # E: Missing named argument "init_var" for "replace" of "Union[A[int], B]"
_ = replace(a_or_b, x=42, y=True, z='42', init_var=42) # E: Argument "z" to "replace" of "Union[A[int], B]" has incompatible type "str"; expected <nothing>
_ = replace(a_or_b, x=42, y=True, w={}, init_var=42) # E: Argument "w" to "replace" of "Union[A[int], B]" has incompatible type "Dict[<nothing>, <nothing>]"; expected <nothing>
_ = replace(a_or_b, x=42, y=True, z='42', init_var=42) # E: Argument "z" to "replace" of "Union[A[int], B]" has incompatible type "str"; expected Never
_ = replace(a_or_b, x=42, y=True, w={}, init_var=42) # E: Argument "w" to "replace" of "Union[A[int], B]" has incompatible type "Dict[Never, Never]"; expected Never
_ = replace(a_or_b, y=42, init_var=42) # E: Argument "y" to "replace" of "Union[A[int], B]" has incompatible type "int"; expected "bool"

[builtins fixtures/tuple.pyi]
Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/check-generic-subtyping.test
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ B(1)
C(1)
C('a') # E: Argument 1 to "C" has incompatible type "str"; expected "int"
D(A(1))
D(1) # E: Argument 1 to "D" has incompatible type "int"; expected "A[<nothing>]"
D(1) # E: Argument 1 to "D" has incompatible type "int"; expected "A[Never]"


[case testInheritedConstructor2]
Expand Down
12 changes: 6 additions & 6 deletions test-data/unit/check-generics.test
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ def func(x: IntNode[T]) -> IntNode[T]:
return x
reveal_type(func) # N: Revealed type is "def [T] (x: __main__.Node[builtins.int, T`-1]) -> __main__.Node[builtins.int, T`-1]"

func(1) # E: Argument 1 to "func" has incompatible type "int"; expected "Node[int, <nothing>]"
func(1) # E: Argument 1 to "func" has incompatible type "int"; expected "Node[int, Never]"
func(Node('x', 1)) # E: Argument 1 to "Node" has incompatible type "str"; expected "int"
reveal_type(func(Node(1, 'x'))) # N: Revealed type is "__main__.Node[builtins.int, builtins.str]"

Expand Down Expand Up @@ -834,7 +834,7 @@ reveal_type(x) # N: Revealed type is "builtins.int"
def f2(x: IntTP[T]) -> IntTP[T]:
return x

f2((1, 2, 3)) # E: Argument 1 to "f2" has incompatible type "Tuple[int, int, int]"; expected "Tuple[int, <nothing>]"
f2((1, 2, 3)) # E: Argument 1 to "f2" has incompatible type "Tuple[int, int, int]"; expected "Tuple[int, Never]"
reveal_type(f2((1, 'x'))) # N: Revealed type is "Tuple[builtins.int, builtins.str]"

[builtins fixtures/for.pyi]
Expand Down Expand Up @@ -904,7 +904,7 @@ n.y = 'x' # E: Incompatible types in assignment (expression has type "str", vari
def f(x: Node[T, T]) -> TupledNode[T]:
return Node(x.x, (x.x, x.x))

f(1) # E: Argument 1 to "f" has incompatible type "int"; expected "Node[<nothing>, <nothing>]"
f(1) # E: Argument 1 to "f" has incompatible type "int"; expected "Node[Never, Never]"
f(Node(1, 'x')) # E: Cannot infer type argument 1 of "f"
reveal_type(Node('x', 'x')) # N: Revealed type is "a.Node[builtins.str, builtins.str]"

Expand Down Expand Up @@ -2279,7 +2279,7 @@ class Box(Generic[T]):

class IteratorBox(Box[Iterator[T]]): ...

@IteratorBox.wrap # E: Argument 1 to "wrap" of "Box" has incompatible type "Callable[[], int]"; expected "Callable[[], Iterator[<nothing>]]"
@IteratorBox.wrap # E: Argument 1 to "wrap" of "Box" has incompatible type "Callable[[], int]"; expected "Callable[[], Iterator[Never]]"
def g() -> int:
...
[builtins fixtures/classmethod.pyi]
Expand Down Expand Up @@ -3034,8 +3034,8 @@ def id2(x: V) -> V:
reveal_type(dec1(id1)) # N: Revealed type is "def [S <: __main__.B] (S`1) -> builtins.list[S`1]"
reveal_type(dec1(id2)) # N: Revealed type is "def [S in (builtins.int, builtins.str)] (S`3) -> builtins.list[S`3]"
reveal_type(dec2(id1)) # N: Revealed type is "def [UC <: __main__.C] (UC`5) -> builtins.list[UC`5]"
reveal_type(dec2(id2)) # N: Revealed type is "def (<nothing>) -> builtins.list[<nothing>]" \
# E: Argument 1 to "dec2" has incompatible type "Callable[[V], V]"; expected "Callable[[<nothing>], <nothing>]"
reveal_type(dec2(id2)) # N: Revealed type is "def (Never) -> builtins.list[Never]" \
# E: Argument 1 to "dec2" has incompatible type "Callable[[V], V]"; expected "Callable[[Never], Never]"

[case testInferenceAgainstGenericLambdas]
# flags: --new-type-inference
Expand Down
16 changes: 8 additions & 8 deletions test-data/unit/check-inference-context.test
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ if int():
if int():
ab = f()
if int():
b = f() # E: Incompatible types in assignment (expression has type "A[<nothing>]", variable has type "B")
b = f() # E: Incompatible types in assignment (expression has type "A[Never]", variable has type "B")
[case testBasicContextInferenceForConstructor]
from typing import TypeVar, Generic
T = TypeVar('T')
Expand All @@ -37,7 +37,7 @@ if int():
if int():
ab = A()
if int():
b = A() # E: Incompatible types in assignment (expression has type "A[<nothing>]", variable has type "B")
b = A() # E: Incompatible types in assignment (expression has type "A[Never]", variable has type "B")
[case testIncompatibleContextInference]
from typing import TypeVar, Generic
T = TypeVar('T')
Expand Down Expand Up @@ -372,7 +372,7 @@ ao: List[object]
a: A
def f(): a, aa, ao # Prevent redefinition

a = [] # E: Incompatible types in assignment (expression has type "List[<nothing>]", variable has type "A")
a = [] # E: Incompatible types in assignment (expression has type "List[Never]", variable has type "A")

aa = []
ao = []
Expand Down Expand Up @@ -842,7 +842,7 @@ T = TypeVar('T')
def f(x: Union[List[T], str]) -> None: pass
f([1])
f('')
f(1) # E: Argument 1 to "f" has incompatible type "int"; expected "Union[List[<nothing>], str]"
f(1) # E: Argument 1 to "f" has incompatible type "int"; expected "Union[List[Never], str]"
[builtins fixtures/isinstancelist.pyi]

[case testIgnoringInferenceContext]
Expand Down Expand Up @@ -911,7 +911,7 @@ from typing import TypeVar, Callable, Generic
T = TypeVar('T')
class A(Generic[T]):
pass
reveal_type(A()) # N: Revealed type is "__main__.A[<nothing>]"
reveal_type(A()) # N: Revealed type is "__main__.A[Never]"
b = reveal_type(A()) # type: A[int] # N: Revealed type is "__main__.A[builtins.int]"

[case testUnionWithGenericTypeItemContext]
Expand Down Expand Up @@ -1311,7 +1311,7 @@ from typing import List, TypeVar
T = TypeVar('T', bound=int)
def f(x: List[T]) -> T: ...

# mypy infers List[<nothing>] here, and <nothing> is a subtype of str
# mypy infers List[Never] here, and Never is a subtype of str
y: str = f([])
[builtins fixtures/list.pyi]

Expand All @@ -1323,7 +1323,7 @@ def f(x: List[T]) -> List[T]: ...

# TODO: improve error message for such cases, see #3283 and #5706
y: List[str] = f([]) \
# E: Incompatible types in assignment (expression has type "List[<nothing>]", variable has type "List[str]") \
# E: Incompatible types in assignment (expression has type "List[Never]", variable has type "List[str]") \
# N: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance \
# N: Consider using "Sequence" instead, which is covariant
[builtins fixtures/list.pyi]
Expand All @@ -1343,7 +1343,7 @@ T = TypeVar('T', bound=int)
def f(x: Optional[T] = None) -> List[T]: ...

y: List[str] = f() \
# E: Incompatible types in assignment (expression has type "List[<nothing>]", variable has type "List[str]") \
# E: Incompatible types in assignment (expression has type "List[Never]", variable has type "List[str]") \
# N: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance \
# N: Consider using "Sequence" instead, which is covariant
[builtins fixtures/list.pyi]
Expand Down
Loading