(&self, cls: &Self, vm: &VirtualMachine)
| 449 | } |
| 450 | |
| 451 | fn abstract_issubclass(&self, cls: &Self, vm: &VirtualMachine) -> PyResult<bool> { |
| 452 | // Store the current derived class to check |
| 453 | let mut bases: PyTupleRef; |
| 454 | let mut derived = self; |
| 455 | |
| 456 | // First loop: handle single inheritance without recursion |
| 457 | let bases = loop { |
| 458 | if derived.is(cls) { |
| 459 | return Ok(true); |
| 460 | } |
| 461 | |
| 462 | let Some(derived_bases) = derived.abstract_get_bases(vm)? else { |
| 463 | return Ok(false); |
| 464 | }; |
| 465 | |
| 466 | let n = derived_bases.len(); |
| 467 | match n { |
| 468 | 0 => return Ok(false), |
| 469 | 1 => { |
| 470 | // Avoid recursion in the single inheritance case |
| 471 | // Get the next derived class and continue the loop |
| 472 | bases = derived_bases; |
| 473 | derived = &bases.as_slice()[0]; |
| 474 | continue; |
| 475 | } |
| 476 | _ => { |
| 477 | // Multiple inheritance - handle recursively |
| 478 | break derived_bases; |
| 479 | } |
| 480 | } |
| 481 | }; |
| 482 | |
| 483 | let n = bases.len(); |
| 484 | // At this point we know n >= 2 |
| 485 | debug_assert!(n >= 2); |
| 486 | |
| 487 | for i in 0..n { |
| 488 | let result = vm.with_recursion("in __issubclass__", || { |
| 489 | bases.as_slice()[i].abstract_issubclass(cls, vm) |
| 490 | })?; |
| 491 | if result { |
| 492 | return Ok(true); |
| 493 | } |
| 494 | } |
| 495 | |
| 496 | Ok(false) |
| 497 | } |
| 498 | |
| 499 | fn recursive_issubclass(&self, cls: &Self, vm: &VirtualMachine) -> PyResult<bool> { |
| 500 | // Fast path for both being types (matches CPython's PyType_Check) |
no test coverage detected