Skip to content

Inline with-suppress return blocks and extend return duplication#7622

Merged
youknowone merged 4 commits intoRustPython:mainfrom
youknowone:bytecode-parity-string
Apr 18, 2026
Merged

Inline with-suppress return blocks and extend return duplication#7622
youknowone merged 4 commits intoRustPython:mainfrom
youknowone:bytecode-parity-string

Conversation

@youknowone
Copy link
Copy Markdown
Member

@youknowone youknowone commented Apr 18, 2026

Summary by CodeRabbit

  • Bug Fixes

    • Fixed template-string evaluation/interpolation order and surrogate-preserving literals; improved loop-target line attribution and no-op anchoring; clarified dictionary lookup behavior for built-ins vs subclasses.
  • Performance

    • Expanded constant-folding (subscripting, string/bytes/concat/repeat) and optimized large collection literal emission and jump/no-op threading.
  • Features

    • Improved generic class/type-parameter initialization ordering and conditional-annotation bookkeeping.
  • Tests

    • Added regression tests covering these behaviors.

- Add inline_with_suppress_return_blocks pass to inline return
  epilogues after with-suppress cleanup sequences
- Extend duplicate_end_returns to handle conditional jumps to the
  final return block, not just unconditional ones
- Process jump targets in reverse order to preserve indices
- Add extra deoptimize_store_fast_store_fast pass after superinstructions
- Add tests for listcomp cleanup tail and with-suppress tail
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 18, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 49d81339-39cf-410e-944a-7a2f8682fcfd

📥 Commits

Reviewing files that changed from the base of the PR and between dda6ff2 and a5b9f0e.

📒 Files selected for processing (1)
  • crates/codegen/src/symboltable.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/codegen/src/symboltable.rs

📝 Walkthrough

Walkthrough

Deferred early collection-literal folding to later IR passes; rewrote t-string lowering to CPython ordering; tightened annotation and generic-class bookkeeping; added metadata-aware IR return duplication and new cleanup passes; refined jump/NOP/threading behavior; expanded constant folding; consolidated VM mapping lookup.

Changes

Cohort / File(s) Summary
Collection folding & literal streaming
crates/codegen/src/compile.rs
Disabled early constant-folding for list/set literals; added element prescan to choose emitting BuildList/BuildSet for large non-const literals and defer tuple-backed constants to later passes.
Template string (t-string) lowering
crates/codegen/src/compile.rs
Rewrote t"..." lowering to collect string segments then evaluate interpolations L→R; emit BuildTemplate without SWAP; added compile_tstring_literal_value to preserve surrogate WTF-8.
Loop targets & annotation cell handling
crates/codegen/src/compile.rs
Removed synthetic Nop before loop-target stores; factored conditional-annotation cell logic into scope_needs_conditional_annotations_cell(&SymbolTable) and used it for cellvars and __conditional_annotations__ emission.
Generic class / type-params emission
crates/codegen/src/compile.rs, crates/codegen/src/symboltable.rs
Set __type_params__ earlier from enclosing .type_params; compute .generic_base after pushing class body to match CPython prologue; symboltable marks .generic_base and adjusts .type_params/__type_params__ registration.
Constant folding expansions
crates/codegen/src/compile.rs, crates/codegen/src/ir.rs
Added folding for Subscript when container is str/bytes/tuple and index is an integer (incl. negative indices); expanded Str/Bytes concat and repeats with size guards.
IR: metadata-aware return duplication & new passes
crates/codegen/src/ir.rs
duplicate_end_returns uses &self.metadata and strict LoadConst None detection; new late passes: inline_with_suppress_return_blocks, inline_pop_except_return_blocks, duplicate_named_except_cleanup_returns, plus extra unreachable-block elimination.
IR: jump-threading, NOP removal & dead-store changes
crates/codegen/src/ir.rs
Jump-threading skips leading NOPs when resolving targets; redundant NOP removal preserves adjacent-jump line anchors; dead-store elimination limited to adjacent STORE_FAST duplicates only.
IR: superinstruction & deopt ordering tweaks
crates/codegen/src/ir.rs
Avoid certain StoreFast+LoadFast superinstructions in generators when preceding real instruction is ForIter (with exception); run deoptimize_store_fast_store_fast_after_cleanup() again after swaps/superinstructions.
Symbol table: annotation bookkeeping
crates/codegen/src/symboltable.rs
Refactored annotation scanning to compute future-vs-nonfuture conditions; unconditionally flip has_conditional_annotations for non-future conditional case; register __conditional_annotations__ (Assigned+Used) only when consolidated condition holds; register .type_params/__type_params__ for generic classes.
VM: mapping lookup consolidation & dict note
crates/vm/src/frame.rs, crates/vm/src/builtins/dict.rs
Unified missing-key lookup into mapping_get_optional helper with exact-dict fast path (PyDict::get_item_opt) and generic mapping get_item with KeyErrorNone; clarified __missing__ behavior in PyDict::get_item_opt comment.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • coolreader18

