Skip to content

Commit 8d4a245

Browse files
committed
Use Never in more messages, use ambiguous in join
Switches the logic from python#16994 to use ambiguous (since is_noreturn was only meant for error messages) See also python#15996
1 parent 5059ffd commit 8d4a245

File tree

10 files changed

+18
-28
lines changed

10 files changed

+18
-28
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: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2629,10 +2629,7 @@ def format_literal_value(typ: LiteralType) -> str:
26292629
elif isinstance(typ, DeletedType):
26302630
return "<deleted>"
26312631
elif isinstance(typ, UninhabitedType):
2632-
if typ.is_noreturn:
2633-
return "NoReturn"
2634-
else:
2635-
return "Never"
2632+
return "Never"
26362633
elif isinstance(typ, TypeType):
26372634
type_name = "type" if options.use_lowercase_names() else "Type"
26382635
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-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-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

test-data/unit/check-type-aliases.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ Never = NoReturn
5757
a: Never # Used to be an error here
5858

5959
def f(a: Never): ...
60-
f(5) # E: Argument 1 to "f" has incompatible type "int"; expected "NoReturn"
60+
f(5) # E: Argument 1 to "f" has incompatible type "int"; expected Never
6161
[case testImportUnionAlias]
6262
import typing
6363
from _m import U

test-data/unit/check-typeddict.test

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1648,7 +1648,7 @@ a.setdefault('y', '') # E: Argument 2 to "setdefault" of "TypedDict" has incompa
16481648
x = ''
16491649
a.setdefault(x, 1) # E: Expected TypedDict key to be string literal
16501650
alias = a.setdefault
1651-
alias(x, 1) # E: Argument 1 has incompatible type "str"; expected "NoReturn"
1651+
alias(x, 1) # E: Argument 1 has incompatible type "str"; expected Never
16521652

16531653
a.update({})
16541654
a.update({'x': 1})
@@ -1680,8 +1680,8 @@ b.pop('x') # E: Key "x" of TypedDict "B" cannot be deleted
16801680
x = ''
16811681
b.pop(x) # E: Expected TypedDict key to be string literal
16821682
pop = b.pop
1683-
pop('x') # E: Argument 1 has incompatible type "str"; expected "NoReturn"
1684-
pop('invalid') # E: Argument 1 has incompatible type "str"; expected "NoReturn"
1683+
pop('x') # E: Argument 1 has incompatible type "str"; expected Never
1684+
pop('invalid') # E: Argument 1 has incompatible type "str"; expected Never
16851685
[builtins fixtures/dict.pyi]
16861686

16871687
[case testTypedDictDel]

0 commit comments

Comments
 (0)