Skip to content

Commit 6b537f1

Browse files
committed
Add objsequence::{opt_,}len
1 parent 7d40f45 commit 6b537f1

File tree

3 files changed

+33
-7
lines changed

3 files changed

+33
-7
lines changed

vm/src/builtins.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use crate::obj::objdict::PyDictRef;
2222
use crate::obj::objfunction::PyFunctionRef;
2323
use crate::obj::objint::{self, PyIntRef};
2424
use crate::obj::objiter;
25+
use crate::obj::objsequence;
2526
use crate::obj::objstr::{PyString, PyStringRef};
2627
use crate::obj::objtype::{self, PyClassRef};
2728
use crate::pyhash;
@@ -384,11 +385,8 @@ fn builtin_iter(iter_target: PyObjectRef, vm: &VirtualMachine) -> PyResult {
384385
objiter::get_iter(vm, &iter_target)
385386
}
386387

387-
fn builtin_len(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
388-
let method = vm.get_method_or_type_error(obj.clone(), "__len__", || {
389-
format!("object of type '{}' has no len()", obj.class().name)
390-
})?;
391-
vm.invoke(&method, PyFuncArgs::default())
388+
fn builtin_len(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
389+
objsequence::len(&obj, vm)
392390
}
393391

394392
fn builtin_locals(vm: &VirtualMachine) -> PyDictRef {

vm/src/exceptions.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,6 @@ pub fn write_exception_inner<W: Write>(
250250
write_traceback_entry(output, traceback)?;
251251
tb = traceback.next.as_ref();
252252
}
253-
} else {
254-
writeln!(output, "No traceback set on exception")?;
255253
}
256254

257255
let varargs = exc.args();

vm/src/obj/objsequence.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,3 +263,33 @@ pub fn is_valid_slice_arg(
263263
Ok(None)
264264
}
265265
}
266+
267+
pub fn opt_len(obj: &PyObjectRef, vm: &VirtualMachine) -> Option<PyResult<usize>> {
268+
vm.get_method(obj.clone(), "__len__").map(|len| {
269+
let len = vm.invoke(&len?, vec![])?;
270+
let len = len
271+
.payload_if_subclass::<PyInt>(vm)
272+
.ok_or_else(|| {
273+
vm.new_type_error(format!(
274+
"'{}' object cannot be interpreted as an integer",
275+
len.class().name
276+
))
277+
})?
278+
.as_bigint();
279+
if len.is_negative() {
280+
return Err(vm.new_value_error("__len__() should return >= 0".to_string()));
281+
}
282+
len.to_usize().ok_or_else(|| {
283+
vm.new_overflow_error("cannot fit __len__() result into usize".to_string())
284+
})
285+
})
286+
}
287+
288+
pub fn len(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
289+
opt_len(obj, vm).unwrap_or_else(|| {
290+
Err(vm.new_type_error(format!(
291+
"object of type '{}' has no len()",
292+
obj.class().name
293+
)))
294+
})
295+
}

0 commit comments

Comments
 (0)