@@ -20,7 +20,7 @@ mod decl {
20
20
use crate :: builtins:: pybool:: IntoPyBool ;
21
21
use crate :: builtins:: pystr:: { PyStr , PyStrRef } ;
22
22
use crate :: builtins:: pytype:: PyTypeRef ;
23
- use crate :: builtins:: { PyByteArray , PyBytes } ;
23
+ use crate :: builtins:: { PyByteArray , PyBytes , PyTupleRef } ;
24
24
use crate :: byteslike:: ArgBytesLike ;
25
25
use crate :: common:: { hash:: PyHash , str:: to_ascii} ;
26
26
#[ cfg( feature = "rustpython-compiler" ) ]
@@ -832,7 +832,7 @@ mod decl {
832
832
pub fn __build_class__ (
833
833
function : PyFunctionRef ,
834
834
qualified_name : PyStrRef ,
835
- bases : Args < PyTypeRef > ,
835
+ bases : Args ,
836
836
mut kwargs : KwArgs ,
837
837
vm : & VirtualMachine ,
838
838
) -> PyResult {
@@ -845,7 +845,41 @@ mod decl {
845
845
vm. ctx . types . type_type . clone ( )
846
846
} ;
847
847
848
- for base in bases. clone ( ) {
848
+ let mut new_bases: Option < Vec < PyObjectRef > > = None ;
849
+
850
+ let bases = PyTupleRef :: with_elements ( bases. into_vec ( ) , & vm. ctx ) ;
851
+
852
+ for ( i, base) in bases. as_slice ( ) . iter ( ) . enumerate ( ) {
853
+ if base. isinstance ( & vm. ctx . types . type_type ) {
854
+ if let Some ( bases) = & mut new_bases {
855
+ bases. push ( base. clone ( ) ) ;
856
+ }
857
+ continue ;
858
+ }
859
+ let mro_entries = vm. get_attribute_opt ( base. clone ( ) , "__mro_entries__" ) ?;
860
+ let entries = match mro_entries {
861
+ Some ( meth) => vm. invoke ( & meth, ( bases. clone ( ) , ) ) ?,
862
+ None => {
863
+ if let Some ( bases) = & mut new_bases {
864
+ bases. push ( base. clone ( ) ) ;
865
+ }
866
+ continue ;
867
+ }
868
+ } ;
869
+ let entries: PyTupleRef = entries
870
+ . downcast ( )
871
+ . map_err ( |_| vm. new_type_error ( "__mro_entries__ must return a tuple" . to_owned ( ) ) ) ?;
872
+ let new_bases = new_bases. get_or_insert_with ( || bases. as_slice ( ) [ ..i] . to_vec ( ) ) ;
873
+ new_bases. extend_from_slice ( entries. as_slice ( ) ) ;
874
+ }
875
+
876
+ let new_bases = new_bases. map ( |v| PyTupleRef :: with_elements ( v, & vm. ctx ) ) ;
877
+ let ( orig_bases, bases) = match new_bases {
878
+ Some ( new) => ( Some ( bases) , new) ,
879
+ None => ( None , bases) ,
880
+ } ;
881
+
882
+ for base in bases. as_slice ( ) . iter ( ) {
849
883
let base_class = base. class ( ) ;
850
884
if base_class. issubclass ( & metaclass) {
851
885
metaclass = base. clone_class ( ) ;
@@ -858,7 +892,7 @@ mod decl {
858
892
}
859
893
}
860
894
861
- let bases = bases. into_tuple ( vm ) ;
895
+ let bases = bases. into_object ( ) ;
862
896
863
897
// Prepare uses full __getattribute__ resolution chain.
864
898
let prepare = vm. get_attribute ( metaclass. clone ( ) . into_object ( ) , "__prepare__" ) ?;
@@ -872,6 +906,10 @@ mod decl {
872
906
let classcell = function. invoke_with_locals ( ( ) . into ( ) , Some ( namespace. clone ( ) ) , vm) ?;
873
907
let classcell = <Option < PyCellRef > >:: try_from_object ( vm, classcell) ?;
874
908
909
+ if let Some ( orig_bases) = orig_bases {
910
+ namespace. set_item ( "__orig_bases__" , orig_bases. into_object ( ) , vm) ?;
911
+ }
912
+
875
913
let class = vm. invoke (
876
914
metaclass. as_object ( ) ,
877
915
FuncArgs :: new ( vec ! [ name_obj, bases, namespace. into_object( ) ] , kwargs) ,
0 commit comments