@@ -892,13 +892,12 @@ mod builtins {
892892 #[ pyfunction]
893893 pub fn __build_class__ (
894894 function : PyRef < PyFunction > ,
895- qualified_name : PyStrRef ,
895+ name : PyStrRef ,
896896 bases : PosArgs ,
897897 mut kwargs : KwArgs ,
898898 vm : & VirtualMachine ,
899899 ) -> PyResult {
900- let name = qualified_name. as_str ( ) . split ( '.' ) . next_back ( ) . unwrap ( ) ;
901- let name_obj = vm. ctx . new_str ( name) ;
900+ let name_obj: PyObjectRef = name. clone ( ) . into ( ) ;
902901
903902 // Update bases.
904903 let mut new_bases: Option < Vec < PyObjectRef > > = None ;
@@ -942,20 +941,33 @@ mod builtins {
942941 . downcast_exact :: < PyType > ( vm)
943942 . map ( |m| m. into_pyref ( ) )
944943 } )
945- . unwrap_or_else ( || Ok ( vm. ctx . types . type_type . to_owned ( ) ) ) ;
944+ . unwrap_or_else ( || {
945+ // if there are no bases, use type; else get the type of the first base
946+ Ok ( if bases. is_empty ( ) {
947+ vm. ctx . types . type_type . to_owned ( )
948+ } else {
949+ bases. first ( ) . unwrap ( ) . class ( ) . to_owned ( )
950+ } )
951+ } ) ;
946952
947953 let ( metaclass, meta_name) = match metaclass {
948954 Ok ( mut metaclass) => {
949955 for base in bases. iter ( ) {
950956 let base_class = base. class ( ) ;
957+ // if winner is subtype of tmptype, continue (winner is more derived)
958+ if metaclass. fast_issubclass ( base_class) {
959+ continue ;
960+ }
961+ // if tmptype is subtype of winner, update (tmptype is more derived)
951962 if base_class. fast_issubclass ( & metaclass) {
952- metaclass = base. class ( ) . to_owned ( ) ;
953- } else if !metaclass. fast_issubclass ( base_class) {
954- return Err ( vm. new_type_error (
955- "metaclass conflict: the metaclass of a derived class must be a (non-strict) \
956- subclass of the metaclasses of all its bases",
957- ) ) ;
963+ metaclass = base_class. to_owned ( ) ;
964+ continue ;
958965 }
966+ // Metaclass conflict
967+ return Err ( vm. new_type_error (
968+ "metaclass conflict: the metaclass of a derived class must be a (non-strict) \
969+ subclass of the metaclasses of all its bases",
970+ ) ) ;
959971 }
960972 let meta_name = metaclass. slot_name ( ) ;
961973 ( metaclass. to_owned ( ) . into ( ) , meta_name. to_owned ( ) )
@@ -969,8 +981,7 @@ mod builtins {
969981 let namespace = vm
970982 . get_attribute_opt ( metaclass. clone ( ) , identifier ! ( vm, __prepare__) ) ?
971983 . map_or ( Ok ( vm. ctx . new_dict ( ) . into ( ) ) , |prepare| {
972- let args =
973- FuncArgs :: new ( vec ! [ name_obj. clone( ) . into( ) , bases. clone( ) ] , kwargs. clone ( ) ) ;
984+ let args = FuncArgs :: new ( vec ! [ name_obj. clone( ) , bases. clone( ) ] , kwargs. clone ( ) ) ;
974985 prepare. call ( args, vm)
975986 } ) ?;
976987
@@ -1013,7 +1024,7 @@ mod builtins {
10131024 . del_item ( vm. ctx . intern_str ( ".type_params" ) , vm)
10141025 . ok ( ) ;
10151026
1016- let args = FuncArgs :: new ( vec ! [ name_obj. into ( ) , bases, namespace. into( ) ] , kwargs) ;
1027+ let args = FuncArgs :: new ( vec ! [ name_obj, bases, namespace. into( ) ] , kwargs) ;
10171028 let class = metaclass. call ( args, vm) ?;
10181029
10191030 // For PEP 695 classes, set __type_params__ on the class from the function
@@ -1028,16 +1039,21 @@ mod builtins {
10281039 class. set_attr ( identifier ! ( vm, __parameters__) , type_params, vm) ?;
10291040 }
10301041
1031- if let Some ( ref classcell) = classcell {
1032- let classcell = classcell. get ( ) . ok_or_else ( || {
1033- vm. new_type_error ( format ! (
1034- "__class__ not set defining {meta_name:?} as {class:?}. Was __classcell__ propagated to type.__new__?"
1042+ // only check cell if cls is a type and cell is a cell object
1043+ if let Some ( ref classcell) = classcell
1044+ && class. fast_isinstance ( vm. ctx . types . type_type )
1045+ {
1046+ let cell_value = classcell. get ( ) . ok_or_else ( || {
1047+ vm. new_runtime_error ( format ! (
1048+ "__class__ not set defining {:?} as {:?}. Was __classcell__ propagated to type.__new__?" ,
1049+ name, class
10351050 ) )
10361051 } ) ?;
10371052
1038- if !classcell . is ( & class) {
1053+ if !cell_value . is ( & class) {
10391054 return Err ( vm. new_type_error ( format ! (
1040- "__class__ set to {classcell:?} defining {meta_name:?} as {class:?}"
1055+ "__class__ set to {:?} defining {:?} as {:?}" ,
1056+ cell_value, name, class
10411057 ) ) ) ;
10421058 }
10431059 }
0 commit comments