Poem

"I'm a rabbit in the bytecode glen,
I hop through templates, tuples, then—
constants wait till IR's awake,
annotations find their tiny stake,
jumps skip nops — I nibble code again 🐇"

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 69.23% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes in the pull request: inlining with-suppress return blocks and extending return duplication logic in the IR optimization passes.

✏️ 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.

- Remove unnecessary NOP between FOR_ITER and unpack/store
  by compiling loop target directly on target range
- Fix t-string compilation to match stack order: build
  strings tuple first, then evaluate interpolations
- Split compile_tstring_into into collect_tstring_strings
  and compile_tstring_interpolations
- Handle debug text literals and default repr conversion
  for debug specifier in t-strings
- Always set bit 1 in BUILD_INTERPOLATION oparg encoding
@youknowone youknowone force-pushed the bytecode-parity-string branch from 553b04a to e21cabc Compare April 18, 2026 04:36
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 18, 2026

📦 Library Dependencies

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

(module 'compile test_peepholer test_tstring test_typing' not found)

Legend:

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

@youknowone youknowone marked this pull request as ready for review April 18, 2026 05:16
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.

Actionable comments posted: 4

🧹 Nitpick comments (3)
crates/codegen/src/ir.rs (3)

2397-2431: prev_real/next_real walk includes NOPs.

find_map(|info| info.instr.real()) returns the first real() hit, but Instruction::Nop is a Real variant — so the "previous real instruction" can be a NOP and the ForIter guard silently fails if any NOP remains between ForIter and the StoreFast/LoadFast pair. This happens to be safe here because insert_superinstructions is always invoked after remove_nops / remove_redundant_nops_and_jumps, but the current expression does not encode that invariant.

Suggest filtering NOPs explicitly for clarity and to be robust to future pipeline reordering:

