Skip to content

Commit 1c3d7ae

Browse files
authored
Merge pull request RustPython#2251 from youknowone/type
clean up PyType
2 parents 54cfdf2 + 81581a9 commit 1c3d7ae

File tree

4 files changed

+89
-81
lines changed

4 files changed

+89
-81
lines changed

vm/src/obj/objobject.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ impl PyBaseObject {
6666
}
6767
PyComparisonOp::Ne => {
6868
let cmp = zelf
69-
.class()
70-
.first_in_mro(|cls| cls.slots.cmp.load())
69+
.lease_class()
70+
.mro_find_map(|cls| cls.slots.cmp.load())
7171
.unwrap();
7272
let value = match cmp(zelf, other, PyComparisonOp::Eq, vm)? {
7373
Either::A(obj) => PyArithmaticValue::from_object(vm, obj)

vm/src/obj/objtype.rs

Lines changed: 71 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -56,29 +56,29 @@ impl PyValue for PyType {
5656
}
5757
}
5858

59-
impl PyTypeRef {
60-
fn tp_name(zelf: Self, vm: &VirtualMachine) -> String {
61-
let opt_name = zelf.slots.name.read().clone();
59+
impl PyType {
60+
fn tp_name(&self, vm: &VirtualMachine) -> String {
61+
let opt_name = self.slots.name.read().clone();
6262
opt_name.unwrap_or_else(|| {
63-
let module = zelf.attributes.read().get("__module__").cloned();
63+
let module = self.attributes.read().get("__module__").cloned();
6464
let new_name = if let Some(module) = module {
6565
// FIXME: "unknown" case is a bug.
6666
let module_str = PyStrRef::try_from_object(vm, module)
6767
.map_or("<unknown>".to_owned(), |m| m.borrow_value().to_owned());
68-
format!("{}.{}", module_str, &zelf.name)
68+
format!("{}.{}", module_str, &self.name)
6969
} else {
70-
zelf.name.clone()
70+
self.name.clone()
7171
};
72-
*zelf.slots.name.write() = Some(new_name.clone());
72+
*self.slots.name.write() = Some(new_name.clone());
7373
new_name
7474
})
7575
}
7676

77-
pub fn iter_mro(&self) -> impl Iterator<Item = &PyTypeRef> + DoubleEndedIterator {
78-
std::iter::once(self).chain(self.mro.iter())
77+
pub fn iter_mro(&self) -> impl Iterator<Item = &PyType> + DoubleEndedIterator {
78+
std::iter::once(self).chain(self.mro.iter().map(|cls| cls.deref()))
7979
}
8080

81-
pub(crate) fn first_in_mro<F, R>(&self, f: F) -> Option<R>
81+
pub(crate) fn mro_find_map<F, R>(&self, f: F) -> Option<R>
8282
where
8383
F: Fn(&Self) -> Option<R>,
8484
{
@@ -87,27 +87,50 @@ impl PyTypeRef {
8787
if let Some(r) = f(self) {
8888
Some(r)
8989
} else {
90-
self.mro.iter().filter_map(|cls| f(cls)).next()
90+
self.mro.iter().find_map(|cls| f(&cls))
9191
}
9292
}
9393

94-
pub fn iter_base_chain(&self) -> impl Iterator<Item = &PyTypeRef> {
95-
std::iter::successors(Some(self), |cls| cls.base.as_ref())
96-
}
97-
9894
// This is used for class initialisation where the vm is not yet available.
9995
pub fn set_str_attr<V: Into<PyObjectRef>>(&self, attr_name: &str, value: V) {
10096
self.attributes
10197
.write()
10298
.insert(attr_name.to_owned(), value.into());
10399
}
104100

101+
/// This is the internal get_attr implementation for fast lookup on a class.
102+
pub fn get_attr(&self, attr_name: &str) -> Option<PyObjectRef> {
103+
flame_guard!(format!("class_get_attr({:?})", attr_name));
104+
105+
self.get_direct_attr(attr_name)
106+
.or_else(|| self.get_super_attr(attr_name))
107+
}
108+
109+
pub fn get_direct_attr(&self, attr_name: &str) -> Option<PyObjectRef> {
110+
self.attributes.read().get(attr_name).cloned()
111+
}
112+
113+
pub fn get_super_attr(&self, attr_name: &str) -> Option<PyObjectRef> {
114+
self.mro
115+
.iter()
116+
.find_map(|class| class.attributes.read().get(attr_name).cloned())
117+
}
118+
119+
// This is the internal has_attr implementation for fast lookup on a class.
120+
pub fn has_attr(&self, attr_name: &str) -> bool {
121+
self.attributes.read().contains_key(attr_name)
122+
|| self
123+
.mro
124+
.iter()
125+
.any(|c| c.attributes.read().contains_key(attr_name))
126+
}
127+
105128
pub fn get_attributes(&self) -> PyAttributes {
106129
// Gather all members here:
107130
let mut attributes = PyAttributes::new();
108131

109132
for bc in self.iter_mro().rev() {
110-
for (name, value) in bc.attributes.read().clone().iter() {
133+
for (name, value) in bc.attributes.read().iter() {
111134
attributes.insert(name.to_owned(), value.clone());
112135
}
113136
}
@@ -177,6 +200,16 @@ impl PyTypeRef {
177200
}
178201
}
179202

203+
impl PyTypeRef {
204+
pub fn iter_mro(&self) -> impl Iterator<Item = &PyTypeRef> + DoubleEndedIterator {
205+
std::iter::once(self).chain(self.mro.iter())
206+
}
207+
208+
pub fn iter_base_chain(&self) -> impl Iterator<Item = &PyTypeRef> {
209+
std::iter::successors(Some(self), |cls| cls.base.as_ref())
210+
}
211+
}
212+
180213
#[inline]
181214
fn get_class_magic(zelf: &PyObjectRef, name: &str) -> PyObjectRef {
182215
zelf.get_class_attr(name).unwrap()
@@ -237,8 +270,8 @@ impl PyType {
237270
}
238271

239272
#[pymethod(magic)]
240-
fn repr(zelf: PyRef<Self>, vm: &VirtualMachine) -> String {
241-
format!("<class '{}'>", PyRef::<Self>::tp_name(zelf, vm))
273+
fn repr(&self, vm: &VirtualMachine) -> String {
274+
format!("<class '{}'>", self.tp_name(vm))
242275
}
243276

244277
#[pyproperty(magic)]
@@ -471,8 +504,8 @@ impl PyType {
471504
}
472505

473506
impl SlotGetattro for PyType {
474-
fn getattro(zelf: PyRef<Self>, name_ref: PyStrRef, vm: &VirtualMachine) -> PyResult {
475-
let name = name_ref.borrow_value();
507+
fn getattro(zelf: PyRef<Self>, name_str: PyStrRef, vm: &VirtualMachine) -> PyResult {
508+
let name = name_str.borrow_value();
476509
vm_trace!("type.__getattribute__({:?}, {:?})", zelf, name);
477510
let mcl = zelf.lease_class();
478511

@@ -482,7 +515,7 @@ impl SlotGetattro for PyType {
482515
let attr_class = attr.lease_class();
483516
if attr_class.has_attr("__set__") {
484517
if let Some(ref descr_get) =
485-
PyLease::into_pyref(attr_class).first_in_mro(|cls| cls.slots.descr_get.load())
518+
attr_class.mro_find_map(|cls| cls.slots.descr_get.load())
486519
{
487520
let mcl = PyLease::into_pyref(mcl).into_object();
488521
return descr_get(attr.clone(), Some(zelf.into_object()), Some(mcl), vm);
@@ -493,8 +526,10 @@ impl SlotGetattro for PyType {
493526
let zelf_attr = zelf.get_attr(name);
494527

495528
if let Some(ref attr) = zelf_attr {
496-
let attr_class = attr.class();
497-
if let Some(descr_get) = attr_class.first_in_mro(|cls| cls.slots.descr_get.load()) {
529+
if let Some(descr_get) = attr
530+
.lease_class()
531+
.mro_find_map(|cls| cls.slots.descr_get.load())
532+
{
498533
drop(mcl);
499534
return descr_get(attr.clone(), None, Some(zelf.into_object()), vm);
500535
}
@@ -510,7 +545,7 @@ impl SlotGetattro for PyType {
510545
getter,
511546
vec![
512547
PyLease::into_pyref(mcl).into_object(),
513-
name_ref.into_object(),
548+
name_str.into_object(),
514549
],
515550
)
516551
} else {
@@ -596,25 +631,25 @@ pub(crate) fn init(ctx: &PyContext) {
596631
PyType::extend_class(ctx, &ctx.types.type_type);
597632
}
598633

599-
pub trait DerefToPyClass {
600-
fn deref_to_class(&self) -> &PyType;
634+
pub trait DerefToPyType {
635+
fn deref_to_type(&self) -> &PyType;
601636
}
602637

603-
impl DerefToPyClass for PyTypeRef {
604-
fn deref_to_class(&self) -> &PyType {
638+
impl DerefToPyType for PyTypeRef {
639+
fn deref_to_type(&self) -> &PyType {
605640
self.deref()
606641
}
607642
}
608643

609-
impl<'a> DerefToPyClass for PyLease<'a, PyType> {
610-
fn deref_to_class(&self) -> &PyType {
644+
impl<'a> DerefToPyType for PyLease<'a, PyType> {
645+
fn deref_to_type(&self) -> &PyType {
611646
self.deref()
612647
}
613648
}
614649

615-
impl<T: DerefToPyClass> DerefToPyClass for &'_ T {
616-
fn deref_to_class(&self) -> &PyType {
617-
(&**self).deref_to_class()
650+
impl<T: DerefToPyType> DerefToPyType for &'_ T {
651+
fn deref_to_type(&self) -> &PyType {
652+
(&**self).deref_to_type()
618653
}
619654
}
620655

@@ -628,8 +663,8 @@ pub fn isinstance<T: TypeProtocol>(obj: &T, cls: &PyTypeRef) -> bool {
628663
/// Determines if `subclass` is actually a subclass of `cls`, this doesn't call __subclasscheck__,
629664
/// so only use this if `cls` is known to have not overridden the base __subclasscheck__ magic
630665
/// method.
631-
pub fn issubclass<T: DerefToPyClass + IdProtocol, R: IdProtocol>(subclass: T, cls: R) -> bool {
632-
subclass.is(&cls) || subclass.deref_to_class().mro.iter().any(|c| c.is(&cls))
666+
pub fn issubclass<T: DerefToPyType + IdProtocol, R: IdProtocol>(subclass: T, cls: R) -> bool {
667+
subclass.is(&cls) || subclass.deref_to_type().mro.iter().any(|c| c.is(&cls))
633668
}
634669

635670
fn call_tp_new(
@@ -638,7 +673,7 @@ fn call_tp_new(
638673
args: PyFuncArgs,
639674
vm: &VirtualMachine,
640675
) -> PyResult {
641-
for cls in typ.iter_mro() {
676+
for cls in typ.deref().iter_mro() {
642677
if let Some(new_meth) = cls.get_attr("__new__") {
643678
if !vm.ctx.is_tp_new_wrapper(&new_meth) {
644679
let new_meth = vm.call_if_get_descriptor(new_meth, typ.clone().into_object())?;
@@ -668,35 +703,6 @@ pub fn tp_new_wrapper(
668703
call_tp_new(zelf, cls, args, vm)
669704
}
670705

671-
impl PyType {
672-
/// This is the internal get_attr implementation for fast lookup on a class.
673-
pub fn get_attr(&self, attr_name: &str) -> Option<PyObjectRef> {
674-
flame_guard!(format!("class_get_attr({:?})", attr_name));
675-
676-
self.get_direct_attr(attr_name)
677-
.or_else(|| self.get_super_attr(attr_name))
678-
}
679-
680-
pub fn get_direct_attr(&self, attr_name: &str) -> Option<PyObjectRef> {
681-
self.attributes.read().get(attr_name).cloned()
682-
}
683-
684-
pub fn get_super_attr(&self, attr_name: &str) -> Option<PyObjectRef> {
685-
self.mro
686-
.iter()
687-
.find_map(|class| class.attributes.read().get(attr_name).cloned())
688-
}
689-
690-
// This is the internal has_attr implementation for fast lookup on a class.
691-
pub fn has_attr(&self, attr_name: &str) -> bool {
692-
self.attributes.read().contains_key(attr_name)
693-
|| self
694-
.mro
695-
.iter()
696-
.any(|c| c.attributes.read().contains_key(attr_name))
697-
}
698-
}
699-
700706
fn take_next_base(mut bases: Vec<Vec<PyTypeRef>>) -> (Option<PyTypeRef>, Vec<Vec<PyTypeRef>>) {
701707
bases = bases.into_iter().filter(|x| !x.is_empty()).collect();
702708

vm/src/pyobjectrc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ where
146146

147147
// CPython-compatible drop implementation
148148
let zelf = Self::into_ref(self.clone());
149-
if let Some(del_slot) = zelf.class().first_in_mro(|cls| cls.slots.del.load()) {
149+
if let Some(del_slot) = zelf.lease_class().mro_find_map(|cls| cls.slots.del.load()) {
150150
crate::vm::thread::with_vm(&zelf, |vm| {
151151
if let Err(e) = del_slot(&zelf, vm) {
152152
// exception in del will be ignored but printed

vm/src/vm.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -885,10 +885,10 @@ impl VirtualMachine {
885885
obj: Option<PyObjectRef>,
886886
cls: Option<PyObjectRef>,
887887
) -> Option<PyResult> {
888-
descr
889-
.class()
890-
.first_in_mro(|cls| cls.slots.descr_get.load())
891-
.map(|descr_get| descr_get(descr, obj, cls, self))
888+
let descr_get = descr
889+
.lease_class()
890+
.mro_find_map(|cls| cls.slots.descr_get.load());
891+
descr_get.map(|descr_get| descr_get(descr, obj, cls, self))
892892
}
893893

894894
pub fn call_get_descriptor(&self, descr: PyObjectRef, obj: PyObjectRef) -> Option<PyResult> {
@@ -920,7 +920,9 @@ impl VirtualMachine {
920920

921921
fn _invoke(&self, callable: &PyObjectRef, args: PyFuncArgs) -> PyResult {
922922
vm_trace!("Invoke: {:?} {:?}", callable, args);
923-
let slot_call = callable.class().first_in_mro(|cls| cls.slots.call.load());
923+
let slot_call = callable
924+
.lease_class()
925+
.mro_find_map(|cls| cls.slots.call.load());
924926
match slot_call {
925927
Some(slot_call) => {
926928
self.trace_event(TraceEvent::Call)?;
@@ -1014,8 +1016,8 @@ impl VirtualMachine {
10141016
let attr_name = attr_name.try_into_ref(self)?;
10151017
vm_trace!("vm.__getattribute__: {:?} {:?}", obj, attr_name);
10161018
let getattro = obj
1017-
.class()
1018-
.first_in_mro(|cls| cls.slots.getattro.load())
1019+
.lease_class()
1020+
.mro_find_map(|cls| cls.slots.getattro.load())
10191021
.unwrap();
10201022
getattro(obj, attr_name, self)
10211023
}
@@ -1158,8 +1160,8 @@ impl VirtualMachine {
11581160
}
11591161

11601162
pub fn is_callable(&self, obj: &PyObjectRef) -> bool {
1161-
obj.class()
1162-
.first_in_mro(|cls| cls.slots.call.load())
1163+
obj.lease_class()
1164+
.mro_find_map(|cls| cls.slots.call.load())
11631165
.is_some()
11641166
}
11651167

@@ -1442,8 +1444,8 @@ impl VirtualMachine {
14421444

14431445
let call_cmp = |obj: &PyObjectRef, other, op| {
14441446
let cmp = obj
1445-
.class()
1446-
.first_in_mro(|cls| cls.slots.cmp.load())
1447+
.lease_class()
1448+
.mro_find_map(|cls| cls.slots.cmp.load())
14471449
.unwrap();
14481450
Ok(match cmp(obj, other, op, self)? {
14491451
Either::A(obj) => PyArithmaticValue::from_object(self, obj).map(Either::A),
@@ -1494,8 +1496,8 @@ impl VirtualMachine {
14941496

14951497
pub fn _hash(&self, obj: &PyObjectRef) -> PyResult<rustpython_common::hash::PyHash> {
14961498
let hash = obj
1497-
.class()
1498-
.first_in_mro(|cls| cls.slots.hash.load())
1499+
.lease_class()
1500+
.mro_find_map(|cls| cls.slots.hash.load())
14991501
.unwrap(); // hash always exist
15001502
hash(&obj, self)
15011503
}

0 commit comments

Comments
 (0)