1use super::VirtualMachine;
2use crate::stdlib::_warnings;
3use crate::{
4 Py, PyRef,
5 builtins::{PyInt, PyStr, PyStrInterned, PyStrRef, PyType, PyUtf8Str},
6 object::{AsObject, PyObject, PyObjectRef, PyResult},
7 protocol::{PyNumberBinaryOp, PyNumberSlots, PyNumberTernaryOp, PyNumberUnaryFunc, PySequence},
8 types::PyComparisonOp,
9};
10use num_traits::ToPrimitive;
11
12fn method_is_overloaded(
14 class_a: &Py<PyType>,
15 class_b: &Py<PyType>,
16 rop_name: Option<&'static PyStrInterned>,
17 vm: &VirtualMachine,
18) -> PyResult<bool> {
19 let Some(rop_name) = rop_name else {
20 return Ok(false);
21 };
22 let Some(method_b) = class_b.get_attr(rop_name) else {
23 return Ok(false);
24 };
25 class_a.get_attr(rop_name).map_or(Ok(true), |method_a| {
26 vm.identical_or_equal(&method_a, &method_b).map(|eq| !eq)
27 })
28}
29
30macro_rules! binary_func {
31 ($fn:ident, $op_slot:ident, $op:expr) => {
32 pub fn $fn(&self, a: &PyObject, b: &PyObject) -> PyResult {
33 self.binary_op(a, b, PyNumberBinaryOp::$op_slot, $op)
34 }
35 };
36}
37
38macro_rules! ternary_func {
39 ($fn:ident, $op_slot:ident, $op:expr) => {
40 pub fn $fn(&self, a: &PyObject, b: &PyObject, c: &PyObject) -> PyResult {
41 self.ternary_op(a, b, c, PyNumberTernaryOp::$op_slot, $op)
42 }
43 };
44}
45
46macro_rules! inplace_binary_func {
47 ($fn:ident, $iop_slot:ident, $op_slot:ident, $op:expr) => {
48 pub fn $fn(&self, a: &PyObject, b: &PyObject) -> PyResult {
49 self.binary_iop(
50 a,
51 b,
52 PyNumberBinaryOp::$iop_slot,
53 PyNumberBinaryOp::$op_slot,
54 $op,
55 )
56 }
57 };
58}
59
60macro_rules! inplace_ternary_func {
61 ($fn:ident, $iop_slot:ident, $op_slot:ident, $op:expr) => {
62 pub fn $fn(&self, a: &PyObject, b: &PyObject, c: &PyObject) -> PyResult {
63 self.ternary_iop(
64 a,
65 b,
66 c,
67 PyNumberTernaryOp::$iop_slot,
68 PyNumberTernaryOp::$op_slot,
69 $op,
70 )
71 }
72 };
73}
74
75impl VirtualMachine {
77 #[inline]
78 pub fn bool_eq(&self, a: &PyObject, b: &PyObject) -> PyResult<bool> {
79 a.rich_compare_bool(b, PyComparisonOp::Eq, self)
80 }
81
82 pub fn identical_or_equal(&self, a: &PyObject, b: &PyObject) -> PyResult<bool> {
83 if a.is(b) {
84 Ok(true)
85 } else {
86 self.bool_eq(a, b)
87 }
88 }
89
90 pub fn bool_seq_lt(&self, a: &PyObject, b: &PyObject) -> PyResult<Option<bool>> {
91 let value = if a.rich_compare_bool(b, PyComparisonOp::Lt, self)? {
92 Some(true)
93 } else if !self.bool_eq(a, b)? {
94 Some(false)
95 } else {
96 None
97 };
98 Ok(value)
99 }
100
101 pub fn bool_seq_gt(&self, a: &PyObject, b: &PyObject) -> PyResult<Option<bool>> {
102 let value = if a.rich_compare_bool(b, PyComparisonOp::Gt, self)? {
103 Some(true)
104 } else if !self.bool_eq(a, b)? {
105 Some(false)
106 } else {
107 None
108 };
109 Ok(value)
110 }
111
112 pub fn length_hint_opt(&self, iter: PyObjectRef) -> PyResult<Option<usize>> {
113 if let Some(len) = iter.length_opt(self) {
120 match len {
121 Ok(len) => return Ok(Some(len)),
122 Err(e) => {
123 if !e.fast_isinstance(self.ctx.exceptions.type_error) {
124 return Err(e);
125 }
126 }
127 }
128 }
129 let hint = match self.get_method(iter, identifier!(self, __length_hint__)) {
130 Some(hint) => hint?,
131 None => return Ok(None),
132 };
133 let result = match hint.call((), self) {
134 Ok(res) => {
135 if res.is(&self.ctx.not_implemented) {
136 return Ok(None);
137 }
138 res
139 }
140 Err(e) => {
141 return if e.fast_isinstance(self.ctx.exceptions.type_error) {
142 Ok(None)
143 } else {
144 Err(e)
145 };
146 }
147 };
148 let hint = result
149 .downcast_ref::<PyInt>()
150 .ok_or_else(|| {
151 self.new_type_error(format!(
152 "'{}' object cannot be interpreted as an integer",
153 result.class().name()
154 ))
155 })?
156 .try_to_primitive::<isize>(self)?;
157 if hint.is_negative() {
158 Err(self.new_value_error("__length_hint__() should return >= 0"))
159 } else {
160 Ok(Some(hint as usize))
161 }
162 }
163
164 pub fn check_repeat_or_overflow_error(&self, length: usize, n: isize) -> PyResult<usize> {
167 if n <= 0 {
168 Ok(0)
169 } else {
170 let n = n as usize;
171 if length > crate::stdlib::sys::MAXSIZE as usize / n {
172 Err(self.new_overflow_error("repeated value are too long"))
173 } else {
174 Ok(n)
175 }
176 }
177 }
178
179 pub fn new_zeroed_bytes(&self, len: usize) -> PyResult<Vec<u8>> {
185 if len == 0 {
186 return Ok(Vec::new());
187 }
188 let layout = core::alloc::Layout::array::<u8>(len).map_err(|_| self.no_memory_error())?;
189 let ptr = unsafe { alloc::alloc::alloc_zeroed(layout) };
191 if ptr.is_null() {
192 return Err(self.no_memory_error());
193 }
194 Ok(unsafe { Vec::from_raw_parts(ptr, len, len) })
197 }
198
199 pub fn binary_op1(&self, a: &PyObject, b: &PyObject, op_slot: PyNumberBinaryOp) -> PyResult {
206 let class_a = a.class();
207 let class_b = b.class();
208
209 let slot_a = class_a.slots.as_number.left_binary_op(op_slot);
211 let slot_a_addr = slot_a.map(|x| crate::types::fn_addr(x));
212 let mut slot_b = None;
213 let left_b_addr = if class_a.is(class_b) {
214 slot_a_addr
215 } else {
216 let slot_bb = class_b.slots.as_number.right_binary_op(op_slot);
217 if slot_bb.map(|x| crate::types::fn_addr(x)) != slot_a_addr {
218 slot_b = slot_bb;
219 }
220
221 class_b
222 .slots
223 .as_number
224 .left_binary_op(op_slot)
225 .map(|x| crate::types::fn_addr(x))
226 };
227
228 if let Some(slot_a) = slot_a {
229 if let Some(slot_bb) = slot_b
230 && class_b.fast_issubclass(class_a)
231 && (slot_a_addr != left_b_addr
232 || method_is_overloaded(
233 class_a,
234 class_b,
235 op_slot.right_method_name(self),
236 self,
237 )?)
238 {
239 let ret = slot_bb(a, b, self)?;
240 if !ret.is(&self.ctx.not_implemented) {
241 return Ok(ret);
242 }
243 slot_b = None;
244 }
245 let ret = slot_a(a, b, self)?;
246 if !ret.is(&self.ctx.not_implemented) {
247 return Ok(ret);
248 }
249 }
250
251 if let Some(slot_b) = slot_b {
252 let ret = slot_b(a, b, self)?;
253 if !ret.is(&self.ctx.not_implemented) {
254 return Ok(ret);
255 }
256 }
257
258 Ok(self.ctx.not_implemented())
259 }
260
261 pub fn binary_op(
262 &self,
263 a: &PyObject,
264 b: &PyObject,
265 op_slot: PyNumberBinaryOp,
266 op: &str,
267 ) -> PyResult {
268 let result = self.binary_op1(a, b, op_slot)?;
269 if !result.is(&self.ctx.not_implemented) {
270 return Ok(result);
271 }
272 Err(self.new_unsupported_bin_op_error(a, b, op))
273 }
274
275 pub(crate) fn binary_iop1(
289 &self,
290 a: &PyObject,
291 b: &PyObject,
292 iop_slot: PyNumberBinaryOp,
293 op_slot: PyNumberBinaryOp,
294 ) -> PyResult {
295 if let Some(slot) = a.class().slots().as_number.left_binary_op(iop_slot) {
296 let x = slot(a, b, self)?;
297 if !x.is(&self.ctx.not_implemented) {
298 return Ok(x);
299 }
300 }
301 self.binary_op1(a, b, op_slot)
302 }
303
304 fn binary_iop(
305 &self,
306 a: &PyObject,
307 b: &PyObject,
308 iop_slot: PyNumberBinaryOp,
309 op_slot: PyNumberBinaryOp,
310 op: &str,
311 ) -> PyResult {
312 let result = self.binary_iop1(a, b, iop_slot, op_slot)?;
313 if !result.is(&self.ctx.not_implemented) {
314 return Ok(result);
315 }
316 Err(self.new_unsupported_bin_op_error(a, b, op))
317 }
318
319 fn ternary_op(
320 &self,
321 a: &PyObject,
322 b: &PyObject,
323 c: &PyObject,
324 op_slot: PyNumberTernaryOp,
325 op_str: &str,
326 ) -> PyResult {
327 let class_a = a.class();
328 let class_b = b.class();
329 let class_c = c.class();
330
331 let slot_a = class_a.slots.as_number.left_ternary_op(op_slot);
333 let slot_a_addr = slot_a.map(|x| crate::types::fn_addr(x));
334 let mut slot_b = None;
335 let left_b_addr = if class_a.is(class_b) {
336 slot_a_addr
337 } else {
338 let slot_bb = class_b.slots.as_number.right_ternary_op(op_slot);
339 if slot_bb.map(|x| crate::types::fn_addr(x)) != slot_a_addr {
340 slot_b = slot_bb;
341 }
342
343 class_b
344 .slots
345 .as_number
346 .left_ternary_op(op_slot)
347 .map(|x| crate::types::fn_addr(x))
348 };
349
350 if let Some(slot_a) = slot_a {
351 if let Some(slot_bb) = slot_b
352 && class_b.fast_issubclass(class_a)
353 && (slot_a_addr != left_b_addr
354 || method_is_overloaded(
355 class_a,
356 class_b,
357 op_slot.right_method_name(self),
358 self,
359 )?)
360 {
361 let ret = slot_bb(a, b, c, self)?;
362 if !ret.is(&self.ctx.not_implemented) {
363 return Ok(ret);
364 }
365 slot_b = None;
366 }
367 let ret = slot_a(a, b, c, self)?;
368 if !ret.is(&self.ctx.not_implemented) {
369 return Ok(ret);
370 }
371 }
372
373 if let Some(slot_b) = slot_b {
374 let ret = slot_b(a, b, c, self)?;
375 if !ret.is(&self.ctx.not_implemented) {
376 return Ok(ret);
377 }
378 }
379
380 if let Some(slot_c) = class_c.slots.as_number.left_ternary_op(op_slot)
384 && slot_a.is_none_or(|slot_a| !core::ptr::fn_addr_eq(slot_a, slot_c))
385 && slot_b.is_none_or(|slot_b| !core::ptr::fn_addr_eq(slot_b, slot_c))
386 {
387 let ret = slot_c(a, b, c, self)?;
388 if !ret.is(&self.ctx.not_implemented) {
389 return Ok(ret);
390 }
391 }
392
393 Err(if self.is_none(c) {
394 self.new_type_error(format!(
395 "unsupported operand type(s) for {}: \
396 '{}' and '{}'",
397 op_str,
398 a.class().slot_name(),
399 b.class().slot_name()
400 ))
401 } else {
402 self.new_type_error(format!(
403 "unsupported operand type(s) for {}: \
404 '{}', '{}', '{}'",
405 op_str,
406 a.class().slot_name(),
407 b.class().slot_name(),
408 c.class().slot_name()
409 ))
410 })
411 }
412
413 fn ternary_iop(
414 &self,
415 a: &PyObject,
416 b: &PyObject,
417 c: &PyObject,
418 iop_slot: PyNumberTernaryOp,
419 op_slot: PyNumberTernaryOp,
420 op_str: &str,
421 ) -> PyResult {
422 if let Some(slot) = a.class().slots().as_number.left_ternary_op(iop_slot) {
423 let x = slot(a, b, c, self)?;
424 if !x.is(&self.ctx.not_implemented) {
425 return Ok(x);
426 }
427 }
428 self.ternary_op(a, b, c, op_slot, op_str)
429 }
430
431 binary_func!(_sub, Subtract, "-");
432 binary_func!(_mod, Remainder, "%");
433 binary_func!(_divmod, Divmod, "divmod()");
434 binary_func!(_lshift, Lshift, "<<");
435 binary_func!(_rshift, Rshift, ">>");
436 binary_func!(_and, And, "&");
437 binary_func!(_xor, Xor, "^");
438 binary_func!(_or, Or, "|");
439 binary_func!(_floordiv, FloorDivide, "//");
440 binary_func!(_truediv, TrueDivide, "/");
441 binary_func!(_matmul, MatrixMultiply, "@");
442
443 inplace_binary_func!(_isub, InplaceSubtract, Subtract, "-=");
444 inplace_binary_func!(_imod, InplaceRemainder, Remainder, "%=");
445 inplace_binary_func!(_ilshift, InplaceLshift, Lshift, "<<=");
446 inplace_binary_func!(_irshift, InplaceRshift, Rshift, ">>=");
447 inplace_binary_func!(_iand, InplaceAnd, And, "&=");
448 inplace_binary_func!(_ixor, InplaceXor, Xor, "^=");
449 inplace_binary_func!(_ior, InplaceOr, Or, "|=");
450 inplace_binary_func!(_ifloordiv, InplaceFloorDivide, FloorDivide, "//=");
451 inplace_binary_func!(_itruediv, InplaceTrueDivide, TrueDivide, "/=");
452 inplace_binary_func!(_imatmul, InplaceMatrixMultiply, MatrixMultiply, "@=");
453
454 ternary_func!(_pow, Power, "** or pow()");
455 inplace_ternary_func!(_ipow, InplacePower, Power, "**=");
456
457 pub fn _add(&self, a: &PyObject, b: &PyObject) -> PyResult {
458 let result = self.binary_op1(a, b, PyNumberBinaryOp::Add)?;
459 if !result.is(&self.ctx.not_implemented) {
460 return Ok(result);
461 }
462 let seq = a.sequence_unchecked();
464 if let Some(f) = seq.slots().concat.load() {
465 let result = f(seq, b, self)?;
466 if !result.is(&self.ctx.not_implemented) {
467 return Ok(result);
468 }
469 }
470 Err(self.new_unsupported_bin_op_error(a, b, "+"))
471 }
472
473 pub fn _iadd(&self, a: &PyObject, b: &PyObject) -> PyResult {
474 let result = self.binary_iop1(a, b, PyNumberBinaryOp::InplaceAdd, PyNumberBinaryOp::Add)?;
475 if !result.is(&self.ctx.not_implemented) {
476 return Ok(result);
477 }
478 let seq = a.sequence_unchecked();
480 let slots = seq.slots();
481 if let Some(f) = slots.inplace_concat.load().or_else(|| slots.concat.load()) {
482 let result = f(seq, b, self)?;
483 if !result.is(&self.ctx.not_implemented) {
484 return Ok(result);
485 }
486 }
487 Err(self.new_unsupported_bin_op_error(a, b, "+="))
488 }
489
490 pub fn _mul(&self, a: &PyObject, b: &PyObject) -> PyResult {
491 let result = self.binary_op1(a, b, PyNumberBinaryOp::Multiply)?;
492 if !result.is(&self.ctx.not_implemented) {
493 return Ok(result);
494 }
495 if let Some(f) = a.sequence_unchecked().slots().repeat.load() {
496 return self.sequence_repeat(f, a, b);
497 }
498 if let Some(f) = b.sequence_unchecked().slots().repeat.load() {
499 return self.sequence_repeat(f, b, a);
500 }
501 Err(self.new_unsupported_bin_op_error(a, b, "*"))
502 }
503
504 pub fn _imul(&self, a: &PyObject, b: &PyObject) -> PyResult {
505 let result = self.binary_iop1(
506 a,
507 b,
508 PyNumberBinaryOp::InplaceMultiply,
509 PyNumberBinaryOp::Multiply,
510 )?;
511 if !result.is(&self.ctx.not_implemented) {
512 return Ok(result);
513 }
514 let a_seq = a.sequence_unchecked();
515 let a_slots = a_seq.slots();
516 if let Some(f) = a_slots
517 .inplace_repeat
518 .load()
519 .or_else(|| a_slots.repeat.load())
520 {
521 return self.sequence_repeat(f, a, b);
522 }
523 if !a_slots.has_any()
526 && a.class().heaptype_ext().is_none()
527 && let Some(f) = b.sequence_unchecked().slots().repeat.load()
528 {
529 return self.sequence_repeat(f, b, a);
530 }
531 Err(self.new_unsupported_bin_op_error(a, b, "*="))
532 }
533
534 fn sequence_repeat(
536 &self,
537 repeat: fn(PySequence<'_>, isize, &Self) -> PyResult,
538 seq: &PyObject,
539 n: &PyObject,
540 ) -> PyResult {
541 let index = n.try_index_opt(self).ok_or_else(|| {
542 self.new_type_error(format!(
543 "can't multiply sequence by non-int of type '{}'",
544 n.class().slot_name()
545 ))
546 })??;
547 let count = index.as_bigint().to_isize().ok_or_else(|| {
548 self.new_overflow_error(format!(
549 "cannot fit '{}' into an index-sized integer",
550 n.class().slot_name()
551 ))
552 })?;
553 repeat(seq.sequence_unchecked(), count, self)
554 }
555
556 fn unary_op(
557 &self,
558 a: &PyObject,
559 slot: impl FnOnce(&PyNumberSlots) -> Option<PyNumberUnaryFunc>,
560 op: &str,
561 ) -> PyResult {
562 let f = slot(&a.class().slots.as_number)
563 .ok_or_else(|| self.new_unsupported_unary_error(a, op))?;
564 f(a.number(), self)
565 }
566
567 pub fn _abs(&self, a: &PyObject) -> PyResult<PyObjectRef> {
569 self.unary_op(a, |s| s.absolute.load(), "abs()")
570 }
571
572 pub fn _pos(&self, a: &PyObject) -> PyResult {
574 self.unary_op(a, |s| s.positive.load(), "unary +")
575 }
576
577 pub fn _neg(&self, a: &PyObject) -> PyResult {
579 self.unary_op(a, |s| s.negative.load(), "unary -")
580 }
581
582 pub fn _invert(&self, a: &PyObject) -> PyResult {
583 const STR: &str = "Bitwise inversion '~' on bool is deprecated and will be removed in Python 3.16. \
584 This returns the bitwise inversion of the underlying int object and is usually not what you expect from negating a bool. \
585 Use the 'not' operator for boolean negation or ~int(x) if you really want the bitwise inversion of the underlying int.";
586 if a.fast_isinstance(self.ctx.types.bool_type) {
587 _warnings::warn(
588 self.ctx.exceptions.deprecation_warning,
589 STR.to_owned(),
590 1,
591 self,
592 )?;
593 }
594 self.unary_op(a, |s| s.invert.load(), "unary ~")
595 }
596
597 pub fn format(&self, obj: &PyObject, format_spec: PyStrRef) -> PyResult<PyStrRef> {
599 if format_spec.is_empty() {
600 let obj = match obj.to_owned().downcast_exact::<PyStr>(self) {
601 Ok(s) => return Ok(s.into_pyref()),
602 Err(obj) => obj,
603 };
604 if obj.class().is(self.ctx.types.int_type) {
605 return obj.str(self);
606 }
607 }
608 let bound_format = self
609 .get_special_method(obj, identifier!(self, __format__))?
610 .ok_or_else(|| {
611 self.new_type_error(format!(
612 "Type {} doesn't define __format__",
613 obj.class().name()
614 ))
615 })?;
616 let formatted = bound_format.invoke((format_spec,), self)?;
617 formatted.downcast().map_err(|result| {
618 self.new_type_error(format!(
619 "__format__ must return a str, not {}",
620 result.class().name()
621 ))
622 })
623 }
624 pub fn format_utf8(&self, obj: &PyObject, format_spec: PyStrRef) -> PyResult<PyRef<PyUtf8Str>> {
625 self.format(obj, format_spec)?.try_into_utf8(self)
626 }
627
628 pub fn _contains(&self, haystack: &PyObject, needle: &PyObject) -> PyResult<bool> {
629 let seq = haystack.sequence_unchecked();
630 seq.contains(needle, self)
631 }
632}