forked from Rust-related/RustPython
single_or_tuple_any uses TryFromObject instead of PyValue
This commit is contained in:
@@ -363,10 +363,14 @@ fn builtin_input(prompt: OptionalArg<PyStringRef>, vm: &VirtualMachine) -> PyRes
|
||||
}
|
||||
}
|
||||
|
||||
fn builtin_isinstance(obj: PyObjectRef, typ: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
|
||||
pub fn builtin_isinstance(
|
||||
obj: PyObjectRef,
|
||||
typ: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<bool> {
|
||||
single_or_tuple_any(
|
||||
typ,
|
||||
|cls: PyClassRef| vm.isinstance(&obj, &cls),
|
||||
|cls: &PyClassRef| vm.isinstance(&obj, cls),
|
||||
|o| {
|
||||
format!(
|
||||
"isinstance() arg 2 must be a type or tuple of types, not {}",
|
||||
@@ -384,7 +388,7 @@ fn builtin_issubclass(
|
||||
) -> PyResult<bool> {
|
||||
single_or_tuple_any(
|
||||
typ,
|
||||
|cls: PyClassRef| vm.issubclass(&subclass, &cls),
|
||||
|cls: &PyClassRef| vm.issubclass(&subclass, cls),
|
||||
|o| {
|
||||
format!(
|
||||
"issubclass() arg 2 must be a class or tuple of classes, not {}",
|
||||
|
||||
@@ -5,9 +5,10 @@ use std::sync::Mutex;
|
||||
use indexmap::IndexMap;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::builtins::builtin_isinstance;
|
||||
use crate::bytecode;
|
||||
use crate::exceptions::{self, ExceptionCtor, PyBaseExceptionRef};
|
||||
use crate::function::{single_or_tuple_any, PyFuncArgs};
|
||||
use crate::function::PyFuncArgs;
|
||||
use crate::obj::objasyncgenerator::PyAsyncGenWrappedValue;
|
||||
use crate::obj::objbool;
|
||||
use crate::obj::objcode::PyCodeRef;
|
||||
@@ -1353,25 +1354,6 @@ impl ExecutingFrame<'_> {
|
||||
!a.is(&b)
|
||||
}
|
||||
|
||||
fn exc_match(
|
||||
&self,
|
||||
vm: &VirtualMachine,
|
||||
exc: PyObjectRef,
|
||||
exc_type: PyObjectRef,
|
||||
) -> PyResult<bool> {
|
||||
single_or_tuple_any(
|
||||
exc_type,
|
||||
|cls: PyClassRef| vm.isinstance(&exc, &cls),
|
||||
|o| {
|
||||
format!(
|
||||
"isinstance() arg 2 must be a type or tuple of types, not {}",
|
||||
o.class()
|
||||
)
|
||||
},
|
||||
vm,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "flame-it", flame("Frame"))]
|
||||
fn execute_compare(
|
||||
&mut self,
|
||||
@@ -1391,7 +1373,9 @@ impl ExecutingFrame<'_> {
|
||||
bytecode::ComparisonOperator::IsNot => vm.new_bool(self._is_not(a, b)),
|
||||
bytecode::ComparisonOperator::In => vm.new_bool(self._in(vm, a, b)?),
|
||||
bytecode::ComparisonOperator::NotIn => vm.new_bool(self._not_in(vm, a, b)?),
|
||||
bytecode::ComparisonOperator::ExceptionMatch => vm.new_bool(self.exc_match(vm, a, b)?),
|
||||
bytecode::ComparisonOperator::ExceptionMatch => {
|
||||
vm.new_bool(builtin_isinstance(a, b, vm)?)
|
||||
}
|
||||
};
|
||||
|
||||
self.push_value(value);
|
||||
|
||||
@@ -7,7 +7,7 @@ use result_like::impl_option_like;
|
||||
use smallbox::{smallbox, space::S1, SmallBox};
|
||||
|
||||
use crate::exceptions::PyBaseExceptionRef;
|
||||
use crate::obj::objtuple::PyTuple;
|
||||
use crate::obj::objtuple::PyTupleRef;
|
||||
use crate::obj::objtype::{isinstance, PyClassRef};
|
||||
use crate::pyobject::{
|
||||
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));
|
||||
/// test that any of the values contained within the tuples satisfies the predicate. Type parameter
|
||||
/// T specifies the type that is expected, if the input value is not of that type or a tuple of
|
||||
/// values of that type, then a TypeError is raised.
|
||||
pub fn single_or_tuple_any<T: PyValue, F: Fn(PyRef<T>) -> PyResult<bool>>(
|
||||
pub fn single_or_tuple_any<T, F, M>(
|
||||
obj: PyObjectRef,
|
||||
predicate: F,
|
||||
message: fn(&PyObjectRef) -> String,
|
||||
message: M,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<bool> {
|
||||
) -> PyResult<bool>
|
||||
where
|
||||
T: TryFromObject,
|
||||
F: Fn(&T) -> PyResult<bool>,
|
||||
M: Fn(&PyObjectRef) -> String,
|
||||
{
|
||||
// TODO: figure out some way to have recursive calls without... this
|
||||
use std::marker::PhantomData;
|
||||
struct Checker<'vm, T: PyValue, F: Fn(PyRef<T>) -> PyResult<bool>> {
|
||||
struct Checker<T, F, M>
|
||||
where
|
||||
F: Fn(&T) -> PyResult<bool>,
|
||||
M: Fn(&PyObjectRef) -> String,
|
||||
{
|
||||
predicate: F,
|
||||
message: fn(&PyObjectRef) -> String,
|
||||
vm: &'vm VirtualMachine,
|
||||
t: PhantomData<T>,
|
||||
message: M,
|
||||
t: std::marker::PhantomData<T>,
|
||||
}
|
||||
impl<T: PyValue, F: Fn(PyRef<T>) -> PyResult<bool>> Checker<'_, T, F> {
|
||||
fn check(&self, obj: PyObjectRef) -> PyResult<bool> {
|
||||
match_class!(match obj {
|
||||
obj @ T => (self.predicate)(obj),
|
||||
tuple @ PyTuple => {
|
||||
impl<T, F, M> Checker<T, F, M>
|
||||
where
|
||||
T: TryFromObject,
|
||||
F: Fn(&T) -> PyResult<bool>,
|
||||
M: Fn(&PyObjectRef) -> String,
|
||||
{
|
||||
fn check(&self, obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
|
||||
match T::try_from_object(vm, obj.clone()) {
|
||||
Ok(single) => (self.predicate)(&single),
|
||||
Err(_) => {
|
||||
let tuple = PyTupleRef::try_from_object(vm, obj.clone())
|
||||
.map_err(|_| vm.new_type_error((self.message)(&obj)))?;
|
||||
for obj in tuple.as_slice().iter() {
|
||||
if self.check(obj.clone())? {
|
||||
if self.check(&obj, vm)? {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
obj => Err(self.vm.new_type_error((self.message)(&obj))),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
let checker = Checker {
|
||||
predicate,
|
||||
message,
|
||||
vm,
|
||||
t: PhantomData,
|
||||
t: std::marker::PhantomData,
|
||||
};
|
||||
checker.check(obj)
|
||||
checker.check(&obj, vm)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -530,7 +530,7 @@ impl PyString {
|
||||
let value = &self.value[range];
|
||||
single_or_tuple_any(
|
||||
suffix,
|
||||
|s: PyStringRef| Ok(value.ends_with(&s.value)),
|
||||
|s: &PyStringRef| Ok(value.ends_with(&s.value)),
|
||||
|o| {
|
||||
format!(
|
||||
"endswith first arg must be str or a tuple of str, not {}",
|
||||
@@ -557,7 +557,7 @@ impl PyString {
|
||||
let value = &self.value[range];
|
||||
single_or_tuple_any(
|
||||
prefix,
|
||||
|s: PyStringRef| Ok(value.starts_with(&s.value)),
|
||||
|s: &PyStringRef| Ok(value.starts_with(&s.value)),
|
||||
|o| {
|
||||
format!(
|
||||
"startswith first arg must be str or a tuple of str, not {}",
|
||||
|
||||
Reference in New Issue
Block a user