mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Add non-iterability guard, deduplicate dict flush and missing args format
This commit is contained in:
1 parent
cc8d9a2c53
commit
8303c7a48b
3 files changed
+68
-74
No files matched your search
@@ -6670,6 +6670,23 @@ impl Compiler {
|
||||
let mut have_dict = false;
|
||||
let mut elements: u32 = 0;
|
||||
|
||||
// Flush pending regular pairs as a BUILD_MAP, merging into the
|
||||
// accumulator dict via DICT_UPDATE when one already exists.
|
||||
macro_rules! flush_pending {
|
||||
() => {
|
||||
#[allow(unused_assignments)]
|
||||
if elements > 0 {
|
||||
emit!(self, Instruction::BuildMap { size: elements });
|
||||
if have_dict {
|
||||
emit!(self, Instruction::DictUpdate { index: 1 });
|
||||
} else {
|
||||
have_dict = true;
|
||||
}
|
||||
elements = 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
for item in items {
|
||||
if let Some(key) = &item.key {
|
||||
// Regular key: value pair
|
||||
@@ -6678,17 +6695,7 @@ impl Compiler {
|
||||
elements += 1;
|
||||
} else {
|
||||
// ** unpacking entry
|
||||
if elements > 0 {
|
||||
// Flush pending regular pairs
|
||||
if !have_dict {
|
||||
emit!(self, Instruction::BuildMap { size: elements });
|
||||
have_dict = true;
|
||||
} else {
|
||||
emit!(self, Instruction::BuildMap { size: elements });
|
||||
emit!(self, Instruction::DictUpdate { index: 1 });
|
||||
}
|
||||
elements = 0;
|
||||
}
|
||||
flush_pending!();
|
||||
if !have_dict {
|
||||
emit!(self, Instruction::BuildMap { size: 0 });
|
||||
have_dict = true;
|
||||
@@ -6698,13 +6705,9 @@ impl Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
if elements > 0 || !have_dict {
|
||||
if !have_dict {
|
||||
emit!(self, Instruction::BuildMap { size: elements });
|
||||
} else {
|
||||
emit!(self, Instruction::BuildMap { size: elements });
|
||||
emit!(self, Instruction::DictUpdate { index: 1 });
|
||||
}
|
||||
flush_pending!();
|
||||
if !have_dict {
|
||||
emit!(self, Instruction::BuildMap { size: 0 });
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -25,6 +25,37 @@ use itertools::Itertools;
|
||||
#[cfg(feature = "jit")]
|
||||
use rustpython_jit::CompiledCode;
|
||||
|
||||
fn format_missing_args(
|
||||
qualname: impl core::fmt::Display,
|
||||
kind: &str,
|
||||
missing: &mut Vec<impl core::fmt::Display>,
|
||||
) -> String {
|
||||
let count = missing.len();
|
||||
let last = if missing.len() > 1 {
|
||||
missing.pop()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let (and, right): (&str, String) = if let Some(last) = last {
|
||||
(
|
||||
if missing.len() == 1 {
|
||||
"' and '"
|
||||
} else {
|
||||
"', and '"
|
||||
},
|
||||
format!("{last}"),
|
||||
)
|
||||
} else {
|
||||
("", String::new())
|
||||
};
|
||||
format!(
|
||||
"{qualname}() missing {count} required {kind} argument{}: '{}{}{right}'",
|
||||
if count == 1 { "" } else { "s" },
|
||||
missing.iter().join("', '"),
|
||||
and,
|
||||
)
|
||||
}
|
||||
|
||||
#[pyclass(module = false, name = "function", traverse = "manual")]
|
||||
#[derive(Debug)]
|
||||
pub struct PyFunction {
|
||||
@@ -343,36 +374,12 @@ impl PyFunction {
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let missing_args_len = missing.len();
|
||||
|
||||
if !missing.is_empty() {
|
||||
let last = if missing.len() > 1 {
|
||||
missing.pop()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (and, right) = if let Some(last) = last {
|
||||
(
|
||||
if missing.len() == 1 {
|
||||
"' and '"
|
||||
} else {
|
||||
"', and '"
|
||||
},
|
||||
last.as_str(),
|
||||
)
|
||||
} else {
|
||||
("", "")
|
||||
};
|
||||
|
||||
return Err(vm.new_type_error(format!(
|
||||
"{}() missing {} required positional argument{}: '{}{}{}'",
|
||||
return Err(vm.new_type_error(format_missing_args(
|
||||
self.__qualname__(),
|
||||
missing_args_len,
|
||||
if missing_args_len == 1 { "" } else { "s" },
|
||||
missing.iter().join("', '"),
|
||||
and,
|
||||
right,
|
||||
"positional",
|
||||
&mut missing,
|
||||
)));
|
||||
}
|
||||
|
||||
@@ -413,34 +420,10 @@ impl PyFunction {
|
||||
}
|
||||
|
||||
if !missing.is_empty() {
|
||||
let missing_len = missing.len();
|
||||
let last = if missing.len() > 1 {
|
||||
missing.pop()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (and, right) = if let Some(last) = last {
|
||||
(
|
||||
if missing.len() == 1 {
|
||||
"' and '"
|
||||
} else {
|
||||
"', and '"
|
||||
},
|
||||
last.as_str(),
|
||||
)
|
||||
} else {
|
||||
("", "")
|
||||
};
|
||||
|
||||
return Err(vm.new_type_error(format!(
|
||||
"{}() missing {} required keyword-only argument{}: '{}{}{}'",
|
||||
return Err(vm.new_type_error(format_missing_args(
|
||||
self.__qualname__(),
|
||||
missing_len,
|
||||
if missing_len == 1 { "" } else { "s" },
|
||||
missing.iter().join("', '"),
|
||||
and,
|
||||
right,
|
||||
"keyword-only",
|
||||
&mut missing,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
+10
-2
@@ -2803,8 +2803,12 @@ impl ExecutingFrame<'_> {
|
||||
fn execute_unpack_ex(&mut self, vm: &VirtualMachine, before: u8, after: u8) -> FrameResult {
|
||||
let (before, after) = (before as usize, after as usize);
|
||||
let value = self.pop_value();
|
||||
let not_iterable = value.class().slots.iter.load().is_none()
|
||||
&& value
|
||||
.get_class_attr(vm.ctx.intern_str("__getitem__"))
|
||||
.is_none();
|
||||
let elements: Vec<_> = value.try_to_value(vm).map_err(|e| {
|
||||
if e.class().is(vm.ctx.exceptions.type_error) {
|
||||
if not_iterable && e.class().is(vm.ctx.exceptions.type_error) {
|
||||
vm.new_type_error(format!(
|
||||
"cannot unpack non-iterable {} object",
|
||||
value.class().name()
|
||||
@@ -3013,8 +3017,12 @@ impl ExecutingFrame<'_> {
|
||||
|
||||
fn unpack_sequence(&mut self, size: u32, vm: &VirtualMachine) -> FrameResult {
|
||||
let value = self.pop_value();
|
||||
let not_iterable = value.class().slots.iter.load().is_none()
|
||||
&& value
|
||||
.get_class_attr(vm.ctx.intern_str("__getitem__"))
|
||||
.is_none();
|
||||
let elements: Vec<_> = value.try_to_value(vm).map_err(|e| {
|
||||
if e.class().is(vm.ctx.exceptions.type_error) {
|
||||
if not_iterable && e.class().is(vm.ctx.exceptions.type_error) {
|
||||
vm.new_type_error(format!(
|
||||
"cannot unpack non-iterable {} object",
|
||||
value.class().name()
|
||||
|
||||
Reference in new issue
Block a user