Skip to content

Commit a9ee2e3

Browse files
committed
Fix vectorcall to use slot_new from type slots, fix stat_result
Pattern B vectorcall functions now call through zelf.slots.new instead of calling PyXxx::slot_new directly. This ensures Rust-level subclasses with custom slot_new (e.g. stat_result subclassing tuple) get their own constructor called correctly. Fix PyStatResult::slot_new to use struct_sequence_new for proper length validation and hidden field padding, matching structseq_new behavior. Derive st_atime/st_mtime/st_ctime and their _ns variants from integer time fields when not explicitly provided.
1 parent 9d02708 commit a9ee2e3

File tree

9 files changed

+32
-30
lines changed

9 files changed

+32
-30
lines changed

crates/vm/src/builtins/bool.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ fn vectorcall_bool(
191191
) -> PyResult {
192192
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
193193
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
194-
PyBool::slot_new(zelf.to_owned(), func_args, vm)
194+
(zelf.slots.new.load().unwrap())(zelf.to_owned(), func_args, vm)
195195
}
196196

197197
pub(crate) fn init(context: &'static Context) {

crates/vm/src/builtins/bytes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ fn vectorcall_bytes(
9595
) -> PyResult {
9696
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
9797
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
98-
PyBytes::slot_new(zelf.to_owned(), func_args, vm)
98+
(zelf.slots.new.load().unwrap())(zelf.to_owned(), func_args, vm)
9999
}
100100

101101
pub(crate) fn init(context: &'static Context) {

crates/vm/src/builtins/complex.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ fn vectorcall_complex(
138138
) -> PyResult {
139139
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
140140
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
141-
PyComplex::slot_new(zelf.to_owned(), func_args, vm)
141+
(zelf.slots.new.load().unwrap())(zelf.to_owned(), func_args, vm)
142142
}
143143

144144
pub fn init(context: &'static Context) {

crates/vm/src/builtins/float.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ fn vectorcall_float(
534534
) -> PyResult {
535535
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
536536
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
537-
PyFloat::slot_new(zelf.to_owned(), func_args, vm)
537+
(zelf.slots.new.load().unwrap())(zelf.to_owned(), func_args, vm)
538538
}
539539

540540
#[rustfmt::skip] // to avoid line splitting

crates/vm/src/builtins/int.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,7 @@ fn vectorcall_int(
800800
) -> PyResult {
801801
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
802802
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
803-
PyInt::slot_new(zelf.to_owned(), func_args, vm)
803+
(zelf.slots.new.load().unwrap())(zelf.to_owned(), func_args, vm)
804804
}
805805

806806
pub(crate) fn init(context: &'static Context) {

crates/vm/src/builtins/set.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1444,7 +1444,7 @@ fn vectorcall_frozenset(
14441444
) -> PyResult {
14451445
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
14461446
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
1447-
PyFrozenSet::slot_new(zelf.to_owned(), func_args, vm)
1447+
(zelf.slots.new.load().unwrap())(zelf.to_owned(), func_args, vm)
14481448
}
14491449

14501450
pub fn init(context: &'static Context) {

crates/vm/src/builtins/str.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1790,7 +1790,7 @@ fn vectorcall_str(
17901790
) -> PyResult {
17911791
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
17921792
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
1793-
PyStr::slot_new(zelf.to_owned(), func_args, vm)
1793+
(zelf.slots.new.load().unwrap())(zelf.to_owned(), func_args, vm)
17941794
}
17951795

17961796
pub fn init(ctx: &'static Context) {

crates/vm/src/builtins/tuple.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,9 @@ fn vectorcall_tuple(
704704
) -> PyResult {
705705
let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
706706
let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
707-
PyTuple::slot_new(zelf.to_owned(), func_args, vm)
707+
// Use the type's own slot_new rather than calling PyTuple::slot_new directly,
708+
// so Rust-level subclasses (e.g. struct sequences) get their custom slot_new called.
709+
(zelf.slots.new.load().unwrap())(zelf.to_owned(), func_args, vm)
708710
}
709711

710712
pub(crate) fn init(context: &'static Context) {

crates/vm/src/stdlib/os.rs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,6 @@ pub(super) mod _os {
178178
};
179179
use core::time::Duration;
180180
use crossbeam_utils::atomic::AtomicCell;
181-
use itertools::Itertools;
182181
use rustpython_common::wtf8::Wtf8Buf;
183182
use std::{env, fs, fs::OpenOptions, io, path::PathBuf, time::SystemTime};
184183

@@ -1363,29 +1362,30 @@ pub(super) mod _os {
13631362
#[pyclass(with(PyStructSequence))]
13641363
impl PyStatResult {
13651364
#[pyslot]
1366-
fn slot_new(_cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1367-
let flatten_args = |r: &[PyObjectRef]| {
1368-
let mut vec_args = Vec::from(r);
1369-
loop {
1370-
if let Ok(obj) = vec_args.iter().exactly_one() {
1371-
match obj.downcast_ref::<PyTuple>() {
1372-
Some(t) => {
1373-
vec_args = Vec::from(t.as_slice());
1374-
}
1375-
None => {
1376-
return vec_args;
1377-
}
1378-
}
1379-
} else {
1380-
return vec_args;
1381-
}
1365+
fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1366+
let seq: PyObjectRef = args.bind(vm)?;
1367+
let result = crate::types::struct_sequence_new(cls.clone(), seq, vm)?;
1368+
let tuple = result.downcast_ref::<PyTuple>().unwrap();
1369+
let mut items: Vec<PyObjectRef> = tuple.to_vec();
1370+
1371+
// Derive hidden time fields from integer time fields.
1372+
// indices 7-9 are st_atime_int, st_mtime_int, st_ctime_int.
1373+
// i+3 → st_atime/st_mtime/st_ctime (float)
1374+
// i+6 → st_atime_ns/st_mtime_ns/st_ctime_ns (int nanoseconds)
1375+
for i in 7..=9 {
1376+
if vm.is_none(&items[i + 3]) {
1377+
let float_val = items[i].try_float(vm)?;
1378+
items[i + 3] = float_val.into();
13821379
}
1383-
};
1384-
1385-
let args: FuncArgs = flatten_args(&args.args).into();
1380+
if vm.is_none(&items[i + 6]) {
1381+
let int_val: i64 = items[i].clone().try_into_value(vm)?;
1382+
items[i + 6] = vm.ctx.new_int(int_val as i128 * 1_000_000_000).into();
1383+
}
1384+
}
13861385

1387-
let stat: StatResultData = args.bind(vm)?;
1388-
Ok(stat.to_pyobject(vm))
1386+
PyTuple::new_unchecked(items.into_boxed_slice())
1387+
.into_ref_with_type(vm, cls)
1388+
.map(Into::into)
13891389
}
13901390
}
13911391

0 commit comments

Comments
 (0)