Skip to content

Commit 7a43269

Browse files
committed
tp_base and better implementation for best_base
1 parent 7cdaba7 commit 7a43269

File tree

3 files changed

+64
-29
lines changed

3 files changed

+64
-29
lines changed

vm/src/obj/objtype.rs

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::pyobject::{
1414
IdProtocol, PyAttributes, PyClassImpl, PyContext, PyIterable, PyObject, PyObjectRef, PyRef,
1515
PyResult, PyValue, TypeProtocol,
1616
};
17-
use crate::slots::{PyClassSlots, PyTpFlags};
17+
use crate::slots::{PyClassSlot, PyTpFlags};
1818
use crate::vm::VirtualMachine;
1919

2020
/// type(object_or_name, bases, dict)
@@ -24,11 +24,12 @@ use crate::vm::VirtualMachine;
2424
#[derive(Debug)]
2525
pub struct PyClass {
2626
pub name: String,
27-
pub bases: Vec<PyClassRef>,
27+
pub base: Option<PyClassRef>, // tp_base
28+
pub bases: Vec<PyClassRef>, // tp_bases
2829
pub mro: Vec<PyClassRef>,
2930
pub subclasses: RefCell<Vec<PyWeak>>,
3031
pub attributes: RefCell<PyAttributes>,
31-
pub slots: RefCell<PyClassSlots>,
32+
pub slots: RefCell<PyClassSlot>,
3233
}
3334

3435
impl fmt::Display for PyClass {
@@ -361,6 +362,22 @@ pub fn issubclass(subclass: &PyClassRef, cls: &PyClassRef) -> bool {
361362
subclass.is(cls) || mro.iter().any(|c| c.is(cls.as_object()))
362363
}
363364

365+
pub fn is_subtype_base_chain(subclass: &PyClassRef, cls: &PyClassRef) -> bool {
366+
let mut a = subclass;
367+
loop {
368+
if subclass.is(cls) {
369+
return true;
370+
} else {
371+
if let Some(ref base) = a.base {
372+
a = base;
373+
} else {
374+
break;
375+
}
376+
}
377+
}
378+
cls.base.is_none()
379+
}
380+
364381
pub fn type_new(
365382
zelf: PyClassRef,
366383
cls: PyClassRef,
@@ -491,7 +508,7 @@ fn linearise_mro(mut bases: Vec<Vec<PyClassRef>>) -> Option<Vec<PyClassRef>> {
491508
pub fn new(
492509
typ: PyClassRef,
493510
name: &str,
494-
_base: PyClassRef,
511+
base: PyClassRef,
495512
bases: Vec<PyClassRef>,
496513
dict: HashMap<String, PyObjectRef>,
497514
) -> PyResult<PyClassRef> {
@@ -500,6 +517,7 @@ pub fn new(
500517
let new_type = PyObject {
501518
payload: PyClass {
502519
name: String::from(name),
520+
base: Some(base.clone()),
503521
bases,
504522
mro,
505523
subclasses: RefCell::default(),
@@ -548,8 +566,8 @@ fn calculate_meta_class(
548566
}
549567

550568
fn best_base<'a>(bases: &'a [PyClassRef], vm: &VirtualMachine) -> PyResult<PyClassRef> {
551-
// let mut base = None;
552-
// let mut winner = None;
569+
let mut base = None;
570+
let mut winner = None;
553571

554572
for base_i in bases {
555573
// base_proto = PyTuple_GET_ITEM(bases, i);
@@ -571,28 +589,41 @@ fn best_base<'a>(bases: &'a [PyClassRef], vm: &VirtualMachine) -> PyResult<PyCla
571589
base_i.name
572590
)));
573591
}
574-
// candidate = solid_base(base_i);
575-
// if (winner == NULL) {
576-
// winner = candidate;
577-
// base = base_i;
578-
// }
579-
// else if (PyType_IsSubtype(winner, candidate))
580-
// ;
581-
// else if (PyType_IsSubtype(candidate, winner)) {
582-
// winner = candidate;
583-
// base = base_i;
584-
// }
585-
// else {
586-
// PyErr_SetString(
587-
// PyExc_TypeError,
588-
// "multiple bases have "
589-
// "instance lay-out conflict");
590-
// return NULL;
591-
// }
592+
let candidate = solid_base(base_i, vm);
593+
if winner.is_none() {
594+
winner = Some(candidate);
595+
base = Some(base_i);
596+
} else if issubclass(winner.unwrap(), candidate) {
597+
} else if issubclass(candidate, winner.unwrap()) {
598+
winner = Some(candidate);
599+
base = Some(base_i);
600+
} else {
601+
return Err(
602+
vm.new_type_error("multiple bases have instance lay-out conflict".to_owned())
603+
);
604+
}
592605
}
593606

594-
// FIXME: Ok(base.unwrap()) is expected
595-
Ok(bases[0].clone())
607+
Ok(base.unwrap().clone())
608+
}
609+
610+
fn extra_ivars(_typ: &PyClassRef, _base: &PyClassRef) -> bool {
611+
// TODO
612+
false
613+
}
614+
615+
fn solid_base<'a>(typ: &'a PyClassRef, vm: &'a VirtualMachine) -> &'a PyClassRef {
616+
let base = if let Some(ref tp_base) = typ.base {
617+
solid_base(tp_base, vm)
618+
} else {
619+
&vm.ctx.types.type_type
620+
};
621+
622+
if extra_ivars(typ, base) {
623+
typ
624+
} else {
625+
base
626+
}
596627
}
597628

598629
#[cfg(test)]

vm/src/slots.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,16 @@ impl Default for PyTpFlags {
2424
}
2525

2626
#[derive(Default)]
27-
pub struct PyClassSlots {
27+
pub struct PyClassSlot {
2828
pub flags: PyTpFlags,
2929
pub new: Option<PyNativeFunc>,
3030
pub call: Option<PyNativeFunc>,
3131
pub descr_get: Option<PyNativeFunc>,
3232
}
3333

34-
impl std::fmt::Debug for PyClassSlots {
34+
impl std::fmt::Debug for PyClassSlot {
3535
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36-
f.write_str("PyClassSlots")
36+
f.write_str("PyClassSlot")
3737
}
3838
}
3939

vm/src/types.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
279279
dict: None,
280280
payload: PyClass {
281281
name: String::from("type"),
282+
base: None,
282283
bases: vec![],
283284
mro: vec![],
284285
subclasses: RefCell::default(),
@@ -293,6 +294,7 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
293294
dict: None,
294295
payload: PyClass {
295296
name: String::from("object"),
297+
base: None,
296298
bases: vec![],
297299
mro: vec![],
298300
subclasses: RefCell::default(),
@@ -319,6 +321,7 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
319321
// dummy PyClass
320322
let cls = PyClass {
321323
name: Default::default(),
324+
base: Default::default(),
322325
bases: Default::default(),
323326
mro: Default::default(),
324327
subclasses: Default::default(),
@@ -348,6 +351,7 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
348351
let object_type = PyClassRef::new_ref_unchecked(Rc::from_raw(object_type_ptr));
349352

350353
(*type_type_ptr).payload.mro = vec![object_type.clone()];
354+
(*type_type_ptr).payload.base = Some(object_type.clone());
351355
(*type_type_ptr).payload.bases = vec![object_type.clone()];
352356

353357
(type_type, object_type)

0 commit comments

Comments
 (0)