cpython compatible type_new

This commit is contained in:
Jeong YunWon
2020-01-27 15:24:58 +09:00
parent 1ecc8228d9
commit 869645203d
4 changed files with 66 additions and 26 deletions

View File

@@ -264,35 +264,42 @@ impl PyClassRef {
}
let (name, bases, dict): (PyStringRef, PyIterable<PyClassRef>, PyDictRef) =
args.bind(vm)?;
args.clone().bind(vm)?;
let bases: Vec<PyClassRef> = bases.iter(vm)?.collect::<Result<Vec<_>, _>>()?;
let bases = if bases.is_empty() {
vec![vm.ctx.object()]
let (metatype, base, bases) = if bases.is_empty() {
let base = vm.ctx.object();
(metatype, base.clone(), vec![base])
} else {
bases
// TODO
// for base in &bases {
// if PyType_Check(base) { continue; }
// _PyObject_LookupAttrId(base, PyId___mro_entries__, &base)?
// Err(new_type_error( "type() doesn't support MRO entry resolution; "
// "use types.new_class()"))
// }
// Search the bases for the proper metatype to deal with this:
let winner = calculate_meta_class(metatype.clone(), &bases, vm)?;
let metatype = if !winner.is(&metatype) {
if let Some(ref tp_new) = winner.clone().slots.borrow().new {
// Pass it to the winner
return tp_new(vm, args.insert(winner.into_object()));
}
winner
} else {
metatype
};
// let base = best_base(bases)?;
let base = bases[0].clone();
(metatype, base, bases)
};
let attributes = dict.to_attributes();
let mut winner = metatype;
for base in &bases {
let base_type = base.class();
if issubclass(&winner, &base_type) {
continue;
} else if issubclass(&base_type, &winner) {
winner = base_type.clone();
continue;
}
return Err(vm.new_type_error(
"metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass \
of the metaclasses of all its bases"
.to_string(),
));
}
new(winner, name.as_str(), bases, attributes).map(Into::into)
new(metatype, name.as_str(), base, bases, attributes).map(Into::into)
}
#[pyslot]
@@ -483,6 +490,7 @@ fn linearise_mro(mut bases: Vec<Vec<PyClassRef>>) -> Option<Vec<PyClassRef>> {
pub fn new(
typ: PyClassRef,
name: &str,
_base: PyClassRef,
bases: Vec<PyClassRef>,
dict: HashMap<String, PyObjectRef>,
) -> PyResult<PyClassRef> {
@@ -513,6 +521,31 @@ pub fn new(
Ok(new_type)
}
fn calculate_meta_class(
metatype: PyClassRef,
bases: &[PyClassRef],
vm: &VirtualMachine,
) -> PyResult<PyClassRef> {
// = _PyType_CalculateMetaclass
let mut winner = metatype;
for base in bases {
let base_type = base.class();
if issubclass(&winner, &base_type) {
continue;
} else if issubclass(&base_type, &winner) {
winner = base_type.clone();
continue;
}
return Err(vm.new_type_error(
"metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass \
of the metaclasses of all its bases"
.to_string(),
));
}
Ok(winner)
}
#[cfg(test)]
mod tests {
use super::{linearise_mro, new};

View File

@@ -458,7 +458,7 @@ impl PyContext {
}
pub fn new_class(&self, name: &str, base: PyClassRef) -> PyClassRef {
objtype::new(self.type_type(), name, vec![base], PyAttributes::new()).unwrap()
create_type(name, &self.type_type(), &base)
}
pub fn new_namespace(&self) -> PyObjectRef {

View File

@@ -10,7 +10,7 @@ impl PyTpFlags {
pub const BASETYPE: u64 = 1 << 10;
pub fn has_feature(&self, flag: u64) -> bool {
(self.0 | flag) != 0
(self.0 & flag) != 0
}
}

View File

@@ -233,7 +233,14 @@ impl TypeZoo {
pub fn create_type(name: &str, type_type: &PyClassRef, base: &PyClassRef) -> PyClassRef {
let dict = PyAttributes::new();
objtype::new(type_type.clone(), name, vec![base.clone()], dict).unwrap()
objtype::new(
type_type.clone(),
name,
base.clone(),
vec![base.clone()],
dict,
)
.unwrap()
}
fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {