(
&self,
frame: &Frame,
func_args: FuncArgs,
vm: &VirtualMachine,
)
| 220 | } |
| 221 | |
| 222 | fn fill_locals_from_args( |
| 223 | &self, |
| 224 | frame: &Frame, |
| 225 | func_args: FuncArgs, |
| 226 | vm: &VirtualMachine, |
| 227 | ) -> PyResult<()> { |
| 228 | let code: &Py<PyCode> = &self.code; |
| 229 | let nargs = func_args.args.len(); |
| 230 | let n_expected_args = code.arg_count as usize; |
| 231 | let total_args = code.arg_count as usize + code.kwonlyarg_count as usize; |
| 232 | // let arg_names = self.code.arg_names(); |
| 233 | |
| 234 | // This parses the arguments from args and kwargs into |
| 235 | // the proper variables keeping into account default values |
| 236 | // and star-args and kwargs. |
| 237 | // See also: PyEval_EvalCodeWithName in cpython: |
| 238 | // https://github.com/python/cpython/blob/main/Python/ceval.c#L3681 |
| 239 | |
| 240 | // SAFETY: Frame was just created and not yet executing. |
| 241 | let fastlocals = unsafe { frame.fastlocals_mut() }; |
| 242 | |
| 243 | let mut args_iter = func_args.args.into_iter(); |
| 244 | |
| 245 | // Copy positional arguments into local variables |
| 246 | // zip short-circuits if either iterator returns None, which is the behavior we want -- |
| 247 | // only fill as much as there is to fill with as much as we have |
| 248 | for (local, arg) in Iterator::zip( |
| 249 | fastlocals.iter_mut().take(n_expected_args), |
| 250 | args_iter.by_ref().take(nargs), |
| 251 | ) { |
| 252 | *local = Some(arg); |
| 253 | } |
| 254 | |
| 255 | let mut vararg_offset = total_args; |
| 256 | // Pack other positional arguments in to *args: |
| 257 | if code.flags.contains(bytecode::CodeFlags::VARARGS) { |
| 258 | let vararg_value = vm.ctx.new_tuple(args_iter.collect()); |
| 259 | fastlocals[vararg_offset] = Some(vararg_value.into()); |
| 260 | vararg_offset += 1; |
| 261 | } else { |
| 262 | // Check the number of positional arguments |
| 263 | if nargs > n_expected_args { |
| 264 | let n_defaults = self |
| 265 | .defaults_and_kwdefaults |
| 266 | .lock() |
| 267 | .0 |
| 268 | .as_ref() |
| 269 | .map_or(0, |d| d.len()); |
| 270 | let n_required = n_expected_args - n_defaults; |
| 271 | let takes_msg = if n_defaults > 0 { |
| 272 | format!("from {} to {}", n_required, n_expected_args) |
| 273 | } else { |
| 274 | n_expected_args.to_string() |
| 275 | }; |
| 276 | |
| 277 | // Count keyword-only arguments that were actually provided |
| 278 | let kw_only_given = if code.kwonlyarg_count > 0 { |
| 279 | let start = code.arg_count as usize; |
no test coverage detected