|
1 | 1 | use super::VirtualMachine; |
2 | 2 | use crate::stdlib::_warnings; |
3 | 3 | use crate::{ |
4 | | - PyRef, |
5 | | - builtins::{PyInt, PyStr, PyStrRef, PyUtf8Str}, |
| 4 | + Py, PyRef, |
| 5 | + builtins::{PyInt, PyStr, PyStrInterned, PyStrRef, PyType, PyUtf8Str}, |
6 | 6 | object::{AsObject, PyObject, PyObjectRef, PyResult}, |
7 | 7 | protocol::{PyNumberBinaryOp, PyNumberTernaryOp}, |
8 | 8 | types::PyComparisonOp, |
9 | 9 | }; |
10 | 10 | use num_traits::ToPrimitive; |
11 | 11 |
|
| 12 | +//github.com/ [CPython `method_is_overloaded`](https://github.com/python/cpython/blob/v3.14.3/Objects/typeobject.c#L9849-L9879) |
| 13 | +fn method_is_overloaded( |
| 14 | + class_a: &Py<PyType>, |
| 15 | + class_b: &Py<PyType>, |
| 16 | + rop_name: Option<&'static PyStrInterned>, |
| 17 | + vm: &VirtualMachine, |
| 18 | +) -> PyResult<bool> { |
| 19 | + let Some(rop_name) = rop_name else { |
| 20 | + return Ok(false); |
| 21 | + }; |
| 22 | + let Some(method_b) = class_b.get_attr(rop_name) else { |
| 23 | + return Ok(false); |
| 24 | + }; |
| 25 | + class_a.get_attr(rop_name).map_or(Ok(true), |method_a| { |
| 26 | + vm.identical_or_equal(&method_a, &method_b).map(|eq| !eq) |
| 27 | + }) |
| 28 | +} |
| 29 | + |
12 | 30 | macro_rules! binary_func { |
13 | 31 | ($fn:ident, $op_slot:ident, $op:expr) => { |
14 | 32 | pub fn $fn(&self, a: &PyObject, b: &PyObject) -> PyResult { |
@@ -162,18 +180,34 @@ impl VirtualMachine { |
162 | 180 |
|
163 | 181 | // Number slots are inherited, direct access is O(1) |
164 | 182 | let slot_a = class_a.slots.as_number.left_binary_op(op_slot); |
| 183 | + let slot_a_addr = slot_a.map(|x| x as usize); |
165 | 184 | let mut slot_b = None; |
| 185 | + let left_b_addr; |
166 | 186 |
|
167 | 187 | if !class_a.is(class_b) { |
168 | 188 | let slot_bb = class_b.slots.as_number.right_binary_op(op_slot); |
169 | | - if slot_bb.map(|x| x as usize) != slot_a.map(|x| x as usize) { |
| 189 | + if slot_bb.map(|x| x as usize) != slot_a_addr { |
170 | 190 | slot_b = slot_bb; |
171 | 191 | } |
| 192 | + left_b_addr = class_b |
| 193 | + .slots |
| 194 | + .as_number |
| 195 | + .left_binary_op(op_slot) |
| 196 | + .map(|x| x as usize); |
| 197 | + } else { |
| 198 | + left_b_addr = slot_a_addr; |
172 | 199 | } |
173 | 200 |
|
174 | 201 | if let Some(slot_a) = slot_a { |
175 | 202 | if let Some(slot_bb) = slot_b |
176 | 203 | && class_b.fast_issubclass(class_a) |
| 204 | + && (slot_a_addr != left_b_addr |
| 205 | + || method_is_overloaded( |
| 206 | + class_a, |
| 207 | + class_b, |
| 208 | + op_slot.right_method_name(self), |
| 209 | + self, |
| 210 | + )?) |
177 | 211 | { |
178 | 212 | let ret = slot_bb(a, b, self)?; |
179 | 213 | if !ret.is(&self.ctx.not_implemented) { |
@@ -269,18 +303,34 @@ impl VirtualMachine { |
269 | 303 |
|
270 | 304 | // Number slots are inherited, direct access is O(1) |
271 | 305 | let slot_a = class_a.slots.as_number.left_ternary_op(op_slot); |
| 306 | + let slot_a_addr = slot_a.map(|x| x as usize); |
272 | 307 | let mut slot_b = None; |
| 308 | + let left_b_addr; |
273 | 309 |
|
274 | 310 | if !class_a.is(class_b) { |
275 | 311 | let slot_bb = class_b.slots.as_number.right_ternary_op(op_slot); |
276 | | - if slot_bb.map(|x| x as usize) != slot_a.map(|x| x as usize) { |
| 312 | + if slot_bb.map(|x| x as usize) != slot_a_addr { |
277 | 313 | slot_b = slot_bb; |
278 | 314 | } |
| 315 | + left_b_addr = class_b |
| 316 | + .slots |
| 317 | + .as_number |
| 318 | + .left_ternary_op(op_slot) |
| 319 | + .map(|x| x as usize); |
| 320 | + } else { |
| 321 | + left_b_addr = slot_a_addr; |
279 | 322 | } |
280 | 323 |
|
281 | 324 | if let Some(slot_a) = slot_a { |
282 | 325 | if let Some(slot_bb) = slot_b |
283 | 326 | && class_b.fast_issubclass(class_a) |
| 327 | + && (slot_a_addr != left_b_addr |
| 328 | + || method_is_overloaded( |
| 329 | + class_a, |
| 330 | + class_b, |
| 331 | + op_slot.right_method_name(self), |
| 332 | + self, |
| 333 | + )?) |
284 | 334 | { |
285 | 335 | let ret = slot_bb(a, b, c, self)?; |
286 | 336 | if !ret.is(&self.ctx.not_implemented) { |
|
0 commit comments