♻️ Suggested refactor
-                let prev_real = block.instructions[..i]
-                    .iter()
-                    .rev()
-                    .find_map(|info| info.instr.real());
-                let next_real = block.instructions[(j + 1)..]
-                    .iter()
-                    .find_map(|info| info.instr.real());
+                let prev_real = block.instructions[..i]
+                    .iter()
+                    .rev()
+                    .find_map(|info| info.instr.real())
+                    .filter(|i| !matches!(i, Instruction::Nop));
+                let next_real = block.instructions[(j + 1)..]
+                    .iter()
+                    .find_map(|info| info.instr.real())
+                    .filter(|i| !matches!(i, Instruction::Nop));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/codegen/src/ir.rs` around lines 2397 - 2431, The current
prev_real/next_real lookup uses find_map(|info| info.instr.real()) which treats
Instruction::Nop as a "real" instruction and can make the ForIter guard misfire;
modify the searches around block.instructions[..i].iter().rev() and
block.instructions[(j + 1)..].iter() to explicitly skip Nop results (e.g. use
find_map(|info| match info.instr.real() { Some(Instruction::Nop) => None, other
=> other })) so prev_real and next_real never return Nop and the
Generator/ForIter checks behave correctly.

5554-5616: duplicate_named_except_cleanup_returns: inner-loop scan is O(n²).

The inner for block_idx in 0..blocks.len() runs for every named-except cleanup target, and find_layout_predecessor itself is O(n). For codebases with many try/except ... as name: patterns this can become a hot spot during compilation. Not blocking, but consider precomputing layout predecessors and a map of trailing-conditional-jump targets if compile-time regressions are observed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/codegen/src/ir.rs` around lines 5554 - 5616,
duplicate_named_except_cleanup_returns currently does an O(n²) scan by calling
find_layout_predecessor and iterating all blocks per target; instead precompute
data once: compute layout_predecessor for every block (cache results of
find_layout_predecessor), and build a map from target BlockIdx to a Vec of
(block_idx, instr_idx) by scanning each block once with
trailing_conditional_jump_index and next_nonempty_block to record which blocks
jump to which target; then iterate only the targets that are
named-except-cleanup and use the precomputed predecessors, layout_predecessor
and the jump-map to populate clones, avoiding repeated full scans of blocks.
Ensure you reuse the existing predecessors vector and update references to
find_layout_predecessor, trailing_conditional_jump_index, next_nonempty_block,
clones, and blocks accordingly.

1201-1237: Constant folding misses (negative int) * str/bytes.

n.try_into().ok()? on a negative BigInt fails and aborts folding, but Python defines -2 * "ab" == "" and -2 * b"ab" == b"" (any non-positive multiplier yields an empty sequence). Same for the existing Str * Integer branch at line 1189. Minor missed optimization, not a correctness issue.

♻️ Suggested refactor
-            (ConstantData::Integer { value: n }, ConstantData::Str { value: s })
-                if matches!(op, BinOp::Multiply) =>
-            {
-                let n: usize = n.try_into().ok()?;
-                if n > 4096 {
-                    return None;
-                }
-                let result = s.to_string().repeat(n);
-                Some(ConstantData::Str {
-                    value: result.into(),
-                })
-            }
+            (ConstantData::Integer { value: n }, ConstantData::Str { value: s })
+                if matches!(op, BinOp::Multiply) =>
+            {
+                let n: usize = n.try_into().ok().unwrap_or(0);
+                if n > 4096 {
+                    return None;
+                }
+                let result = s.to_string().repeat(n);
+                Some(ConstantData::Str {
+                    value: result.into(),
+                })
+            }

