Skip to content

Commit 3d3889f

Browse files
committed
Add a getattro slot
1 parent 25409c4 commit 3d3889f

9 files changed

Lines changed: 182 additions & 134 deletions

File tree

vm/src/obj/objfunction.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::pyobject::{
1919
PyRef, PyResult, PyValue, TypeProtocol,
2020
};
2121
use crate::scope::Scope;
22-
use crate::slots::{Callable, Comparable, PyComparisonOp, SlotDescriptor};
22+
use crate::slots::{Callable, Comparable, PyComparisonOp, SlotDescriptor, SlotGetattro};
2323
use crate::VirtualMachine;
2424
use itertools::Itertools;
2525
#[cfg(feature = "jit")]
@@ -357,7 +357,16 @@ impl Comparable for PyBoundMethod {
357357
}
358358
}
359359

360-
#[pyimpl(with(Callable, Comparable), flags(HAS_DICT))]
360+
impl SlotGetattro for PyBoundMethod {
361+
fn getattro(zelf: PyRef<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
362+
if let Some(obj) = zelf.get_class_attr(name.borrow_value()) {
363+
return vm.call_if_get_descriptor(obj, zelf.into_object());
364+
}
365+
vm.get_attribute(zelf.function.clone(), name)
366+
}
367+
}
368+
369+
#[pyimpl(with(Callable, Comparable, SlotGetattro), flags(HAS_DICT))]
361370
impl PyBoundMethod {
362371
pub fn new(object: PyObjectRef, function: PyObjectRef) -> Self {
363372
PyBoundMethod { object, function }
@@ -376,14 +385,6 @@ impl PyBoundMethod {
376385
vm.get_attribute(self.function.clone(), "__doc__")
377386
}
378387

379-
#[pymethod(magic)]
380-
fn getattribute(zelf: PyRef<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
381-
if let Some(obj) = zelf.get_class_attr(name.borrow_value()) {
382-
return vm.call_if_get_descriptor(obj, zelf.into_object());
383-
}
384-
vm.get_attribute(zelf.function.clone(), name)
385-
}
386-
387388
#[pyproperty(magic)]
388389
fn func(&self) -> PyObjectRef {
389390
self.function.clone()

vm/src/obj/objmodule.rs

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::pyobject::{
66
BorrowValue, IntoPyObject, ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult,
77
PyValue,
88
};
9+
use crate::slots::SlotGetattro;
910
use crate::vm::VirtualMachine;
1011

1112
#[pyclass(module = false, name = "module")]
@@ -42,36 +43,36 @@ pub fn init_module_dict(
4243
.expect("Failed to set __spec__ on module");
4344
}
4445

45-
#[pyimpl(flags(BASETYPE, HAS_DICT))]
46-
impl PyModuleRef {
46+
#[pyimpl(with(SlotGetattro), flags(BASETYPE, HAS_DICT))]
47+
impl PyModule {
4748
#[pyslot]
4849
fn tp_new(cls: PyTypeRef, _args: PyFuncArgs, vm: &VirtualMachine) -> PyResult<PyModuleRef> {
4950
PyModule {}.into_ref_with_type(vm, cls)
5051
}
5152

5253
#[pymethod(magic)]
5354
fn init(
54-
self,
55+
zelf: PyRef<Self>,
5556
name: PyStrRef,
5657
doc: OptionalOption<PyStrRef>,
5758
vm: &VirtualMachine,
5859
) -> PyResult<()> {
59-
debug_assert!(crate::pyobject::TypeProtocol::lease_class(self.as_object())
60+
debug_assert!(crate::pyobject::TypeProtocol::lease_class(zelf.as_object())
6061
.slots
6162
.flags
6263
.has_feature(crate::slots::PyTpFlags::HAS_DICT));
6364
init_module_dict(
6465
vm,
65-
&self.as_object().dict().unwrap(),
66+
&zelf.as_object().dict().unwrap(),
6667
name.into_object(),
6768
doc.flatten().into_pyobject(vm),
6869
);
6970
Ok(())
7071
}
7172

72-
fn name(self, vm: &VirtualMachine) -> Option<String> {
73+
fn name(zelf: PyRef<Self>, vm: &VirtualMachine) -> Option<String> {
7374
vm.generic_getattribute_opt(
74-
self.as_object().clone(),
75+
zelf.as_object().clone(),
7576
PyStr::from("__name__").into_ref(vm),
7677
None,
7778
)
@@ -80,30 +81,15 @@ impl PyModuleRef {
8081
}
8182

8283
#[pymethod(magic)]
83-
fn getattribute(self, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
84-
vm.generic_getattribute_opt(self.as_object().clone(), name.clone(), None)?
85-
.ok_or_else(|| {
86-
let module_name = if let Some(name) = self.name(vm) {
87-
format!(" '{}'", name)
88-
} else {
89-
"".to_owned()
90-
};
91-
vm.new_attribute_error(
92-
format!("module{} has no attribute '{}'", module_name, name,),
93-
)
94-
})
95-
}
96-
97-
#[pymethod(magic)]
98-
fn repr(self, vm: &VirtualMachine) -> PyResult {
84+
fn repr(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
9985
let importlib = vm.import("_frozen_importlib", &[], 0)?;
10086
let module_repr = vm.get_attribute(importlib, "_module_repr")?;
101-
vm.invoke(&module_repr, vec![self.into_object()])
87+
vm.invoke(&module_repr, vec![zelf.into_object()])
10288
}
10389

10490
#[pymethod(magic)]
105-
fn dir(self, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
106-
let dict = self
91+
fn dir(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
92+
let dict = zelf
10793
.as_object()
10894
.dict()
10995
.ok_or_else(|| vm.new_value_error("module has no dict".to_owned()))?;
@@ -112,6 +98,22 @@ impl PyModuleRef {
11298
}
11399
}
114100

101+
impl SlotGetattro for PyModule {
102+
fn getattro(zelf: PyRef<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
103+
vm.generic_getattribute_opt(zelf.as_object().clone(), name.clone(), None)?
104+
.ok_or_else(|| {
105+
let module_name = if let Some(name) = Self::name(zelf, vm) {
106+
format!(" '{}'", name)
107+
} else {
108+
"".to_owned()
109+
};
110+
vm.new_attribute_error(
111+
format!("module{} has no attribute '{}'", module_name, name,),
112+
)
113+
})
114+
}
115+
}
116+
115117
pub(crate) fn init(context: &PyContext) {
116-
PyModuleRef::extend_class(&context, &context.types.module_type);
118+
PyModule::extend_class(&context, &context.types.module_type);
117119
}

vm/src/obj/objobject.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,9 @@ impl PyBaseObject {
242242
}
243243
}
244244

245-
#[pymethod(magic)]
246-
fn getattribute(obj: PyObjectRef, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
245+
#[pymethod(name = "__getattribute__")]
246+
#[pyslot]
247+
fn getattro(obj: PyObjectRef, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
247248
vm_trace!("object.__getattribute__({:?}, {:?})", obj, name);
248249
vm.generic_getattribute(obj, name)
249250
}

vm/src/obj/objsuper.rs

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::pyobject::{
1414
TryFromObject, TypeProtocol,
1515
};
1616
use crate::scope::NameProtocol;
17-
use crate::slots::SlotDescriptor;
17+
use crate::slots::{SlotDescriptor, SlotGetattro};
1818
use crate::vm::VirtualMachine;
1919

2020
use itertools::Itertools;
@@ -34,7 +34,7 @@ impl PyValue for PySuper {
3434
}
3535
}
3636

37-
#[pyimpl(with(SlotDescriptor))]
37+
#[pyimpl(with(SlotGetattro, SlotDescriptor))]
3838
impl PySuper {
3939
fn new(typ: PyTypeRef, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<Self> {
4040
let obj = if vm.is_none(&obj) {
@@ -55,29 +55,6 @@ impl PySuper {
5555
}
5656
}
5757

58-
#[pymethod(name = "__getattribute__")]
59-
fn getattribute(zelf: PyRef<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
60-
let (inst, obj_type) = match zelf.obj.clone() {
61-
Some(o) => o,
62-
None => return vm.generic_getattribute(zelf.into_object(), name),
63-
};
64-
// skip the classes in obj_type.mro up to and including zelf.typ
65-
let mut it = obj_type.iter_mro().peekable();
66-
for _ in it.peeking_take_while(|cls| !cls.is(&zelf.typ)) {}
67-
for cls in it.skip(1) {
68-
if let Some(descr) = cls.get_attr(name.borrow_value()) {
69-
return vm
70-
.call_get_descriptor_specific(
71-
descr.clone(),
72-
if inst.is(&obj_type) { None } else { Some(inst) },
73-
Some(obj_type.clone().into_object()),
74-
)
75-
.unwrap_or(Ok(descr));
76-
}
77-
}
78-
vm.generic_getattribute(zelf.into_object(), name)
79-
}
80-
8158
#[pyslot]
8259
fn tp_new(
8360
cls: PyTypeRef,
@@ -130,6 +107,30 @@ impl PySuper {
130107
}
131108
}
132109

110+
impl SlotGetattro for PySuper {
111+
fn getattro(zelf: PyRef<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
112+
let (inst, obj_type) = match zelf.obj.clone() {
113+
Some(o) => o,
114+
None => return vm.generic_getattribute(zelf.into_object(), name),
115+
};
116+
// skip the classes in obj_type.mro up to and including zelf.typ
117+
let mut it = obj_type.iter_mro().peekable();
118+
for _ in it.peeking_take_while(|cls| !cls.is(&zelf.typ)) {}
119+
for cls in it.skip(1) {
120+
if let Some(descr) = cls.get_attr(name.borrow_value()) {
121+
return vm
122+
.call_get_descriptor_specific(
123+
descr.clone(),
124+
if inst.is(&obj_type) { None } else { Some(inst) },
125+
Some(obj_type.clone().into_object()),
126+
)
127+
.unwrap_or(Ok(descr));
128+
}
129+
}
130+
vm.generic_getattribute(zelf.into_object(), name)
131+
}
132+
}
133+
133134
impl SlotDescriptor for PySuper {
134135
fn descr_get(
135136
zelf: PyObjectRef,

vm/src/obj/objtype.rs

Lines changed: 62 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::pyobject::{
1717
BorrowValue, Either, IdProtocol, PyAttributes, PyClassImpl, PyContext, PyIterable, PyLease,
1818
PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol,
1919
};
20-
use crate::slots::{self, Callable, PyTpFlags, PyTypeSlots};
20+
use crate::slots::{self, Callable, PyTpFlags, PyTypeSlots, SlotGetattro};
2121
use crate::vm::VirtualMachine;
2222
use itertools::Itertools;
2323
use std::ops::Deref;
@@ -165,7 +165,14 @@ impl PyTypeRef {
165165
} as _;
166166
self.slots.cmp.store(Some(func))
167167
}
168-
_ => (),
168+
"__getattribute__" => {
169+
let func: slots::GetattroFunc = |zelf, name, vm| {
170+
let magic = get_class_magic(&zelf, "__getattribute__");
171+
vm.invoke(&magic, vec![zelf, name.into_object()])
172+
};
173+
self.slots.getattro.store(Some(func))
174+
}
175+
_ => {}
169176
}
170177
}
171178
}
@@ -180,7 +187,7 @@ fn get_class_magic(zelf: &PyObjectRef, name: &str) -> PyObjectRef {
180187
// attrs.get(name).unwrap().clone()
181188
}
182189

183-
#[pyimpl(with(Callable), flags(BASETYPE))]
190+
#[pyimpl(with(SlotGetattro, Callable), flags(BASETYPE))]
184191
impl PyType {
185192
#[pyproperty(name = "__mro__")]
186193
fn get_mro(zelf: PyRef<Self>) -> PyTuple {
@@ -266,53 +273,6 @@ impl PyType {
266273
vm.ctx.new_dict()
267274
}
268275

269-
#[pymethod(magic)]
270-
fn getattribute(zelf: PyRef<Self>, name_ref: PyStrRef, vm: &VirtualMachine) -> PyResult {
271-
let name = name_ref.borrow_value();
272-
vm_trace!("type.__getattribute__({:?}, {:?})", zelf, name);
273-
let mcl = zelf.lease_class();
274-
275-
if let Some(attr) = mcl.get_attr(&name) {
276-
let attr_class = attr.lease_class();
277-
if attr_class.has_attr("__set__") {
278-
if let Some(ref descr_get) =
279-
PyLease::into_pyref(attr_class).first_in_mro(|cls| cls.slots.descr_get.load())
280-
{
281-
let mcl = PyLease::into_pyref(mcl).into_object();
282-
return descr_get(attr, Some(zelf.into_object()), Some(mcl), vm);
283-
}
284-
}
285-
}
286-
287-
if let Some(attr) = zelf.get_attr(&name) {
288-
let attr_class = attr.class();
289-
if let Some(ref descr_get) = attr_class.first_in_mro(|cls| cls.slots.descr_get.load()) {
290-
drop(mcl);
291-
return descr_get(attr, None, Some(zelf.into_object()), vm);
292-
}
293-
}
294-
295-
if let Some(cls_attr) = zelf.get_attr(&name) {
296-
Ok(cls_attr)
297-
} else if let Some(attr) = mcl.get_attr(&name) {
298-
drop(mcl);
299-
vm.call_if_get_descriptor(attr, zelf.into_object())
300-
} else if let Some(ref getter) = zelf.get_attr("__getattr__") {
301-
vm.invoke(
302-
getter,
303-
vec![
304-
PyLease::into_pyref(mcl).into_object(),
305-
name_ref.into_object(),
306-
],
307-
)
308-
} else {
309-
Err(vm.new_attribute_error(format!(
310-
"type object '{}' has no attribute '{}'",
311-
zelf, name
312-
)))
313-
}
314-
}
315-
316276
#[pymethod(magic)]
317277
fn setattr(
318278
zelf: PyRef<Self>,
@@ -510,6 +470,58 @@ impl PyType {
510470
}
511471
}
512472

473+
impl SlotGetattro for PyType {
474+
fn getattro(zelf: PyRef<Self>, name_ref: PyStrRef, vm: &VirtualMachine) -> PyResult {
475+
let name = name_ref.borrow_value();
476+
vm_trace!("type.__getattribute__({:?}, {:?})", zelf, name);
477+
let mcl = zelf.lease_class();
478+
479+
let mcl_attr = mcl.get_attr(name);
480+
481+
if let Some(ref attr) = mcl_attr {
482+
let attr_class = attr.lease_class();
483+
if attr_class.has_attr("__set__") {
484+
if let Some(ref descr_get) =
485+
PyLease::into_pyref(attr_class).first_in_mro(|cls| cls.slots.descr_get.load())
486+
{
487+
let mcl = PyLease::into_pyref(mcl).into_object();
488+
return descr_get(attr.clone(), Some(zelf.into_object()), Some(mcl), vm);
489+
}
490+
}
491+
}
492+
493+
let zelf_attr = zelf.get_attr(name);
494+
495+
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()) {
498+
drop(mcl);
499+
return descr_get(attr.clone(), None, Some(zelf.into_object()), vm);
500+
}
501+
}
502+
503+
if let Some(cls_attr) = zelf_attr {
504+
Ok(cls_attr)
505+
} else if let Some(attr) = mcl_attr {
506+
drop(mcl);
507+
vm.call_if_get_descriptor(attr, zelf.into_object())
508+
} else if let Some(ref getter) = zelf.get_attr("__getattr__") {
509+
vm.invoke(
510+
getter,
511+
vec![
512+
PyLease::into_pyref(mcl).into_object(),
513+
name_ref.into_object(),
514+
],
515+
)
516+
} else {
517+
Err(vm.new_attribute_error(format!(
518+
"type object '{}' has no attribute '{}'",
519+
zelf, name
520+
)))
521+
}
522+
}
523+
}
524+
513525
impl Callable for PyType {
514526
fn call(zelf: &PyRef<Self>, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
515527
vm_trace!("type_call: {:?}", zelf);

0 commit comments

Comments
 (0)