Skip to content

Commit c3bbd1c

Browse files
authored
Use Never in more messages, use ambiguous in join (#17304)
Switches the logic from #16994 to use ambiguous (since is_noreturn was only meant for error messages) See also #15996
1 parent 77cfb98 commit c3bbd1c

File tree

12 files changed

+23
-33
lines changed

12 files changed

+23
-33
lines changed

mypy/copytype.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def visit_none_type(self, t: NoneType) -> ProperType:
5353
return self.copy_common(t, NoneType())
5454

5555
def visit_uninhabited_type(self, t: UninhabitedType) -> ProperType:
56-
dup = UninhabitedType(t.is_noreturn)
56+
dup = UninhabitedType()
5757
dup.ambiguous = t.ambiguous
5858
return self.copy_common(t, dup)
5959

mypy/join.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,9 @@ def join_instances(self, t: Instance, s: Instance) -> ProperType:
108108
# TODO: contravariant case should use meet but pass seen instances as
109109
# an argument to keep track of recursive checks.
110110
elif type_var.variance in (INVARIANT, CONTRAVARIANT):
111-
if isinstance(ta_proper, UninhabitedType) and not ta_proper.is_noreturn:
111+
if isinstance(ta_proper, UninhabitedType) and ta_proper.ambiguous:
112112
new_type = sa
113-
elif isinstance(sa_proper, UninhabitedType) and not sa_proper.is_noreturn:
113+
elif isinstance(sa_proper, UninhabitedType) and sa_proper.ambiguous:
114114
new_type = ta
115115
elif not is_equivalent(ta, sa):
116116
self.seen_instances.pop()

mypy/messages.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2430,7 +2430,7 @@ def quote_type_string(type_string: str) -> str:
24302430
"""Quotes a type representation for use in messages."""
24312431
no_quote_regex = r"^<(tuple|union): \d+ items>$"
24322432
if (
2433-
type_string in ["Module", "overloaded function", "Never", "<deleted>"]
2433+
type_string in ["Module", "overloaded function", "<deleted>"]
24342434
or type_string.startswith("Module ")
24352435
or re.match(no_quote_regex, type_string) is not None
24362436
or type_string.endswith("?")
@@ -2633,10 +2633,7 @@ def format_literal_value(typ: LiteralType) -> str:
26332633
elif isinstance(typ, DeletedType):
26342634
return "<deleted>"
26352635
elif isinstance(typ, UninhabitedType):
2636-
if typ.is_noreturn:
2637-
return "NoReturn"
2638-
else:
2639-
return "Never"
2636+
return "Never"
26402637
elif isinstance(typ, TypeType):
26412638
type_name = "type" if options.use_lowercase_names() else "Type"
26422639
return f"{type_name}[{format(typ.item)}]"

mypy/typeanal.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Typ
645645
return AnyType(TypeOfAny.from_error)
646646
return self.anal_type(t.args[0])
647647
elif fullname in NEVER_NAMES:
648-
return UninhabitedType(is_noreturn=True)
648+
return UninhabitedType()
649649
elif fullname in LITERAL_TYPE_NAMES:
650650
return self.analyze_literal_type(t)
651651
elif fullname in ANNOTATED_TYPE_NAMES:

mypy/types.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,17 +1169,12 @@ class UninhabitedType(ProperType):
11691169
is_subtype(UninhabitedType, T) = True
11701170
"""
11711171

1172-
__slots__ = ("ambiguous", "is_noreturn")
1172+
__slots__ = ("ambiguous",)
11731173

1174-
is_noreturn: bool # Does this come from a NoReturn? Purely for error messages.
1175-
# It is important to track whether this is an actual NoReturn type, or just a result
1176-
# of ambiguous type inference, in the latter case we don't want to mark a branch as
1177-
# unreachable in binder.
11781174
ambiguous: bool # Is this a result of inference for a variable without constraints?
11791175

1180-
def __init__(self, is_noreturn: bool = False, line: int = -1, column: int = -1) -> None:
1176+
def __init__(self, line: int = -1, column: int = -1) -> None:
11811177
super().__init__(line, column)
1182-
self.is_noreturn = is_noreturn
11831178
self.ambiguous = False
11841179

11851180
def can_be_true_default(self) -> bool:
@@ -1198,12 +1193,12 @@ def __eq__(self, other: object) -> bool:
11981193
return isinstance(other, UninhabitedType)
11991194

12001195
def serialize(self) -> JsonDict:
1201-
return {".class": "UninhabitedType", "is_noreturn": self.is_noreturn}
1196+
return {".class": "UninhabitedType"}
12021197

12031198
@classmethod
12041199
def deserialize(cls, data: JsonDict) -> UninhabitedType:
12051200
assert data[".class"] == "UninhabitedType"
1206-
return UninhabitedType(is_noreturn=data["is_noreturn"])
1201+
return UninhabitedType()
12071202

12081203

12091204
class NoneType(ProperType):

test-data/unit/check-dataclasses.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2080,8 +2080,8 @@ class B:
20802080
a_or_b: Union[A[int], B]
20812081
_ = replace(a_or_b, x=42, y=True, init_var=42)
20822082
_ = replace(a_or_b, x=42, y=True) # E: Missing named argument "init_var" for "replace" of "Union[A[int], B]"
2083-
_ = 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
2084-
_ = 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
2083+
_ = 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"
2084+
_ = 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"
20852085
_ = 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"
20862086

20872087
[builtins fixtures/tuple.pyi]

test-data/unit/check-flags.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ reveal_type(f() or no_return()) # N: Revealed type is "builtins.int"
408408
# flags: --warn-no-return
409409
from mypy_extensions import NoReturn
410410

411-
x = 0 # type: NoReturn # E: Incompatible types in assignment (expression has type "int", variable has type "NoReturn")
411+
x = 0 # type: NoReturn # E: Incompatible types in assignment (expression has type "int", variable has type "Never")
412412
[builtins fixtures/dict.pyi]
413413

414414
[case testNoReturnAsync]
@@ -477,7 +477,7 @@ def no_return() -> NoReturn: pass
477477
def f() -> NoReturn:
478478
no_return()
479479

480-
x: NoReturn = 0 # E: Incompatible types in assignment (expression has type "int", variable has type "NoReturn")
480+
x: NoReturn = 0 # E: Incompatible types in assignment (expression has type "int", variable has type "Never")
481481
[builtins fixtures/dict.pyi]
482482

483483
[case testShowErrorContextFunction]

test-data/unit/check-literal.test

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -839,14 +839,13 @@ b: NoReturn
839839
c: None
840840

841841
fa(lit)
842-
fb(lit) # E: Argument 1 to "fb" has incompatible type "Literal[1]"; expected "NoReturn"
842+
fb(lit) # E: Argument 1 to "fb" has incompatible type "Literal[1]"; expected "Never"
843843
fc(lit) # E: Argument 1 to "fc" has incompatible type "Literal[1]"; expected "None"
844844

845845
f_lit(a)
846846
f_lit(b)
847847
f_lit(c) # E: Argument 1 to "f_lit" has incompatible type "None"; expected "Literal[1]"
848848
[builtins fixtures/tuple.pyi]
849-
[out]
850849

851850
[case testLiteralCheckSubtypingNoStrictOptional]
852851
# flags: --no-strict-optional
@@ -865,14 +864,13 @@ b: NoReturn
865864
c: None
866865

867866
fa(lit)
868-
fb(lit) # E: Argument 1 to "fb" has incompatible type "Literal[1]"; expected "NoReturn"
867+
fb(lit) # E: Argument 1 to "fb" has incompatible type "Literal[1]"; expected "Never"
869868
fc(lit) # E: Argument 1 to "fc" has incompatible type "Literal[1]"; expected "None"
870869

871870
f_lit(a)
872871
f_lit(b)
873872
f_lit(c)
874873
[builtins fixtures/tuple.pyi]
875-
[out]
876874

877875
[case testLiteralCallingOverloadedFunction]
878876
from typing import overload, Generic, TypeVar, Any

test-data/unit/check-plugin-attrs.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2170,8 +2170,8 @@ class B:
21702170

21712171
a_or_b: A[int] | B
21722172
a2 = attrs.evolve(a_or_b, x=42, y=True)
2173-
a2 = attrs.evolve(a_or_b, x=42, y=True, z='42') # E: Argument "z" to "evolve" of "Union[A[int], B]" has incompatible type "str"; expected Never
2174-
a2 = attrs.evolve(a_or_b, x=42, y=True, w={}) # E: Argument "w" to "evolve" of "Union[A[int], B]" has incompatible type "Dict[Never, Never]"; expected Never
2173+
a2 = attrs.evolve(a_or_b, x=42, y=True, z='42') # E: Argument "z" to "evolve" of "Union[A[int], B]" has incompatible type "str"; expected "Never"
2174+
a2 = attrs.evolve(a_or_b, x=42, y=True, w={}) # E: Argument "w" to "evolve" of "Union[A[int], B]" has incompatible type "Dict[Never, Never]"; expected "Never"
21752175

21762176
[builtins fixtures/plugin_attrs.pyi]
21772177

test-data/unit/check-python310.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1406,7 +1406,7 @@ def f(value: int) -> int: # E: Missing return statement
14061406
case 2:
14071407
return 1
14081408
case o:
1409-
assert_never(o) # E: Argument 1 to "assert_never" has incompatible type "int"; expected "NoReturn"
1409+
assert_never(o) # E: Argument 1 to "assert_never" has incompatible type "int"; expected "Never"
14101410

14111411
[case testMatchExhaustiveNoError]
14121412
from typing import NoReturn, Union, Literal

0 commit comments

Comments
 (0)