Skip to content

Commit 94a1903

Browse files
committed
Update __build_class__
1 parent 7d8f0b9 commit 94a1903

File tree

1 file changed

+35
-19
lines changed

1 file changed

+35
-19
lines changed

crates/vm/src/stdlib/builtins.rs

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)