Lokasi ngalangkungan proxy:   [ UP ]  
[Ngawartoskeun bug]   [Panyetelan cookie]                
Skip to content

Bytecode parity: align borrow optimization with CFG traversal#7773

Merged
youknowone merged 6 commits intoRustPython:mainfrom
youknowone:bytecode-parity-typealias
May 5, 2026
Merged

Bytecode parity: align borrow optimization with CFG traversal#7773
youknowone merged 6 commits intoRustPython:mainfrom
youknowone:bytecode-parity-typealias

Conversation

@youknowone
Copy link
Copy Markdown
Member

@youknowone youknowone commented May 4, 2026

Summary

Align LOAD_FAST_BORROW optimization with CPython-style CFG traversal instead of post-processing bytecode after borrow optimization.

Details

  • Marks assertion-success and unprotected debug>=4 tails before optimize_load_fast_borrow, so those blocks are excluded during traversal rather than rewritten afterward.
  • Treats exception handlers that POP_EXCEPT and then return/continue normally as resuming handlers, avoiding over-deoptimization after conditional reraises.
  • Narrows async-finally early-return borrow deoptimization so async-for GET_ANEXT/SEND iterator paths are not mistaken for relevant async-finally sends.
  • Adds regression coverage for imaplib.Idler.__exit__-style debug tails and the test_compile.py async comprehension capture case.

Validation

  • cargo fmt
  • cargo test -p rustpython-codegen test_match_async_comprehension_iter_keeps_capture_borrow -- --nocapture
  • cargo test -p rustpython-codegen test_imap_idle_status_debug_tail_keeps_borrow -- --nocapture
  • cargo test -p rustpython-codegen deopts -- --nocapture
  • cargo build --release
  • python scripts/compare_bytecode.py --filter 'test/test_compile.py' --detail --max-diffs 300 -j 1 -o /tmp/compare_test_compile.after_rebase.report
  • python scripts/compare_bytecode.py --filter 'imaplib.py' --detail --max-diffs 200 -j 1 -o /tmp/compare_imaplib.after_rebase.report

Summary by CodeRabbit

  • Chores
    • Updated spell-check word allowlist configuration with additional correctly-spelled terms for enhanced recognition.
    • Improved symbol-table free-variable analysis within the compiler for more accurate scoping behavior in functions.
    • Enhanced development tooling with better temporary file creation and explicit UTF-8 encoding support.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 4, 2026

📝 Walkthrough

Walkthrough

Three independent changes: spell-check word additions, compiler symbol-table free-variable analysis refinement for cell scopes, and temporary file handling in bytecode comparison script.

Changes

Spell-Check Configuration

Layer / File(s) Summary
Word Allowlist Update
.cspell.json
Added deoptimized, fnfe, reborrow, reraises, and reraising to the spell-check allowlist.

Symbol-Table Free-Variable Analysis

Layer / File(s) Summary
Analysis Predicate
crates/codegen/src/symboltable.rs
Introduced remove_owned_cells_from_free predicate to enable cell-scope removal in function-like scopes (Function, AsyncFunction, Lambda, Comprehension, Annotation).
Cell Scope Filtering
crates/codegen/src/symboltable.rs
During per-symbol analysis, symbols with scope == Cell are removed from the newfree set via shift_remove when the predicate is enabled.
Lambda Scope Finalization
crates/codegen/src/symboltable.rs
After entering lambda scope with parameters, explicitly set the current scope's typ to CompilerScope::Lambda.

Bytecode Comparison Script

Layer / File(s) Summary
Temporary File Creation
scripts/compare_bytecode.py
Modified NamedTemporaryFile calls to remove dir=PROJECT_ROOT and add explicit prefix values while retaining UTF-8 encoding and delete=False behavior.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

🎯 3 (Moderate) | ⏱️ ~25 minutes

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐰 Five words now pass the spell-check's gate,
Cell-scoped symbols find their proper fate,
Lambdas scope themselves with crystal care,
Temp files bloom with prefix in the air,
Three patches dance, yet none shall interfere!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Bytecode parity: align borrow optimization with CFG traversal' directly reflects the main objective of the PR, which is to realign the LOAD_FAST_BORROW optimization with CFG traversal instead of bytecode post-processing.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 4, 2026

📦 Library Dependencies

The following Lib/ modules were modified. Here are their dependencies:

[x] test: cpython/Lib/test/test_coroutines.py (TODO: 18)

dependencies:

dependent tests: (7 tests)
- [ ] asyncio: test_asyncio test_contextlib_async test_inspect test_logging test_os test_sys_settrace test_unittest

[x] test: cpython/Lib/test/test_compile.py (TODO: 16)
[x] test: cpython/Lib/test/test_compiler_assemble.py
[x] test: cpython/Lib/test/test_compiler_codegen.py
[x] test: cpython/Lib/test/test_peepholer.py (TODO: 6)

dependencies:

dependent tests: (no tests depend on compile)

Legend:

  • [+] path exists in CPython
  • [x] up-to-date, [ ] outdated

