Skip to content

Commit 8ec1af5

Browse files
authored
Merge pull request RustPython#660 from RustPython/typetype_clean
Typetype clean
2 parents 3d306fc + 633a9b0 commit 8ec1af5

File tree

3 files changed

+108
-81
lines changed

3 files changed

+108
-81
lines changed

vm/src/obj/objobject.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::objlist::PyList;
12
use super::objstr;
23
use super::objtype;
34
use crate::obj::objproperty::PropertyBuilder;
@@ -133,16 +134,13 @@ fn object_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
133134
Ok(vm.new_str(format!("<{} object at 0x{:x}>", type_name, address)))
134135
}
135136

136-
pub fn object_dir(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
137-
arg_check!(vm, args, required = [(obj, None)]);
138-
137+
pub fn object_dir(obj: PyObjectRef, vm: &mut VirtualMachine) -> PyList {
139138
let attributes = get_attributes(&obj);
140-
Ok(vm.ctx.new_list(
141-
attributes
142-
.keys()
143-
.map(|k| vm.ctx.new_str(k.to_string()))
144-
.collect(),
145-
))
139+
let attributes: Vec<PyObjectRef> = attributes
140+
.keys()
141+
.map(|k| vm.ctx.new_str(k.to_string()))
142+
.collect();
143+
PyList::from(attributes)
146144
}
147145

148146
fn object_format(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -260,7 +258,7 @@ fn object_getattribute(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
260258

261259
pub fn get_attributes(obj: &PyObjectRef) -> PyAttributes {
262260
// Get class attributes:
263-
let mut attributes = objtype::get_attributes(&obj.typ());
261+
let mut attributes = objtype::get_attributes(obj.type_pyref());
264262

265263
// Get instance attributes:
266264
if let Some(dict) = &obj.dict {

vm/src/obj/objtype.rs

Lines changed: 84 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ use std::cell::RefCell;
22
use std::collections::HashMap;
33

44
use crate::pyobject::{
5-
AttributeProtocol, IdProtocol, PyAttributes, PyContext, PyFuncArgs, PyObject, PyObjectRef,
6-
PyRef, PyResult, PyValue, TypeProtocol,
5+
AttributeProtocol, FromPyObjectRef, IdProtocol, PyAttributes, PyContext, PyFuncArgs, PyObject,
6+
PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
77
};
88
use crate::vm::VirtualMachine;
99

1010
use super::objdict;
11-
use super::objstr;
11+
use super::objlist::PyList;
12+
use super::objstr::{self, PyStringRef};
13+
use super::objtuple::PyTuple;
1214

1315
#[derive(Clone, Debug)]
1416
pub struct PyClass {
@@ -24,6 +26,70 @@ impl PyValue for PyClass {
2426
}
2527
}
2628

29+
struct IterMro<'a> {
30+
cls: &'a PyClassRef,
31+
offset: Option<usize>,
32+
}
33+
34+
impl<'a> Iterator for IterMro<'a> {
35+
type Item = &'a PyObjectRef;
36+
37+
fn next(&mut self) -> Option<Self::Item> {
38+
match self.offset {
39+
None => {
40+
self.offset = Some(0);
41+
Some(&self.cls.as_object())
42+
}
43+
Some(offset) => {
44+
if offset < self.cls.mro.len() {
45+
self.offset = Some(offset + 1);
46+
Some(&self.cls.mro[offset])
47+
} else {
48+
None
49+
}
50+
}
51+
}
52+
}
53+
}
54+
55+
impl PyClassRef {
56+
fn iter_mro(&self) -> IterMro {
57+
IterMro {
58+
cls: self,
59+
offset: None,
60+
}
61+
}
62+
63+
fn mro(self, _vm: &mut VirtualMachine) -> PyTuple {
64+
PyTuple::from(_mro(&self))
65+
}
66+
67+
fn dir(self, vm: &mut VirtualMachine) -> PyList {
68+
let attributes = get_attributes(self);
69+
let attributes: Vec<PyObjectRef> = attributes
70+
.keys()
71+
.map(|k| vm.ctx.new_str(k.to_string()))
72+
.collect();
73+
PyList::from(attributes)
74+
}
75+
76+
fn instance_check(self, obj: PyObjectRef, _vm: &mut VirtualMachine) -> bool {
77+
isinstance(&obj, self.as_object())
78+
}
79+
80+
fn subclass_check(self, subclass: PyObjectRef, _vm: &mut VirtualMachine) -> bool {
81+
issubclass(&subclass, self.as_object())
82+
}
83+
84+
fn repr(self, _vm: &mut VirtualMachine) -> String {
85+
format!("<class '{}'>", self.name)
86+
}
87+
88+
fn prepare(_name: PyStringRef, _bases: PyObjectRef, vm: &mut VirtualMachine) -> PyObjectRef {
89+
vm.new_dict()
90+
}
91+
}
92+
2793
/*
2894
* The magical type type
2995
*/
@@ -49,33 +115,19 @@ pub fn init(ctx: &PyContext) {
49115
extend_class!(&ctx, &ctx.type_type, {
50116
"__call__" => ctx.new_rustfunc(type_call),
51117
"__new__" => ctx.new_rustfunc(type_new),
52-
"__mro__" => ctx.new_property(type_mro),
53-
"__repr__" => ctx.new_rustfunc(type_repr),
54-
"__prepare__" => ctx.new_rustfunc(type_prepare),
118+
"__mro__" => ctx.new_property(PyClassRef::mro),
119+
"__repr__" => ctx.new_rustfunc(PyClassRef::repr),
120+
"__prepare__" => ctx.new_rustfunc(PyClassRef::prepare),
55121
"__getattribute__" => ctx.new_rustfunc(type_getattribute),
56-
"__instancecheck__" => ctx.new_rustfunc(type_instance_check),
57-
"__subclasscheck__" => ctx.new_rustfunc(type_subclass_check),
122+
"__instancecheck__" => ctx.new_rustfunc(PyClassRef::instance_check),
123+
"__subclasscheck__" => ctx.new_rustfunc(PyClassRef::subclass_check),
58124
"__doc__" => ctx.new_str(type_doc.to_string()),
59-
"__dir__" => ctx.new_rustfunc(type_dir),
125+
"__dir__" => ctx.new_rustfunc(PyClassRef::dir),
60126
});
61127
}
62128

63-
fn type_mro(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
64-
arg_check!(vm, args, required = [(cls, Some(vm.ctx.type_type()))]);
65-
match _mro(cls.clone()) {
66-
Some(mro) => Ok(vm.context().new_tuple(mro)),
67-
None => Err(vm.new_type_error("Only classes have an MRO.".to_string())),
68-
}
69-
}
70-
71-
fn _mro(cls: PyObjectRef) -> Option<Vec<PyObjectRef>> {
72-
if let Some(PyClass { ref mro, .. }) = cls.payload::<PyClass>() {
73-
let mut mro = mro.clone();
74-
mro.insert(0, cls.clone());
75-
Some(mro)
76-
} else {
77-
None
78-
}
129+
fn _mro(cls: &PyClassRef) -> Vec<PyObjectRef> {
130+
cls.iter_mro().cloned().collect()
79131
}
80132

81133
/// Determines if `obj` actually an instance of `cls`, this doesn't call __instancecheck__, so only
@@ -84,15 +136,6 @@ pub fn isinstance(obj: &PyObjectRef, cls: &PyObjectRef) -> bool {
84136
issubclass(obj.type_ref(), &cls)
85137
}
86138

87-
fn type_instance_check(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
88-
arg_check!(
89-
vm,
90-
args,
91-
required = [(typ, Some(vm.ctx.type_type())), (obj, None)]
92-
);
93-
Ok(vm.new_bool(isinstance(obj, typ)))
94-
}
95-
96139
/// Determines if `subclass` is actually a subclass of `cls`, this doesn't call __subclasscheck__,
97140
/// so only use this if `cls` is known to have not overridden the base __subclasscheck__ magic
98141
/// method.
@@ -101,18 +144,6 @@ pub fn issubclass(subclass: &PyObjectRef, cls: &PyObjectRef) -> bool {
101144
subclass.is(&cls) || mro.iter().any(|c| c.is(&cls))
102145
}
103146

104-
fn type_subclass_check(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
105-
arg_check!(
106-
vm,
107-
args,
108-
required = [
109-
(cls, Some(vm.ctx.type_type())),
110-
(subclass, Some(vm.ctx.type_type()))
111-
]
112-
);
113-
Ok(vm.new_bool(issubclass(subclass, cls)))
114-
}
115-
116147
pub fn get_type_name(typ: &PyObjectRef) -> String {
117148
if let Some(PyClass { name, .. }) = &typ.payload::<PyClass>() {
118149
name.clone()
@@ -212,24 +243,13 @@ pub fn type_getattribute(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult
212243
}
213244
}
214245

215-
pub fn type_dir(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
216-
arg_check!(vm, args, required = [(obj, None)]);
217-
218-
let attributes = get_attributes(&obj);
219-
Ok(vm.ctx.new_list(
220-
attributes
221-
.keys()
222-
.map(|k| vm.ctx.new_str(k.to_string()))
223-
.collect(),
224-
))
225-
}
226-
227-
pub fn get_attributes(obj: &PyObjectRef) -> PyAttributes {
246+
pub fn get_attributes(cls: PyClassRef) -> PyAttributes {
228247
// Gather all members here:
229248
let mut attributes = PyAttributes::new();
230249

231-
let mut base_classes = _mro(obj.clone()).expect("Type get_attributes on non-type");
250+
let mut base_classes: Vec<&PyObjectRef> = cls.iter_mro().collect();
232251
base_classes.reverse();
252+
233253
for bc in base_classes {
234254
if let Some(ref dict) = &bc.dict {
235255
for (name, value) in dict.borrow().iter() {
@@ -294,7 +314,10 @@ pub fn new(
294314
bases: Vec<PyObjectRef>,
295315
dict: HashMap<String, PyObjectRef>,
296316
) -> PyResult {
297-
let mros = bases.into_iter().map(|x| _mro(x).unwrap()).collect();
317+
let mros = bases
318+
.into_iter()
319+
.map(|x| _mro(&FromPyObjectRef::from_pyobj(&x)))
320+
.collect();
298321
let mro = linearise_mro(mros).unwrap();
299322
Ok(PyObject {
300323
payload: Box::new(PyClass {
@@ -307,16 +330,6 @@ pub fn new(
307330
.into_ref())
308331
}
309332

310-
fn type_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
311-
arg_check!(vm, args, required = [(obj, Some(vm.ctx.type_type()))]);
312-
let type_name = get_type_name(&obj);
313-
Ok(vm.new_str(format!("<class '{}'>", type_name)))
314-
}
315-
316-
fn type_prepare(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult {
317-
Ok(vm.new_dict())
318-
}
319-
320333
#[cfg(test)]
321334
mod tests {
322335
use super::{linearise_mro, new};

vm/src/pyobject.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,9 @@ pub trait TypeProtocol {
791791
fn typ(&self) -> PyObjectRef {
792792
self.type_ref().clone()
793793
}
794+
fn type_pyref(&self) -> PyClassRef {
795+
FromPyObjectRef::from_pyobj(self.type_ref())
796+
}
794797
fn type_ref(&self) -> &PyObjectRef;
795798
}
796799

@@ -1548,6 +1551,19 @@ pub trait PyValue: Any + fmt::Debug {
15481551
fn required_type(ctx: &PyContext) -> PyObjectRef;
15491552
}
15501553

1554+
impl FromPyObjectRef for PyRef<PyClass> {
1555+
fn from_pyobj(obj: &PyObjectRef) -> Self {
1556+
if let Some(_) = obj.payload::<PyClass>() {
1557+
PyRef {
1558+
obj: obj.clone(),
1559+
_payload: PhantomData,
1560+
}
1561+
} else {
1562+
panic!("Error getting inner type.")
1563+
}
1564+
}
1565+
}
1566+
15511567
#[cfg(test)]
15521568
mod tests {
15531569
use super::PyContext;

0 commit comments

Comments
 (0)