Skip to content

Commit 7ed4bc4

Browse files
Merge pull request #698 from palaviv/super
Use first argument in super
2 parents 5e74d53 + 2c8657c commit 7ed4bc4

File tree

3 files changed

+74
-9
lines changed

3 files changed

+74
-9
lines changed

tests/snippets/class.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,33 @@ def test1(self):
7575
assert c.test() == 100
7676
assert c.test1() == 200
7777

78+
class Me():
79+
80+
def test(me):
81+
return 100
82+
83+
class Me2(Me):
84+
85+
def test(me):
86+
return super().test()
87+
88+
class A():
89+
def f(self):
90+
pass
91+
92+
class B(A):
93+
def f(self):
94+
super().f()
95+
96+
class C(B):
97+
def f(self):
98+
super().f()
99+
100+
C().f()
101+
102+
me = Me2()
103+
assert me.test() == 100
104+
78105
a = super(bool, True)
79106
assert isinstance(a, super)
80107
assert type(a) is super

vm/src/frame.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ pub trait NameProtocol {
126126
fn load_name(&self, vm: &VirtualMachine, name: &str) -> Option<PyObjectRef>;
127127
fn store_name(&self, vm: &VirtualMachine, name: &str, value: PyObjectRef);
128128
fn delete_name(&self, vm: &VirtualMachine, name: &str);
129+
fn load_cell(&self, vm: &VirtualMachine, name: &str) -> Option<PyObjectRef>;
129130
}
130131

131132
impl NameProtocol for Scope {
@@ -143,6 +144,15 @@ impl NameProtocol for Scope {
143144
vm.builtins.get_item(name)
144145
}
145146

147+
fn load_cell(&self, _vm: &VirtualMachine, name: &str) -> Option<PyObjectRef> {
148+
for dict in self.locals.iter().skip(1) {
149+
if let Some(value) = dict.get_item(name) {
150+
return Some(value);
151+
}
152+
}
153+
None
154+
}
155+
146156
fn store_name(&self, vm: &VirtualMachine, key: &str, value: PyObjectRef) {
147157
self.get_locals().set_item(&vm.ctx, key, value)
148158
}

vm/src/obj/objsuper.rs

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ https://github.com/python/cpython/blob/50b48572d9a90c5bb36e2bef6179548ea927a35a/
66
77
*/
88

9+
use crate::frame::NameProtocol;
910
use crate::function::PyFuncArgs;
11+
use crate::obj::objstr;
1012
use crate::obj::objtype::PyClass;
1113
use crate::pyobject::{
1214
DictProtocol, PyContext, PyObject, PyObjectRef, PyResult, PyValue, TypeProtocol,
@@ -18,6 +20,7 @@ use super::objtype;
1820
#[derive(Debug)]
1921
pub struct PySuper {
2022
obj: PyObjectRef,
23+
typ: PyObjectRef,
2124
}
2225

2326
impl PyValue for PySuper {
@@ -67,15 +70,20 @@ fn super_getattribute(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
6770
);
6871

6972
let inst = super_obj.payload::<PySuper>().unwrap().obj.clone();
73+
let typ = super_obj.payload::<PySuper>().unwrap().typ.clone();
7074

71-
match inst.typ().payload::<PyClass>() {
75+
match typ.payload::<PyClass>() {
7276
Some(PyClass { ref mro, .. }) => {
7377
for class in mro {
7478
if let Ok(item) = vm.get_attribute(class.as_object().clone(), name_str.clone()) {
7579
return Ok(vm.ctx.new_bound_method(item, inst.clone()));
7680
}
7781
}
78-
Err(vm.new_attribute_error(format!("{} has no attribute '{}'", inst, name_str)))
82+
Err(vm.new_attribute_error(format!(
83+
"{} has no attribute '{}'",
84+
inst,
85+
objstr::get_value(name_str)
86+
)))
7987
}
8088
_ => panic!("not Class"),
8189
}
@@ -98,9 +106,13 @@ fn super_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
98106
let py_type = if let Some(ty) = py_type {
99107
ty.clone()
100108
} else {
101-
match vm.get_locals().get_item("self") {
102-
Some(obj) => obj.typ().clone(),
103-
_ => panic!("No self"),
109+
match vm.current_scope().load_cell(vm, "__class__") {
110+
Some(obj) => obj.clone(),
111+
_ => {
112+
return Err(vm.new_type_error(
113+
"super must be called with 1 argument or from inside class method".to_string(),
114+
));
115+
}
104116
}
105117
};
106118

@@ -117,9 +129,19 @@ fn super_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
117129
let py_obj = if let Some(obj) = py_obj {
118130
obj.clone()
119131
} else {
120-
match vm.get_locals().get_item("self") {
121-
Some(obj) => obj,
122-
_ => panic!("No self"),
132+
let frame = vm.current_frame();
133+
if let Some(first_arg) = frame.code.arg_names.get(0) {
134+
match vm.get_locals().get_item(first_arg) {
135+
Some(obj) => obj.clone(),
136+
_ => {
137+
return Err(vm
138+
.new_type_error(format!("super arguement {} was not supplied", first_arg)));
139+
}
140+
}
141+
} else {
142+
return Err(vm.new_type_error(
143+
"super must be called with 1 argument or from inside class method".to_string(),
144+
));
123145
}
124146
};
125147

@@ -130,5 +152,11 @@ fn super_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
130152
));
131153
}
132154

133-
Ok(PyObject::new(PySuper { obj: py_obj }, cls.clone()))
155+
Ok(PyObject::new(
156+
PySuper {
157+
obj: py_obj,
158+
typ: py_type,
159+
},
160+
cls.clone(),
161+
))
134162
}

0 commit comments

Comments
 (0)