Skip to content

Commit

Permalink
Represent bottom type as Never in messages (python#15996)
Browse files Browse the repository at this point in the history
  • Loading branch information
hauntsaninja authored Aug 31, 2023
1 parent 9a0aca1 commit df4717e
Show file tree
Hide file tree
Showing 32 changed files with 111 additions and 111 deletions.
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 @@ -2444,7 +2444,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 @@ -2068,7 +2068,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 @@ -2395,7 +2395,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 @@ -2597,7 +2597,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

0 comments on commit df4717e

Please sign in to comment.