| 444 | |
| 445 | #[pygetset(setter)] |
| 446 | fn set___class__( |
| 447 | instance: PyObjectRef, |
| 448 | value: PyObjectRef, |
| 449 | vm: &VirtualMachine, |
| 450 | ) -> PyResult<()> { |
| 451 | match value.downcast::<PyType>() { |
| 452 | Ok(cls) => { |
| 453 | let current_cls = instance.class(); |
| 454 | let both_module = current_cls.fast_issubclass(vm.ctx.types.module_type) |
| 455 | && cls.fast_issubclass(vm.ctx.types.module_type); |
| 456 | let both_mutable = !current_cls |
| 457 | .slots |
| 458 | .flags |
| 459 | .has_feature(PyTypeFlags::IMMUTABLETYPE) |
| 460 | && !cls.slots.flags.has_feature(PyTypeFlags::IMMUTABLETYPE); |
| 461 | // FIXME(#1979) cls instances might have a payload |
| 462 | if both_mutable || both_module { |
| 463 | let has_dict = |
| 464 | |typ: &Py<PyType>| typ.slots.flags.has_feature(PyTypeFlags::HAS_DICT); |
| 465 | let has_weakref = |
| 466 | |typ: &Py<PyType>| typ.slots.flags.has_feature(PyTypeFlags::HAS_WEAKREF); |
| 467 | // Compare slots tuples |
| 468 | let slots_equal = match ( |
| 469 | current_cls |
| 470 | .heaptype_ext |
| 471 | .as_ref() |
| 472 | .and_then(|e| e.slots.as_ref()), |
| 473 | cls.heaptype_ext.as_ref().and_then(|e| e.slots.as_ref()), |
| 474 | ) { |
| 475 | (Some(a), Some(b)) => { |
| 476 | a.len() == b.len() |
| 477 | && a.iter() |
| 478 | .zip(b.iter()) |
| 479 | .all(|(x, y)| x.as_wtf8() == y.as_wtf8()) |
| 480 | } |
| 481 | (None, None) => true, |
| 482 | _ => false, |
| 483 | }; |
| 484 | if current_cls.slots.basicsize != cls.slots.basicsize |
| 485 | || !slots_equal |
| 486 | || has_dict(current_cls) != has_dict(&cls) |
| 487 | || has_weakref(current_cls) != has_weakref(&cls) |
| 488 | || current_cls.slots.member_count != cls.slots.member_count |
| 489 | { |
| 490 | return Err(vm.new_type_error(format!( |
| 491 | "__class__ assignment: '{}' object layout differs from '{}'", |
| 492 | cls.name(), |
| 493 | current_cls.name() |
| 494 | ))); |
| 495 | } |
| 496 | instance.set_class(cls, vm); |
| 497 | Ok(()) |
| 498 | } else { |
| 499 | Err(vm.new_type_error( |
| 500 | "__class__ assignment only supported for mutable types or ModuleType subclasses", |
| 501 | )) |
| 502 | } |
| 503 | } |