mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Bytecode parity: align borrow optimization with CFG traversal (#7773)
* Align CFG cleanup bytecode with CPython * Bytecode parity: fblock unwind, fstring join, folding, scope - compile.rs: unwind_fblock_stack returns whether a finally ran so return-statement emission can adjust location handling; restructure try/except/finally cleanup to preserve or drop boundary NOPs based on whether the body falls through; rework f-string lowering with count/join helpers; remove the per-collection-type heuristic for AST-level folding and defer to flowgraph passes; add several folding helpers and a ComprehensionLoopControl enum. - ir.rs: re-run unary/binop folding around tuple folding, add reorder_conditional_scope_exit_and_jump_back_blocks and several block classification helpers, add MAX_STR_SIZE, change is_exit_without_lineno to take the block list. - symboltable.rs: in analyze_cells, remove names owned as cells in function-like scopes from the parent's free set; mark lambda scope type explicitly. * Refine CFG scope-exit backedge ordering
This commit is contained in:
@@ -60,9 +60,11 @@
|
||||
"dedentations",
|
||||
"dedents",
|
||||
"deduped",
|
||||
"deoptimized",
|
||||
"deoptimize",
|
||||
"emscripten",
|
||||
"excs",
|
||||
"fnfe",
|
||||
"interps",
|
||||
"jitted",
|
||||
"jitting",
|
||||
@@ -72,6 +74,9 @@
|
||||
"oparg",
|
||||
"opargs",
|
||||
"pyc",
|
||||
"reborrow",
|
||||
"reraises",
|
||||
"reraising",
|
||||
"significand",
|
||||
"summands",
|
||||
"unraisable",
|
||||
|
||||
1
Lib/test/test_coroutines.py
vendored
1
Lib/test/test_coroutines.py
vendored
@@ -2065,7 +2065,6 @@ class CoroutineTest(unittest.TestCase):
|
||||
run_async(f()),
|
||||
([], {1: 1, 2: 2, 3: 3}))
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: __aiter__
|
||||
def test_nested_comp(self):
|
||||
async def run_list_inside_list():
|
||||
return [[i + j async for i in asynciter([1, 2])] for j in [10, 20]]
|
||||
|
||||
4
Lib/test/test_peepholer.py
vendored
4
Lib/test/test_peepholer.py
vendored
@@ -243,7 +243,6 @@ class TestTranforms(BytecodeTestCase):
|
||||
self.assertTrue(g(4))
|
||||
self.check_lnotab(g)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_constant_folding_small_int(self):
|
||||
tests = [
|
||||
('(0, )[0]', 0),
|
||||
@@ -278,7 +277,6 @@ class TestTranforms(BytecodeTestCase):
|
||||
self.assertNotInBytecode(code, 'LOAD_SMALL_INT')
|
||||
self.check_lnotab(code)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 'UNARY_NEGATIVE' starts with 'UNARY_'
|
||||
def test_constant_folding_unaryop(self):
|
||||
intrinsic_positive = 5
|
||||
tests = [
|
||||
@@ -324,7 +322,6 @@ class TestTranforms(BytecodeTestCase):
|
||||
self.assertNotStartsWith(instr.opname, 'UNARY_')
|
||||
self.check_lnotab(negzero)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; BINARY_OP 26 ([])
|
||||
def test_constant_folding_binop(self):
|
||||
tests = [
|
||||
('1 + 2', 'NB_ADD', True, 'LOAD_SMALL_INT', 3),
|
||||
@@ -672,7 +669,6 @@ class TestTranforms(BytecodeTestCase):
|
||||
return 6
|
||||
self.check_lnotab(f)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 2 != 1
|
||||
def test_assignment_idiom_in_comprehensions(self):
|
||||
def listcomp():
|
||||
return [y for x in a for y in [f(x)]]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -591,6 +591,14 @@ impl SymbolTableAnalyzer {
|
||||
}
|
||||
|
||||
// Analyze symbols in current scope
|
||||
let remove_owned_cells_from_free = matches!(
|
||||
symbol_table.typ,
|
||||
CompilerScope::Function
|
||||
| CompilerScope::AsyncFunction
|
||||
| CompilerScope::Lambda
|
||||
| CompilerScope::Comprehension
|
||||
| CompilerScope::Annotation
|
||||
);
|
||||
for symbol in symbol_table.symbols.values_mut() {
|
||||
self.analyze_symbol(
|
||||
symbol,
|
||||
@@ -600,6 +608,13 @@ impl SymbolTableAnalyzer {
|
||||
class_entry,
|
||||
)?;
|
||||
|
||||
// CPython analyze_cells(): once a function-like scope owns a
|
||||
// child-requested name as a cell, that name is no longer free in
|
||||
// the enclosing scope.
|
||||
if remove_owned_cells_from_free && symbol.scope == SymbolScope::Cell {
|
||||
newfree.shift_remove(symbol.name.as_str());
|
||||
}
|
||||
|
||||
// Collect free variables from this scope
|
||||
if symbol.scope == SymbolScope::Free || symbol.flags.contains(SymbolFlags::FREE_CLASS) {
|
||||
newfree.insert(symbol.name.clone());
|
||||
@@ -2128,6 +2143,7 @@ impl SymbolTableBuilder {
|
||||
false, // lambdas are never async
|
||||
false, // don't skip defaults
|
||||
)?;
|
||||
self.tables.last_mut().unwrap().typ = CompilerScope::Lambda;
|
||||
} else {
|
||||
self.enter_scope(
|
||||
"lambda",
|
||||
|
||||
@@ -74,10 +74,16 @@ def _start_one(interpreter, targets, base_dir):
|
||||
output_file = None
|
||||
try:
|
||||
files_file = tempfile.NamedTemporaryFile(
|
||||
mode="w", encoding="utf-8", delete=False, dir=PROJECT_ROOT
|
||||
mode="w",
|
||||
encoding="utf-8",
|
||||
delete=False,
|
||||
prefix="compare-bytecode-files-",
|
||||
)
|
||||
output_file = tempfile.NamedTemporaryFile(
|
||||
mode="w", encoding="utf-8", delete=False, dir=PROJECT_ROOT
|
||||
mode="w",
|
||||
encoding="utf-8",
|
||||
delete=False,
|
||||
prefix="compare-bytecode-output-",
|
||||
)
|
||||
for _, path in targets:
|
||||
files_file.write(path)
|
||||
|
||||
Reference in New Issue
Block a user