(and similar for the Bytes branches)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/codegen/src/ir.rs` around lines 1201 - 1237, The integer multiplier
branches for ConstantData::Str/Bytes currently call n.try_into().ok()? which
aborts folding for negative BigInt multipliers; change each BinOp::Multiply
branch handling (the patterns with ConstantData::Integer + ConstantData::Str and
both Bytes+Integer / Integer+Bytes and the existing Str*Integer branch) to first
check if the BigInt n is <= 0 and in that case return an empty ConstantData::Str
or ConstantData::Bytes respectively, otherwise convert n to usize (try_into) and
proceed with the existing 4096 cap and repeat logic; reference the
ConstantData::Integer, ConstantData::Str, ConstantData::Bytes patterns and
BinOp::Multiply in ir.rs to locate and update the branches.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/codegen/src/compile.rs`:
- Around line 2132-2140: The helper scope_needs_conditional_annotations_cell
currently returns false for CompilerScope::Class unless
has_conditional_annotations is true, but symboltable.rs registers the
"__conditional_annotations__" symbol for class scopes even when
has_conditional_annotations is false; update
scope_needs_conditional_annotations_cell (and the Class arm) to also return true
when the SymbolTable already contains the "__conditional_annotations__" symbol
(e.g., check whatever lookup/contains API exists on SymbolTable for
"__conditional_annotations__"), so class scopes that registered that symbol
still create the implicit cell and prologue.
- Around line 9928-9942: The current ConstantData::Str fold converts the Wtf8Buf
via to_string() which can replace surrogates with REPLACEMENT_CHARACTER; update
the match arm in compile.rs so you first call value.to_string(), check if it
contains the REPLACEMENT_CHARACTER constant (as done in compile_string_value /
compile_fstring_literal_value / compile_fstring_part_literal_value) and if so
return Ok(None) to skip the fold; only proceed to collect chars, compute idx,
and build the folded ConstantData::Str when no replacement characters are
present.
- Around line 10839-10843: The t-string literal loop in the tstring.elements
handling currently appends lit.value directly, which loses escaped surrogate
(WTF-8) data; change the handling to reparse the literal like the f-string path:
use the same approach as compile_fstring_literal_value(...) plus push_wtf8(...)
to append the reparsed bytes instead of push_str(&lit.value). Because
compile_fstring_literal_value takes ast::FStringFlags while tstring.flags is
ast::TStringFlags, either add a parallel helper (e.g.,
compile_tstring_literal_value or a helper that accepts TStringFlags) or provide
a safe conversion/adaptor from TStringFlags to FStringFlags/AnyStringFlags, then
call that helper inside the loop over tstring.elements and replace
current_string.push_str(&lit.value) with pushing the returned WTF-8 bytes via
push_wtf8 on the same buffer used for f-strings.

In `@crates/codegen/src/symboltable.rs`:
- Around line 1295-1312: The guard that skips registration when
tables.last().and_then(|table|
table.lookup("__conditional_annotations__")).is_none() prevents adding the
bookkeeping flags for existing symbols; instead always call register_name to
merge ASSIGNED/REFERENCED flags so future-annotation bookkeeping is preserved.
Update the block guarded by needs_module_future_annotation_bookkeeping to
unconditionally invoke self.register_name("__conditional_annotations__",
SymbolUsage::Assigned, annotation.range()) and
self.register_name("__conditional_annotations__", SymbolUsage::Used,
annotation.range()) (register_name is idempotent and merges flags), referencing
the needs_module_future_annotation_bookkeeping check,
tables.last().lookup("__conditional_annotations__"), and the register_name
method to locate the change.

---

Nitpick comments:
In `@crates/codegen/src/ir.rs`:
- Around line 2397-2431: The current prev_real/next_real lookup uses
find_map(|info| info.instr.real()) which treats Instruction::Nop as a "real"
instruction and can make the ForIter guard misfire; modify the searches around
block.instructions[..i].iter().rev() and block.instructions[(j + 1)..].iter() to
explicitly skip Nop results (e.g. use find_map(|info| match info.instr.real() {
Some(Instruction::Nop) => None, other => other })) so prev_real and next_real
never return Nop and the Generator/ForIter checks behave correctly.
- Around line 5554-5616: duplicate_named_except_cleanup_returns currently does
an O(n²) scan by calling find_layout_predecessor and iterating all blocks per
target; instead precompute data once: compute layout_predecessor for every block
(cache results of find_layout_predecessor), and build a map from target BlockIdx
to a Vec of (block_idx, instr_idx) by scanning each block once with
trailing_conditional_jump_index and next_nonempty_block to record which blocks
jump to which target; then iterate only the targets that are
named-except-cleanup and use the precomputed predecessors, layout_predecessor
and the jump-map to populate clones, avoiding repeated full scans of blocks.
Ensure you reuse the existing predecessors vector and update references to
find_layout_predecessor, trailing_conditional_jump_index, next_nonempty_block,
clones, and blocks accordingly.
- Around line 1201-1237: The integer multiplier branches for
ConstantData::Str/Bytes currently call n.try_into().ok()? which aborts folding
for negative BigInt multipliers; change each BinOp::Multiply branch handling
(the patterns with ConstantData::Integer + ConstantData::Str and both
Bytes+Integer / Integer+Bytes and the existing Str*Integer branch) to first
check if the BigInt n is <= 0 and in that case return an empty ConstantData::Str
or ConstantData::Bytes respectively, otherwise convert n to usize (try_into) and
proceed with the existing 4096 cap and repeat logic; reference the
ConstantData::Integer, ConstantData::Str, ConstantData::Bytes patterns and
BinOp::Multiply in ir.rs to locate and update the branches.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: e08cb85e-c3d4-431d-8ff7-8e9a28a71e14

