Skip to content

Commit 0d2b817

Browse files
committed
single_or_tuple_any uses TryFromObject instead of PyValue
1 parent 1c93a36 commit 0d2b817

File tree

4 files changed

+47
-47
lines changed

4 files changed

+47
-47
lines changed

vm/src/builtins.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,10 +363,14 @@ fn builtin_input(prompt: OptionalArg<PyStringRef>, vm: &VirtualMachine) -> PyRes
363363
}
364364
}
365365

366-
fn builtin_isinstance(obj: PyObjectRef, typ: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
366+
pub fn builtin_isinstance(
367+
obj: PyObjectRef,
368+
typ: PyObjectRef,
369+
vm: &VirtualMachine,
370+
) -> PyResult<bool> {
367371
single_or_tuple_any(
368372
typ,
369-
|cls: PyClassRef| vm.isinstance(&obj, &cls),
373+
|cls: &PyClassRef| vm.isinstance(&obj, cls),
370374
|o| {
371375
format!(
372376
"isinstance() arg 2 must be a type or tuple of types, not {}",
@@ -384,7 +388,7 @@ fn builtin_issubclass(
384388
) -> PyResult<bool> {
385389
single_or_tuple_any(
386390
typ,
387-
|cls: PyClassRef| vm.issubclass(&subclass, &cls),
391+
|cls: &PyClassRef| vm.issubclass(&subclass, cls),
388392
|o| {
389393
format!(
390394
"issubclass() arg 2 must be a class or tuple of classes, not {}",

vm/src/frame.rs

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ use std::sync::Mutex;
55
use indexmap::IndexMap;
66
use itertools::Itertools;
77

8+
use crate::builtins::builtin_isinstance;
89
use crate::bytecode;
910
use crate::exceptions::{self, ExceptionCtor, PyBaseExceptionRef};
10-
use crate::function::{single_or_tuple_any, PyFuncArgs};
11+
use crate::function::PyFuncArgs;
1112
use crate::obj::objasyncgenerator::PyAsyncGenWrappedValue;
1213
use crate::obj::objbool;
1314
use crate::obj::objcode::PyCodeRef;
@@ -1353,25 +1354,6 @@ impl ExecutingFrame<'_> {
13531354
!a.is(&b)
13541355
}
13551356

1356-
fn exc_match(
1357-
&self,
1358-
vm: &VirtualMachine,
1359-
exc: PyObjectRef,
1360-
exc_type: PyObjectRef,
1361-
) -> PyResult<bool> {
1362-
single_or_tuple_any(
1363-
exc_type,
1364-
|cls: PyClassRef| vm.isinstance(&exc, &cls),
1365-
|o| {
1366-
format!(
1367-
"isinstance() arg 2 must be a type or tuple of types, not {}",
1368-
o.class()
1369-
)
1370-
},
1371-
vm,
1372-
)
1373-
}
1374-
13751357
#[cfg_attr(feature = "flame-it", flame("Frame"))]
13761358
fn execute_compare(
13771359
&mut self,
@@ -1391,7 +1373,9 @@ impl ExecutingFrame<'_> {
13911373
bytecode::ComparisonOperator::IsNot => vm.new_bool(self._is_not(a, b)),
13921374
bytecode::ComparisonOperator::In => vm.new_bool(self._in(vm, a, b)?),
13931375
bytecode::ComparisonOperator::NotIn => vm.new_bool(self._not_in(vm, a, b)?),
1394-
bytecode::ComparisonOperator::ExceptionMatch => vm.new_bool(self.exc_match(vm, a, b)?),
1376+
bytecode::ComparisonOperator::ExceptionMatch => {
1377+
vm.new_bool(builtin_isinstance(a, b, vm)?)
1378+
}
13951379
};
13961380

13971381
self.push_value(value);

vm/src/function.rs

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use result_like::impl_option_like;
77
use smallbox::{smallbox, space::S1, SmallBox};
88

99
use crate::exceptions::PyBaseExceptionRef;
10-
use crate::obj::objtuple::PyTuple;
10+
use crate::obj::objtuple::PyTupleRef;
1111
use crate::obj::objtype::{isinstance, PyClassRef};
1212
use crate::pyobject::{
1313
IntoPyObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol,
@@ -564,43 +564,55 @@ into_py_native_func_tuple!((a, A), (b, B), (c, C), (d, D), (e, E));
564564
/// test that any of the values contained within the tuples satisfies the predicate. Type parameter
565565
/// T specifies the type that is expected, if the input value is not of that type or a tuple of
566566
/// values of that type, then a TypeError is raised.
567-
pub fn single_or_tuple_any<T: PyValue, F: Fn(PyRef<T>) -> PyResult<bool>>(
567+
pub fn single_or_tuple_any<T, F, M>(
568568
obj: PyObjectRef,
569569
predicate: F,
570-
message: fn(&PyObjectRef) -> String,
570+
message: M,
571571
vm: &VirtualMachine,
572-
) -> PyResult<bool> {
572+
) -> PyResult<bool>
573+
where
574+
T: TryFromObject,
575+
F: Fn(&T) -> PyResult<bool>,
576+
M: Fn(&PyObjectRef) -> String,
577+
{
573578
// TODO: figure out some way to have recursive calls without... this
574-
use std::marker::PhantomData;
575-
struct Checker<'vm, T: PyValue, F: Fn(PyRef<T>) -> PyResult<bool>> {
579+
struct Checker<T, F, M>
580+
where
581+
F: Fn(&T) -> PyResult<bool>,
582+
M: Fn(&PyObjectRef) -> String,
583+
{
576584
predicate: F,
577-
message: fn(&PyObjectRef) -> String,
578-
vm: &'vm VirtualMachine,
579-
t: PhantomData<T>,
580-
}
581-
impl<T: PyValue, F: Fn(PyRef<T>) -> PyResult<bool>> Checker<'_, T, F> {
582-
fn check(&self, obj: PyObjectRef) -> PyResult<bool> {
583-
match_class!(match obj {
584-
obj @ T => (self.predicate)(obj),
585-
tuple @ PyTuple => {
585+
message: M,
586+
t: std::marker::PhantomData<T>,
587+
}
588+
impl<T, F, M> Checker<T, F, M>
589+
where
590+
T: TryFromObject,
591+
F: Fn(&T) -> PyResult<bool>,
592+
M: Fn(&PyObjectRef) -> String,
593+
{
594+
fn check(&self, obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
595+
match T::try_from_object(vm, obj.clone()) {
596+
Ok(single) => (self.predicate)(&single),
597+
Err(_) => {
598+
let tuple = PyTupleRef::try_from_object(vm, obj.clone())
599+
.map_err(|_| vm.new_type_error((self.message)(&obj)))?;
586600
for obj in tuple.as_slice().iter() {
587-
if self.check(obj.clone())? {
601+
if self.check(&obj, vm)? {
588602
return Ok(true);
589603
}
590604
}
591605
Ok(false)
592606
}
593-
obj => Err(self.vm.new_type_error((self.message)(&obj))),
594-
})
607+
}
595608
}
596609
}
597610
let checker = Checker {
598611
predicate,
599612
message,
600-
vm,
601-
t: PhantomData,
613+
t: std::marker::PhantomData,
602614
};
603-
checker.check(obj)
615+
checker.check(&obj, vm)
604616
}
605617

606618
#[cfg(test)]

vm/src/obj/objstr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ impl PyString {
530530
let value = &self.value[range];
531531
single_or_tuple_any(
532532
suffix,
533-
|s: PyStringRef| Ok(value.ends_with(&s.value)),
533+
|s: &PyStringRef| Ok(value.ends_with(&s.value)),
534534
|o| {
535535
format!(
536536
"endswith first arg must be str or a tuple of str, not {}",
@@ -557,7 +557,7 @@ impl PyString {
557557
let value = &self.value[range];
558558
single_or_tuple_any(
559559
prefix,
560-
|s: PyStringRef| Ok(value.starts_with(&s.value)),
560+
|s: &PyStringRef| Ok(value.starts_with(&s.value)),
561561
|o| {
562562
format!(
563563
"startswith first arg must be str or a tuple of str, not {}",

0 commit comments

Comments
 (0)