Skip to content

Commit c24c950

Browse files
committed
report all revealed types, not only those of the last iterations step
1 parent c4bea4e commit c24c950

File tree

5 files changed

+33
-24
lines changed

5 files changed

+33
-24
lines changed

mypy/checker.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -637,15 +637,21 @@ def accept_loop(
637637
if iter == 20:
638638
raise RuntimeError("Too many iterations when checking a loop")
639639

640-
# Report those unreachable and redundant expression errors that have been
641-
# identified in all iteration steps, as well as the revealed types identified
642-
# in the last iteration step:
643-
for notes_and_errors in itertools.chain(uselessness_errors, watcher.revealed_types):
644-
context = Context(line=notes_and_errors[2], column=notes_and_errors[3])
645-
context.end_line = notes_and_errors[4]
646-
context.end_column = notes_and_errors[5]
647-
reporter = self.msg.note if notes_and_errors[0] == codes.MISC else self.msg.fail
648-
reporter(notes_and_errors[1], context, code=notes_and_errors[0])
640+
# Report those unreachable and redundant expression errors identified in all
641+
# iteration steps:
642+
for error_info in uselessness_errors:
643+
context = Context(line=error_info[2], column=error_info[3])
644+
context.end_line = error_info[4]
645+
context.end_column = error_info[5]
646+
self.msg.fail(error_info[1], context, code=error_info[0])
647+
# Report all types revealed in at least one iteration step:
648+
for note_info, types in watcher.revealed_types.items():
649+
sorted_ = sorted(types, key=lambda typ: typ.lower())
650+
revealed = sorted_[0] if len(types) == 1 else f"Union[{', '.join(sorted_)}]"
651+
context = Context(line=note_info[1], column=note_info[2])
652+
context.end_line = note_info[3]
653+
context.end_column = note_info[4]
654+
self.note(f'Revealed type is "{revealed}"', context)
649655

650656
# If exit_condition is set, assume it must be False on exit from the loop:
651657
if exit_condition:

mypy/errors.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,13 @@ def filtered_errors(self) -> list[ErrorInfo]:
222222

223223
class LoopErrorWatcher(ErrorWatcher):
224224
"""Error watcher that filters and separately collects unreachable errors, redundant
225-
expression errors, and revealed type notes when analysing loops iteratively to help
226-
avoid making too-hasty reports."""
225+
expression errors, and revealed types when analysing loops iteratively to help avoid
226+
making too-hasty reports."""
227227

228-
# Meaning of the entries: ErrorCode, message, line, column, end_line, end_column:
228+
# Meaning of the tuple items: ErrorCode, message, line, column, end_line, end_column:
229229
useless_statements: set[tuple[ErrorCode, str, int, int, int, int]]
230-
revealed_types: set[tuple[ErrorCode, str, int, int, int, int]]
230+
# Meaning of the tuple items: function_or_member, line, column, end_line, end_column:
231+
revealed_types: dict[tuple[str | None, int, int, int, int], set[str]]
231232

232233
def __init__(
233234
self,
@@ -244,7 +245,7 @@ def __init__(
244245
filter_deprecated=filter_deprecated,
245246
)
246247
self.useless_statements = set()
247-
self.revealed_types = set()
248+
self.revealed_types = defaultdict(set)
248249

249250
def on_error(self, file: str, info: ErrorInfo) -> bool:
250251
if info.code in (codes.UNREACHABLE, codes.REDUNDANT_EXPR):
@@ -253,9 +254,12 @@ def on_error(self, file: str, info: ErrorInfo) -> bool:
253254
)
254255
return True
255256
if info.code == codes.MISC and info.message.startswith("Revealed type is "):
256-
self.revealed_types.add(
257-
(info.code, info.message, info.line, info.column, info.end_line, info.end_column)
258-
)
257+
key = info.function_or_member, info.line, info.column, info.end_line, info.end_column
258+
types = info.message.split('"')[1]
259+
if types.startswith("Union["):
260+
self.revealed_types[key].update(types[6:-1].split(", "))
261+
else:
262+
self.revealed_types[key].add(types)
259263
return True
260264
return super().on_error(file, info)
261265

test-data/unit/check-inference.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ for var2 in [g, h, i, j, k, l]:
343343
reveal_type(var2) # N: Revealed type is "Union[builtins.int, builtins.str]"
344344

345345
for var3 in [m, n, o, p, q, r]:
346-
reveal_type(var3) # N: Revealed type is "Union[builtins.int, Any]"
346+
reveal_type(var3) # N: Revealed type is "Union[Any, builtins.int]"
347347

348348
T = TypeVar("T", bound=Type[Foo])
349349

@@ -1247,7 +1247,7 @@ class X(TypedDict):
12471247

12481248
x: X
12491249
for a in ("hourly", "daily"):
1250-
reveal_type(a) # N: Revealed type is "Union[Literal['hourly']?, Literal['daily']?]"
1250+
reveal_type(a) # N: Revealed type is "Union[Literal['daily']?, Literal['hourly']?]"
12511251
reveal_type(x[a]) # N: Revealed type is "builtins.int"
12521252
reveal_type(a.upper()) # N: Revealed type is "builtins.str"
12531253
c = a

test-data/unit/check-redefine2.test

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ def f1() -> None:
628628
def f2() -> None:
629629
x = None
630630
while int():
631-
reveal_type(x) # N: Revealed type is "Union[None, builtins.str]"
631+
reveal_type(x) # N: Revealed type is "Union[builtins.str, None]"
632632
if int():
633633
x = ""
634634
reveal_type(x) # N: Revealed type is "Union[None, builtins.str]"
@@ -808,8 +808,7 @@ def f4() -> None:
808808
x = None
809809
break
810810
finally:
811-
reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str, None]" \
812-
# N: Revealed type is "Union[builtins.int, None]"
811+
reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str, None]"
813812
reveal_type(x) # N: Revealed type is "Union[builtins.int, None]"
814813
[builtins fixtures/exception.pyi]
815814

@@ -925,7 +924,7 @@ class X(TypedDict):
925924

926925
x: X
927926
for a in ("hourly", "daily"):
928-
reveal_type(a) # N: Revealed type is "Union[Literal['hourly']?, Literal['daily']?]"
927+
reveal_type(a) # N: Revealed type is "Union[Literal['daily']?, Literal['hourly']?]"
929928
reveal_type(x[a]) # N: Revealed type is "builtins.int"
930929
reveal_type(a.upper()) # N: Revealed type is "builtins.str"
931930
c = a

test-data/unit/check-typevar-tuple.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,7 @@ from typing_extensions import Unpack
989989

990990
def pipeline(*xs: Unpack[Tuple[int, Unpack[Tuple[float, ...]], bool]]) -> None:
991991
for x in xs:
992-
reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.float]"
992+
reveal_type(x) # N: Revealed type is "Union[builtins.float, builtins.int]"
993993
[builtins fixtures/tuple.pyi]
994994

995995
[case testFixedUnpackItemInInstanceArguments]

0 commit comments

Comments
 (0)