Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 87 additions & 77 deletions Lib/test/test_faulthandler.py

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion Lib/test/test_inspect/test_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,6 @@ def test_abuse_done(self):
self.istest(inspect.istraceback, 'git.ex.__traceback__')
self.istest(inspect.isframe, 'mod.fr')

@unittest.expectedFailure # TODO: RUSTPYTHON
def test_stack(self):
self.assertTrue(len(mod.st) >= 5)
frame1, frame2, frame3, frame4, *_ = mod.st
Expand Down
2 changes: 0 additions & 2 deletions Lib/test/test_listcomps.py
Original file line number Diff line number Diff line change
Expand Up @@ -716,8 +716,6 @@ def test_multiple_comprehension_name_reuse(self):
self._check_in_scopes(code, {"x": 2, "y": [3]}, ns={"x": 3}, scopes=["class"])
self._check_in_scopes(code, {"x": 2, "y": [2]}, ns={"x": 3}, scopes=["function", "module"])

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_exception_locations(self):
# The location of an exception raised from __init__ or
# __next__ should should be the iterator expression
Expand Down
1 change: 0 additions & 1 deletion Lib/test/test_setcomps.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@
"""

class SetComprehensionTest(unittest.TestCase):
@unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: 'FrameSummary' object has no attribute 'end_lineno'
def test_exception_locations(self):
# The location of an exception raised from __init__ or
# __next__ should should be the iterator expression
Expand Down
4 changes: 0 additions & 4 deletions Lib/test/test_traceback.py
Original file line number Diff line number Diff line change
Expand Up @@ -3423,8 +3423,6 @@ def test_no_locals(self):
s = traceback.StackSummary.extract(iter([(f, 6)]))
self.assertEqual(s[0].locals, None)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_format_locals(self):
def some_inner(k, v):
a = 1
Expand All @@ -3441,8 +3439,6 @@ def some_inner(k, v):
' v = 4\n' % (__file__, some_inner.__code__.co_firstlineno + 3)
], s.format())

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_custom_format_frame(self):
class CustomStackSummary(traceback.StackSummary):
def format_frame_summary(self, frame_summary, colorize=False):
Expand Down
19 changes: 15 additions & 4 deletions crates/codegen/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4638,7 +4638,7 @@ impl Compiler {
self.emit_load_const(ConstantData::Str { value: name.into() });

if let Some(arguments) = arguments {
self.codegen_call_helper(2, arguments)?;
self.codegen_call_helper(2, arguments, self.current_source_range)?;
} else {
Comment on lines 4640 to 4642
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Preserve class statement range for build_class call.

current_source_range is likely overwritten while compiling decorators and the class body, so the call location can incorrectly point inside the class body instead of the class statement. Capture the class statement range at the start of compile_class_def and reuse it here.

🛠️ Suggested fix
 fn compile_class_def(
     &mut self,
     name: &str,
     body: &[ast::Stmt],
     decorator_list: &[ast::Decorator],
     type_params: Option<&ast::TypeParams>,
     arguments: Option<&ast::Arguments>,
 ) -> CompileResult<()> {
+    // Preserve the class statement range for __build_class__ call location.
+    let class_call_range = self.current_source_range;
     self.prepare_decorators(decorator_list)?;

     let is_generic = type_params.is_some();
     let firstlineno = self.get_source_line_number().get().to_u32();
@@
-            if let Some(arguments) = arguments {
-                self.codegen_call_helper(2, arguments, self.current_source_range)?;
+            if let Some(arguments) = arguments {
+                self.codegen_call_helper(2, arguments, class_call_range)?;
             } else {
                 emit!(self, Instruction::Call { nargs: 2 });
             }
🤖 Prompt for AI Agents
In `@crates/codegen/src/compile.rs` around lines 4626 - 4628, In
compile_class_def, capture the class statement source range at the start (e.g.,
let class_stmt_range = self.current_source_range.clone() or equivalent) before
compiling decorators/body, and then use that saved class_stmt_range when
emitting the __build_class__ call (replace uses of self.current_source_range in
the codegen_call_helper(2, arguments, self.current_source_range)? invocation
with the saved class_stmt_range) so the call site points to the class statement
instead of a range overwritten by decorator/body compilation.

emit!(self, Instruction::Call { nargs: 2 });
}
Expand Down Expand Up @@ -7079,6 +7079,10 @@ impl Compiler {
}

fn compile_call(&mut self, func: &ast::Expr, args: &ast::Arguments) -> CompileResult<()> {
// Save the call expression's source range so CALL instructions use the
// call start line, not the last argument's line.
let call_range = self.current_source_range;

// Method call: obj → LOAD_ATTR_METHOD → [method, self_or_null] → args → CALL
// Regular call: func → PUSH_NULL → args → CALL
if let ast::Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = &func {
Expand All @@ -7096,21 +7100,21 @@ impl Compiler {
self.emit_load_zero_super_method(idx);
}
}
self.codegen_call_helper(0, args)?;
self.codegen_call_helper(0, args, call_range)?;
} else {
// Normal method call: compile object, then LOAD_ATTR with method flag
// LOAD_ATTR(method=1) pushes [method, self_or_null] on stack
self.compile_expression(value)?;
let idx = self.name(attr.as_str());
self.emit_load_attr_method(idx);
self.codegen_call_helper(0, args)?;
self.codegen_call_helper(0, args, call_range)?;
}
} else {
// Regular call: push func, then NULL for self_or_null slot
// Stack layout: [func, NULL, args...] - same as method call [func, self, args...]
self.compile_expression(func)?;
emit!(self, Instruction::PushNull);
self.codegen_call_helper(0, args)?;
self.codegen_call_helper(0, args, call_range)?;
}
Ok(())
}
Expand Down Expand Up @@ -7152,10 +7156,13 @@ impl Compiler {
}

/// Compile call arguments and emit the appropriate CALL instruction.
/// `call_range` is the source range of the call expression, used to set
/// the correct line number on the CALL instruction.
fn codegen_call_helper(
&mut self,
additional_positional: u32,
arguments: &ast::Arguments,
call_range: TextRange,
) -> CompileResult<()> {
let nelts = arguments.args.len();
let nkwelts = arguments.keywords.len();
Expand Down Expand Up @@ -7186,13 +7193,16 @@ impl Compiler {
self.compile_expression(&keyword.value)?;
}

// Restore call expression range for kwnames and CALL_KW
self.set_source_range(call_range);
self.emit_load_const(ConstantData::Tuple {
elements: kwarg_names,
});

let nargs = additional_positional + nelts.to_u32() + nkwelts.to_u32();
emit!(self, Instruction::CallKw { nargs });
} else {
self.set_source_range(call_range);
let nargs = additional_positional + nelts.to_u32();
emit!(self, Instruction::Call { nargs });
}
Expand Down Expand Up @@ -7284,6 +7294,7 @@ impl Compiler {
emit!(self, Instruction::PushNull);
}

self.set_source_range(call_range);
emit!(self, Instruction::CallFunctionEx);
}

Expand Down
Loading
Loading