📥 Commits

Reviewing files that changed from the base of the PR and between 1f1be5e and e21cabc.

⛔ Files ignored due to path filters (4)
  • Lib/test/test_compile.py is excluded by !Lib/**
  • Lib/test/test_peepholer.py is excluded by !Lib/**
  • Lib/test/test_tstring.py is excluded by !Lib/**
  • Lib/test/test_typing.py is excluded by !Lib/**
📒 Files selected for processing (4)
  • crates/codegen/src/compile.rs
  • crates/codegen/src/ir.rs
  • crates/codegen/src/symboltable.rs
  • crates/vm/src/frame.rs

Comment thread crates/codegen/src/compile.rs
Comment thread crates/codegen/src/compile.rs
Comment thread crates/codegen/src/compile.rs
Comment thread crates/codegen/src/symboltable.rs Outdated
Constant folding:
- Add string/bytes multiply and bytes concat folding in IR
- Add constant subscript folding (str, bytes, tuple indexing)
- Delegate list/set constant folding to IR passes
- Stream big non-const list/set via BUILD+LIST_APPEND

Class/generic compilation:
- Reorder class body prologue: __type_params__ before __classdict__
- Build class function before .generic_base in generic classes
- Register .type_params/.generic_base symbols in proper scopes
- Use load_name/store_name helpers for synthetic variables

Return block handling:
- Only duplicate return-None epilogues, not arbitrary returns
- Add inline_pop_except_return_blocks pass
- Add duplicate_named_except_cleanup_returns pass

Other fixes:
- Fix eliminate_dead_stores to only collapse adjacent duplicates
- Skip STORE_FAST_LOAD_FAST superinstruction in generators after FOR_ITER
- Thread jumps through NOP-only blocks
- Transfer NOP line info to following unconditional jumps
- Extract scope_needs_conditional_annotations_cell helper
- Register __conditional_annotations__ for module future annotations
@youknowone youknowone force-pushed the bytecode-parity-string branch from e21cabc to caf8d55 Compare April 18, 2026 06:18
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 (1)
crates/codegen/src/symboltable.rs (1)

1269-1309: Deduplicate the __conditional_annotations__ registration.

The future and non-future paths now share the same two register_name calls; compute the condition first and perform the common registration once.

♻️ Proposed refactor
         let current_scope = self.tables.last().map(|t| t.typ);
+        let is_annotation_bookkeeping_scope = matches!(
+            current_scope,
+            Some(CompilerScope::Module | CompilerScope::Class)
+        );
         let needs_future_annotation_bookkeeping = is_ann_assign
             && self.future_annotations
-            && matches!(
-                current_scope,
-                Some(CompilerScope::Module | CompilerScope::Class)
-            );
+            && is_annotation_bookkeeping_scope;
+        let mut needs_conditional_annotation_bookkeeping =
+            needs_future_annotation_bookkeeping;
 
         // PEP 649: Only AnnAssign annotations can be conditional.
         // Function parameter/return annotations are never conditional.
         if is_ann_assign && !self.future_annotations {
             let is_conditional = matches!(current_scope, Some(CompilerScope::Module))
                 || (matches!(current_scope, Some(CompilerScope::Class))
                     && self.in_conditional_block);
 
             if is_conditional && !self.tables.last().unwrap().has_conditional_annotations {
                 self.tables.last_mut().unwrap().has_conditional_annotations = true;
-                self.register_name(
-                    "__conditional_annotations__",
-                    SymbolUsage::Assigned,
-                    annotation.range(),
-                )?;
-                self.register_name(
-                    "__conditional_annotations__",
-                    SymbolUsage::Used,
-                    annotation.range(),
-                )?;
+                needs_conditional_annotation_bookkeeping = true;
             }
         }
 
-        if needs_future_annotation_bookkeeping {
+        if needs_conditional_annotation_bookkeeping {
             self.register_name(
                 "__conditional_annotations__",
                 SymbolUsage::Assigned,
                 annotation.range(),

As per coding guidelines, “When branches differ only in a value but share common logic, extract the differing value first, then call the common logic once to avoid duplicate code.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/codegen/src/symboltable.rs` around lines 1269 - 1309, The two branches
duplicate the same register_name calls for "__conditional_annotations__";
compute a single boolean (e.g., should_register_conditional_annotations) by
combining the existing conditions (is_ann_assign && self.future_annotations &&
matches!(current_scope, Some(CompilerScope::Module|CompilerScope::Class)) OR the
non-future path: is_ann_assign && !self.future_annotations &&
(matches!(current_scope, Some(CompilerScope::Module)) ||
(matches!(current_scope, Some(CompilerScope::Class)) &&
self.in_conditional_block)) and also ensure the table flag
(self.tables.last().unwrap().has_conditional_annotations) is respected for the
non-future path; then if should_register_conditional_annotations is true, set
the table flag as needed and call the two
register_name("__conditional_annotations__", SymbolUsage::Assigned,
annotation.range()) and register_name("__conditional_annotations__",
SymbolUsage::Used, annotation.range()) once.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/codegen/src/symboltable.rs`:
- Around line 1269-1309: The two branches duplicate the same register_name calls
for "__conditional_annotations__"; compute a single boolean (e.g.,
should_register_conditional_annotations) by combining the existing conditions
(is_ann_assign && self.future_annotations && matches!(current_scope,
Some(CompilerScope::Module|CompilerScope::Class)) OR the non-future path:
is_ann_assign && !self.future_annotations && (matches!(current_scope,
Some(CompilerScope::Module)) || (matches!(current_scope,
Some(CompilerScope::Class)) && self.in_conditional_block)) and also ensure the
table flag (self.tables.last().unwrap().has_conditional_annotations) is
respected for the non-future path; then if
should_register_conditional_annotations is true, set the table flag as needed
and call the two register_name("__conditional_annotations__",
SymbolUsage::Assigned, annotation.range()) and
register_name("__conditional_annotations__", SymbolUsage::Used,
annotation.range()) once.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 77ed5473-a8a3-4c25-a56e-324539041d69

📥 Commits

Reviewing files that changed from the base of the PR and between e21cabc and caf8d55.

⛔ Files ignored due to path filters (4)
  • Lib/test/test_compile.py is excluded by !Lib/**
  • Lib/test/test_peepholer.py is excluded by !Lib/**
  • Lib/test/test_tstring.py is excluded by !Lib/**
  • Lib/test/test_typing.py is excluded by !Lib/**
📒 Files selected for processing (5)
  • crates/codegen/src/compile.rs
  • crates/codegen/src/ir.rs
  • crates/codegen/src/symboltable.rs
  • crates/vm/src/builtins/dict.rs
  • crates/vm/src/frame.rs
✅ Files skipped from review due to trivial changes (2)
  • crates/vm/src/builtins/dict.rs
  • crates/codegen/src/ir.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/vm/src/frame.rs

@youknowone youknowone force-pushed the bytecode-parity-string branch from dda6ff2 to a5b9f0e Compare April 18, 2026 08:20
@youknowone youknowone merged commit b80c2bd into RustPython:main Apr 18, 2026
21 checks passed
@youknowone youknowone deleted the bytecode-parity-string branch April 18, 2026 08:52
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