Assign opcode ids by ShaharNaveh · Pull Request #6637 · RustPython/RustPython
🏁 Script executed:
# First, let's examine the compile.rs file at the mentioned lines head -c 1000000 crates/codegen/src/compile.rs | wc -l
Repository: RustPython/RustPython
Length of output: 69
🏁 Script executed:
# Look at the code around the specified lines sed -n '1875,1890p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 762
🏁 Script executed:
# Find all occurrences of CallKw and Call instructions in the codebase rg -n "CallKw|Instruction::Call\b" crates/codegen/src/compile.rs | head -50
Repository: RustPython/RustPython
Length of output: 1029
🏁 Script executed:
# Find the compile_call_inner function rg -n "fn compile_call_inner" crates
Repository: RustPython/RustPython
Length of output: 126
🏁 Script executed:
# Search for CALL and CALL_KW instruction implementations in the VM rg -n "CALL_KW|CALL\b" crates --type rust | grep -i "opcode\|instruction\|match" | head -40
Repository: RustPython/RustPython
Length of output: 158
🏁 Script executed:
# Read the compile_call_inner function (around line 6127) sed -n '6120,6200p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 3137
🏁 Script executed:
# Look for CallKw enum variant definition rg -n "CallKw" crates/codegen/src/compile.rs -B2 -A2
Repository: RustPython/RustPython
Length of output: 583
🏁 Script executed:
# Find instruction definitions - look for CallKw struct/variant fd "bytecode.rs\|instruction" crates --type f | head -10
Repository: RustPython/RustPython
Length of output: 47
🏁 Script executed:
# Search for where Call/CallKw instructions are defined rg -n "pub enum Instruction|struct Call|struct CallKw" crates --type rust | head -20
Repository: RustPython/RustPython
Length of output: 249
🏁 Script executed:
# Read the Instruction enum definition in bytecode.rs around line 677 sed -n '677,750p' crates/compiler-core/src/bytecode.rs
Repository: RustPython/RustPython
Length of output: 1937
🏁 Script executed:
# Search for Call and CallKw variants in the enum rg -n "Call\s*\{|CallKw\s*\{" crates/compiler-core/src/bytecode.rs -A2
Repository: RustPython/RustPython
Length of output: 1373
🏁 Script executed:
# Find VM implementation of CALL and CALL_KW instructions rg -n "Instruction::Call\s*\{|Instruction::CallKw\s*\{" crates/vm/src --type rust -B2 -A5 | head -80
Repository: RustPython/RustPython
Length of output: 927
🏁 Script executed:
# Look for the execute function that handles instructions in the VM fd "interpreter.rs\|execute.rs" crates/vm/src --type f
Repository: RustPython/RustPython
Length of output: 47
🏁 Script executed:
# Find collect_keyword_args and collect_positional_args implementations rg -n "fn collect_keyword_args|fn collect_positional_args" crates/vm/src -A10
Repository: RustPython/RustPython
Length of output: 1214
🏁 Script executed:
# Look at the context around CallKw in frame.rs to understand the full call flow sed -n '700,730p' crates/vm/src/frame.rs
Repository: RustPython/RustPython
Length of output: 1505
🏁 Script executed:
# Search for stack effect calculations to understand the contract better rg -n "CallKw.*stack|collect_keyword" crates --type rust | head -20
Repository: RustPython/RustPython
Length of output: 351
🏁 Script executed:
# Look at the context around line 3733-3735 where CallKw is emitted differently sed -n '3720,3760p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 1713
🏁 Script executed:
# Find what function this is in sed -n '3700,3750p' crates/codegen/src/compile.rs | head -60
Repository: RustPython/RustPython
Length of output: 2052
🏁 Script executed:
# Check if there are multiple compile functions handling different call contexts rg -n "fn compile.*call" crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 304
🏁 Script executed:
# Look for the function containing the class definition code at line 3733 sed -n '3600,3650p' crates/codegen/src/compile.rs | head -60
Repository: RustPython/RustPython
Length of output: 1745
🏁 Script executed:
# Search for tests of generic class definitions to verify this code path executes rg -n "generic.*class|TypeParam" crates --type rust | grep test | head -20
Repository: RustPython/RustPython
Length of output: 47
🏁 Script executed:
# Get the full function signature where line 3733 is located sed -n '3600,3650p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 1745
🏁 Script executed:
# Look at the full context of the compile_class_def function, especially the CallKw usage sed -n '3630,3780p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 5811
🏁 Script executed:
# Check if this is within an if statement checking for generics/type params sed -n '3650,3770p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 4735
🏁 Script executed:
# Let's verify how the generic class CallKw differs from the normal call path # by examining what should be on the stack rg -n "emit_load_const.*Tuple|BuildTuple" crates/codegen/src/compile.rs | grep -A2 -B2 "keyword\|kw"
Repository: RustPython/RustPython
Length of output: 47
🏁 Script executed:
# Check the implementation of compile_keywords to see the correct pattern rg -n "fn compile_keywords" crates/codegen/src/compile.rs -A20
Repository: RustPython/RustPython
Length of output: 1112
🏁 Script executed:
# Look at how non-generic class handles keywords via compile_call_inner sed -n '6160,6175p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 663
🏁 Script executed:
# Verify the emit_load_const pattern used in the generic class case (line 3728) sed -n '3720,3745p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 1017
🏁 Script executed:
# Let's trace through what stack state emerges from the generic class keyword code # Look at the exact sequence of stack operations sed -n '3721,3743p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 931
🏁 Script executed:
# Search for tests or examples of generic classes with keyword arguments rg -n "class.*\[.*\].*:" tests --type py | head -10
Repository: RustPython/RustPython
Length of output: 110
🏁 Script executed:
# Check if there are any Python test files with generic classes fd "test.*\.py" tests --type f | xargs grep -l "class.*\[.*\]" | head -5
Repository: RustPython/RustPython
Length of output: 157
🏁 Script executed:
# Find test directories find . -type d -name "*test*" | head -10
Repository: RustPython/RustPython
Length of output: 136
🏁 Script executed:
# Look for Python files with generics rg -n "TypeVar|class.*\[" --type py | head -20
Repository: RustPython/RustPython
Length of output: 1579
🏁 Script executed:
# Let's check if there are any tests that would exercise generic class definitions rg -n "class.*Generic\|TypeParams" --type py | head -10
Repository: RustPython/RustPython
Length of output: 47
🏁 Script executed:
# Let's verify the stack state at the generic class CallKw point # by checking if the pattern matches what compile_keywords produces sed -n '6059,6085p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 1154
🏁 Script executed:
# Let's verify the exact stack layout difference # For the generic class case, trace what's on stack before CallKw # Line 3721: first load function # Line 3724: load class name string # Line 3727-3730: load bases # Line 3732: load generic_base # Then the keyword loop at 3734-3742 # Now let's check what compile_keywords produces vs what generic class produces sed -n '6059,6085p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 1154
🏁 Script executed:
# Check the exact difference: does compile_keywords build a map or tuple? sed -n '6079,6088p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 304
🏁 Script executed:
# Look at CallMethodKeyword to see if there's another CallKw pattern rg -n "CallMethodKeyword" crates/codegen/src/compile.rs -B3 -A3
Repository: RustPython/RustPython
Length of output: 446
🏁 Script executed:
# Check the stack effect difference between the two patterns # Look at line 6165 in compile_call_inner sed -n '6163,6167p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 258
🏁 Script executed:
# Let me verify the critical difference in stack patterns # Generic class (line 3734-3742): for each keyword: emit STRING, then compile_expression for value # compile_call_inner (line 6161-6167): builds a TUPLE of all strings, then compiles expressions # Let's confirm this difference by looking at what's built echo "=== Generic class pattern ===" sed -n '3734,3742p' crates/codegen/src/compile.rs echo "" echo "=== compile_call_inner pattern ===" sed -n '6161,6167p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 744
🏁 Script executed:
# Verify if compile_keywords (used by compile_call_inner) creates a tuple # and compile_keywords is called from where rg -n "compile_keywords" crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 215
🏁 Script executed:
# The key question: does the generic class CallKw ever get executed? # Look for any tests or examples that would use generic classes with kwargs rg -n "class.*\[.*\].*:" extra_tests --type py | head -20
Repository: RustPython/RustPython
Length of output: 176
🏁 Script executed:
# Let me trace the exact stack layout for the generic class CallKw case # At line 3734-3742, what's the exact sequence? echo "=== Full generic class keyword handling (lines 3721-3743) ===" sed -n '3721,3743p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 993
🏁 Script executed:
# Now compare with the correct compile_call_inner pattern (lines 6161-6168) echo "=== Correct compile_call_inner CallKw pattern (lines 6161-6168) ===" sed -n '6161,6168p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 452
🏁 Script executed:
# Let's verify the critical difference: # In generic class: individual STRING constants are emitted # In compile_call_inner: a TUPLE of strings is built and emitted as a single constant # Check the exact bytecode produced echo "=== What does emit_load_const produce for each? ===" rg -n "fn emit_load_const" crates/codegen/src/compile.rs -A5
Repository: RustPython/RustPython
Length of output: 387
🏁 Script executed:
# Let me understand the exact stack layout difference # For generic class, we need to see the full picture echo "=== Stack analysis ===" echo "Generic class with kwargs: emits individual STRINGS in loop, then CallKw" echo "compile_call_inner with kwargs: builds TUPLE of strings, emits LoadConst with tuple, then CallKw" echo "" # Let's look at what the VM actually does with CallKw sed -n '2072,2090p' crates/vm/src/frame.rs
Repository: RustPython/RustPython
Length of output: 986
🏁 Script executed:
# The key insight: generic class emits strings individually in a loop # But collect_keyword_args pops a TUPLE first! # This is a stack mismatch! # Let's verify by checking if generic class CallKw is even reachable # Search for any test that would hit the is_generic && !arguments.keywords.is_empty() path rg -n "TypeParam\|generic" extra_tests --type py | head -20
Repository: RustPython/RustPython
Length of output: 47
🏁 Script executed:
# Search for Python 3.12+ generic class tests fd "*.py" extra_tests | xargs grep -l "class.*\[.*\]:" 2>/dev/null | head -10
Repository: RustPython/RustPython
Length of output: 348
🏁 Script executed:
# Final confirmation: check if there's any comment or note about this being a known issue rg -n "TODO\|FIXME\|BUG\|HACK" crates/codegen/src/compile.rs | grep -A2 -B2 "373[0-5]\|CallKw"
Repository: RustPython/RustPython
Length of output: 47
🏁 Script executed:
# Verify the nargs calculation in the generic class case one more time echo "=== Generic class nargs calculation ===" sed -n '3739,3746p' crates/codegen/src/compile.rs echo "" echo "=== compile_call_inner nargs calculation ===" sed -n '6170,6172p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 452
🏁 Script executed:
# Let me get the exact nargs value at line 3733-3735 sed -n '3720,3747p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 1130
🏁 Script executed:
# Understand what nargs contains before the keyword handling sed -n '3718,3735p' crates/codegen/src/compile.rs
Repository: RustPython/RustPython
Length of output: 774
Critical: CallKw nargs ABI violation and stack layout mismatch in generic class handler
The generic class keyword argument handling at lines 3721–3747 contains two critical bugs that contradict the compile_call_inner pattern (lines 6161–6168):
The non-generic class path correctly uses compile_call_inner (line 3777), which follows the proper ABI. Fix the generic class code to build a tuple of keyword name strings (via ConstantData::Tuple) and pass only the positional argument count as nargs, matching the compile_call_inner implementation.