Skip to content

Commit 05ef4ca

Browse files
authored
gh-104504: cases generator: Add --warn-unreachable to the mypy config (#108112)
1 parent 6323bc3 commit 05ef4ca

File tree

4 files changed

+36
-28
lines changed

4 files changed

+36
-28
lines changed
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"""Backports from newer versions of the typing module.
2+
3+
We backport these features here so that Python can still build
4+
while using an older Python version for PYTHON_FOR_REGEN.
5+
"""
6+
7+
from typing import NoReturn
8+
9+
10+
def assert_never(obj: NoReturn) -> NoReturn:
11+
"""Statically assert that a line of code is unreachable.
12+
13+
Backport of typing.assert_never (introduced in Python 3.11).
14+
"""
15+
raise AssertionError(f"Expected code to be unreachable, but got: {obj}")

Tools/cases_generator/analysis.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import sys
33
import typing
44

5+
from _typing_backports import assert_never
56
from flags import InstructionFlags, variable_used
67
from formatting import prettify_filename, UNUSED
78
from instructions import (
@@ -172,7 +173,7 @@ def parse_file(self, filename: str, instrs_idx: dict[str, int]) -> None:
172173
self.pseudos[name] = thing
173174
self.everything.append(thing)
174175
case _:
175-
typing.assert_never(thing)
176+
assert_never(thing)
176177
if not psr.eof():
177178
raise psr.make_syntax_error(f"Extra stuff at the end of {filename}")
178179

@@ -368,7 +369,7 @@ def analyze_macro(self, macro: parsing.Macro) -> MacroInstruction:
368369
# SAVE_IP in a macro is a no-op in Tier 1
369370
flags.add(instr.instr_flags)
370371
case _:
371-
typing.assert_never(component)
372+
assert_never(component)
372373
format = "IB" if flags.HAS_ARG_FLAG else "IX"
373374
if offset:
374375
format += "C" + "0" * (offset - 1)
@@ -409,5 +410,5 @@ def check_macro_components(
409410
case parsing.CacheEffect():
410411
components.append(uop)
411412
case _:
412-
typing.assert_never(uop)
413+
assert_never(uop)
413414
return components

Tools/cases_generator/generate_cases.py

+13-20
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from collections.abc import Iterator
1414

1515
import stacking # Early import to avoid circular import
16+
from _typing_backports import assert_never
1617
from analysis import Analyzer
1718
from formatting import Formatter, list_effect_size
1819
from flags import InstructionFlags, variable_used
@@ -146,16 +147,14 @@
146147
class Generator(Analyzer):
147148
def get_stack_effect_info(
148149
self, thing: parsing.InstDef | parsing.Macro | parsing.Pseudo
149-
) -> tuple[AnyInstruction | None, str | None, str | None]:
150+
) -> tuple[AnyInstruction | None, str, str]:
150151
def effect_str(effects: list[StackEffect]) -> str:
151152
n_effect, sym_effect = list_effect_size(effects)
152153
if sym_effect:
153154
return f"{sym_effect} + {n_effect}" if n_effect else sym_effect
154155
return str(n_effect)
155156

156157
instr: AnyInstruction | None
157-
popped: str | None
158-
pushed: str | None
159158
match thing:
160159
case parsing.InstDef():
161160
if thing.kind != "op" or self.instrs[thing.name].is_viable_uop():
@@ -171,25 +170,23 @@ def effect_str(effects: list[StackEffect]) -> str:
171170
popped, pushed = stacking.get_stack_effect_info_for_macro(instr)
172171
case parsing.Pseudo():
173172
instr = self.pseudo_instrs[thing.name]
174-
popped = pushed = None
175173
# Calculate stack effect, and check that it's the the same
176174
# for all targets.
177-
for target in self.pseudos[thing.name].targets:
175+
for idx, target in enumerate(self.pseudos[thing.name].targets):
178176
target_instr = self.instrs.get(target)
179177
# Currently target is always an instr. This could change
180178
# in the future, e.g., if we have a pseudo targetting a
181179
# macro instruction.
182180
assert target_instr
183181
target_popped = effect_str(target_instr.input_effects)
184182
target_pushed = effect_str(target_instr.output_effects)
185-
if pushed is None:
186-
assert popped is None
183+
if idx == 0:
187184
popped, pushed = target_popped, target_pushed
188185
else:
189186
assert popped == target_popped
190187
assert pushed == target_pushed
191188
case _:
192-
typing.assert_never(thing)
189+
assert_never(thing)
193190
return instr, popped, pushed
194191

195192
@contextlib.contextmanager
@@ -209,7 +206,6 @@ def write_stack_effect_functions(self) -> None:
209206
continue
210207
instr, popped, pushed = self.get_stack_effect_info(thing)
211208
if instr is not None:
212-
assert popped is not None and pushed is not None
213209
popped_data.append((instr, popped))
214210
pushed_data.append((instr, pushed))
215211

@@ -379,7 +375,6 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No
379375
# Compute the set of all instruction formats.
380376
all_formats: set[str] = set()
381377
for thing in self.everything:
382-
format: str | None
383378
match thing:
384379
case OverriddenInstructionPlaceHolder():
385380
continue
@@ -388,17 +383,15 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No
388383
case parsing.Macro():
389384
format = self.macro_instrs[thing.name].instr_fmt
390385
case parsing.Pseudo():
391-
format = None
392-
for target in self.pseudos[thing.name].targets:
386+
for idx, target in enumerate(self.pseudos[thing.name].targets):
393387
target_instr = self.instrs.get(target)
394388
assert target_instr
395-
if format is None:
389+
if idx == 0:
396390
format = target_instr.instr_fmt
397391
else:
398392
assert format == target_instr.instr_fmt
399-
assert format is not None
400393
case _:
401-
typing.assert_never(thing)
394+
assert_never(thing)
402395
all_formats.add(format)
403396

404397
# Turn it into a sorted list of enum values.
@@ -488,7 +481,7 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No
488481
self.pseudo_instrs[thing.name]
489482
)
490483
case _:
491-
typing.assert_never(thing)
484+
assert_never(thing)
492485

493486
with self.metadata_item(
494487
"const struct opcode_macro_expansion "
@@ -525,7 +518,7 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No
525518
case parsing.Pseudo():
526519
pass
527520
case _:
528-
typing.assert_never(thing)
521+
assert_never(thing)
529522

530523
with self.metadata_item(
531524
"const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE]", "=", ";"
@@ -774,7 +767,7 @@ def write_instructions(
774767
case parsing.Pseudo():
775768
pass
776769
case _:
777-
typing.assert_never(thing)
770+
assert_never(thing)
778771

779772
print(
780773
f"Wrote {n_instrs} instructions and {n_macros} macros "
@@ -818,7 +811,7 @@ def write_executor_instructions(
818811
case parsing.Pseudo():
819812
pass
820813
case _:
821-
typing.assert_never(thing)
814+
assert_never(thing)
822815
print(
823816
f"Wrote {n_instrs} instructions and {n_uops} ops to {executor_filename}",
824817
file=sys.stderr,
@@ -850,7 +843,7 @@ def write_abstract_interpreter_instructions(
850843
case parsing.Pseudo():
851844
pass
852845
case _:
853-
typing.assert_never(thing)
846+
assert_never(thing)
854847
print(
855848
f"Wrote some stuff to {abstract_interpreter_filename}",
856849
file=sys.stderr,

Tools/cases_generator/mypy.ini

+4-5
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22
files = Tools/cases_generator/
33
pretty = True
44

5+
# Make sure Python can still be built
6+
# using Python 3.10 for `PYTHON_FOR_REGEN`...
57
python_version = 3.10
68

7-
# Be strict:
9+
# ...And be strict:
810
strict = True
911
strict_concatenate = True
1012
enable_error_code = ignore-without-code,redundant-expr,truthy-bool
11-
12-
# Don't enable this one yet;
13-
# it has a lot of false positives on `cases_generator`
14-
warn_unreachable = False
13+
warn_unreachable = True

0 commit comments

Comments
 (0)