youknowone added 5 commits May 4, 2026 21:52
- 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.
@youknowone youknowone force-pushed the bytecode-parity-typealias branch from e6c29b9 to a24ceb9 Compare May 4, 2026 12:54
@youknowone youknowone force-pushed the bytecode-parity-typealias branch from a24ceb9 to e04ca46 Compare May 4, 2026 14:42
@youknowone youknowone marked this pull request as ready for review May 5, 2026 01:24
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
crates/codegen/src/symboltable.rs (2)

594-643: 💤 Low value

Optional: deduplicate the function-like scope predicate.

remove_owned_cells_from_free (594–601) and promote_inlined_cells_to_cell (628–635) test the exact same set of CompilerScope variants. Extracting a small helper such as is_function_like_scope(typ) (or a single local bound once) would prevent the two lists from drifting if future scope variants are added (e.g. a new type-param-like scope that should — or shouldn't — be considered function-like for both passes).

♻️ Sketch
fn is_function_like(typ: CompilerScope) -> bool {
    matches!(
        typ,
        CompilerScope::Function
            | CompilerScope::AsyncFunction
            | CompilerScope::Lambda
            | CompilerScope::Comprehension
            | CompilerScope::Annotation
    )
}

Then reuse at both call sites.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/codegen/src/symboltable.rs` around lines 594 - 643, The two boolean
predicates remove_owned_cells_from_free and promote_inlined_cells_to_cell
duplicate the same matches(...) over symbol_table.typ; refactor by extracting a
small helper (e.g. is_function_like or is_function_like_scope) that accepts a
CompilerScope (or the symbol_table.typ) and returns whether it is one of
Function | AsyncFunction | Lambda | Comprehension | Annotation, then replace
both match expressions with calls to that helper (update the uses around
symbol_table.typ so remove_owned_cells_from_free and
promote_inlined_cells_to_cell are computed via
is_function_like(symbol_table.typ) or by binding the helper result once).

2131-2153: 💤 Low value

Lambda scope type set post-hoc — consider threading the scope type through the helper instead.

enter_scope_with_parameters always creates the scope as Function/AsyncFunction based on is_async, so the new line 2146 patches the typ back to Lambda only on the with-parameters path; the without-parameters branch (line 2148) already passes Lambda directly. Functionally this works because parameter registration doesn't observe typ in a way that differs between Function and Lambda, and the new cell-pruning logic at lines 594–601 already treats Lambda as function-like.

That said, the post-hoc mutation is easy to overlook for future readers. A cleaner long-term shape would be to pass the scope kind into enter_scope_with_parameters (e.g. an enum or a dedicated is_lambda: bool) so both branches construct the table with the final typ from the start. Optional in this PR.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/codegen/src/symboltable.rs` around lines 2131 - 2153, The Lambda
branch mutates the scope.kind after calling enter_scope_with_parameters because
that helper currently infers Function/AsyncFunction from is_async; modify
enter_scope_with_parameters to accept an explicit scope kind (e.g., a new enum
parameter like scope_kind or a boolean is_lambda) and use that when constructing
the new CompilerScope table so the created scope is Lambda from the start;
update the Expr::Lambda call site to pass the Lambda kind (and preserve existing
async handling for other callers), and adjust any internal logic in
enter_scope_with_parameters that previously derived typ from is_async to instead
use the provided scope kind.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@crates/codegen/src/symboltable.rs`:
- Around line 594-643: The two boolean predicates remove_owned_cells_from_free
and promote_inlined_cells_to_cell duplicate the same matches(...) over
symbol_table.typ; refactor by extracting a small helper (e.g. is_function_like
or is_function_like_scope) that accepts a CompilerScope (or the
symbol_table.typ) and returns whether it is one of Function | AsyncFunction |
Lambda | Comprehension | Annotation, then replace both match expressions with
calls to that helper (update the uses around symbol_table.typ so
remove_owned_cells_from_free and promote_inlined_cells_to_cell are computed via
is_function_like(symbol_table.typ) or by binding the helper result once).
- Around line 2131-2153: The Lambda branch mutates the scope.kind after calling
enter_scope_with_parameters because that helper currently infers
Function/AsyncFunction from is_async; modify enter_scope_with_parameters to
accept an explicit scope kind (e.g., a new enum parameter like scope_kind or a
boolean is_lambda) and use that when constructing the new CompilerScope table so
the created scope is Lambda from the start; update the Expr::Lambda call site to
pass the Lambda kind (and preserve existing async handling for other callers),
and adjust any internal logic in enter_scope_with_parameters that previously
derived typ from is_async to instead use the provided scope kind.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: df128704-a615-42bb-b02d-227922125963

📥 Commits

Reviewing files that changed from the base of the PR and between 0325fd4 and e04ca46.

⛔ Files ignored due to path filters (2)
  • Lib/test/test_coroutines.py is excluded by !Lib/**
  • Lib/test/test_peepholer.py is excluded by !Lib/**
📒 Files selected for processing (5)
  • .cspell.json
  • crates/codegen/src/compile.rs
  • crates/codegen/src/ir.rs
  • crates/codegen/src/symboltable.rs
  • scripts/compare_bytecode.py

@youknowone youknowone merged commit ad5a55c into RustPython:main May 5, 2026
22 checks passed
@youknowone youknowone deleted the bytecode-parity-typealias branch May 5, 2026 05:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant