| """Test runner for data-flow analysis test cases.""" | |
| from __future__ import annotations | |
| import os.path | |
| from mypy.errors import CompileError | |
| from mypy.test.config import test_temp_dir | |
| from mypy.test.data import DataDrivenTestCase | |
| from mypyc.analysis import dataflow | |
| from mypyc.common import TOP_LEVEL_NAME | |
| from mypyc.ir.func_ir import all_values | |
| from mypyc.ir.ops import Value | |
| from mypyc.ir.pprint import format_func, generate_names_for_ir | |
| from mypyc.test.testutil import ( | |
| ICODE_GEN_BUILTINS, | |
| MypycDataSuite, | |
| assert_test_output, | |
| build_ir_for_single_file, | |
| use_custom_builtins, | |
| ) | |
| from mypyc.transform import exceptions | |
| files = ["analysis.test"] | |
| class TestAnalysis(MypycDataSuite): | |
| files = files | |
| base_path = test_temp_dir | |
| optional_out = True | |
| def run_case(self, testcase: DataDrivenTestCase) -> None: | |
| """Perform a data-flow analysis test case.""" | |
| with use_custom_builtins(os.path.join(self.data_prefix, ICODE_GEN_BUILTINS), testcase): | |
| try: | |
| ir = build_ir_for_single_file(testcase.input) | |
| except CompileError as e: | |
| actual = e.messages | |
| else: | |
| actual = [] | |
| for fn in ir: | |
| if fn.name == TOP_LEVEL_NAME and not testcase.name.endswith("_toplevel"): | |
| continue | |
| exceptions.insert_exception_handling(fn, True) | |
| actual.extend(format_func(fn)) | |
| cfg = dataflow.get_cfg(fn.blocks) | |
| args: set[Value] = set(fn.arg_regs) | |
| name = testcase.name | |
| if name.endswith("_MaybeDefined"): | |
| # Forward, maybe | |
| analysis_result = dataflow.analyze_maybe_defined_regs(fn.blocks, cfg, args) | |
| elif name.endswith("_Liveness"): | |
| # Backward, maybe | |
| analysis_result = dataflow.analyze_live_regs(fn.blocks, cfg) | |
| elif name.endswith("_MustDefined"): | |
| # Forward, must | |
| analysis_result = dataflow.analyze_must_defined_regs( | |
| fn.blocks, cfg, args, regs=all_values(fn.arg_regs, fn.blocks) | |
| ) | |
| elif name.endswith("_BorrowedArgument"): | |
| # Forward, must | |
| analysis_result = dataflow.analyze_borrowed_arguments(fn.blocks, cfg, args) | |
| else: | |
| assert False, "No recognized _AnalysisName suffix in test case" | |
| names = generate_names_for_ir(fn.arg_regs, fn.blocks) | |
| for key in sorted( | |
| analysis_result.before.keys(), key=lambda x: (x[0].label, x[1]) | |
| ): | |
| pre = ", ".join(sorted(names[reg] for reg in analysis_result.before[key])) | |
| post = ", ".join(sorted(names[reg] for reg in analysis_result.after[key])) | |
| actual.append( | |
| "%-8s %-23s %s" % ((key[0].label, key[1]), "{%s}" % pre, "{%s}" % post) | |
| ) | |
| assert_test_output(testcase, actual, "Invalid source code output") |