Resolve the receiver's method and call directly; args come from CallMethodArgs. */
(&mut self, attr_idx: u16, call_op: u16, chunk: &SSAChunk, slots: &mut [Val])
| 263 | |
| 264 | /* Resolve the receiver's method and call directly; args come from CallMethodArgs. */ |
| 265 | fn exec_call_method(&mut self, attr_idx: u16, call_op: u16, chunk: &SSAChunk, slots: &mut [Val]) -> Result<(), VmErr> { |
| 266 | let raw = call_op as usize; |
| 267 | let num_kw = (raw >> 8) & 0xFF; |
| 268 | let num_pos = raw & 0xFF; |
| 269 | let total = num_pos + 2 * num_kw; |
| 270 | |
| 271 | let mut stack_items: Vec<Val> = (0..total).map(|_| self.pop()).collect::<Result<_, _>>()?; |
| 272 | stack_items.reverse(); |
| 273 | |
| 274 | let kw_flat: Vec<Val> = stack_items.split_off(num_pos); |
| 275 | let positional = stack_items; |
| 276 | |
| 277 | let obj = self.pop()?; |
| 278 | let name = chunk.names.get(attr_idx as usize).ok_or(VmErr::Runtime("CallMethod: bad name index"))?.clone(); |
| 279 | |
| 280 | let lookup = match self.resolve_attr(obj, &name) { |
| 281 | Ok(l) => l, |
| 282 | Err(VmErr::Attribute(msg)) => { |
| 283 | // if `__getattr__` resolves the name to a callable, invoke it with the positional args. |
| 284 | if let Some(v) = self.try_getattr_fallback(obj, &name, chunk, slots)? { |
| 285 | self.push(v); |
| 286 | for a in &positional { self.push(*a); } |
| 287 | for a in &kw_flat { self.push(*a); } |
| 288 | let argc = positional.len() as u16; |
| 289 | let encoded = ((kw_flat.len() as u16 / 2) << 8) | argc; |
| 290 | return self.exec_call(encoded, chunk, slots); |
| 291 | } |
| 292 | return Err(VmErr::Attribute(msg)); |
| 293 | } |
| 294 | Err(other) => return Err(other), |
| 295 | }; |
| 296 | match lookup { |
| 297 | handlers::methods::AttrLookup::ModuleAttr(callee) |
| 298 | | handlers::methods::AttrLookup::ClassMember(callee) => { |
| 299 | // Direct call on the resolved value, no `self` prepended. |
| 300 | self.push(callee); |
| 301 | for a in &positional { self.push(*a); } |
| 302 | for a in &kw_flat { self.push(*a); } |
| 303 | let argc = positional.len() as u16; |
| 304 | let encoded = ((kw_flat.len() as u16 / 2) << 8) | argc; |
| 305 | self.exec_call(encoded, chunk, slots) |
| 306 | } |
| 307 | handlers::methods::AttrLookup::InstanceMethod { recv, func, class } => { |
| 308 | // Prepend `self`; kwargs aren't forwarded (preserved behaviour). `super()` reads the binding off `pending`. |
| 309 | self.pending.method_binding = Some((class, recv)); |
| 310 | self.push(func); |
| 311 | self.push(recv); |
| 312 | for a in &positional { self.push(*a); } |
| 313 | let argc = (positional.len() + 1) as u16; |
| 314 | let encoded = ((kw_flat.len() as u16 / 2) << 8) | argc; |
| 315 | self.exec_call(encoded, chunk, slots) |
| 316 | } |
| 317 | handlers::methods::AttrLookup::BuiltinMethod(id) => { |
| 318 | // sort runs user __lt__, so it needs chunk/slots the builtin-method table can't carry. |
| 319 | if id.name() == "sort" { return self.exec_sort(obj, &positional, &kw_flat, chunk, slots); } |
| 320 | self.exec_bound_method(obj, id, &positional, &kw_flat) |
| 321 | } |
| 322 | handlers::methods::AttrLookup::InstanceField(field) => { |
no test coverage detected