mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Use i-methods for in-place operations
This commit is contained in:
@@ -71,6 +71,7 @@ pub enum Instruction {
|
||||
},
|
||||
BinaryOperation {
|
||||
op: BinaryOperator,
|
||||
inplace: bool,
|
||||
},
|
||||
LoadAttr {
|
||||
name: String,
|
||||
|
||||
@@ -608,7 +608,7 @@ impl Compiler {
|
||||
self.compile_expression(value)?;
|
||||
|
||||
// Perform operation:
|
||||
self.compile_op(op);
|
||||
self.compile_op(op, true);
|
||||
self.compile_store(target)?;
|
||||
}
|
||||
ast::Statement::Delete { targets } => {
|
||||
@@ -757,7 +757,7 @@ impl Compiler {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_op(&mut self, op: &ast::Operator) {
|
||||
fn compile_op(&mut self, op: &ast::Operator, inplace: bool) {
|
||||
let i = match op {
|
||||
ast::Operator::Add => bytecode::BinaryOperator::Add,
|
||||
ast::Operator::Sub => bytecode::BinaryOperator::Subtract,
|
||||
@@ -773,7 +773,7 @@ impl Compiler {
|
||||
ast::Operator::BitXor => bytecode::BinaryOperator::Xor,
|
||||
ast::Operator::BitAnd => bytecode::BinaryOperator::And,
|
||||
};
|
||||
self.emit(Instruction::BinaryOperation { op: i });
|
||||
self.emit(Instruction::BinaryOperation { op: i, inplace });
|
||||
}
|
||||
|
||||
fn compile_test(
|
||||
@@ -852,13 +852,14 @@ impl Compiler {
|
||||
self.compile_expression(b)?;
|
||||
|
||||
// Perform operation:
|
||||
self.compile_op(op);
|
||||
self.compile_op(op, false);
|
||||
}
|
||||
ast::Expression::Subscript { a, b } => {
|
||||
self.compile_expression(a)?;
|
||||
self.compile_expression(b)?;
|
||||
self.emit(Instruction::BinaryOperation {
|
||||
op: bytecode::BinaryOperator::Subscript,
|
||||
inplace: false,
|
||||
});
|
||||
}
|
||||
ast::Expression::Unop { op, a } => {
|
||||
|
||||
@@ -316,7 +316,9 @@ impl Frame {
|
||||
vm.call_method(&dict_obj, "__setitem__", vec![key, value])?;
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::BinaryOperation { ref op } => self.execute_binop(vm, op),
|
||||
bytecode::Instruction::BinaryOperation { ref op, inplace } => {
|
||||
self.execute_binop(vm, op, *inplace)
|
||||
}
|
||||
bytecode::Instruction::LoadAttr { ref name } => self.load_attr(vm, name),
|
||||
bytecode::Instruction::StoreAttr { ref name } => self.store_attr(vm, name),
|
||||
bytecode::Instruction::DeleteAttr { ref name } => self.delete_attr(vm, name),
|
||||
@@ -893,23 +895,39 @@ impl Frame {
|
||||
&mut self,
|
||||
vm: &mut VirtualMachine,
|
||||
op: &bytecode::BinaryOperator,
|
||||
inplace: bool,
|
||||
) -> FrameResult {
|
||||
let b_ref = self.pop_value();
|
||||
let a_ref = self.pop_value();
|
||||
let value = match *op {
|
||||
bytecode::BinaryOperator::Subtract if inplace => vm._isub(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Subtract => vm._sub(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Add if inplace => vm._iadd(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Add => vm._add(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Multiply if inplace => vm._imul(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Multiply => vm._mul(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::MatrixMultiply if inplace => vm._imatmul(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::MatrixMultiply => vm._matmul(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Power if inplace => vm._ipow(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Power => vm._pow(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Divide if inplace => vm._itruediv(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Divide => vm._truediv(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::FloorDivide if inplace => vm._ifloordiv(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::FloorDivide => vm._floordiv(a_ref, b_ref),
|
||||
// TODO: Subscript should probably have its own op
|
||||
bytecode::BinaryOperator::Subscript if inplace => unreachable!(),
|
||||
bytecode::BinaryOperator::Subscript => self.subscript(vm, a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Modulo if inplace => vm._imod(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Modulo => vm._mod(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Lshift if inplace => vm._ilshift(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Lshift => vm._lshift(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Rshift if inplace => vm._irshift(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Rshift => vm._rshift(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Xor if inplace => vm._ixor(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Xor => vm._xor(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Or if inplace => vm._ior(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Or => vm._or(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::And if inplace => vm._iand(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::And => vm._and(a_ref, b_ref),
|
||||
}?;
|
||||
|
||||
|
||||
239
vm/src/vm.rs
239
vm/src/vm.rs
@@ -499,171 +499,276 @@ impl VirtualMachine {
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls default method, reverse method or exception
|
||||
/// Calls a method on `obj` passing `arg`, if the method exists.
|
||||
///
|
||||
/// * `a` - First argument.
|
||||
/// * `b` - Second argument.
|
||||
/// * `d` - Default method to try and call (such as `__and__`).
|
||||
/// * `r` - Reverse method to try and call (such as `__rand__`), in case first one fails.
|
||||
/// * `op` - Operator for the exception text, for example `&`.
|
||||
///
|
||||
/// Given the above example, it will
|
||||
/// 1. Try to call `__and__` with `a` and `b`
|
||||
/// 2. If above fails try to call `__rand__` with `a` and `b`
|
||||
/// 3. If above in not implemented, call unsupported(a, b) for result.
|
||||
///
|
||||
pub fn call_or_unsupported(
|
||||
/// Otherwise, or if the result is the special `NotImplemented` built-in constant,
|
||||
/// calls `unsupported` to determine fallback value.
|
||||
pub fn call_or_unsupported<F>(
|
||||
&mut self,
|
||||
a: PyObjectRef,
|
||||
b: PyObjectRef,
|
||||
d: &str,
|
||||
r: &str,
|
||||
obj: PyObjectRef,
|
||||
arg: PyObjectRef,
|
||||
method: &str,
|
||||
unsupported: F,
|
||||
) -> PyResult
|
||||
where
|
||||
F: Fn(&mut VirtualMachine, PyObjectRef, PyObjectRef) -> PyResult,
|
||||
{
|
||||
if let Ok(method) = self.get_method(obj.clone(), method) {
|
||||
let result = self.invoke(
|
||||
method,
|
||||
PyFuncArgs {
|
||||
args: vec![arg.clone()],
|
||||
kwargs: vec![],
|
||||
},
|
||||
)?;
|
||||
if !result.is(&self.ctx.not_implemented()) {
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
|
||||
unsupported(self, obj, arg)
|
||||
}
|
||||
|
||||
/// Calls a method, falling back to its reflection with the operands
|
||||
/// reversed, and then to the value provided by `unsupported`.
|
||||
///
|
||||
/// For example: the following:
|
||||
///
|
||||
/// `call_or_reflection(lhs, rhs, "__and__", "__rand__", unsupported)`
|
||||
///
|
||||
/// 1. Calls `__and__` with `lhs` and `rhs`.
|
||||
/// 2. If above is not implemented, calls `__rand__` with `rhs` and `lhs`.
|
||||
/// 3. If above is not implemented, invokes `unsupported` for the result.
|
||||
pub fn call_or_reflection(
|
||||
&mut self,
|
||||
lhs: PyObjectRef,
|
||||
rhs: PyObjectRef,
|
||||
default: &str,
|
||||
reflection: &str,
|
||||
unsupported: fn(&mut VirtualMachine, PyObjectRef, PyObjectRef) -> PyResult,
|
||||
) -> PyResult {
|
||||
// Try to call the first method
|
||||
if let Ok(method) = self.get_method(a.clone(), d) {
|
||||
let result = self.invoke(
|
||||
method,
|
||||
PyFuncArgs {
|
||||
args: vec![b.clone()],
|
||||
kwargs: vec![],
|
||||
},
|
||||
)?;
|
||||
|
||||
if !result.is(&self.ctx.not_implemented()) {
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Try to call reverse method
|
||||
if let Ok(method) = self.get_method(b.clone(), r) {
|
||||
let result = self.invoke(
|
||||
method,
|
||||
PyFuncArgs {
|
||||
args: vec![a.clone()],
|
||||
kwargs: vec![],
|
||||
},
|
||||
)?;
|
||||
|
||||
if !result.is(&self.ctx.not_implemented()) {
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
|
||||
unsupported(self, a, b)
|
||||
// Try to call the default method
|
||||
self.call_or_unsupported(lhs, rhs, default, move |vm, lhs, rhs| {
|
||||
// Try to call the reflection method
|
||||
vm.call_or_unsupported(rhs, lhs, reflection, unsupported)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _sub(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__sub__", "__rsub__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__sub__", "__rsub__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "-"))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _isub(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__isub__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__sub__", "__rsub__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "-="))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _add(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__add__", "__radd__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__add__", "__radd__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "+"))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _iadd(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__iadd__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__add__", "__radd__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "+="))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _mul(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__mul__", "__rmul__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__mul__", "__rmul__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "*"))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _imul(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__imul__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__mul__", "__rmul__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "*="))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _matmul(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__matmul__", "__rmatmul__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__matmul__", "__rmatmul__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "@"))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _imatmul(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__imatmul__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__matmul__", "__rmatmul__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "@="))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _truediv(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__truediv__", "__rtruediv__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__truediv__", "__rtruediv__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "/"))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _itruediv(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__itruediv__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__truediv__", "__rtruediv__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "/="))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _floordiv(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__floordiv__", "__rfloordiv__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__floordiv__", "__rfloordiv__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "//"))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _ifloordiv(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__ifloordiv__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__floordiv__", "__rfloordiv__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "//="))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _pow(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__pow__", "__rpow__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__pow__", "__rpow__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "**"))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _ipow(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__ipow__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__pow__", "__rpow__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "**="))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _mod(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__mod__", "__rmod__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__mod__", "__rmod__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "%"))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _imod(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__imod__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__mod__", "__rmod__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "%="))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _lshift(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__lshift__", "__rlshift__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__lshift__", "__rlshift__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "<<"))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _ilshift(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__ilshift__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__lshift__", "__rlshift__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "<<="))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _rshift(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__rshift__", "__rrshift__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__rshift__", "__rrshift__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, ">>"))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _irshift(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__irshift__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__rshift__", "__rrshift__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, ">>="))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _xor(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__xor__", "__rxor__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__xor__", "__rxor__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "^"))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _ixor(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__ixor__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__xor__", "__rxor__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "^="))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _or(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__or__", "__ror__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__or__", "__ror__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "|"))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _ior(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__ior__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__or__", "__ror__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "|="))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _and(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__and__", "__rand__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__and__", "__rand__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "&"))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _iand(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__iand__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__and__", "__rand__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "&="))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _eq(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__eq__", "__eq__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__eq__", "__eq__", |vm, a, b| {
|
||||
Ok(vm.new_bool(a.is(&b)))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _ne(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__ne__", "__ne__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__ne__", "__ne__", |vm, a, b| {
|
||||
let eq = vm._eq(a, b)?;
|
||||
objbool::not(vm, &eq)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _lt(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__lt__", "__gt__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__lt__", "__gt__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "<"))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _le(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__le__", "__ge__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__le__", "__ge__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, "<="))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _gt(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__gt__", "__lt__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__gt__", "__lt__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, ">"))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _ge(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__ge__", "__le__", |vm, a, b| {
|
||||
self.call_or_reflection(a, b, "__ge__", "__le__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_operand_error(a, b, ">="))
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user