* Slight cleanup of super.rs

* frame.rs

* buffer.rs

* bool.rs
This commit is contained in:
Shahar Naveh
2026-05-19 07:31:21 +03:00
committed by GitHub
parent e16f1aa657
commit 67e66bdc75
8 changed files with 116 additions and 80 deletions

View File

@@ -18,7 +18,7 @@ type UnpackFunc = fn(&VirtualMachine, &[u8]) -> PyObjectRef;
static OVERFLOW_MSG: &str = "total struct size too long"; // not a const to reduce code size
#[derive(Debug, Copy, Clone, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum Endianness {
Native,
Little,
@@ -40,7 +40,12 @@ impl Endianness {
Some(b'>' | b'!') => Self::Big,
_ => return Self::Native,
};
chars.next().unwrap();
// SAFETY:
// We just ensured with `chars.peek()` that this is safe
unsafe {
let _ = chars.next().unwrap_unchecked();
}
e
}
}
@@ -48,13 +53,17 @@ impl Endianness {
trait ByteOrder {
fn convert<I: PrimInt>(i: I) -> I;
}
enum BigEndian {}
impl ByteOrder for BigEndian {
fn convert<I: PrimInt>(i: I) -> I {
i.to_be()
}
}
enum LittleEndian {}
impl ByteOrder for LittleEndian {
fn convert<I: PrimInt>(i: I) -> I {
i.to_le()
@@ -66,7 +75,7 @@ type NativeEndian = cfg_select! {
target_endian = "little" => LittleEndian,
};
#[derive(Copy, Clone, num_enum::TryFromPrimitive)]
#[derive(Copy, Clone, num_enum::TryFromPrimitive, Eq, PartialEq)]
#[repr(u8)]
pub(crate) enum FormatType {
Pad = b'x',
@@ -105,6 +114,7 @@ impl FormatType {
fn info(self, e: Endianness) -> &'static FormatInfo {
use FormatType::*;
use mem::{align_of, size_of};
macro_rules! native_info {
($t:ty) => {{
&FormatInfo {
@@ -115,6 +125,7 @@ impl FormatType {
}
}};
}
macro_rules! nonnative_info {
($t:ty, $end:ty) => {{
&FormatInfo {
@@ -125,6 +136,7 @@ impl FormatType {
}
}};
}
macro_rules! match_nonnative {
($zelf:expr, $end:ty) => {{
match $zelf {
@@ -158,6 +170,7 @@ impl FormatType {
}
}};
}
match e {
Endianness::Native => match self {
Pad | Str | Pascal => &FormatInfo {
@@ -381,6 +394,7 @@ pub(crate) struct FormatInfo {
pub pack: Option<PackFunc>,
pub unpack: Option<UnpackFunc>,
}
impl fmt::Debug for FormatInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FormatInfo")

View File

@@ -37,8 +37,7 @@ impl PyObjectRef {
pub fn try_to_bool(self, vm: &VirtualMachine) -> PyResult<bool> {
if self.is(&vm.ctx.true_value) {
return Ok(true);
}
if self.is(&vm.ctx.false_value) {
} else if self.is(&vm.ctx.false_value) {
return Ok(false);
}
@@ -83,10 +82,9 @@ impl Constructor for PyBool {
fn slot_new(zelf: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
let x: Self::Args = args.bind(vm)?;
if !zelf.fast_isinstance(vm.ctx.types.type_type) {
let actual_class = zelf.class();
let actual_type = &actual_class.name();
return Err(vm.new_type_error(format!(
"requires a 'type' object but received a '{actual_type}'"
"requires a 'type' object but received a '{}'",
zelf.class().name()
)));
}
let val = x.map_or(Ok(false), |val| val.try_to_bool(vm))?;

View File

@@ -43,19 +43,19 @@ pub(crate) mod stack_analysis {
}
impl Kind {
fn from_i64(v: i64) -> Option<Self> {
match v {
1 => Some(Self::Iterator),
2 => Some(Self::Except),
3 => Some(Self::Object),
4 => Some(Self::Null),
5 => Some(Self::Lasti),
_ => None,
}
const fn from_i64(v: i64) -> Option<Self> {
Some(match v {
1 => Self::Iterator,
2 => Self::Except,
3 => Self::Object,
4 => Self::Null,
5 => Self::Lasti,
_ => return None,
})
}
}
pub(crate) fn push_value(stack: i64, kind: i64) -> i64 {
pub(crate) const fn push_value(stack: i64, kind: i64) -> i64 {
if (stack as u64) >= WILL_OVERFLOW {
OVERFLOWED
} else {
@@ -63,20 +63,20 @@ pub(crate) mod stack_analysis {
}
}
pub(crate) fn pop_value(stack: i64) -> i64 {
pub(crate) const fn pop_value(stack: i64) -> i64 {
stack >> BITS_PER_BLOCK
}
pub(crate) fn top_of_stack(stack: i64) -> i64 {
pub(crate) const fn top_of_stack(stack: i64) -> i64 {
stack & MASK
}
fn peek(stack: i64, n: u32) -> i64 {
const fn peek(stack: i64, n: u32) -> i64 {
debug_assert!(n >= 1);
(stack >> (BITS_PER_BLOCK * (n - 1))) & MASK
}
fn stack_swap(stack: i64, n: u32) -> i64 {
const fn stack_swap(stack: i64, n: u32) -> i64 {
debug_assert!(n >= 1);
let to_swap = peek(stack, n);
let top = top_of_stack(stack);
@@ -85,7 +85,7 @@ pub(crate) mod stack_analysis {
(replaced_low & !MASK) | to_swap
}
fn pop_to_level(mut stack: i64, level: u32) -> i64 {
const fn pop_to_level(mut stack: i64, level: u32) -> i64 {
if level == 0 {
return EMPTY_STACK;
}
@@ -97,20 +97,21 @@ pub(crate) mod stack_analysis {
stack
}
fn compatible_kind(from: i64, to: i64) -> bool {
#[must_use]
const fn compatible_kind(from: i64, to: i64) -> bool {
if to == 0 {
return false;
false
} else if to == Kind::Object as i64 {
from != Kind::Null as i64
} else if to == Kind::Null as i64 {
true
} else {
from == to
}
if to == Kind::Object as i64 {
return from != Kind::Null as i64;
}
if to == Kind::Null as i64 {
return true;
}
from == to
}
pub(crate) fn compatible_stack(from_stack: i64, to_stack: i64) -> bool {
#[must_use]
pub(crate) const fn compatible_stack(from_stack: i64, to_stack: i64) -> bool {
if from_stack < 0 || to_stack < 0 {
return false;
}
@@ -131,14 +132,17 @@ pub(crate) mod stack_analysis {
to == 0
}
pub(crate) fn explain_incompatible_stack(to_stack: i64) -> &'static str {
pub(crate) const fn explain_incompatible_stack(to_stack: i64) -> &'static str {
debug_assert!(to_stack != 0);
if to_stack == OVERFLOWED {
return "stack is too deep to analyze";
}
if to_stack == UNINITIALIZED {
return "can't jump into an exception handler, or code may be unreachable";
}
match Kind::from_i64(top_of_stack(to_stack)) {
Some(Kind::Except) => "can't jump into an 'except' block as there's no exception",
Some(Kind::Lasti) => "can't jump into a re-raising block as there's no location",

View File

@@ -33,11 +33,13 @@ fn format_missing_args(
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 {
@@ -45,11 +47,12 @@ fn format_missing_args(
} else {
"', and '"
},
format!("{last}"),
last.to_string(),
)
} else {
("", String::new())
};
format!(
"{qualname}() missing {count} required {kind} argument{}: '{}{}{right}'",
if count == 1 { "" } else { "s" },
@@ -1268,12 +1271,12 @@ impl PyBoundMethod {
}
#[inline]
pub(crate) fn function_obj(&self) -> &PyObjectRef {
pub(crate) const fn function_obj(&self) -> &PyObjectRef {
&self.function
}
#[inline]
pub(crate) fn self_obj(&self) -> &PyObjectRef {
pub(crate) const fn self_obj(&self) -> &PyObjectRef {
&self.object
}
@@ -1398,6 +1401,7 @@ impl Representable for PyBoundMethod {
pub(crate) struct PyCell {
contents: PyMutex<Option<PyObjectRef>>,
}
pub(crate) type PyCellRef = PyRef<PyCell>;
impl PyPayload for PyCell {
@@ -1426,6 +1430,7 @@ impl PyCell {
pub(crate) fn get(&self) -> Option<PyObjectRef> {
self.contents.lock().clone()
}
pub(crate) fn set(&self, x: Option<PyObjectRef>) {
*self.contents.lock() = x;
}
@@ -1435,6 +1440,7 @@ impl PyCell {
self.get()
.ok_or_else(|| vm.new_value_error("Cell is empty"))
}
#[pygetset(setter)]
fn set_cell_contents(&self, x: PySetterValue) {
match x {
@@ -1488,6 +1494,7 @@ pub(crate) fn vectorcall_function(
args.truncate(nargs);
FuncArgs::from(args)
};
zelf.invoke(func_args, vm)
}

View File

@@ -86,6 +86,7 @@ impl Initializer for PySuper {
if frame.code.arg_count == 0 {
return Err(vm.new_runtime_error("super(): no arguments"));
}
// SAFETY: Frame is current and not concurrently mutated.
use rustpython_compiler_core::bytecode::CO_FAST_CELL;
let obj = unsafe { frame.fastlocals() }[0]
@@ -165,9 +166,9 @@ impl GetAttr for PySuper {
Some(o) => o.clone(),
None => return skip(zelf, name),
};
// We want __class__ to return the class of the super object
// (i.e. super, or a subclass), not the class of su->obj.
if name.as_bytes() == b"__class__" {
return skip(zelf, name);
}
@@ -280,21 +281,23 @@ pub(crate) fn init(context: &'static Context) {
let super_type = &context.types.super_type;
PySuper::extend_class(context, super_type);
let super_doc = "super() -> same as super(__class__, <first argument>)\n\
super(type) -> unbound super object\n\
super(type, obj) -> bound super object; requires isinstance(obj, type)\n\
super(type, type2) -> bound super object; requires issubclass(type2, type)\n\
Typical use to call a cooperative superclass method:\n\
class C(B):\n \
def meth(self, arg):\n \
super().meth(arg)\n\
This works for class methods too:\n\
class C(B):\n \
@classmethod\n \
def cmeth(cls, arg):\n \
super().cmeth(arg)\n";
const SUPER_DOC: &str = "\
super() -> same as super(__class__, <first argument>)
super(type) -> unbound super object
super(type, obj) -> bound super object; requires isinstance(obj, type)
super(type, type2) -> bound super object; requires issubclass(type2, type)
Typical use to call a cooperative superclass method:
class C(B):
def meth(self, arg):
super().meth(arg)
This works for class methods too:
class C(B):
@classmethod
def cmeth(cls, arg):
super().cmeth(arg)
";
extend_class!(context, super_type, {
"__doc__" => context.new_str(super_doc),
"__doc__" => context.new_str(SUPER_DOC),
});
}

View File

@@ -1,3 +1,5 @@
// cspell:ignore pyhash
use super::{
PositionIterInternal, PyGenericAlias, PyStrRef, PyType, PyTypeRef, iter::builtins_iter,
};
@@ -296,13 +298,13 @@ impl<R> PyTuple<R> {
#[inline]
#[must_use]
pub fn len(&self) -> usize {
pub const fn len(&self) -> usize {
self.elements.len()
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
pub const fn is_empty(&self) -> bool {
self.elements.is_empty()
}
@@ -725,23 +727,29 @@ pub(crate) fn init(context: &'static Context) {
}
pub(super) fn tuple_hash(elements: &[PyObjectRef], vm: &VirtualMachine) -> PyResult<PyHash> {
#[cfg(target_pointer_width = "64")]
const PRIME1: PyUHash = 11400714785074694791;
#[cfg(target_pointer_width = "64")]
const PRIME2: PyUHash = 14029467366897019727;
#[cfg(target_pointer_width = "64")]
const PRIME5: PyUHash = 2870177450012600261;
#[cfg(target_pointer_width = "64")]
const ROTATE: u32 = 31;
const PRIME1: PyUHash = cfg_select! {
target_pointer_width = "64" => 11400714785074694791,
target_pointer_width = "32" => 2654435761,
_ => unreachable!(),
};
#[cfg(target_pointer_width = "32")]
const PRIME1: PyUHash = 2654435761;
#[cfg(target_pointer_width = "32")]
const PRIME2: PyUHash = 2246822519;
#[cfg(target_pointer_width = "32")]
const PRIME5: PyUHash = 374761393;
#[cfg(target_pointer_width = "32")]
const ROTATE: u32 = 13;
const PRIME2: PyUHash = cfg_select! {
target_pointer_width = "64" => 14029467366897019727,
target_pointer_width = "32" => 2246822519,
_ => unreachable!(),
};
const PRIME5: PyUHash = cfg_select! {
target_pointer_width = "64" => 2870177450012600261,
target_pointer_width = "32" => 374761393,
_ => unreachable!(),
};
const ROTATE: u32 = cfg_select! {
target_pointer_width = "64" => 31,
target_pointer_width = "32" => 13,
_ => unreachable!(),
};
let mut acc = PRIME5;
let len = elements.len() as PyUHash;
@@ -755,8 +763,10 @@ pub(super) fn tuple_hash(elements: &[PyObjectRef], vm: &VirtualMachine) -> PyRes
acc = acc.wrapping_add(len ^ (PRIME5 ^ 3527539));
if acc as PyHash == -1 {
let acc_pyhash = acc as PyHash;
if acc_pyhash == -1 {
return Ok(1546275796);
}
Ok(acc as PyHash)
Ok(acc_pyhash)
}

View File

@@ -136,7 +136,7 @@ impl IterNext for PyWeakProxy {
fn next(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
let obj = zelf.try_upgrade(vm)?;
if obj.class().slots.iternext.load().is_none() {
return Err(vm.new_type_error("Weakref proxy referenced a non-iterator".to_owned()));
return Err(vm.new_type_error("Weakref proxy referenced a non-iterator"));
}
PyIter::new(obj).next(vm)
}

View File

@@ -32,6 +32,7 @@ impl PyPayload for PyWeak {
impl Callable for PyWeak {
type Args = ();
#[inline]
fn call(zelf: &Py<Self>, _: Self::Args, vm: &VirtualMachine) -> PyResult {
Ok(vm.unwrap_or_none(zelf.upgrade()))
@@ -50,10 +51,10 @@ impl Constructor for PyWeak {
.ok_or_else(|| vm.new_type_error("__new__ expected at least 1 argument, got 0"))?;
let callback = positional.next();
if let Some(_extra) = positional.next() {
return Err(vm.new_type_error(format!(
"__new__ expected at most 2 arguments, got {}",
3 + positional.count()
)));
let got = positional.count() + 3;
return Err(
vm.new_type_error(format!("__new__ expected at most 2 arguments, got {got}"))
);
}
let weak = referent.downgrade_with_typ(callback, cls, vm)?;
Ok(weak.into())
@@ -151,7 +152,7 @@ impl Representable for PyWeak {
#[inline]
fn repr_str(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
let id = zelf.get_id();
let repr = if let Some(o) = zelf.upgrade() {
Ok(if let Some(o) = zelf.upgrade() {
format!(
"<weakref at {:#x}; to '{}' at {:#x}>",
id,
@@ -160,8 +161,7 @@ impl Representable for PyWeak {
)
} else {
format!("<weakref at {id:#x}; dead>")
};
Ok(repr)
})
}
}