mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
gh-104504: cases generator: Add --warn-unreachable
to the mypy config (#108112)
This commit is contained in:
parent
6323bc33ff
commit
05ef4ca94c
4 changed files with 36 additions and 28 deletions
15
Tools/cases_generator/_typing_backports.py
Normal file
15
Tools/cases_generator/_typing_backports.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
"""Backports from newer versions of the typing module.
|
||||||
|
|
||||||
|
We backport these features here so that Python can still build
|
||||||
|
while using an older Python version for PYTHON_FOR_REGEN.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import NoReturn
|
||||||
|
|
||||||
|
|
||||||
|
def assert_never(obj: NoReturn) -> NoReturn:
|
||||||
|
"""Statically assert that a line of code is unreachable.
|
||||||
|
|
||||||
|
Backport of typing.assert_never (introduced in Python 3.11).
|
||||||
|
"""
|
||||||
|
raise AssertionError(f"Expected code to be unreachable, but got: {obj}")
|
|
@ -2,6 +2,7 @@ import re
|
||||||
import sys
|
import sys
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
|
from _typing_backports import assert_never
|
||||||
from flags import InstructionFlags, variable_used
|
from flags import InstructionFlags, variable_used
|
||||||
from formatting import prettify_filename, UNUSED
|
from formatting import prettify_filename, UNUSED
|
||||||
from instructions import (
|
from instructions import (
|
||||||
|
@ -172,7 +173,7 @@ class Analyzer:
|
||||||
self.pseudos[name] = thing
|
self.pseudos[name] = thing
|
||||||
self.everything.append(thing)
|
self.everything.append(thing)
|
||||||
case _:
|
case _:
|
||||||
typing.assert_never(thing)
|
assert_never(thing)
|
||||||
if not psr.eof():
|
if not psr.eof():
|
||||||
raise psr.make_syntax_error(f"Extra stuff at the end of {filename}")
|
raise psr.make_syntax_error(f"Extra stuff at the end of {filename}")
|
||||||
|
|
||||||
|
@ -368,7 +369,7 @@ class Analyzer:
|
||||||
# SAVE_IP in a macro is a no-op in Tier 1
|
# SAVE_IP in a macro is a no-op in Tier 1
|
||||||
flags.add(instr.instr_flags)
|
flags.add(instr.instr_flags)
|
||||||
case _:
|
case _:
|
||||||
typing.assert_never(component)
|
assert_never(component)
|
||||||
format = "IB" if flags.HAS_ARG_FLAG else "IX"
|
format = "IB" if flags.HAS_ARG_FLAG else "IX"
|
||||||
if offset:
|
if offset:
|
||||||
format += "C" + "0" * (offset - 1)
|
format += "C" + "0" * (offset - 1)
|
||||||
|
@ -409,5 +410,5 @@ class Analyzer:
|
||||||
case parsing.CacheEffect():
|
case parsing.CacheEffect():
|
||||||
components.append(uop)
|
components.append(uop)
|
||||||
case _:
|
case _:
|
||||||
typing.assert_never(uop)
|
assert_never(uop)
|
||||||
return components
|
return components
|
||||||
|
|
|
@ -13,6 +13,7 @@ import typing
|
||||||
from collections.abc import Iterator
|
from collections.abc import Iterator
|
||||||
|
|
||||||
import stacking # Early import to avoid circular import
|
import stacking # Early import to avoid circular import
|
||||||
|
from _typing_backports import assert_never
|
||||||
from analysis import Analyzer
|
from analysis import Analyzer
|
||||||
from formatting import Formatter, list_effect_size
|
from formatting import Formatter, list_effect_size
|
||||||
from flags import InstructionFlags, variable_used
|
from flags import InstructionFlags, variable_used
|
||||||
|
@ -146,7 +147,7 @@ arg_parser.add_argument(
|
||||||
class Generator(Analyzer):
|
class Generator(Analyzer):
|
||||||
def get_stack_effect_info(
|
def get_stack_effect_info(
|
||||||
self, thing: parsing.InstDef | parsing.Macro | parsing.Pseudo
|
self, thing: parsing.InstDef | parsing.Macro | parsing.Pseudo
|
||||||
) -> tuple[AnyInstruction | None, str | None, str | None]:
|
) -> tuple[AnyInstruction | None, str, str]:
|
||||||
def effect_str(effects: list[StackEffect]) -> str:
|
def effect_str(effects: list[StackEffect]) -> str:
|
||||||
n_effect, sym_effect = list_effect_size(effects)
|
n_effect, sym_effect = list_effect_size(effects)
|
||||||
if sym_effect:
|
if sym_effect:
|
||||||
|
@ -154,8 +155,6 @@ class Generator(Analyzer):
|
||||||
return str(n_effect)
|
return str(n_effect)
|
||||||
|
|
||||||
instr: AnyInstruction | None
|
instr: AnyInstruction | None
|
||||||
popped: str | None
|
|
||||||
pushed: str | None
|
|
||||||
match thing:
|
match thing:
|
||||||
case parsing.InstDef():
|
case parsing.InstDef():
|
||||||
if thing.kind != "op" or self.instrs[thing.name].is_viable_uop():
|
if thing.kind != "op" or self.instrs[thing.name].is_viable_uop():
|
||||||
|
@ -171,10 +170,9 @@ class Generator(Analyzer):
|
||||||
popped, pushed = stacking.get_stack_effect_info_for_macro(instr)
|
popped, pushed = stacking.get_stack_effect_info_for_macro(instr)
|
||||||
case parsing.Pseudo():
|
case parsing.Pseudo():
|
||||||
instr = self.pseudo_instrs[thing.name]
|
instr = self.pseudo_instrs[thing.name]
|
||||||
popped = pushed = None
|
|
||||||
# Calculate stack effect, and check that it's the the same
|
# Calculate stack effect, and check that it's the the same
|
||||||
# for all targets.
|
# for all targets.
|
||||||
for target in self.pseudos[thing.name].targets:
|
for idx, target in enumerate(self.pseudos[thing.name].targets):
|
||||||
target_instr = self.instrs.get(target)
|
target_instr = self.instrs.get(target)
|
||||||
# Currently target is always an instr. This could change
|
# Currently target is always an instr. This could change
|
||||||
# in the future, e.g., if we have a pseudo targetting a
|
# in the future, e.g., if we have a pseudo targetting a
|
||||||
|
@ -182,14 +180,13 @@ class Generator(Analyzer):
|
||||||
assert target_instr
|
assert target_instr
|
||||||
target_popped = effect_str(target_instr.input_effects)
|
target_popped = effect_str(target_instr.input_effects)
|
||||||
target_pushed = effect_str(target_instr.output_effects)
|
target_pushed = effect_str(target_instr.output_effects)
|
||||||
if pushed is None:
|
if idx == 0:
|
||||||
assert popped is None
|
|
||||||
popped, pushed = target_popped, target_pushed
|
popped, pushed = target_popped, target_pushed
|
||||||
else:
|
else:
|
||||||
assert popped == target_popped
|
assert popped == target_popped
|
||||||
assert pushed == target_pushed
|
assert pushed == target_pushed
|
||||||
case _:
|
case _:
|
||||||
typing.assert_never(thing)
|
assert_never(thing)
|
||||||
return instr, popped, pushed
|
return instr, popped, pushed
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
|
@ -209,7 +206,6 @@ class Generator(Analyzer):
|
||||||
continue
|
continue
|
||||||
instr, popped, pushed = self.get_stack_effect_info(thing)
|
instr, popped, pushed = self.get_stack_effect_info(thing)
|
||||||
if instr is not None:
|
if instr is not None:
|
||||||
assert popped is not None and pushed is not None
|
|
||||||
popped_data.append((instr, popped))
|
popped_data.append((instr, popped))
|
||||||
pushed_data.append((instr, pushed))
|
pushed_data.append((instr, pushed))
|
||||||
|
|
||||||
|
@ -379,7 +375,6 @@ class Generator(Analyzer):
|
||||||
# Compute the set of all instruction formats.
|
# Compute the set of all instruction formats.
|
||||||
all_formats: set[str] = set()
|
all_formats: set[str] = set()
|
||||||
for thing in self.everything:
|
for thing in self.everything:
|
||||||
format: str | None
|
|
||||||
match thing:
|
match thing:
|
||||||
case OverriddenInstructionPlaceHolder():
|
case OverriddenInstructionPlaceHolder():
|
||||||
continue
|
continue
|
||||||
|
@ -388,17 +383,15 @@ class Generator(Analyzer):
|
||||||
case parsing.Macro():
|
case parsing.Macro():
|
||||||
format = self.macro_instrs[thing.name].instr_fmt
|
format = self.macro_instrs[thing.name].instr_fmt
|
||||||
case parsing.Pseudo():
|
case parsing.Pseudo():
|
||||||
format = None
|
for idx, target in enumerate(self.pseudos[thing.name].targets):
|
||||||
for target in self.pseudos[thing.name].targets:
|
|
||||||
target_instr = self.instrs.get(target)
|
target_instr = self.instrs.get(target)
|
||||||
assert target_instr
|
assert target_instr
|
||||||
if format is None:
|
if idx == 0:
|
||||||
format = target_instr.instr_fmt
|
format = target_instr.instr_fmt
|
||||||
else:
|
else:
|
||||||
assert format == target_instr.instr_fmt
|
assert format == target_instr.instr_fmt
|
||||||
assert format is not None
|
|
||||||
case _:
|
case _:
|
||||||
typing.assert_never(thing)
|
assert_never(thing)
|
||||||
all_formats.add(format)
|
all_formats.add(format)
|
||||||
|
|
||||||
# Turn it into a sorted list of enum values.
|
# Turn it into a sorted list of enum values.
|
||||||
|
@ -488,7 +481,7 @@ class Generator(Analyzer):
|
||||||
self.pseudo_instrs[thing.name]
|
self.pseudo_instrs[thing.name]
|
||||||
)
|
)
|
||||||
case _:
|
case _:
|
||||||
typing.assert_never(thing)
|
assert_never(thing)
|
||||||
|
|
||||||
with self.metadata_item(
|
with self.metadata_item(
|
||||||
"const struct opcode_macro_expansion "
|
"const struct opcode_macro_expansion "
|
||||||
|
@ -525,7 +518,7 @@ class Generator(Analyzer):
|
||||||
case parsing.Pseudo():
|
case parsing.Pseudo():
|
||||||
pass
|
pass
|
||||||
case _:
|
case _:
|
||||||
typing.assert_never(thing)
|
assert_never(thing)
|
||||||
|
|
||||||
with self.metadata_item(
|
with self.metadata_item(
|
||||||
"const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE]", "=", ";"
|
"const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE]", "=", ";"
|
||||||
|
@ -774,7 +767,7 @@ class Generator(Analyzer):
|
||||||
case parsing.Pseudo():
|
case parsing.Pseudo():
|
||||||
pass
|
pass
|
||||||
case _:
|
case _:
|
||||||
typing.assert_never(thing)
|
assert_never(thing)
|
||||||
|
|
||||||
print(
|
print(
|
||||||
f"Wrote {n_instrs} instructions and {n_macros} macros "
|
f"Wrote {n_instrs} instructions and {n_macros} macros "
|
||||||
|
@ -818,7 +811,7 @@ class Generator(Analyzer):
|
||||||
case parsing.Pseudo():
|
case parsing.Pseudo():
|
||||||
pass
|
pass
|
||||||
case _:
|
case _:
|
||||||
typing.assert_never(thing)
|
assert_never(thing)
|
||||||
print(
|
print(
|
||||||
f"Wrote {n_instrs} instructions and {n_uops} ops to {executor_filename}",
|
f"Wrote {n_instrs} instructions and {n_uops} ops to {executor_filename}",
|
||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
|
@ -850,7 +843,7 @@ class Generator(Analyzer):
|
||||||
case parsing.Pseudo():
|
case parsing.Pseudo():
|
||||||
pass
|
pass
|
||||||
case _:
|
case _:
|
||||||
typing.assert_never(thing)
|
assert_never(thing)
|
||||||
print(
|
print(
|
||||||
f"Wrote some stuff to {abstract_interpreter_filename}",
|
f"Wrote some stuff to {abstract_interpreter_filename}",
|
||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
|
|
|
@ -2,13 +2,12 @@
|
||||||
files = Tools/cases_generator/
|
files = Tools/cases_generator/
|
||||||
pretty = True
|
pretty = True
|
||||||
|
|
||||||
|
# Make sure Python can still be built
|
||||||
|
# using Python 3.10 for `PYTHON_FOR_REGEN`...
|
||||||
python_version = 3.10
|
python_version = 3.10
|
||||||
|
|
||||||
# Be strict:
|
# ...And be strict:
|
||||||
strict = True
|
strict = True
|
||||||
strict_concatenate = True
|
strict_concatenate = True
|
||||||
enable_error_code = ignore-without-code,redundant-expr,truthy-bool
|
enable_error_code = ignore-without-code,redundant-expr,truthy-bool
|
||||||
|
warn_unreachable = True
|
||||||
# Don't enable this one yet;
|
|
||||||
# it has a lot of false positives on `cases_generator`
|
|
||||||
warn_unreachable = False
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue