(zelf: &Py<Self>, bases: Vec<PyTypeRef>, vm: &VirtualMachine)
| 1311 | } |
| 1312 | #[pygetset(setter, name = "__bases__")] |
| 1313 | fn set_bases(zelf: &Py<Self>, bases: Vec<PyTypeRef>, vm: &VirtualMachine) -> PyResult<()> { |
| 1314 | // TODO: Assigning to __bases__ is only used in typing.NamedTupleMeta.__new__ |
| 1315 | // Rather than correctly re-initializing the class, we are skipping a few steps for now |
| 1316 | if zelf.slots.flags.has_feature(PyTypeFlags::IMMUTABLETYPE) { |
| 1317 | return Err(vm.new_type_error(format!( |
| 1318 | "cannot set '__bases__' attribute of immutable type '{}'", |
| 1319 | zelf.name() |
| 1320 | ))); |
| 1321 | } |
| 1322 | if bases.is_empty() { |
| 1323 | return Err(vm.new_type_error(format!( |
| 1324 | "can only assign non-empty tuple to %s.__bases__, not {}", |
| 1325 | zelf.name() |
| 1326 | ))); |
| 1327 | } |
| 1328 | |
| 1329 | // TODO: check for mro cycles |
| 1330 | |
| 1331 | // TODO: Remove this class from all subclass lists |
| 1332 | // for base in self.bases.read().iter() { |
| 1333 | // let subclasses = base.subclasses.write(); |
| 1334 | // // TODO: how to uniquely identify the subclasses to remove? |
| 1335 | // } |
| 1336 | |
| 1337 | *zelf.bases.write() = bases; |
| 1338 | // Recursively update the mros of this class and all subclasses |
| 1339 | fn update_mro_recursively(cls: &PyType, vm: &VirtualMachine) -> PyResult<()> { |
| 1340 | let mut mro = |
| 1341 | PyType::resolve_mro(&cls.bases.read()).map_err(|msg| vm.new_type_error(msg))?; |
| 1342 | // Preserve self (mro[0]) when updating MRO |
| 1343 | mro.insert(0, cls.mro.read()[0].to_owned()); |
| 1344 | *cls.mro.write() = mro; |
| 1345 | for subclass in cls.subclasses.write().iter() { |
| 1346 | let subclass = subclass.upgrade().unwrap(); |
| 1347 | let subclass: &Py<PyType> = subclass.downcast_ref().unwrap(); |
| 1348 | update_mro_recursively(subclass, vm)?; |
| 1349 | } |
| 1350 | Ok(()) |
| 1351 | } |
| 1352 | update_mro_recursively(zelf, vm)?; |
| 1353 | |
| 1354 | // Invalidate inline caches |
| 1355 | zelf.modified(); |
| 1356 | |
| 1357 | // TODO: do any old slots need to be cleaned up first? |
| 1358 | zelf.init_slots(&vm.ctx); |
| 1359 | |
| 1360 | // Register this type as a subclass of its new bases |
| 1361 | let weakref_type = super::PyWeak::static_type(); |
| 1362 | for base in zelf.bases.read().iter() { |
| 1363 | base.subclasses.write().push( |
| 1364 | zelf.as_object() |
| 1365 | .downgrade_with_weakref_typ_opt(None, weakref_type.to_owned()) |
| 1366 | .unwrap(), |
| 1367 | ); |
| 1368 | } |
| 1369 | |
| 1370 | Ok(()) |
nothing calls this directly
no test coverage detected