Skip to content

Commit 699450d

Browse files
Merge pull request #1447 from RustPython/coolreader18/type-attrs
Fix properties on `type`
2 parents 452e82f + 9361190 commit 699450d

5 files changed

Lines changed: 43 additions & 24 deletions

File tree

tests/snippets/types_snippet.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ class D(B, C): pass
4343
assert C.__subclasses__() == [D]
4444
assert D.__subclasses__() == []
4545

46+
assert D.__bases__ == (B, C)
47+
assert A.__bases__ == (object,)
48+
assert B.__bases__ == (A,)
49+
50+
4651
del D
4752

4853
try: # gc sweep is needed here for CPython...

vm/src/obj/objfunction.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::function::{Args, KwArgs};
1+
use crate::function::PyFuncArgs;
22
use crate::obj::objcode::PyCodeRef;
33
use crate::obj::objdict::PyDictRef;
44
use crate::obj::objtuple::PyTupleRef;
@@ -44,8 +44,8 @@ impl PyValue for PyFunction {
4444
}
4545

4646
impl PyFunctionRef {
47-
fn call(self, args: Args, kwargs: KwArgs, vm: &VirtualMachine) -> PyResult {
48-
vm.invoke(&self.into_object(), (&args, &kwargs))
47+
fn call(func: PyObjectRef, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
48+
vm.invoke(&func, args)
4949
}
5050

5151
fn code(self, _vm: &VirtualMachine) -> PyCodeRef {
@@ -92,7 +92,8 @@ pub fn init(context: &PyContext) {
9292

9393
let builtin_function_or_method_type = &context.types.builtin_function_or_method_type;
9494
extend_class!(context, builtin_function_or_method_type, {
95-
"__get__" => context.new_rustfunc(bind_method)
95+
"__get__" => context.new_rustfunc(bind_method),
96+
"__call__" => context.new_rustfunc(PyFunctionRef::call),
9697
});
9798
}
9899

vm/src/obj/objproperty.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,13 @@ pub type PyReadOnlyPropertyRef = PyRef<PyReadOnlyProperty>;
2828
#[pyimpl]
2929
impl PyReadOnlyProperty {
3030
#[pymethod(name = "__get__")]
31-
fn get(
32-
zelf: PyRef<Self>,
33-
obj: PyObjectRef,
34-
_owner: OptionalArg<PyClassRef>,
35-
vm: &VirtualMachine,
36-
) -> PyResult {
37-
if obj.is(vm.ctx.none.as_object()) {
38-
Ok(zelf.into_object())
31+
fn get(zelf: PyRef<Self>, obj: PyObjectRef, cls: PyClassRef, vm: &VirtualMachine) -> PyResult {
32+
if vm.is_none(&obj) {
33+
if cls.is(&vm.ctx.types.type_type) {
34+
vm.invoke(&zelf.getter, cls.into_object())
35+
} else {
36+
Ok(zelf.into_object())
37+
}
3938
} else {
4039
vm.invoke(&zelf.getter, obj)
4140
}

vm/src/obj/objtype.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use super::objweakref::PyWeak;
2020
#[derive(Debug)]
2121
pub struct PyClass {
2222
pub name: String,
23+
pub bases: Vec<PyClassRef>,
2324
pub mro: Vec<PyClassRef>,
2425
pub subclasses: RefCell<Vec<PyWeak>>,
2526
pub attributes: RefCell<PyAttributes>,
@@ -94,6 +95,11 @@ impl PyClassRef {
9495
Err(vm.new_attribute_error("read-only attribute".to_string()))
9596
}
9697

98+
fn bases(self, vm: &VirtualMachine) -> PyObjectRef {
99+
vm.ctx
100+
.new_tuple(self.bases.iter().map(|x| x.as_object().clone()).collect())
101+
}
102+
97103
fn dir(self, vm: &VirtualMachine) -> PyList {
98104
let attributes = get_attributes(self);
99105
let attributes: Vec<PyObjectRef> = attributes
@@ -241,6 +247,7 @@ pub fn init(ctx: &PyContext) {
241247
.add_getter(PyClassRef::mro)
242248
.add_setter(PyClassRef::set_mro)
243249
.create(),
250+
"__bases__" => ctx.new_property(PyClassRef::bases),
244251
"__name__" => ctx.new_property(PyClassRef::name),
245252
"__repr__" => ctx.new_rustfunc(PyClassRef::repr),
246253
"__qualname__" => ctx.new_property(PyClassRef::qualname),
@@ -290,8 +297,12 @@ fn type_new_slot(metatype: PyClassRef, args: PyFuncArgs, vm: &VirtualMachine) ->
290297

291298
let (name, bases, dict): (PyStringRef, PyIterable<PyClassRef>, PyDictRef) = args.bind(vm)?;
292299

293-
let mut bases: Vec<PyClassRef> = bases.iter(vm)?.collect::<Result<Vec<_>, _>>()?;
294-
bases.push(vm.ctx.object());
300+
let bases: Vec<PyClassRef> = bases.iter(vm)?.collect::<Result<Vec<_>, _>>()?;
301+
let bases = if bases.is_empty() {
302+
vec![vm.ctx.object()]
303+
} else {
304+
bases
305+
};
295306

296307
let attributes = dict.to_attributes();
297308

@@ -446,13 +457,10 @@ fn linearise_mro(mut bases: Vec<Vec<PyClassRef>>) -> Option<Vec<PyClassRef>> {
446457
if (&bases).iter().all(Vec::is_empty) {
447458
break;
448459
}
449-
match take_next_base(bases) {
450-
Some((head, new_bases)) => {
451-
result.push(head);
452-
bases = new_bases;
453-
}
454-
None => return None,
455-
}
460+
let (head, new_bases) = take_next_base(bases)?;
461+
462+
result.push(head);
463+
bases = new_bases;
456464
}
457465
Some(result)
458466
}
@@ -468,6 +476,7 @@ pub fn new(
468476
let new_type = PyObject {
469477
payload: PyClass {
470478
name: String::from(name),
479+
bases,
471480
mro,
472481
subclasses: RefCell::default(),
473482
attributes: RefCell::new(dict),
@@ -477,13 +486,16 @@ pub fn new(
477486
typ,
478487
}
479488
.into_ref();
480-
for base in bases {
489+
490+
let new_type: PyClassRef = new_type.downcast().unwrap();
491+
492+
for base in &new_type.bases {
481493
base.subclasses
482494
.borrow_mut()
483-
.push(PyWeak::downgrade(&new_type));
495+
.push(PyWeak::downgrade(new_type.as_object()));
484496
}
485497

486-
Ok(new_type.downcast().unwrap())
498+
Ok(new_type)
487499
}
488500

489501
#[cfg(test)]

vm/src/types.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
232232
dict: None,
233233
payload: PyClass {
234234
name: String::from("object"),
235+
bases: vec![],
235236
mro: vec![],
236237
subclasses: RefCell::default(),
237238
attributes: RefCell::new(PyAttributes::new()),
@@ -245,6 +246,7 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
245246
dict: None,
246247
payload: PyClass {
247248
name: String::from("type"),
249+
bases: vec![object_type.clone().downcast().unwrap()],
248250
mro: vec![object_type.clone().downcast().unwrap()],
249251
subclasses: RefCell::default(),
250252
attributes: RefCell::new(PyAttributes::new()),

0 commit comments

Comments
 (0)