-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
gh-104504: cases generator: Add --warn-unreachable
to the mypy config
#108112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
833586f
c0a42bc
ba097e0
e4a9e06
82bc6f6
a27ffa0
2f5206d
ec78f7c
8497a68
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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}") |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ | |
from collections.abc import Iterator | ||
|
||
import stacking # Early import to avoid circular import | ||
from _typing_backports import assert_never | ||
from analysis import Analyzer | ||
from formatting import Formatter, list_effect_size | ||
from flags import InstructionFlags, variable_used | ||
|
@@ -146,16 +147,14 @@ | |
class Generator(Analyzer): | ||
def get_stack_effect_info( | ||
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: | ||
n_effect, sym_effect = list_effect_size(effects) | ||
if sym_effect: | ||
return f"{sym_effect} + {n_effect}" if n_effect else sym_effect | ||
return str(n_effect) | ||
|
||
instr: AnyInstruction | None | ||
popped: str | None | ||
pushed: str | None | ||
match thing: | ||
case parsing.InstDef(): | ||
if thing.kind != "op" or self.instrs[thing.name].is_viable_uop(): | ||
|
@@ -171,25 +170,23 @@ def effect_str(effects: list[StackEffect]) -> str: | |
popped, pushed = stacking.get_stack_effect_info_for_macro(instr) | ||
case parsing.Pseudo(): | ||
instr = self.pseudo_instrs[thing.name] | ||
popped = pushed = None | ||
# Calculate stack effect, and check that it's the the same | ||
# for all targets. | ||
for target in self.pseudos[thing.name].targets: | ||
for idx, target in enumerate(self.pseudos[thing.name].targets): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clever idea. I wrote a whole paragraph arguing against using enumerate() here, then realized it wasn't worth arguing over. :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI, the saga continues. Currently we get errors from pyright on this: "popped is possibly unbound" (on all occurrences of popped and pushed in this function below here). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yeah, and mypy will also give you that error if you add There is a third way of fixing this. I'll make a PR and see how you like it. |
||
target_instr = self.instrs.get(target) | ||
# Currently target is always an instr. This could change | ||
# in the future, e.g., if we have a pseudo targetting a | ||
# macro instruction. | ||
assert target_instr | ||
target_popped = effect_str(target_instr.input_effects) | ||
target_pushed = effect_str(target_instr.output_effects) | ||
if pushed is None: | ||
assert popped is None | ||
if idx == 0: | ||
popped, pushed = target_popped, target_pushed | ||
else: | ||
assert popped == target_popped | ||
assert pushed == target_pushed | ||
case _: | ||
typing.assert_never(thing) | ||
assert_never(thing) | ||
return instr, popped, pushed | ||
|
||
@contextlib.contextmanager | ||
|
@@ -209,7 +206,6 @@ def write_stack_effect_functions(self) -> None: | |
continue | ||
instr, popped, pushed = self.get_stack_effect_info(thing) | ||
if instr is not None: | ||
assert popped is not None and pushed is not None | ||
popped_data.append((instr, popped)) | ||
pushed_data.append((instr, pushed)) | ||
|
||
|
@@ -379,7 +375,6 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No | |
# Compute the set of all instruction formats. | ||
all_formats: set[str] = set() | ||
for thing in self.everything: | ||
format: str | None | ||
match thing: | ||
case OverriddenInstructionPlaceHolder(): | ||
continue | ||
|
@@ -388,17 +383,15 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No | |
case parsing.Macro(): | ||
format = self.macro_instrs[thing.name].instr_fmt | ||
case parsing.Pseudo(): | ||
format = None | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly, here mypy was eagerly narrowing the type of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still feels like a mypy bug to me, but your fix is fine. |
||
for target in self.pseudos[thing.name].targets: | ||
for idx, target in enumerate(self.pseudos[thing.name].targets): | ||
target_instr = self.instrs.get(target) | ||
assert target_instr | ||
if format is None: | ||
if idx == 0: | ||
format = target_instr.instr_fmt | ||
else: | ||
assert format == target_instr.instr_fmt | ||
assert format is not None | ||
case _: | ||
typing.assert_never(thing) | ||
assert_never(thing) | ||
all_formats.add(format) | ||
Comment on lines
+389
to
395
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And ditto here for |
||
|
||
# Turn it into a sorted list of enum values. | ||
|
@@ -488,7 +481,7 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No | |
self.pseudo_instrs[thing.name] | ||
) | ||
case _: | ||
typing.assert_never(thing) | ||
assert_never(thing) | ||
|
||
with self.metadata_item( | ||
"const struct opcode_macro_expansion " | ||
|
@@ -525,7 +518,7 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No | |
case parsing.Pseudo(): | ||
pass | ||
case _: | ||
typing.assert_never(thing) | ||
assert_never(thing) | ||
|
||
with self.metadata_item( | ||
"const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE]", "=", ";" | ||
|
@@ -774,7 +767,7 @@ def write_instructions( | |
case parsing.Pseudo(): | ||
pass | ||
case _: | ||
typing.assert_never(thing) | ||
assert_never(thing) | ||
|
||
print( | ||
f"Wrote {n_instrs} instructions and {n_macros} macros " | ||
|
@@ -818,7 +811,7 @@ def write_executor_instructions( | |
case parsing.Pseudo(): | ||
pass | ||
case _: | ||
typing.assert_never(thing) | ||
assert_never(thing) | ||
print( | ||
f"Wrote {n_instrs} instructions and {n_uops} ops to {executor_filename}", | ||
file=sys.stderr, | ||
|
@@ -850,7 +843,7 @@ def write_abstract_interpreter_instructions( | |
case parsing.Pseudo(): | ||
pass | ||
case _: | ||
typing.assert_never(thing) | ||
assert_never(thing) | ||
print( | ||
f"Wrote some stuff to {abstract_interpreter_filename}", | ||
file=sys.stderr, | ||
|
Uh oh!
There was an error while loading. Please reload this page.