@@ -50,7 +50,8 @@ unsafe impl crate::object::Traverse for PyType {
5050 fn traverse ( & self , tracer_fn : & mut crate :: object:: TraverseFn < ' _ > ) {
5151 self . base . traverse ( tracer_fn) ;
5252 self . bases . traverse ( tracer_fn) ;
53- self . mro . traverse ( tracer_fn) ;
53+ // mro contains self as mro[0], so skip traversing to avoid circular reference
54+ // self.mro.traverse(tracer_fn);
5455 self . subclasses . traverse ( tracer_fn) ;
5556 self . attributes
5657 . read_recursive ( )
@@ -341,6 +342,7 @@ impl PyType {
341342 metaclass,
342343 None ,
343344 ) ;
345+ new_type. mro . write ( ) . insert ( 0 , new_type. clone ( ) ) ;
344346
345347 new_type. init_slots ( ctx) ;
346348
@@ -393,6 +395,7 @@ impl PyType {
393395 metaclass,
394396 None ,
395397 ) ;
398+ new_type. mro . write ( ) . insert ( 0 , new_type. clone ( ) ) ;
396399
397400 // Note: inherit_slots is called in PyClassImpl::init_class after
398401 // slots are fully initialized by make_slots()
@@ -413,9 +416,8 @@ impl PyType {
413416 }
414417
415418 pub ( crate ) fn init_slots ( & self , ctx : & Context ) {
416- // Inherit slots from MRO
417- // Note: self.mro does NOT include self, so we iterate all elements
418- let mro: Vec < _ > = self . mro . read ( ) . iter ( ) . cloned ( ) . collect ( ) ;
419+ // Inherit slots from MRO (mro[0] is self, so skip it)
420+ let mro: Vec < _ > = self . mro . read ( ) [ 1 ..] . to_vec ( ) ;
419421 for base in mro. iter ( ) {
420422 self . inherit_slots ( base) ;
421423 }
@@ -424,7 +426,8 @@ impl PyType {
424426 #[ allow( clippy:: mutable_key_type) ]
425427 let mut slot_name_set = std:: collections:: HashSet :: new ( ) ;
426428
427- for cls in self . mro . read ( ) . iter ( ) {
429+ // mro[0] is self, so skip it; self.attributes is checked separately below
430+ for cls in self . mro . read ( ) [ 1 ..] . iter ( ) {
428431 for & name in cls. attributes . read ( ) . keys ( ) {
429432 if name. as_bytes ( ) . starts_with ( b"__" ) && name. as_bytes ( ) . ends_with ( b"__" ) {
430433 slot_name_set. insert ( name) ;
@@ -503,18 +506,12 @@ impl PyType {
503506 /// Equivalent to CPython's find_name_in_mro
504507 /// Look in tp_dict of types in MRO - bypasses descriptors and other attribute access machinery
505508 fn find_name_in_mro ( & self , name : & ' static PyStrInterned ) -> Option < PyObjectRef > {
506- // First check in our own dict
507- if let Some ( value) = self . attributes . read ( ) . get ( name) {
508- return Some ( value. clone ( ) ) ;
509- }
510-
511- // Then check in MRO
512- for base in self . mro . read ( ) . iter ( ) {
513- if let Some ( value) = base. attributes . read ( ) . get ( name) {
509+ // mro[0] is self, so we just iterate through the entire MRO
510+ for cls in self . mro . read ( ) . iter ( ) {
511+ if let Some ( value) = cls. attributes . read ( ) . get ( name) {
514512 return Some ( value. clone ( ) ) ;
515513 }
516514 }
517-
518515 None
519516 }
520517
@@ -530,18 +527,15 @@ impl PyType {
530527 }
531528
532529 pub fn get_super_attr ( & self , attr_name : & ' static PyStrInterned ) -> Option < PyObjectRef > {
533- self . mro
534- . read ( )
530+ self . mro . read ( ) [ 1 ..]
535531 . iter ( )
536532 . find_map ( |class| class. attributes . read ( ) . get ( attr_name) . cloned ( ) )
537533 }
538534
539535 // This is the internal has_attr implementation for fast lookup on a class.
540536 pub fn has_attr ( & self , attr_name : & ' static PyStrInterned ) -> bool {
541537 self . attributes . read ( ) . contains_key ( attr_name)
542- || self
543- . mro
544- . read ( )
538+ || self . mro . read ( ) [ 1 ..]
545539 . iter ( )
546540 . any ( |c| c. attributes . read ( ) . contains_key ( attr_name) )
547541 }
@@ -550,10 +544,8 @@ impl PyType {
550544 // Gather all members here:
551545 let mut attributes = PyAttributes :: default ( ) ;
552546
553- for bc in core:: iter:: once ( self )
554- . chain ( self . mro . read ( ) . iter ( ) . map ( |cls| -> & Self { cls } ) )
555- . rev ( )
556- {
547+ // mro[0] is self, so we iterate through the entire MRO in reverse
548+ for bc in self . mro . read ( ) . iter ( ) . map ( |cls| -> & Self { cls } ) . rev ( ) {
557549 for ( name, value) in bc. attributes . read ( ) . iter ( ) {
558550 attributes. insert ( name. to_owned ( ) , value. clone ( ) ) ;
559551 }
@@ -661,22 +653,21 @@ impl Py<PyType> {
661653 /// so only use this if `cls` is known to have not overridden the base __subclasscheck__ magic
662654 /// method.
663655 pub fn fast_issubclass ( & self , cls : & impl Borrow < PyObject > ) -> bool {
664- self . as_object ( ) . is ( cls. borrow ( ) ) || self . mro . read ( ) . iter ( ) . any ( |c| c. is ( cls. borrow ( ) ) )
656+ self . as_object ( ) . is ( cls. borrow ( ) ) || self . mro . read ( ) [ 1 .. ] . iter ( ) . any ( |c| c. is ( cls. borrow ( ) ) )
665657 }
666658
667659 pub fn mro_map_collect < F , R > ( & self , f : F ) -> Vec < R >
668660 where
669661 F : Fn ( & Self ) -> R ,
670662 {
671- core:: iter:: once ( self )
672- . chain ( self . mro . read ( ) . iter ( ) . map ( |x| x. deref ( ) ) )
673- . map ( f)
674- . collect ( )
663+ self . mro . read ( ) . iter ( ) . map ( |x| x. deref ( ) ) . map ( f) . collect ( )
675664 }
676665
677666 pub fn mro_collect ( & self ) -> Vec < PyRef < PyType > > {
678- core:: iter:: once ( self )
679- . chain ( self . mro . read ( ) . iter ( ) . map ( |x| x. deref ( ) ) )
667+ self . mro
668+ . read ( )
669+ . iter ( )
670+ . map ( |x| x. deref ( ) )
680671 . map ( |x| x. to_owned ( ) )
681672 . collect ( )
682673 }
@@ -745,8 +736,11 @@ impl PyType {
745736 * zelf. bases . write ( ) = bases;
746737 // Recursively update the mros of this class and all subclasses
747738 fn update_mro_recursively ( cls : & PyType , vm : & VirtualMachine ) -> PyResult < ( ) > {
748- * cls . mro . write ( ) =
739+ let mut mro =
749740 PyType :: resolve_mro ( & cls. bases . read ( ) ) . map_err ( |msg| vm. new_type_error ( msg) ) ?;
741+ // Preserve self (mro[0]) when updating MRO
742+ mro. insert ( 0 , cls. mro . read ( ) [ 0 ] . to_owned ( ) ) ;
743+ * cls. mro . write ( ) = mro;
750744 for subclass in cls. subclasses . write ( ) . iter ( ) {
751745 let subclass = subclass. upgrade ( ) . unwrap ( ) ;
752746 let subclass: & Py < PyType > = subclass. downcast_ref ( ) . unwrap ( ) ;
0 commit comments