diff --git a/Cargo.toml b/Cargo.toml index 4e4092f3a5d..e8a56116c15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -249,6 +249,20 @@ unsafe_op_in_unsafe_fn = "deny" elided_lifetimes_in_paths = "warn" [workspace.lints.clippy] +correctness = { level = "warn", priority = -2 } +suspicious = { level = "warn", priority = -2 } +perf = { level = "warn", priority = -2 } +style = { level = "warn", priority = -2 } +complexity = { level = "warn", priority = -2 } +# pedantic = { level = "warn", priority = -2 } # TODO: Enable this + +missing_errors_doc = "allow" # Too many errors. No auto-fix available +missing_panics_doc = "allow" # Too many errors. No auto-fix available +match_same_arms = "allow" # Not always more readable +if_not_else = "allow" # Not always more readable +single_match_else = "allow" +similar_names = "allow" + alloc_instead_of_core = "warn" std_instead_of_alloc = "warn" std_instead_of_core = "warn" @@ -262,8 +276,6 @@ manual_is_variant_and = "warn" or_fun_call = "warn" unnested_or_patterns = "warn" -perf = "warn" -style = "warn" -complexity = "warn" -suspicious = "warn" -correctness = "warn" +# pedantic lints to enforce gradually +cloned_instead_of_copied = "warn" +must_use_candidate = "warn" diff --git a/crates/codegen/src/compile.rs b/crates/codegen/src/compile.rs index 727df5b55c1..34c6e34c525 100644 --- a/crates/codegen/src/compile.rs +++ b/crates/codegen/src/compile.rs @@ -417,6 +417,7 @@ impl Default for PatternContext { } impl PatternContext { + #[must_use] pub const fn new() -> Self { Self { stores: Vec::new(), @@ -426,6 +427,7 @@ impl PatternContext { } } + #[must_use] pub fn fail_pop_size(&self) -> usize { self.fail_pop.len() } @@ -6266,12 +6268,11 @@ impl Compiler { return Err(self.error(CodegenErrorType::UnreachablePattern( PatternUnreachableReason::NameCapture, ))); - } else { - // A wildcard makes remaining patterns unreachable. - return Err(self.error(CodegenErrorType::UnreachablePattern( - PatternUnreachableReason::Wildcard, - ))); } + // A wildcard makes remaining patterns unreachable. + return Err(self.error(CodegenErrorType::UnreachablePattern( + PatternUnreachableReason::Wildcard, + ))); } // If irrefutable matches are allowed, store the name (if any). return self.pattern_helper_store_name(p.name.as_ref(), pc); @@ -10327,9 +10328,8 @@ impl Compiler { if !found_loop { if is_break { return Err(self.error_ranged(CodegenErrorType::InvalidBreak, range)); - } else { - return Err(self.error_ranged(CodegenErrorType::InvalidContinue, range)); } + return Err(self.error_ranged(CodegenErrorType::InvalidContinue, range)); } return Ok(()); } @@ -10368,9 +10368,8 @@ impl Compiler { let Some(loop_idx) = loop_idx else { if is_break { return Err(self.error_ranged(CodegenErrorType::InvalidBreak, range)); - } else { - return Err(self.error_ranged(CodegenErrorType::InvalidContinue, range)); } + return Err(self.error_ranged(CodegenErrorType::InvalidContinue, range)); }; let loop_block = code.fblock[loop_idx].fb_block; diff --git a/crates/codegen/src/symboltable.rs b/crates/codegen/src/symboltable.rs index bafc7c81cf1..94c27722455 100644 --- a/crates/codegen/src/symboltable.rs +++ b/crates/codegen/src/symboltable.rs @@ -125,6 +125,7 @@ impl SymbolTable { builder.finish() } + #[must_use] pub fn lookup(&self, name: &str) -> Option<&Symbol> { self.symbols.get(name) } @@ -226,6 +227,7 @@ impl Symbol { } } + #[must_use] pub const fn is_global(&self) -> bool { matches!( self.scope, @@ -233,10 +235,12 @@ impl Symbol { ) } + #[must_use] pub const fn is_local(&self) -> bool { matches!(self.scope, SymbolScope::Local | SymbolScope::Cell) } + #[must_use] pub const fn is_bound(&self) -> bool { self.flags.intersects(SymbolFlags::BOUND) } @@ -249,6 +253,7 @@ pub struct SymbolTableError { } impl SymbolTableError { + #[must_use] pub fn into_codegen_error(self, source_path: String) -> CodegenError { CodegenError { location: self.location, diff --git a/crates/common/src/atomic.rs b/crates/common/src/atomic.rs index ef7f41074e8..15c95c3e111 100644 --- a/crates/common/src/atomic.rs +++ b/crates/common/src/atomic.rs @@ -64,6 +64,7 @@ impl Default for OncePtr { impl OncePtr { #[inline] + #[must_use] pub fn new() -> Self { Self { inner: Radium::new(ptr::null_mut()), diff --git a/crates/common/src/boxvec.rs b/crates/common/src/boxvec.rs index 3260e76ca87..675420259cb 100644 --- a/crates/common/src/boxvec.rs +++ b/crates/common/src/boxvec.rs @@ -38,6 +38,7 @@ macro_rules! panic_oob { } impl BoxVec { + #[must_use] pub fn new(n: usize) -> Self { Self { xs: Box::new_uninit_slice(n), @@ -46,24 +47,29 @@ impl BoxVec { } #[inline] + #[must_use] pub const fn len(&self) -> usize { self.len } #[inline] + #[must_use] pub const fn is_empty(&self) -> bool { self.len() == 0 } #[inline] + #[must_use] pub const fn capacity(&self) -> usize { self.xs.len() } + #[must_use] pub const fn is_full(&self) -> bool { self.len() == self.capacity() } + #[must_use] pub const fn remaining_capacity(&self) -> usize { self.capacity() - self.len() } @@ -312,6 +318,7 @@ impl BoxVec { } /// Return a slice containing all elements of the vector. + #[must_use] pub fn as_slice(&self) -> &[T] { self } @@ -323,6 +330,7 @@ impl BoxVec { /// Return a raw pointer to the vector's buffer. #[inline] + #[must_use] pub fn as_ptr(&self) -> *const T { self.xs.as_ptr().cast() } @@ -487,6 +495,7 @@ impl DoubleEndedIterator for Drain<'_, T> { impl ExactSizeIterator for Drain<'_, T> {} impl<'a, T> Drain<'a, T> { + #[must_use] pub fn as_slice(&self) -> &'a [T] { self.iter.as_slice() } diff --git a/crates/common/src/cformat.rs b/crates/common/src/cformat.rs index 7b9609e90ae..3b7ac5d76ec 100644 --- a/crates/common/src/cformat.rs +++ b/crates/common/src/cformat.rs @@ -102,6 +102,7 @@ pub enum CFormatType { } impl CFormatType { + #[must_use] pub const fn to_char(self) -> char { match self { Self::Number(x) => x as u8 as char, @@ -137,6 +138,7 @@ bitflags! { impl CConversionFlags { #[inline] + #[must_use] pub const fn sign_string(&self) -> &'static str { if self.contains(Self::SIGN_CHAR) { "+" @@ -408,6 +410,7 @@ impl CFormatSpec { ) } + #[must_use] pub fn format_bytes(&self, bytes: &[u8]) -> Vec { let bytes = if let Some(CFormatPrecision::Quantity(CFormatQuantity::Amount(precision))) = self.precision @@ -432,6 +435,7 @@ impl CFormatSpec { } } + #[must_use] pub fn format_number(&self, num: &BigInt) -> String { use CNumberType::*; let CFormatType::Number(format_type) = self.format_type else { @@ -492,6 +496,7 @@ impl CFormatSpec { } } + #[must_use] pub fn format_float(&self, num: f64) -> String { let sign_string = if num.is_sign_negative() && !num.is_nan() { "-" @@ -740,6 +745,7 @@ pub struct CFormatStrOrBytes { } impl CFormatStrOrBytes { + #[must_use] pub fn check_specifiers(&self) -> Option<(usize, bool)> { let mut count = 0; let mut mapping_required = false; @@ -828,7 +834,7 @@ pub type CFormatBytes = CFormatStrOrBytes>; impl CFormatBytes { pub fn parse_from_bytes(bytes: &[u8]) -> Result { - let mut iter = bytes.iter().cloned().enumerate().peekable(); + let mut iter = bytes.iter().copied().enumerate().peekable(); Self::parse(&mut iter) } } diff --git a/crates/common/src/float_ops.rs b/crates/common/src/float_ops.rs index c5e2e6064fb..fed080dcec8 100644 --- a/crates/common/src/float_ops.rs +++ b/crates/common/src/float_ops.rs @@ -2,6 +2,7 @@ use core::f64; use malachite_bigint::{BigInt, ToBigInt}; use num_traits::{Signed, ToPrimitive}; +#[must_use] pub const fn decompose_float(value: f64) -> (f64, i32) { if 0.0 == value { (0.0, 0i32) @@ -29,6 +30,7 @@ pub const fn decompose_float(value: f64) -> (f64, i32) { /// assert!(!eq_int(c, &b)); /// ``` /// +#[must_use] pub fn eq_int(value: f64, other: &BigInt) -> bool { if let (Some(self_int), Some(other_float)) = (value.to_bigint(), other.to_f64()) { value == other_float && self_int == *other @@ -37,6 +39,7 @@ pub fn eq_int(value: f64, other: &BigInt) -> bool { } } +#[must_use] pub fn lt_int(value: f64, other_int: &BigInt) -> bool { match (value.to_bigint(), other_int.to_f64()) { (Some(self_int), Some(other_float)) => value < other_float || self_int < *other_int, @@ -50,6 +53,7 @@ pub fn lt_int(value: f64, other_int: &BigInt) -> bool { } } +#[must_use] pub fn gt_int(value: f64, other_int: &BigInt) -> bool { match (value.to_bigint(), other_int.to_f64()) { (Some(self_int), Some(other_float)) => value > other_float || self_int > *other_int, @@ -63,14 +67,17 @@ pub fn gt_int(value: f64, other_int: &BigInt) -> bool { } } +#[must_use] pub const fn div(v1: f64, v2: f64) -> Option { if v2 != 0.0 { Some(v1 / v2) } else { None } } +#[must_use] pub fn mod_(v1: f64, v2: f64) -> Option { divmod(v1, v2).map(|(_, m)| m) } +#[must_use] pub fn floordiv(v1: f64, v2: f64) -> Option { divmod(v1, v2).map(|(d, _)| d) } @@ -78,6 +85,7 @@ pub fn floordiv(v1: f64, v2: f64) -> Option { // Canonical (floordiv, mod) for floats matching CPython's _float_div_mod // (Objects/floatobject.c). `mod_` and `floordiv` delegate here so that // `divmod(a, b) == (a // b, a % b)` holds by construction. +#[must_use] pub fn divmod(v1: f64, v2: f64) -> Option<(f64, f64)> { if v2 == 0.0 { return None; @@ -108,6 +116,7 @@ pub fn divmod(v1: f64, v2: f64) -> Option<(f64, f64)> { // nextafter algorithm based off of https://gitlab.com/bronsonbdevost/next_afterf #[allow(clippy::float_cmp)] +#[must_use] pub fn nextafter(x: f64, y: f64) -> f64 { if x == y { y @@ -130,6 +139,7 @@ pub fn nextafter(x: f64, y: f64) -> f64 { } #[allow(clippy::float_cmp)] +#[must_use] pub fn nextafter_with_steps(x: f64, y: f64, steps: u64) -> f64 { if x == y { y @@ -192,6 +202,7 @@ pub fn nextafter_with_steps(x: f64, y: f64, steps: u64) -> f64 { } } +#[must_use] pub fn ulp(x: f64) -> f64 { if x.is_nan() { return x; @@ -207,6 +218,7 @@ pub fn ulp(x: f64) -> f64 { } } +#[must_use] pub fn round_float_digits(x: f64, ndigits: i32) -> Option { // Mirror CPython's `float.__round__` (Objects/floatobject.c), which uses // `_Py_dg_dtoa` to round at the decimal level. Multiplying by 10**ndigits diff --git a/crates/common/src/format.rs b/crates/common/src/format.rs index 58dae34b2ce..8c69e700142 100644 --- a/crates/common/src/format.rs +++ b/crates/common/src/format.rs @@ -53,6 +53,7 @@ impl FormatParse for FormatConversion { } impl FormatConversion { + #[must_use] pub fn from_char(c: CodePoint) -> Option { match c.to_char_lossy() { 's' => Some(Self::Str), @@ -479,6 +480,7 @@ impl FormatSpec { } /// Returns true if this format spec uses the locale-aware 'n' format type. + #[must_use] pub fn has_locale_format(&self) -> bool { matches!(self.format_type, Some(FormatType::Number(Case::Lower))) } @@ -487,6 +489,7 @@ impl FormatSpec { /// subject to `sys.get_int_max_str_digits()` (no spec, 'd', or 'n'). /// Binary bases ('b', 'o', 'x', 'X') are exempt per CPython. 'N' is rejected /// later in `format_int` as `UnknownFormatCode`, so it is not included here. + #[must_use] pub fn is_decimal_int_format(&self) -> bool { matches!( self.format_type, @@ -1354,20 +1357,18 @@ impl FormatString { } else if c == '{' { if nested { return Err(FormatParseError::InvalidFormatSpecifier); - } else { - nested = true; - left.push(c); - continue; } + nested = true; + left.push(c); + continue; } else if c == '}' { if nested { nested = false; left.push(c); continue; - } else { - end_bracket_pos = Some(idx); - break; } + end_bracket_pos = Some(idx); + break; } else { left.push(c); } diff --git a/crates/common/src/hash.rs b/crates/common/src/hash.rs index f8f3783d224..5b16c89e7bc 100644 --- a/crates/common/src/hash.rs +++ b/crates/common/src/hash.rs @@ -40,6 +40,7 @@ impl BuildHasher for HashSecret { } impl HashSecret { + #[must_use] pub fn new(seed: u32) -> Self { let mut buf = [0u8; 16]; lcg_urandom(seed, &mut buf); @@ -68,6 +69,7 @@ impl HashSecret { Ok(fix_sentinel(mod_int(hasher.finish() as PyHash))) } + #[must_use] pub fn hash_bytes(&self, value: &[u8]) -> PyHash { if value.is_empty() { 0 @@ -76,12 +78,14 @@ impl HashSecret { } } + #[must_use] pub fn hash_str(&self, value: &str) -> PyHash { self.hash_bytes(value.as_bytes()) } } #[inline] +#[must_use] pub const fn hash_pointer(value: usize) -> PyHash { // TODO: 32bit? let hash = (value >> 4) | value; @@ -89,6 +93,7 @@ pub const fn hash_pointer(value: usize) -> PyHash { } #[inline] +#[must_use] pub fn hash_float(value: f64) -> Option { // cpython _Py_HashDouble if !value.is_finite() { @@ -130,6 +135,7 @@ pub fn hash_float(value: f64) -> Option { Some(fix_sentinel(x as PyHash * value.signum() as PyHash)) } +#[must_use] pub fn hash_bigint(value: &BigInt) -> PyHash { let ret = match value.to_i64() { Some(i) => mod_int(i), @@ -142,16 +148,19 @@ pub fn hash_bigint(value: &BigInt) -> PyHash { } #[inline] +#[must_use] pub const fn hash_usize(data: usize) -> PyHash { fix_sentinel(mod_int(data as i64)) } #[inline(always)] +#[must_use] pub const fn fix_sentinel(x: PyHash) -> PyHash { if x == SENTINEL { -2 } else { x } } #[inline] +#[must_use] pub const fn mod_int(value: i64) -> PyHash { value % MODULUS as i64 } @@ -165,6 +174,7 @@ pub fn lcg_urandom(mut x: u32, buf: &mut [u8]) { } #[inline] +#[must_use] pub const fn hash_object_id_raw(p: usize) -> PyHash { // TODO: Use commented logic when below issue resolved. // Ref: https://github.com/RustPython/RustPython/pull/3951#issuecomment-1193108966 @@ -176,10 +186,12 @@ pub const fn hash_object_id_raw(p: usize) -> PyHash { } #[inline] +#[must_use] pub const fn hash_object_id(p: usize) -> PyHash { fix_sentinel(hash_object_id_raw(p)) } +#[must_use] pub fn keyed_hash(key: u64, buf: &[u8]) -> u64 { let mut hasher = SipHasher24::new_with_keys(key, 0); buf.hash(&mut hasher); diff --git a/crates/common/src/int.rs b/crates/common/src/int.rs index 9cfe2e0d738..0a8f054bf1a 100644 --- a/crates/common/src/int.rs +++ b/crates/common/src/int.rs @@ -3,6 +3,7 @@ use malachite_bigint::{BigInt, BigUint, Sign}; use malachite_q::Rational; use num_traits::{One, ToPrimitive, Zero}; +#[must_use] pub fn true_div(numerator: &BigInt, denominator: &BigInt) -> f64 { let rational = Rational::from_integers_ref(numerator.into(), denominator.into()); match rational.rounding_into(RoundingMode::Nearest) { @@ -14,6 +15,7 @@ pub fn true_div(numerator: &BigInt, denominator: &BigInt) -> f64 { } } +#[must_use] pub fn float_to_ratio(value: f64) -> Option<(BigInt, BigInt)> { let sign = match core::cmp::PartialOrd::partial_cmp(&value, &0.0)? { core::cmp::Ordering::Less => Sign::Minus, @@ -146,6 +148,7 @@ pub fn bytes_to_int( // num-bigint now returns Some(inf) for to_f64() in some cases, so just keep that the same for now #[inline(always)] +#[must_use] pub fn bigint_to_finite_float(int: &BigInt) -> Option { int.to_f64().filter(|f| f.is_finite()) } diff --git a/crates/common/src/linked_list.rs b/crates/common/src/linked_list.rs index 223d9ce0eb1..e8d3624703d 100644 --- a/crates/common/src/linked_list.rs +++ b/crates/common/src/linked_list.rs @@ -140,6 +140,7 @@ unsafe impl Sync for Pointers {} impl LinkedList { /// Creates an empty linked list. + #[must_use] pub const fn new() -> Self { Self { head: None, @@ -216,6 +217,7 @@ impl LinkedList { } /// Returns whether the linked list does not contain any node + #[must_use] pub const fn is_empty(&self) -> bool { self.head.is_none() // if self.head.is_some() { @@ -354,6 +356,7 @@ where impl Pointers { /// Create a new set of empty pointers + #[must_use] pub const fn new() -> Self { Self { inner: UnsafeCell::new(PointersInner { diff --git a/crates/common/src/lock/thread_mutex.rs b/crates/common/src/lock/thread_mutex.rs index 884556c4476..c996ff80289 100644 --- a/crates/common/src/lock/thread_mutex.rs +++ b/crates/common/src/lock/thread_mutex.rs @@ -35,12 +35,11 @@ impl RawThreadMutex { let id = self.get_thread_id.nonzero_thread_id().get(); if self.owner.load(Ordering::Relaxed) == id { return None; - } else { - if !try_lock() { - return Some(false); - } - self.owner.store(id, Ordering::Relaxed); } + if !try_lock() { + return Some(false); + } + self.owner.store(id, Ordering::Relaxed); Some(true) } diff --git a/crates/common/src/rand.rs b/crates/common/src/rand.rs index 334505ac945..e497049cd72 100644 --- a/crates/common/src/rand.rs +++ b/crates/common/src/rand.rs @@ -6,6 +6,7 @@ /// # Panics /// /// Panics if the OS entropy source returns an error. +#[must_use] pub fn os_random() -> [u8; N] { let mut buf = [0u8; N]; getrandom::fill(&mut buf).unwrap(); diff --git a/crates/common/src/refcount.rs b/crates/common/src/refcount.rs index d17f5ccd9f3..fb4a59438a9 100644 --- a/crates/common/src/refcount.rs +++ b/crates/common/src/refcount.rs @@ -86,6 +86,7 @@ impl Default for RefCount { impl RefCount { /// Create a new RefCount with strong count = 1 + #[must_use] pub fn new() -> Self { // Initial state: strong=1, weak=1 (implicit weak for strong refs) Self { diff --git a/crates/common/src/static_cell.rs b/crates/common/src/static_cell.rs index bf277e60ea7..5095cfbcea5 100644 --- a/crates/common/src/static_cell.rs +++ b/crates/common/src/static_cell.rs @@ -67,10 +67,12 @@ mod non_threading { impl StaticCell { #[doc(hidden)] + #[must_use] pub const fn _from_local_key(inner: &'static LocalKey>) -> Self { Self { inner } } + #[must_use] pub fn get(&'static self) -> Option<&'static T> { self.inner.with(|x| x.get().copied()) } diff --git a/crates/common/src/str.rs b/crates/common/src/str.rs index 171dd80c7a6..36b9c2fb202 100644 --- a/crates/common/src/str.rs +++ b/crates/common/src/str.rs @@ -36,15 +36,18 @@ impl core::ops::BitOr for StrKind { } impl StrKind { + #[must_use] pub const fn is_ascii(&self) -> bool { matches!(self, Self::Ascii) } + #[must_use] pub const fn is_utf8(&self) -> bool { matches!(self, Self::Ascii | Self::Utf8) } #[inline(always)] + #[must_use] pub fn can_encode(&self, code: CodePoint) -> bool { match self { Self::Ascii => code.is_ascii(), @@ -234,6 +237,7 @@ impl StrData { /// # Safety /// /// Given `bytes` must be valid data for given `kind` + #[must_use] pub unsafe fn new_str_unchecked(data: Box, kind: StrKind) -> Self { let len = match kind { StrKind::Ascii => data.len().into(), @@ -245,6 +249,7 @@ impl StrData { /// # Safety /// /// `char_len` must be accurate. + #[must_use] pub unsafe fn new_with_char_len(data: Box, kind: StrKind, char_len: usize) -> Self { Self { data, @@ -364,6 +369,7 @@ pub fn get_chars(s: &str, range: impl RangeBounds) -> &str { } #[inline] +#[must_use] pub fn char_range_end(s: &str, n_chars: usize) -> Option { let i = match n_chars.checked_sub(1) { Some(last_char_index) => { @@ -399,6 +405,7 @@ pub fn get_codepoints(w: &Wtf8, range: impl RangeBounds) -> &Wtf8 { } #[inline] +#[must_use] pub fn codepoint_range_end(s: &Wtf8, n_chars: usize) -> Option { let i = match n_chars.checked_sub(1) { Some(last_char_index) => { @@ -410,6 +417,7 @@ pub fn codepoint_range_end(s: &Wtf8, n_chars: usize) -> Option { Some(i) } +#[must_use] pub fn zfill(bytes: &[u8], width: usize) -> Vec { if width <= bytes.len() { bytes.to_vec() @@ -428,6 +436,7 @@ pub fn zfill(bytes: &[u8], width: usize) -> Vec { /// Convert a string to ascii compatible, escaping unicode-s into escape /// sequences. +#[must_use] pub fn to_ascii(value: &Wtf8) -> AsciiString { let mut ascii = Vec::new(); for cp in value.code_points() { @@ -485,6 +494,7 @@ pub mod levenshtein { if a == b { CASE_COST } else { MOVE_COST } } + #[must_use] pub fn levenshtein_distance(a: &[u8], b: &[u8], max_cost: usize) -> usize { if a == b { return 0; @@ -555,6 +565,7 @@ pub mod levenshtein { } /// Replace all tabs in a string with spaces, using the given tab size. +#[must_use] pub fn expandtabs(input: &str, tab_size: usize) -> String { let tab_stop = tab_size; let mut expanded_str = String::with_capacity(input.len()); @@ -641,6 +652,7 @@ const UNICODE_DECIMAL_VALUES: &[char] = &[ '𞥗', '𞥘', '𞥙', ]; +#[must_use] pub fn char_to_decimal(ch: char) -> Option { UNICODE_DECIMAL_VALUES .binary_search(&ch) diff --git a/crates/compiler-core/src/bytecode.rs b/crates/compiler-core/src/bytecode.rs index eeef411acbe..ab530e703f2 100644 --- a/crates/compiler-core/src/bytecode.rs +++ b/crates/compiler-core/src/bytecode.rs @@ -52,6 +52,7 @@ pub struct ExceptionTableEntry { } impl ExceptionTableEntry { + #[must_use] pub const fn new(start: u32, end: u32, target: u32, depth: u16, push_lasti: bool) -> Self { Self { start, @@ -65,6 +66,7 @@ impl ExceptionTableEntry { /// Encode exception table entries. /// Uses 6-bit varint encoding with start marker (MSB) and continuation bit. +#[must_use] pub fn encode_exception_table(entries: &[ExceptionTableEntry]) -> alloc::boxed::Box<[u8]> { let mut data = Vec::new(); for entry in entries { @@ -80,6 +82,7 @@ pub fn encode_exception_table(entries: &[ExceptionTableEntry]) -> alloc::boxed:: } /// Find exception handler for given instruction offset. +#[must_use] pub fn find_exception_handler(table: &[u8], offset: u32) -> Option { let mut pos = 0; while pos < table.len() { @@ -106,6 +109,7 @@ pub fn find_exception_handler(table: &[u8], offset: u32) -> Option Vec { let mut entries = Vec::new(); let mut pos = 0; @@ -138,6 +142,7 @@ pub fn decode_exception_table(table: &[u8]) -> Vec { /// Parse linetable to build a boolean mask indicating which code units /// have NO_LOCATION (line == -1). Returns a Vec of length `num_units`. +#[must_use] pub fn build_no_location_mask(linetable: &[u8], num_units: usize) -> Vec { let mut mask = Vec::new(); mask.resize(num_units, false); @@ -227,6 +232,7 @@ pub enum PyCodeLocationInfoKind { } impl PyCodeLocationInfoKind { + #[must_use] pub fn from_code(code: u8) -> Option { match code { 0 => Some(Self::Short0), @@ -249,10 +255,12 @@ impl PyCodeLocationInfoKind { } } + #[must_use] pub fn is_short(&self) -> bool { (*self as u8) <= 9 } + #[must_use] pub fn short_column_group(&self) -> Option { if self.is_short() { Some(*self as u8) @@ -261,6 +269,7 @@ impl PyCodeLocationInfoKind { } } + #[must_use] pub fn one_line_delta(&self) -> Option { match self { Self::OneLine0 => Some(0), @@ -483,24 +492,28 @@ const MAX_BACKOFF: u16 = 12; const UNREACHABLE_BACKOFF: u16 = 15; /// Encode an adaptive counter as `(value << 4) | backoff`. +#[must_use] pub const fn adaptive_counter_bits(value: u16, backoff: u16) -> u16 { (value << BACKOFF_BITS) | backoff } /// True when the adaptive counter should trigger specialization. #[inline] +#[must_use] pub const fn adaptive_counter_triggers(counter: u16) -> bool { counter < UNREACHABLE_BACKOFF } /// Decrement adaptive counter by one countdown step. #[inline] +#[must_use] pub const fn advance_adaptive_counter(counter: u16) -> u16 { counter.wrapping_sub(1 << BACKOFF_BITS) } /// Reset adaptive counter with exponential backoff. #[inline] +#[must_use] pub const fn adaptive_counter_backoff(counter: u16) -> u16 { let backoff = counter & ((1 << BACKOFF_BITS) - 1); if backoff < MAX_BACKOFF { @@ -511,6 +524,7 @@ pub const fn adaptive_counter_backoff(counter: u16) -> u16 { } impl CodeUnit { + #[must_use] pub const fn new(op: Instruction, arg: OpArgByte) -> Self { Self { op, arg } } @@ -1016,6 +1030,7 @@ impl BorrowedConstant<'_, C> { } } + #[must_use] pub fn to_owned(self) -> ConstantData { use ConstantData::*; diff --git a/crates/compiler-core/src/bytecode/instruction.rs b/crates/compiler-core/src/bytecode/instruction.rs index 3a0e9a2132b..dc5ef84820e 100644 --- a/crates/compiler-core/src/bytecode/instruction.rs +++ b/crates/compiler-core/src/bytecode/instruction.rs @@ -517,6 +517,7 @@ define_opcodes!( impl Instruction { /// Returns `true` if this is any instrumented opcode /// (regular INSTRUMENTED_*, INSTRUMENTED_LINE, or INSTRUMENTED_INSTRUCTION). + #[must_use] pub const fn is_instrumented(self) -> bool { self.to_base().is_some() || matches!(self, Self::InstrumentedLine | Self::InstrumentedInstruction) @@ -527,6 +528,7 @@ impl Instruction { /// /// # Panics (debug) /// Panics if called on an already-instrumented opcode. + #[must_use] pub fn to_instrumented(self) -> Option { debug_assert!( !self.is_instrumented(), @@ -564,6 +566,7 @@ impl Instruction { /// /// The returned base opcode uses `Arg::marker()` for typed fields — /// only the opcode byte matters since `replace_op` preserves the arg byte. + #[must_use] pub const fn to_base(self) -> Option { Some(match self { Self::InstrumentedResume => Self::Resume { @@ -613,6 +616,7 @@ impl Instruction { /// Map a specialized opcode back to its adaptive (base) variant. /// `_PyOpcode_Deopt` + #[must_use] pub const fn deopt(self) -> Option { let opcode = match self { Self::ResumeCheck => Opcode::Resume, @@ -696,6 +700,7 @@ impl Instruction { } /// Map a specialized or instrumented opcode back to its adaptive (base) variant. + #[must_use] pub const fn deoptimize(self) -> Self { match self.deopt() { Some(v) => v, @@ -714,6 +719,7 @@ impl Instruction { /// Instrumented and specialized opcodes have the same cache entries as their base. /// /// _PyOpcode_Caches + #[must_use] pub const fn cache_entries(self) -> usize { match self.deoptimize().opcode() { Opcode::LoadAttr => 9, @@ -1348,6 +1354,7 @@ impl PseudoInstruction { /// - [`PseudoInstruction::SetupCleanup`] /// - [`PseudoInstruction::SetupFinally`] /// - [`PseudoInstruction::SetupWith`] + #[must_use] pub const fn is_block_push(&self) -> bool { matches!( self.opcode(), @@ -1530,6 +1537,7 @@ impl InstructionMetadata for AnyInstruction { impl AnyInstruction { /// Inner value of [`Self::Real`]. + #[must_use] pub const fn real(self) -> Option { match self { Self::Real(ins) => Some(ins), @@ -1538,6 +1546,7 @@ impl AnyInstruction { } /// Inner value of [`Self::Pseudo`]. + #[must_use] pub const fn pseudo(self) -> Option { match self { Self::Pseudo(ins) => Some(ins), @@ -1546,6 +1555,7 @@ impl AnyInstruction { } /// Get [`Self::Real`] as [`Opcode`]. + #[must_use] pub const fn real_opcode(self) -> Option { match self.real() { Some(ins) => Some(ins.opcode()), @@ -1554,6 +1564,7 @@ impl AnyInstruction { } /// Get [`Self::Pseudo`] as [`PseudoOpcode`]. + #[must_use] pub const fn pseudo_opcode(self) -> Option { match self.pseudo() { Some(ins) => Some(ins.opcode()), @@ -1566,6 +1577,7 @@ impl AnyInstruction { /// # Panics /// /// If was called on something else other than [`Self::Real`]. + #[must_use] pub const fn expect_real(self) -> Instruction { self.real() .expect("Expected AnyInstruction::Real, found AnyInstruction::Pseudo") @@ -1576,17 +1588,20 @@ impl AnyInstruction { /// # Panics /// /// If was called on something else other than [`Self::Pseudo`]. + #[must_use] pub const fn expect_pseudo(self) -> PseudoInstruction { self.pseudo() .expect("Expected AnyInstruction::Pseudo, found AnyInstruction::Real") } /// Returns true if this is a [`PseudoInstruction::PopBlock`]. + #[must_use] pub const fn is_pop_block(self) -> bool { matches!(self, Self::Pseudo(PseudoInstruction::PopBlock)) } /// See [`PseudoInstruction::is_block_push`]. + #[must_use] pub const fn is_block_push(self) -> bool { matches!(self, Self::Pseudo(p) if p.is_block_push()) } @@ -1640,6 +1655,7 @@ impl From for AnyOpcode { impl AnyOpcode { /// Gets the inner value of [`Self::Real`]. + #[must_use] pub const fn real(self) -> Option { match self { Self::Real(op) => Some(op), @@ -1648,6 +1664,7 @@ impl AnyOpcode { } /// Gets the inner value of [`Self::Pseudo`]. + #[must_use] pub const fn pseudo(self) -> Option { match self { Self::Pseudo(op) => Some(op), @@ -1660,6 +1677,7 @@ impl AnyOpcode { /// # Panics /// /// If was called on something else other than [`Self::Real`]. + #[must_use] pub const fn expect_real(self) -> Opcode { self.real() .expect("Expected AnyOpcode::Real, found AnyOpcode::Pseudo") @@ -1670,6 +1688,7 @@ impl AnyOpcode { /// # Panics /// /// If was called on something else other than [`Self::Pseudo`]. + #[must_use] pub const fn expect_pseudo(self) -> PseudoOpcode { self.pseudo() .expect("Expected AnyOpcode::Pseudo, found AnyOpcode::Real") @@ -1687,21 +1706,25 @@ pub struct StackEffect { impl StackEffect { /// Creates a new [`Self`]. + #[must_use] pub const fn new(pushed: u32, popped: u32) -> Self { Self { pushed, popped } } /// Get the calculated stack effect as [`i32`]. + #[must_use] pub fn effect(self) -> i32 { self.into() } /// Get the pushed count. + #[must_use] pub const fn pushed(self) -> u32 { self.pushed } /// Get the popped count. + #[must_use] pub const fn popped(self) -> u32 { self.popped } @@ -1761,6 +1784,7 @@ pub struct Arg(PhantomData); impl Arg { #[inline] + #[must_use] pub const fn marker() -> Self { Self(PhantomData) } @@ -1779,6 +1803,7 @@ impl Arg { } #[inline(always)] + #[must_use] pub fn get(self, arg: OpArg) -> T { self.try_get(arg).unwrap() } @@ -1791,6 +1816,7 @@ impl Arg { /// # Safety /// T::from_op_arg(self) must succeed #[inline(always)] + #[must_use] pub unsafe fn get_unchecked(self, arg: OpArg) -> T { // SAFETY: requirements forwarded from caller unsafe { T::try_from(u32::from(arg)).unwrap_unchecked() } diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index d3d54750797..d0dbdd2657d 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -66,6 +66,7 @@ impl OpArg { /// Returns how many CodeUnits a instruction with this op_arg will be encoded as #[inline] + #[must_use] pub const fn instr_size(self) -> usize { (self.0 > 0xff) as usize + (self.0 > 0xff_ff) as usize + (self.0 > 0xff_ff_ff) as usize + 1 } diff --git a/crates/compiler-core/src/marshal.rs b/crates/compiler-core/src/marshal.rs index 56d9e39c03a..c9115f25359 100644 --- a/crates/compiler-core/src/marshal.rs +++ b/crates/compiler-core/src/marshal.rs @@ -1138,6 +1138,7 @@ pub fn split_localplus( }) } +#[must_use] pub fn linetable_to_locations( linetable: &[u8], first_line: i32, diff --git a/crates/compiler/src/lib.rs b/crates/compiler/src/lib.rs index 815d45f2cd8..0be38ec15be 100644 --- a/crates/compiler/src/lib.rs +++ b/crates/compiler/src/lib.rs @@ -46,6 +46,7 @@ pub enum CompileError { } impl CompileError { + #[must_use] pub fn from_ruff_parse_error(error: parser::ParseError, source_file: &SourceFile) -> Self { let source_code = source_file.to_source_code(); let source_text = source_file.source_text(); @@ -116,6 +117,7 @@ impl CompileError { }) } + #[must_use] pub const fn location(&self) -> Option { match self { Self::Codegen(codegen_error) => codegen_error.location, @@ -123,6 +125,7 @@ impl CompileError { } } + #[must_use] pub const fn python_location(&self) -> (usize, usize) { if let Some(location) = self.location() { (location.line.get(), location.character_offset.get()) @@ -131,6 +134,7 @@ impl CompileError { } } + #[must_use] pub fn python_end_location(&self) -> Option<(usize, usize)> { match self { CompileError::Codegen(_) => None, @@ -141,6 +145,7 @@ impl CompileError { } } + #[must_use] pub fn source_path(&self) -> &str { match self { Self::Codegen(codegen_error) => &codegen_error.source_path, diff --git a/crates/derive-impl/src/compile_bytecode.rs b/crates/derive-impl/src/compile_bytecode.rs index 16984139fcd..1a32f5d99c9 100644 --- a/crates/derive-impl/src/compile_bytecode.rs +++ b/crates/derive-impl/src/compile_bytecode.rs @@ -192,9 +192,8 @@ impl CompilationSource { let joined = path.parent().unwrap().join(real_path.trim()); if joined.exists() { return compile_path(&joined); - } else { - return Err(e); } + return Err(e); } Err(e) }); diff --git a/crates/derive-impl/src/lib.rs b/crates/derive-impl/src/lib.rs index c00299794de..54336db2b8a 100644 --- a/crates/derive-impl/src/lib.rs +++ b/crates/derive-impl/src/lib.rs @@ -36,10 +36,12 @@ fn result_to_tokens(result: Result>) -> Token .unwrap_or_else(ToTokens::into_token_stream) } +#[must_use] pub fn derive_from_args(input: DeriveInput) -> TokenStream { result_to_tokens(from_args::impl_from_args(input)) } +#[must_use] pub fn pyclass(attr: PunctuatedNestedMeta, item: Item) -> TokenStream { if matches!(item, syn::Item::Impl(_) | syn::Item::Trait(_)) { result_to_tokens(pyclass::impl_pyclass_impl(attr, item)) @@ -48,6 +50,7 @@ pub fn pyclass(attr: PunctuatedNestedMeta, item: Item) -> TokenStream { } } +#[must_use] pub fn pyexception(attr: PunctuatedNestedMeta, item: Item) -> TokenStream { if matches!(item, syn::Item::Impl(_)) { result_to_tokens(pyclass::impl_pyexception_impl(attr, item)) @@ -56,14 +59,17 @@ pub fn pyexception(attr: PunctuatedNestedMeta, item: Item) -> TokenStream { } } +#[must_use] pub fn pymodule(attr: PyModuleArgs, item: Item) -> TokenStream { result_to_tokens(pymodule::impl_pymodule(attr, item)) } +#[must_use] pub fn pystruct_sequence(attr: PunctuatedNestedMeta, item: Item) -> TokenStream { result_to_tokens(pystructseq::impl_pystruct_sequence(attr, item)) } +#[must_use] pub fn pystruct_sequence_data(attr: PunctuatedNestedMeta, item: Item) -> TokenStream { result_to_tokens(pystructseq::impl_pystruct_sequence_data(attr, item)) } @@ -76,10 +82,12 @@ pub fn py_freeze(input: TokenStream, compiler: &dyn Compiler) -> TokenStream { result_to_tokens(compile_bytecode::impl_py_freeze(input, compiler)) } +#[must_use] pub fn pypayload(input: DeriveInput) -> TokenStream { result_to_tokens(pypayload::impl_pypayload(input)) } +#[must_use] pub fn pytraverse(item: DeriveInput) -> TokenStream { result_to_tokens(pytraverse::impl_pytraverse(item)) } diff --git a/crates/derive-impl/src/pyclass.rs b/crates/derive-impl/src/pyclass.rs index 4ab63d6f9ca..aa87b193932 100644 --- a/crates/derive-impl/src/pyclass.rs +++ b/crates/derive-impl/src/pyclass.rs @@ -2014,9 +2014,8 @@ where Err(wrong_name) => { if ALL_ALLOWED_NAMES.contains(&attr_name.as_str()) { bail_span!(attr, "#[pyclass] doesn't accept #[{}]", wrong_name) - } else { - continue; } + continue; } }; diff --git a/crates/derive-impl/src/pymodule.rs b/crates/derive-impl/src/pymodule.rs index b4b5535200c..aae1632ab39 100644 --- a/crates/derive-impl/src/pymodule.rs +++ b/crates/derive-impl/src/pymodule.rs @@ -469,9 +469,8 @@ where continue; } else if closed { bail_span!(attr, "Only one #[pyattr] annotated #[py*] item can exist") - } else { - bail_span!(attr, "#[pymodule] doesn't accept #[{}]", wrong_name) } + bail_span!(attr, "#[pymodule] doesn't accept #[{}]", wrong_name) } }; diff --git a/crates/derive-impl/src/pystructseq.rs b/crates/derive-impl/src/pystructseq.rs index 51628d438f1..12fc2d68904 100644 --- a/crates/derive-impl/src/pystructseq.rs +++ b/crates/derive-impl/src/pystructseq.rs @@ -451,9 +451,8 @@ impl PyStructSequenceMeta { inner.meta_ident, "#[pystruct_sequence({KEY}=value)] expects a string value" ) - } else { - Ok(None) } + Ok(None) } pub fn module(&self) -> Result> { @@ -475,9 +474,8 @@ impl PyStructSequenceMeta { inner.meta_ident, "#[pystruct_sequence({KEY}=value)] expects a string value" ) - } else { - Ok(None) } + Ok(None) } fn data_type(&self) -> Result { @@ -499,12 +497,11 @@ impl PyStructSequenceMeta { inner.meta_ident, "#[pystruct_sequence({KEY}=value)] expects a string value" ) - } else { - bail_span!( - inner.meta_ident, - "#[pystruct_sequence] requires data parameter (e.g., data = \"DataStructName\")" - ) } + bail_span!( + inner.meta_ident, + "#[pystruct_sequence] requires data parameter (e.g., data = \"DataStructName\")" + ) } pub fn no_attr(&self) -> Result { diff --git a/crates/host_env/src/crt_fd.rs b/crates/host_env/src/crt_fd.rs index ab7c94f8b3b..a648f181876 100644 --- a/crates/host_env/src/crt_fd.rs +++ b/crates/host_env/src/crt_fd.rs @@ -159,6 +159,7 @@ impl Owned { /// /// `fd` must be a valid file descriptor. #[inline] + #[must_use] pub unsafe fn from_raw(fd: Raw) -> Self { let inner = unsafe { OwnedInner::from_raw_fd(fd) }; Self { inner } @@ -181,20 +182,24 @@ impl Owned { } #[inline] + #[must_use] pub fn borrow(&self) -> Borrowed<'_> { unsafe { Borrowed::borrow_raw(self.as_raw()) } } #[inline] + #[must_use] pub fn as_raw(&self) -> Raw { self.inner.as_raw_fd() } #[inline] + #[must_use] pub fn into_raw(self) -> Raw { self.inner.into_raw_fd() } + #[must_use] pub fn leak<'fd>(self) -> Borrowed<'fd> { unsafe { Borrowed::borrow_raw(self.into_raw()) } } @@ -249,6 +254,7 @@ impl<'fd> Borrowed<'fd> { /// /// `fd` must be a valid file descriptor. #[inline] + #[must_use] pub const unsafe fn borrow_raw(fd: Raw) -> Self { let inner = unsafe { BorrowedInner::borrow_raw(fd) }; Self { inner } @@ -271,6 +277,7 @@ impl<'fd> Borrowed<'fd> { } #[inline] + #[must_use] pub fn as_raw(self) -> Raw { self.inner.as_raw_fd() } diff --git a/crates/host_env/src/fileutils.rs b/crates/host_env/src/fileutils.rs index a20140a6e04..f5a646c73c3 100644 --- a/crates/host_env/src/fileutils.rs +++ b/crates/host_env/src/fileutils.rs @@ -352,6 +352,7 @@ pub mod windows { } } + #[must_use] pub fn stat_basic_info_to_stat(info: &FILE_STAT_BASIC_INFORMATION) -> StatStruct { use windows_sys::Win32::Storage::FileSystem; use windows_sys::Win32::System::Ioctl; diff --git a/crates/host_env/src/msvcrt.rs b/crates/host_env/src/msvcrt.rs index 00a599e3944..6905c2d6556 100644 --- a/crates/host_env/src/msvcrt.rs +++ b/crates/host_env/src/msvcrt.rs @@ -29,10 +29,12 @@ pub fn setmode_binary(fd: crt_fd::Borrowed<'_>) { unsafe { suppress_iph!(_setmode(fd, libc::O_BINARY)) }; } +#[must_use] pub fn getch() -> Vec { vec![unsafe { _getch() } as u8] } +#[must_use] pub fn getwch() -> String { let value = unsafe { _getwch() }; char::from_u32(value) @@ -40,10 +42,12 @@ pub fn getwch() -> String { .to_string() } +#[must_use] pub fn getche() -> Vec { vec![unsafe { _getche() } as u8] } +#[must_use] pub fn getwche() -> String { let value = unsafe { _getwche() }; char::from_u32(value) @@ -77,6 +81,7 @@ pub fn ungetwch(c: char) -> io::Result<()> { } } +#[must_use] pub fn kbhit() -> i32 { unsafe { _kbhit() } } diff --git a/crates/host_env/src/os.rs b/crates/host_env/src/os.rs index 9d5aac5178b..c6dec6bbfeb 100644 --- a/crates/host_env/src/os.rs +++ b/crates/host_env/src/os.rs @@ -14,6 +14,7 @@ use std::{ /// /// On Windows, this supports the full u32 range including STATUS_CONTROL_C_EXIT (0xC000013A). /// On other platforms, only the lower 8 bits are used. +#[must_use] pub fn exit_code(code: u32) -> ExitCode { #[cfg(windows)] { @@ -32,6 +33,7 @@ pub fn current_dir() -> io::Result { env::current_dir() } +#[must_use] pub fn temp_dir() -> PathBuf { env::temp_dir() } @@ -44,10 +46,12 @@ pub fn var_os(key: impl AsRef) -> Option { env::var_os(key) } +#[must_use] pub fn vars_os() -> env::VarsOs { env::vars_os() } +#[must_use] pub fn vars() -> env::Vars { env::vars() } @@ -70,6 +74,7 @@ pub fn set_current_dir(path: impl AsRef) -> io::Result<()> { env::set_current_dir(path) } +#[must_use] pub fn process_id() -> u32 { std::process::id() } @@ -97,6 +102,7 @@ impl ErrorExt for io::Error { /// Get the last error from C runtime library functions (like _dup, _dup2, _fstat, etc.) /// CRT functions set errno, not GetLastError(), so we need to read errno directly. #[cfg(windows)] +#[must_use] pub fn errno_io_error() -> io::Error { let errno: i32 = get_errno(); let winerror = errno_to_winerror(errno); @@ -104,6 +110,7 @@ pub fn errno_io_error() -> io::Error { } #[cfg(not(windows))] +#[must_use] pub fn errno_io_error() -> io::Error { std::io::Error::last_os_error() } @@ -119,6 +126,7 @@ pub fn get_errno() -> i32 { } #[cfg(not(windows))] +#[must_use] pub fn get_errno() -> i32 { std::io::Error::last_os_error().posix_errno() } @@ -206,6 +214,7 @@ pub mod ffi { } #[cfg(windows)] +#[must_use] pub fn errno_to_winerror(errno: i32) -> i32 { use libc::*; use windows_sys::Win32::Foundation::*; @@ -235,6 +244,7 @@ pub fn errno_to_winerror(errno: i32) -> i32 { // winerror: https://learn.microsoft.com/windows/win32/debug/system-error-codes--0-499- // errno: https://learn.microsoft.com/cpp/c-runtime-library/errno-constants?view=msvc-170 #[cfg(windows)] +#[must_use] pub fn winerror_to_errno(winerror: i32) -> i32 { use libc::*; use windows_sys::Win32::{ diff --git a/crates/host_env/src/posix.rs b/crates/host_env/src/posix.rs index f3a5bbf4dcf..36f2e1df966 100644 --- a/crates/host_env/src/posix.rs +++ b/crates/host_env/src/posix.rs @@ -13,6 +13,7 @@ pub fn set_inheritable(fd: BorrowedFd<'_>, inheritable: bool) -> nix::Result<()> } #[cfg(target_os = "macos")] +#[must_use] pub fn get_number_of_os_threads() -> isize { type MachPortT = libc::c_uint; type KernReturnT = libc::c_int; @@ -60,6 +61,7 @@ pub fn get_number_of_os_threads() -> isize { } #[cfg(target_os = "linux")] +#[must_use] pub fn get_number_of_os_threads() -> isize { use std::io::Read as _; @@ -83,6 +85,7 @@ pub fn get_number_of_os_threads() -> isize { } #[cfg(not(any(target_os = "macos", target_os = "linux")))] +#[must_use] pub fn get_number_of_os_threads() -> isize { 0 } diff --git a/crates/host_env/src/select.rs b/crates/host_env/src/select.rs index e5ddc4284f7..dcb78616648 100644 --- a/crates/host_env/src/select.rs +++ b/crates/host_env/src/select.rs @@ -110,6 +110,7 @@ pub use platform::{RawFd, timeval}; pub struct FdSet(MaybeUninit); impl FdSet { + #[must_use] pub fn new() -> Self { let mut fdset = MaybeUninit::zeroed(); unsafe { platform::FD_ZERO(fdset.as_mut_ptr()) }; @@ -168,6 +169,7 @@ pub fn select( } } +#[must_use] pub fn sec_to_timeval(sec: f64) -> timeval { timeval { tv_sec: sec.trunc() as _, diff --git a/crates/host_env/src/signal.rs b/crates/host_env/src/signal.rs index 13a7206c68a..21794cc1827 100644 --- a/crates/host_env/src/signal.rs +++ b/crates/host_env/src/signal.rs @@ -1,7 +1,9 @@ +#[must_use] pub fn timeval_to_double(tv: &libc::timeval) -> f64 { tv.tv_sec as f64 + (tv.tv_usec as f64 / 1_000_000.0) } +#[must_use] pub fn double_to_timeval(val: f64) -> libc::timeval { libc::timeval { tv_sec: val.trunc() as _, @@ -9,6 +11,7 @@ pub fn double_to_timeval(val: f64) -> libc::timeval { } } +#[must_use] pub fn itimerval_to_tuple(it: &libc::itimerval) -> (f64, f64) { ( timeval_to_double(&it.it_value), diff --git a/crates/host_env/src/syslog.rs b/crates/host_env/src/syslog.rs index 67c10f6f21a..a4100ac2a21 100644 --- a/crates/host_env/src/syslog.rs +++ b/crates/host_env/src/syslog.rs @@ -25,6 +25,7 @@ fn global_ident() -> &'static RwLock> { IDENT.get_or_init(|| RwLock::new(None)) } +#[must_use] pub fn is_open() -> bool { global_ident() .read() @@ -55,14 +56,17 @@ pub fn closelog() { } } +#[must_use] pub fn setlogmask(maskpri: i32) -> i32 { unsafe { libc::setlogmask(maskpri) } } +#[must_use] pub const fn log_mask(pri: i32) -> i32 { pri << 1 } +#[must_use] pub const fn log_upto(pri: i32) -> i32 { (1 << (pri + 1)) - 1 } diff --git a/crates/host_env/src/time.rs b/crates/host_env/src/time.rs index b643d9c2e39..0bcabe9957b 100644 --- a/crates/host_env/src/time.rs +++ b/crates/host_env/src/time.rs @@ -16,6 +16,7 @@ pub fn duration_since_system_now() -> Result { #[cfg(target_env = "msvc")] #[cfg(not(target_arch = "wasm32"))] +#[must_use] pub fn get_tz_info() -> windows_sys::Win32::System::Time::TIME_ZONE_INFORMATION { let mut info = unsafe { core::mem::zeroed() }; unsafe { windows_sys::Win32::System::Time::GetTimeZoneInformation(&mut info) }; @@ -23,6 +24,7 @@ pub fn get_tz_info() -> windows_sys::Win32::System::Time::TIME_ZONE_INFORMATION } #[cfg(any(unix, windows))] +#[must_use] pub fn asctime_from_tm(tm: &libc::tm) -> String { const WDAY_NAME: [&str; 7] = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; const MON_NAME: [&str; 12] = [ diff --git a/crates/host_env/src/winapi.rs b/crates/host_env/src/winapi.rs index 26f46969315..70d7feea01d 100644 --- a/crates/host_env/src/winapi.rs +++ b/crates/host_env/src/winapi.rs @@ -1,17 +1,21 @@ use windows_sys::Win32::Foundation::HANDLE; +#[must_use] pub fn get_acp() -> u32 { unsafe { windows_sys::Win32::Globalization::GetACP() } } +#[must_use] pub fn get_current_process() -> HANDLE { unsafe { windows_sys::Win32::System::Threading::GetCurrentProcess() } } +#[must_use] pub fn get_last_error() -> u32 { unsafe { windows_sys::Win32::Foundation::GetLastError() } } +#[must_use] pub fn get_version() -> u32 { unsafe { windows_sys::Win32::System::SystemInformation::GetVersion() } } diff --git a/crates/jit/src/lib.rs b/crates/jit/src/lib.rs index 1e278617661..73dce1fedea 100644 --- a/crates/jit/src/lib.rs +++ b/crates/jit/src/lib.rs @@ -335,8 +335,9 @@ pub struct ArgsBuilder<'a> { } impl<'a> ArgsBuilder<'a> { - fn new(code: &'a CompiledCode) -> ArgsBuilder<'a> { - ArgsBuilder { + #[must_use] + fn new(code: &'a CompiledCode) -> Self { + Self { values: vec![None; code.sig.args.len()], code, } @@ -348,10 +349,12 @@ impl<'a> ArgsBuilder<'a> { }) } + #[must_use] pub fn is_set(&self, idx: usize) -> bool { self.values[idx].is_some() } + #[must_use] pub fn into_args(self) -> Option> { // Ensure all values are set if self.values.iter().any(|v| v.is_none()) { @@ -370,6 +373,7 @@ pub struct Args<'a> { } impl Args<'_> { + #[must_use] pub fn invoke(&self) -> Option { let cif_args: Vec<_> = self.values.iter().map(AbiValue::to_libffi_arg).collect(); unsafe { self.code.invoke_raw(&cif_args) } diff --git a/crates/sre_engine/src/engine.rs b/crates/sre_engine/src/engine.rs index 73e263012fc..a91ea3455fb 100644 --- a/crates/sre_engine/src/engine.rs +++ b/crates/sre_engine/src/engine.rs @@ -60,6 +60,7 @@ impl Default for Marks { } impl Marks { + #[must_use] pub fn get(&self, group_index: usize) -> (Optioned, Optioned) { let marks_index = 2 * group_index; if marks_index + 1 < self.marks.len() { @@ -69,10 +70,12 @@ impl Marks { } } + #[must_use] pub const fn last_index(&self) -> isize { self.last_index } + #[must_use] pub fn raw(&self) -> &[Optioned] { self.marks.as_slice() } @@ -191,9 +194,8 @@ impl State { if flags.contains(SreInfo::PREFIX) { if flags.contains(SreInfo::LITERAL) { return search_info_literal::(&mut req, self, ctx); - } else { - return search_info_literal::(&mut req, self, ctx); } + return search_info_literal::(&mut req, self, ctx); } else if flags.contains(SreInfo::CHARSET) { return search_info_charset(&mut req, self, ctx); } @@ -432,10 +434,9 @@ fn _match(req: &Request<'_, S>, state: &mut State, mut ctx: MatchCo if max_count == MAXREPEAT || ctx.count as usize <= max_count { state.cursor = ctx.cursor; break 'context ctx.next_peek_from(1, req, Jump::MinRepeatOne2); - } else { - state.marks.pop_discard(); - break 'result false; } + state.marks.pop_discard(); + break 'result false; } Jump::MinRepeatOne2 => { if popped_result { @@ -485,10 +486,9 @@ fn _match(req: &Request<'_, S>, state: &mut State, mut ctx: MatchCo ctx.count += 1; ctx.jump = Jump::PossessiveRepeat1; continue 'context; - } else { - state.cursor = ctx.cursor; - break 'result false; } + state.cursor = ctx.cursor; + break 'result false; } Jump::PossessiveRepeat3 => { let max_count = ctx.peek_code(req, 3) as usize; diff --git a/crates/sre_engine/src/string.rs b/crates/sre_engine/src/string.rs index 1350c9a07e1..9639be117a7 100644 --- a/crates/sre_engine/src/string.rs +++ b/crates/sre_engine/src/string.rs @@ -372,6 +372,7 @@ pub(crate) const fn is_linebreak(ch: u32) -> bool { ch == '\n' as u32 } #[inline] +#[must_use] pub fn lower_ascii(ch: u32) -> u32 { u8::try_from(ch) .map(|x| x.to_ascii_lowercase() as u32) @@ -456,6 +457,7 @@ pub(crate) fn is_uni_word(ch: u32) -> bool { ch == '_' as u32 || is_uni_alnum(ch) } #[inline] +#[must_use] pub fn lower_unicode(ch: u32) -> u32 { // TODO: check with cpython char::try_from(ch) @@ -463,6 +465,7 @@ pub fn lower_unicode(ch: u32) -> u32 { .unwrap_or(ch) } #[inline] +#[must_use] pub fn upper_unicode(ch: u32) -> u32 { // TODO: check with cpython char::try_from(ch) diff --git a/crates/stdlib/src/_sqlite3.rs b/crates/stdlib/src/_sqlite3.rs index 3f166ed3029..d55557d17de 100644 --- a/crates/stdlib/src/_sqlite3.rs +++ b/crates/stdlib/src/_sqlite3.rs @@ -457,7 +457,7 @@ mod _sqlite3 { let db = context.db_handle(); let args = args .iter() - .cloned() + .copied() .map(|val| value_to_object(val, db, vm)) .collect::>>()?; @@ -654,7 +654,7 @@ mod _sqlite3 { let db = context.db_handle(); let args = args .iter() - .cloned() + .copied() .map(|val| value_to_object(val, db, vm)) .collect::>>()?; vm.call_method(instance, name, args).map(drop) @@ -680,7 +680,9 @@ mod _sqlite3 { impl Drop for CallbackData { fn drop(&mut self) { - unsafe { PyObjectRef::from_raw(self.obj) }; + unsafe { + let _ = PyObjectRef::from_raw(self.obj); + }; } } diff --git a/crates/stdlib/src/compression.rs b/crates/stdlib/src/compression.rs index ae47ebbff70..1b74ab60110 100644 --- a/crates/stdlib/src/compression.rs +++ b/crates/stdlib/src/compression.rs @@ -162,10 +162,9 @@ pub fn _decompress_chunks( } else if !chunk.is_empty() && consumed == 0 { // we're gonna need a bigger buffer continue; - } else { - // next chunk - continue 'outer; } + // next chunk + continue 'outer; } Err(e) => { d.maybe_set_dict(e)?; diff --git a/crates/stdlib/src/faulthandler.rs b/crates/stdlib/src/faulthandler.rs index e562a382345..236f7b5070e 100644 --- a/crates/stdlib/src/faulthandler.rs +++ b/crates/stdlib/src/faulthandler.rs @@ -1012,7 +1012,7 @@ mod decl { pub fn get_user_signal(signum: usize) -> Option { let guard = USER_SIGNALS.lock(); - guard.as_ref().and_then(|v| v.get(signum).cloned()) + guard.as_ref().and_then(|v| v.get(signum).copied()) } pub fn set_user_signal(signum: usize, signal: UserSignal) { diff --git a/crates/stdlib/src/select.rs b/crates/stdlib/src/select.rs index 1cfe22e7c61..d2ebfd1bb6d 100644 --- a/crates/stdlib/src/select.rs +++ b/crates/stdlib/src/select.rs @@ -47,7 +47,7 @@ mod decl { #[cfg(unix)] { use crate::vm::class::PyClassImpl; - poll::PyPoll::make_static_type(); + let _ = poll::PyPoll::make_static_type(); } __module_exec(vm, module); diff --git a/crates/stdlib/src/ssl/cert.rs b/crates/stdlib/src/ssl/cert.rs index f838733c03d..b79101ba4fe 100644 --- a/crates/stdlib/src/ssl/cert.rs +++ b/crates/stdlib/src/ssl/cert.rs @@ -812,10 +812,9 @@ impl<'a> CertLoader<'a> { return Err(cert_error::der::not_enough_data( "cadata does not contain a certificate", )); - } else { - // Loaded some certificates but failed on subsequent data (garbage) - return Err(cert_error::der::parse_failed(e)); } + // Loaded some certificates but failed on subsequent data (garbage) + return Err(cert_error::der::parse_failed(e)); } } } diff --git a/crates/stdlib/src/ssl/compat.rs b/crates/stdlib/src/ssl/compat.rs index a703ab4d8b0..1b04e85b9c4 100644 --- a/crates/stdlib/src/ssl/compat.rs +++ b/crates/stdlib/src/ssl/compat.rs @@ -2016,30 +2016,28 @@ fn ssl_read_tls_records( if is_bio { // In BIO mode, no data means WANT_READ return Err(SslError::WantRead); - } else { - // In socket mode, empty recv() means TCP EOF (FIN received) - // Need to distinguish: - // 1. Clean shutdown: received TLS close_notify → return ZeroReturn (0 bytes) - // 2. Unexpected EOF: no close_notify → return Eof (SSLEOFError) - // - // SSL_ERROR_ZERO_RETURN vs SSL_ERROR_EOF logic - // CPython checks SSL_get_shutdown() & SSL_RECEIVED_SHUTDOWN - // - // Process any buffered TLS records (may contain close_notify) - match conn.process_new_packets() { - Ok(io_state) => { - if io_state.peer_has_closed() { - // Received close_notify - normal SSL closure (SSL_ERROR_ZERO_RETURN) - return Err(SslError::ZeroReturn); - } else { - // No close_notify - ragged EOF (SSL_ERROR_EOF → SSLEOFError) - // CPython raises SSLEOFError here, which SSLSocket.read() handles - // based on suppress_ragged_eofs setting - return Err(SslError::Eof); - } + } + // In socket mode, empty recv() means TCP EOF (FIN received) + // Need to distinguish: + // 1. Clean shutdown: received TLS close_notify → return ZeroReturn (0 bytes) + // 2. Unexpected EOF: no close_notify → return Eof (SSLEOFError) + // + // SSL_ERROR_ZERO_RETURN vs SSL_ERROR_EOF logic + // CPython checks SSL_get_shutdown() & SSL_RECEIVED_SHUTDOWN + // + // Process any buffered TLS records (may contain close_notify) + match conn.process_new_packets() { + Ok(io_state) => { + if io_state.peer_has_closed() { + // Received close_notify - normal SSL closure (SSL_ERROR_ZERO_RETURN) + return Err(SslError::ZeroReturn); } - Err(e) => return Err(SslError::from_rustls(e)), + // No close_notify - ragged EOF (SSL_ERROR_EOF → SSLEOFError) + // CPython raises SSLEOFError here, which SSLSocket.read() handles + // based on suppress_ragged_eofs setting + return Err(SslError::Eof); } + Err(e) => return Err(SslError::from_rustls(e)), } } diff --git a/crates/vm/src/buffer.rs b/crates/vm/src/buffer.rs index 9a47dd35858..da7965c11e6 100644 --- a/crates/vm/src/buffer.rs +++ b/crates/vm/src/buffer.rs @@ -523,6 +523,7 @@ impl FormatSpec { } #[inline] + #[must_use] pub const fn size(&self) -> usize { self.size } diff --git a/crates/vm/src/builtins/asyncgenerator.rs b/crates/vm/src/builtins/asyncgenerator.rs index dcb1c6d6f81..03337fd7fd3 100644 --- a/crates/vm/src/builtins/asyncgenerator.rs +++ b/crates/vm/src/builtins/asyncgenerator.rs @@ -49,6 +49,7 @@ impl PyAsyncGen { &self.inner } + #[must_use] pub fn new(frame: FrameRef, name: PyStrRef, qualname: PyStrRef) -> Self { Self { inner: Coro::new(frame, name, qualname), diff --git a/crates/vm/src/builtins/bytes.rs b/crates/vm/src/builtins/bytes.rs index 00cf3d2d113..a7ea6eb4252 100644 --- a/crates/vm/src/builtins/bytes.rs +++ b/crates/vm/src/builtins/bytes.rs @@ -205,16 +205,19 @@ impl PyRef { )] impl PyBytes { #[inline] + #[must_use] pub const fn __len__(&self) -> usize { self.inner.len() } #[inline] + #[must_use] pub const fn is_empty(&self) -> bool { self.inner.is_empty() } #[inline] + #[must_use] pub fn as_bytes(&self) -> &[u8] { self.inner.as_bytes() } diff --git a/crates/vm/src/builtins/complex.rs b/crates/vm/src/builtins/complex.rs index 9034c5f3fb3..f64e71de553 100644 --- a/crates/vm/src/builtins/complex.rs +++ b/crates/vm/src/builtins/complex.rs @@ -272,10 +272,12 @@ impl PyComplex { Self::from(value).into_ref(ctx) } + #[must_use] pub const fn to_complex64(self) -> Complex64 { self.value } + #[must_use] pub const fn to_complex(&self) -> Complex64 { self.value } diff --git a/crates/vm/src/builtins/coroutine.rs b/crates/vm/src/builtins/coroutine.rs index 9746dddda87..8d6d7c3e956 100644 --- a/crates/vm/src/builtins/coroutine.rs +++ b/crates/vm/src/builtins/coroutine.rs @@ -40,6 +40,7 @@ impl PyCoroutine { &self.inner } + #[must_use] pub fn new(frame: FrameRef, name: PyStrRef, qualname: PyStrRef) -> Self { Self { inner: Coro::new(frame, name, qualname), diff --git a/crates/vm/src/builtins/float.rs b/crates/vm/src/builtins/float.rs index 4adec5e2a07..87b627ce14f 100644 --- a/crates/vm/src/builtins/float.rs +++ b/crates/vm/src/builtins/float.rs @@ -29,6 +29,7 @@ pub struct PyFloat { } impl PyFloat { + #[must_use] pub const fn to_f64(&self) -> f64 { self.value } diff --git a/crates/vm/src/builtins/function.rs b/crates/vm/src/builtins/function.rs index 93ba3693b93..cb4f78f9f02 100644 --- a/crates/vm/src/builtins/function.rs +++ b/crates/vm/src/builtins/function.rs @@ -1261,6 +1261,7 @@ impl Constructor for PyBoundMethod { } impl PyBoundMethod { + #[must_use] pub const fn new(object: PyObjectRef, function: PyObjectRef) -> Self { Self { object, function } } diff --git a/crates/vm/src/builtins/generator.rs b/crates/vm/src/builtins/generator.rs index 2eee2fecd0d..751c73b12ff 100644 --- a/crates/vm/src/builtins/generator.rs +++ b/crates/vm/src/builtins/generator.rs @@ -42,6 +42,7 @@ impl PyGenerator { &self.inner } + #[must_use] pub fn new(frame: FrameRef, name: PyStrRef, qualname: PyStrRef) -> Self { Self { inner: Coro::new(frame, name, qualname), diff --git a/crates/vm/src/builtins/int.rs b/crates/vm/src/builtins/int.rs index a586a881711..4bab3c62930 100644 --- a/crates/vm/src/builtins/int.rs +++ b/crates/vm/src/builtins/int.rs @@ -303,12 +303,14 @@ impl PyInt { } } + #[must_use] pub const fn as_bigint(&self) -> &BigInt { &self.value } /// Fast decimal string conversion, using i64 path when possible. #[inline] + #[must_use] pub fn to_str_radix_10(&self) -> String { match self.value.to_i64() { Some(i) => i.to_string(), @@ -317,6 +319,7 @@ impl PyInt { } // _PyLong_AsUnsignedLongMask + #[must_use] pub fn as_u32_mask(&self) -> u32 { let v = self.as_bigint(); v.to_u32() diff --git a/crates/vm/src/builtins/iter.rs b/crates/vm/src/builtins/iter.rs index f33b0e9bbbb..a5b4fe0d3cc 100644 --- a/crates/vm/src/builtins/iter.rs +++ b/crates/vm/src/builtins/iter.rs @@ -239,6 +239,7 @@ impl PyPayload for PyCallableIterator { #[pyclass(with(IterNext, Iterable))] impl PyCallableIterator { + #[must_use] pub const fn new(callable: ArgCallable, sentinel: PyObjectRef) -> Self { Self { sentinel, diff --git a/crates/vm/src/builtins/module.rs b/crates/vm/src/builtins/module.rs index cabaf1d63cb..d62a13eec53 100644 --- a/crates/vm/src/builtins/module.rs +++ b/crates/vm/src/builtins/module.rs @@ -113,6 +113,7 @@ pub struct ModuleInitArgs { impl PyModule { #[allow(clippy::new_without_default)] + #[must_use] pub const fn new() -> Self { Self { def: None, @@ -120,6 +121,7 @@ impl PyModule { } } + #[must_use] pub const fn from_def(def: &'static PyModuleDef) -> Self { Self { def: Some(def), diff --git a/crates/vm/src/builtins/range.rs b/crates/vm/src/builtins/range.rs index 6e03ea8b482..b5b8fafa895 100644 --- a/crates/vm/src/builtins/range.rs +++ b/crates/vm/src/builtins/range.rs @@ -128,6 +128,7 @@ impl PyRange { } #[inline] + #[must_use] pub fn index_of(&self, value: &BigInt) -> Option { let step = self.step.as_bigint(); match self.offset(value) { @@ -137,16 +138,19 @@ impl PyRange { } #[inline] + #[must_use] pub fn is_empty(&self) -> bool { self.compute_length().is_zero() } #[inline] + #[must_use] pub fn forward(&self) -> bool { self.start.as_bigint() < self.stop.as_bigint() } #[inline] + #[must_use] pub fn get(&self, index: &BigInt) -> Option { let start = self.start.as_bigint(); let step = self.step.as_bigint(); diff --git a/crates/vm/src/builtins/set.rs b/crates/vm/src/builtins/set.rs index fe1da1174d7..da8e5907d7b 100644 --- a/crates/vm/src/builtins/set.rs +++ b/crates/vm/src/builtins/set.rs @@ -46,6 +46,7 @@ impl PySet { Self::default().into_ref(ctx) } + #[must_use] pub fn elements(&self) -> Vec { self.inner.elements() } diff --git a/crates/vm/src/builtins/staticmethod.rs b/crates/vm/src/builtins/staticmethod.rs index 551e1cb4b88..4be2b14c442 100644 --- a/crates/vm/src/builtins/staticmethod.rs +++ b/crates/vm/src/builtins/staticmethod.rs @@ -62,6 +62,7 @@ impl Constructor for PyStaticMethod { } impl PyStaticMethod { + #[must_use] pub fn new(callable: PyObjectRef) -> Self { Self { callable: PyMutex::new(callable), diff --git a/crates/vm/src/builtins/str.rs b/crates/vm/src/builtins/str.rs index 8a50c4a5268..d0bc2e719af 100644 --- a/crates/vm/src/builtins/str.rs +++ b/crates/vm/src/builtins/str.rs @@ -456,6 +456,7 @@ impl PyStr { /// # Safety /// Given `bytes` must be ascii + #[must_use] pub unsafe fn new_ascii_unchecked(bytes: Vec) -> Self { unsafe { AsciiString::from_ascii_unchecked(bytes) }.into() } @@ -1533,6 +1534,7 @@ impl PyStr { } impl PyRef { + #[must_use] pub fn is_empty(&self) -> bool { (**self).is_empty() } @@ -2221,6 +2223,7 @@ impl Py { impl PyRef { /// Convert to PyStrRef. Safe because PyUtf8Str is a subtype of PyStr. + #[must_use] pub fn into_wtf8(self) -> PyStrRef { unsafe { mem::transmute::(self) } } diff --git a/crates/vm/src/builtins/template.rs b/crates/vm/src/builtins/template.rs index 3f03f9a227a..9aa05df2fcf 100644 --- a/crates/vm/src/builtins/template.rs +++ b/crates/vm/src/builtins/template.rs @@ -34,6 +34,7 @@ impl PyPayload for PyTemplate { } impl PyTemplate { + #[must_use] pub fn new(strings: PyTupleRef, interpolations: PyTupleRef) -> Self { Self { strings, diff --git a/crates/vm/src/builtins/traceback.rs b/crates/vm/src/builtins/traceback.rs index c6eac4e87e7..7bfe7febe3d 100644 --- a/crates/vm/src/builtins/traceback.rs +++ b/crates/vm/src/builtins/traceback.rs @@ -28,6 +28,7 @@ impl PyPayload for PyTraceback { #[pyclass(with(Constructor))] impl PyTraceback { + #[must_use] pub const fn new( next: Option>, frame: FrameRef, diff --git a/crates/vm/src/builtins/tuple.rs b/crates/vm/src/builtins/tuple.rs index b2c2fabc540..cfb71794093 100644 --- a/crates/vm/src/builtins/tuple.rs +++ b/crates/vm/src/builtins/tuple.rs @@ -291,16 +291,19 @@ impl<'a, R> core::iter::IntoIterator for &'a Py> { } impl PyTuple { + #[must_use] pub const fn as_slice(&self) -> &[R] { &self.elements } #[inline] + #[must_use] pub fn len(&self) -> usize { self.elements.len() } #[inline] + #[must_use] pub fn is_empty(&self) -> bool { self.elements.is_empty() } @@ -325,6 +328,7 @@ impl PyTuple { /// Creating a new tuple with given boxed slice. /// NOTE: for usual case, you probably want to use PyTuple::new_ref. /// Calling this function implies trying micro optimization for non-zero-sized tuple. + #[must_use] pub const fn new_unchecked(elements: Box<[PyObjectRef]>) -> Self { Self { elements } } @@ -402,6 +406,7 @@ impl PyTuple { } #[inline] + #[must_use] pub const fn __len__(&self) -> usize { self.elements.len() } @@ -608,6 +613,7 @@ impl PyRef> { } impl PyRef>> { + #[must_use] pub fn into_untyped(self) -> PyRef { // SAFETY: PyTuple> has the same layout as PyTuple unsafe { core::mem::transmute::>(self) } diff --git a/crates/vm/src/builtins/union.rs b/crates/vm/src/builtins/union.rs index c3a7e42c7ab..2d1ebd5d203 100644 --- a/crates/vm/src/builtins/union.rs +++ b/crates/vm/src/builtins/union.rs @@ -53,6 +53,7 @@ impl PyUnion { /// Direct access to args field (_Py_union_args) #[inline] + #[must_use] pub fn args(&self) -> &Py { &self.args } diff --git a/crates/vm/src/class.rs b/crates/vm/src/class.rs index 237e11abbe5..e0179f5451d 100644 --- a/crates/vm/src/class.rs +++ b/crates/vm/src/class.rs @@ -67,14 +67,17 @@ pub trait StaticType { // Ideally, saving PyType is better than PyTypeRef fn static_cell() -> &'static static_cell::StaticCell; #[inline] + #[must_use] fn static_metaclass() -> &'static Py { PyType::static_type() } #[inline] + #[must_use] fn static_baseclass() -> &'static Py { PyBaseObject::static_type() } #[inline] + #[must_use] fn static_type() -> &'static Py { #[cold] fn fail() -> ! { @@ -84,12 +87,14 @@ pub trait StaticType { } Self::static_cell().get().unwrap_or_else(|| fail()) } + #[must_use] fn init_manually(typ: PyTypeRef) -> &'static Py { let cell = Self::static_cell(); cell.set(typ) .unwrap_or_else(|_| panic!("double initialization from init_manually")); cell.get().unwrap() } + #[must_use] fn init_builtin_type() -> &'static Py where Self: PyClassImpl, @@ -100,6 +105,7 @@ pub trait StaticType { .unwrap_or_else(|_| panic!("double initialization of {}", Self::NAME)); cell.get().unwrap() } + #[must_use] fn create_static_type() -> PyTypeRef where Self: PyClassImpl, @@ -206,6 +212,7 @@ pub trait PyClassImpl: PyClassDef { class.extend_methods(class.slots.methods, ctx); } + #[must_use] fn make_static_type() -> PyTypeRef where Self: StaticType + Sized, diff --git a/crates/vm/src/datastack.rs b/crates/vm/src/datastack.rs index b00f1b6dc19..40d94d08186 100644 --- a/crates/vm/src/datastack.rs +++ b/crates/vm/src/datastack.rs @@ -59,6 +59,7 @@ pub struct DataStack { impl DataStack { /// Create a new data stack with an initial root chunk. + #[must_use] pub fn new() -> Self { let chunk = Self::alloc_chunk(MIN_CHUNK_SIZE, ptr::null_mut()); let top = unsafe { (*chunk).data_start() }; @@ -71,6 +72,7 @@ impl DataStack { /// Check if the current chunk has at least `size` bytes available. #[inline(always)] + #[must_use] pub fn has_space(&self, size: usize) -> bool { let aligned_size = (size + ALIGN - 1) & !(ALIGN - 1); (self.limit as usize).saturating_sub(self.top as usize) >= aligned_size diff --git a/crates/vm/src/exception_group.rs b/crates/vm/src/exception_group.rs index 76558af1d35..22f299922f8 100644 --- a/crates/vm/src/exception_group.rs +++ b/crates/vm/src/exception_group.rs @@ -34,6 +34,7 @@ fn create_exception_group(ctx: &Context) -> PyRef { .expect("Failed to create ExceptionGroup type with multiple inheritance") } +#[must_use] pub fn exception_group() -> &'static Py { ::rustpython_vm::common::static_cell! { static CELL: ::rustpython_vm::builtins::PyTypeRef; diff --git a/crates/vm/src/function/argument.rs b/crates/vm/src/function/argument.rs index b39ee6f6bca..40408531cbe 100644 --- a/crates/vm/src/function/argument.rs +++ b/crates/vm/src/function/argument.rs @@ -139,6 +139,7 @@ impl FuncArgs { /// `args[..nargs]` are positional, and if `kwnames` is provided, /// the last `kwnames.len()` entries in `args[nargs..]` are keyword values. /// Convert borrowed vectorcall args to FuncArgs (clones all values). + #[must_use] pub fn from_vectorcall( args: &[PyObjectRef], nargs: usize, @@ -170,6 +171,7 @@ impl FuncArgs { } /// Convert owned vectorcall args to FuncArgs (moves values, no clone). + #[must_use] pub fn from_vectorcall_owned( mut args: Vec, nargs: usize, @@ -198,6 +200,7 @@ impl FuncArgs { Self { args, kwargs } } + #[must_use] pub fn is_empty(&self) -> bool { self.args.is_empty() && self.kwargs.is_empty() } @@ -211,6 +214,7 @@ impl FuncArgs { self.args.remove(0) } + #[must_use] pub fn get_kwarg(&self, key: &str, default: PyObjectRef) -> PyObjectRef { self.kwargs .get(key) @@ -218,6 +222,7 @@ impl FuncArgs { .unwrap_or_else(|| default.clone()) } + #[must_use] pub fn get_optional_kwarg(&self, key: &str) -> Option { self.kwargs.get(key).cloned() } @@ -357,6 +362,7 @@ pub trait FromArgs: Sized { /// The range of positional arguments permitted by the function signature. /// /// Returns an empty range if not applicable. + #[must_use] fn arity() -> RangeInclusive { 0..=0 } @@ -411,6 +417,7 @@ where } impl KwArgs { + #[must_use] pub const fn new(map: IndexMap) -> Self { Self(map) } @@ -419,6 +426,7 @@ impl KwArgs { self.0.swap_remove(name) } + #[must_use] pub fn is_empty(self) -> bool { self.0.is_empty() } @@ -479,10 +487,12 @@ where } impl PosArgs { + #[must_use] pub const fn new(args: Vec) -> Self { Self(args) } + #[must_use] pub fn into_vec(self) -> Vec { self.0 } diff --git a/crates/vm/src/function/buffer.rs b/crates/vm/src/function/buffer.rs index c0dd6473bdc..028f3633d06 100644 --- a/crates/vm/src/function/buffer.rs +++ b/crates/vm/src/function/buffer.rs @@ -39,6 +39,7 @@ impl PyObject { } impl ArgBytesLike { + #[must_use] pub fn borrow_buf(&self) -> BorrowedValue<'_, [u8]> { unsafe { self.0.contiguous_unchecked() } } @@ -50,14 +51,17 @@ impl ArgBytesLike { f(&self.borrow_buf()) } + #[must_use] pub const fn len(&self) -> usize { self.0.desc.len } + #[must_use] pub const fn is_empty(&self) -> bool { self.len() == 0 } + #[must_use] pub fn as_object(&self) -> &PyObject { &self.0.obj } @@ -91,6 +95,7 @@ impl<'a> TryFromBorrowedObject<'a> for ArgBytesLike { pub struct ArgMemoryBuffer(PyBuffer); impl ArgMemoryBuffer { + #[must_use] pub fn borrow_buf_mut(&self) -> BorrowedValueMut<'_, [u8]> { unsafe { self.0.contiguous_mut_unchecked() } } @@ -102,10 +107,12 @@ impl ArgMemoryBuffer { f(&mut self.borrow_buf_mut()) } + #[must_use] pub const fn len(&self) -> usize { self.0.desc.len } + #[must_use] pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -137,6 +144,7 @@ pub enum ArgStrOrBytesLike { } impl ArgStrOrBytesLike { + #[must_use] pub fn as_object(&self) -> &PyObject { match self { Self::Buf(b) => b.as_object(), @@ -154,6 +162,7 @@ impl TryFromObject for ArgStrOrBytesLike { } impl ArgStrOrBytesLike { + #[must_use] pub fn borrow_bytes(&self) -> BorrowedValue<'_, [u8]> { match self { Self::Buf(b) => b.borrow_buf(), @@ -184,6 +193,7 @@ impl TryFromObject for ArgAsciiBuffer { } impl ArgAsciiBuffer { + #[must_use] pub fn len(&self) -> usize { match self { Self::String(s) => s.as_wtf8().len(), @@ -191,6 +201,7 @@ impl ArgAsciiBuffer { } } + #[must_use] pub fn is_empty(&self) -> bool { self.len() == 0 } diff --git a/crates/vm/src/function/fspath.rs b/crates/vm/src/function/fspath.rs index c3ec1221627..5ec81ba63a6 100644 --- a/crates/vm/src/function/fspath.rs +++ b/crates/vm/src/function/fspath.rs @@ -89,6 +89,7 @@ impl FsPath { } } + #[must_use] pub fn as_bytes(&self) -> &[u8] { // TODO: FS encodings match self { @@ -97,6 +98,7 @@ impl FsPath { } } + #[must_use] pub fn to_string_lossy(&self) -> Cow<'_, str> { match self { Self::Str(s) => s.to_string_lossy(), diff --git a/crates/vm/src/function/method.rs b/crates/vm/src/function/method.rs index 295e4d89adf..95635d0a0e9 100644 --- a/crates/vm/src/function/method.rs +++ b/crates/vm/src/function/method.rs @@ -118,6 +118,7 @@ impl PyMethodDef { } } + #[must_use] pub const fn to_function(&'static self) -> PyNativeFunction { PyNativeFunction { zelf: None, @@ -226,6 +227,7 @@ impl PyMethodDef { } #[doc(hidden)] + #[must_use] pub const fn __const_concat_arrays( method_groups: &[&[Self]], ) -> [Self; SUM_LEN] { @@ -286,6 +288,7 @@ pub struct HeapMethodDef { } impl HeapMethodDef { + #[must_use] pub const fn new(method: PyMethodDef) -> Self { Self { method } } diff --git a/crates/vm/src/function/number.rs b/crates/vm/src/function/number.rs index b53208bcd93..a7563eb2bfd 100644 --- a/crates/vm/src/function/number.rs +++ b/crates/vm/src/function/number.rs @@ -22,6 +22,7 @@ pub struct ArgIntoComplex { impl ArgIntoComplex { #[inline] + #[must_use] pub fn into_complex(self) -> Complex64 { self.value } @@ -60,10 +61,12 @@ pub struct ArgIntoFloat { impl ArgIntoFloat { #[inline] + #[must_use] pub fn into_float(self) -> f64 { self.value } + #[must_use] pub fn vec_into_f64(v: Vec) -> Vec { // TODO: Vec::into_raw_parts once stabilized let mut v = core::mem::ManuallyDrop::new(v); @@ -105,6 +108,7 @@ impl ArgIntoBool { pub const FALSE: Self = Self { value: false }; #[inline] + #[must_use] pub fn into_bool(self) -> bool { self.value } @@ -133,6 +137,7 @@ pub struct ArgIndex { impl ArgIndex { #[inline] + #[must_use] pub fn into_int_ref(self) -> PyIntRef { self.value } diff --git a/crates/vm/src/function/protocol.rs b/crates/vm/src/function/protocol.rs index 402f6d0365b..25ef62b458d 100644 --- a/crates/vm/src/function/protocol.rs +++ b/crates/vm/src/function/protocol.rs @@ -124,21 +124,25 @@ pub struct ArgMapping { impl ArgMapping { #[inline] + #[must_use] pub const fn new(obj: PyObjectRef) -> Self { Self { obj } } #[inline(always)] + #[must_use] pub fn from_dict_exact(dict: PyDictRef) -> Self { Self { obj: dict.into() } } #[inline(always)] + #[must_use] pub fn obj(&self) -> &PyObject { &self.obj } #[inline(always)] + #[must_use] pub fn mapping(&self) -> PyMapping<'_> { self.obj.mapping_unchecked() } @@ -191,10 +195,12 @@ unsafe impl Traverse for ArgSequence { impl ArgSequence { #[inline(always)] + #[must_use] pub fn into_vec(self) -> Vec { self.0 } #[inline(always)] + #[must_use] pub fn as_slice(&self) -> &[T] { &self.0 } diff --git a/crates/vm/src/function/time.rs b/crates/vm/src/function/time.rs index 29f14495d14..597da1710b5 100644 --- a/crates/vm/src/function/time.rs +++ b/crates/vm/src/function/time.rs @@ -10,11 +10,13 @@ pub struct TimeoutSeconds { } impl TimeoutSeconds { + #[must_use] pub const fn new(secs: f64) -> Self { Self { value: secs } } #[inline] + #[must_use] pub fn to_secs_f64(self) -> f64 { self.value } diff --git a/crates/vm/src/gc_state.rs b/crates/vm/src/gc_state.rs index 4cadd98a9db..37252bc4a0b 100644 --- a/crates/vm/src/gc_state.rs +++ b/crates/vm/src/gc_state.rs @@ -67,6 +67,7 @@ pub struct GcGeneration { } impl GcGeneration { + #[must_use] pub const fn new(threshold: u32) -> Self { Self { count: AtomicUsize::new(0), @@ -174,6 +175,7 @@ impl Default for GcState { } impl GcState { + #[must_use] pub fn new() -> Self { Self { generations: [ diff --git a/crates/vm/src/macros.rs b/crates/vm/src/macros.rs index 00be9a1c597..17ece048f6e 100644 --- a/crates/vm/src/macros.rs +++ b/crates/vm/src/macros.rs @@ -63,13 +63,12 @@ macro_rules! py_namespace { /// /// # Examples /// -/// ``` +/// ```rust /// use malachite_bigint::ToBigInt; /// use num_traits::Zero; /// -/// use rustpython_vm::match_class; +/// use rustpython_vm::{PyPayload, match_class}; /// use rustpython_vm::builtins::{PyFloat, PyInt}; -/// use rustpython_vm::{PyPayload}; /// /// # rustpython_vm::Interpreter::without_stdlib(Default::default()).enter(|vm| { /// let obj = PyInt::from(0).into_pyobject(vm); @@ -87,13 +86,12 @@ macro_rules! py_namespace { /// /// With a binding to the downcasted type: /// -/// ``` +/// ```rust /// use malachite_bigint::ToBigInt; /// use num_traits::Zero; /// -/// use rustpython_vm::match_class; +/// use rustpython_vm::{PyPayload, match_class}; /// use rustpython_vm::builtins::{PyFloat, PyInt}; -/// use rustpython_vm::{ PyPayload}; /// /// # rustpython_vm::Interpreter::without_stdlib(Default::default()).enter(|vm| { /// let obj = PyInt::from(0).into_pyobject(vm); diff --git a/crates/vm/src/object/core.rs b/crates/vm/src/object/core.rs index 39ef93de5fb..df2e8d893aa 100644 --- a/crates/vm/src/object/core.rs +++ b/crates/vm/src/object/core.rs @@ -1291,6 +1291,7 @@ impl PyObject { impl PyObjectRef { #[inline(always)] + #[must_use] pub const fn into_raw(self) -> NonNull { let ptr = self.ptr; core::mem::forget(self); @@ -1303,6 +1304,7 @@ impl PyObjectRef { /// dropped more than once due to mishandling the reference count by calling this function /// too many times. #[inline(always)] + #[must_use] pub const unsafe fn from_raw(ptr: NonNull) -> Self { Self { ptr } } @@ -1330,6 +1332,7 @@ impl PyObjectRef { /// # Safety /// T must be the exact payload type #[inline(always)] + #[must_use] pub unsafe fn downcast_unchecked(self) -> PyRef { // PyRef::from_obj_unchecked(self) // manual impl to avoid assertion @@ -1926,6 +1929,7 @@ impl PyStackRef { /// Create an owned stack reference, consuming the `PyObjectRef`. /// Refcount is NOT incremented — ownership is transferred. #[inline(always)] + #[must_use] pub fn new_owned(obj: PyObjectRef) -> Self { let ptr = obj.into_raw(); let bits = ptr.as_ptr() as usize; @@ -1957,12 +1961,14 @@ impl PyStackRef { /// Whether this is a borrowed (non-owning) reference. #[inline(always)] + #[must_use] pub fn is_borrowed(&self) -> bool { self.bits.get() & STACKREF_BORROW_TAG != 0 } /// Get a `&PyObject` reference. Works for both owned and borrowed. #[inline(always)] + #[must_use] pub fn as_object(&self) -> &PyObject { unsafe { &*((self.bits.get() & !STACKREF_BORROW_TAG) as *const PyObject) } } @@ -1972,6 +1978,7 @@ impl PyStackRef { /// * If **borrowed** → increments refcount, forgets self. /// * If **owned** → reconstructs `PyObjectRef` from the raw pointer, forgets self. #[inline(always)] + #[must_use] pub fn to_pyobj(self) -> PyObjectRef { let obj = if self.is_borrowed() { self.as_object().to_owned() // inc refcount @@ -2213,6 +2220,7 @@ impl PyRef { } } + #[must_use] pub const fn leak(pyref: Self) -> &'static Py { let ptr = pyref.ptr; core::mem::forget(pyref); @@ -2281,6 +2289,7 @@ where /// # Safety /// T and T::Base must have compatible layouts in size_of::() bytes. #[inline] + #[must_use] pub fn into_base(self) -> PyRef { let obj: PyObjectRef = self.into(); match obj.downcast() { @@ -2289,6 +2298,7 @@ where } } #[inline] + #[must_use] pub fn upcast(self) -> PyRef where T: StaticType, @@ -2404,6 +2414,7 @@ pub struct PyWeakRef { } impl PyWeakRef { + #[must_use] pub fn upgrade(&self) -> Option> { self.weak .upgrade() diff --git a/crates/vm/src/object/ext.rs b/crates/vm/src/object/ext.rs index a87eb3b6dd2..dc4a7bd4fd4 100644 --- a/crates/vm/src/object/ext.rs +++ b/crates/vm/src/object/ext.rs @@ -142,10 +142,12 @@ pub struct PyRefExact { impl PyRefExact { /// # Safety /// obj must have exact type for the payload + #[must_use] pub const unsafe fn new_unchecked(obj: PyRef) -> Self { Self { inner: obj } } + #[must_use] pub fn into_pyref(self) -> PyRef { self.inner } @@ -500,6 +502,7 @@ unsafe impl Send for PyAtomicBorrow {} unsafe impl Sync for PyAtomicBorrow {} impl PyAtomicBorrow { + #[must_use] pub fn new() -> Self { Self { inner: Radium::new(null_mut()), @@ -610,6 +613,7 @@ pub struct PyLease<'a, T: PyPayload> { impl PyLease<'_, T> { #[inline(always)] + #[must_use] pub fn into_owned(self) -> PyRef { self.inner.clone() } diff --git a/crates/vm/src/ospath.rs b/crates/vm/src/ospath.rs index c90d4789db3..0bb3f957059 100644 --- a/crates/vm/src/ospath.rs +++ b/crates/vm/src/ospath.rs @@ -21,6 +21,7 @@ pub struct PathConverter { } impl PathConverter { + #[must_use] pub const fn new() -> Self { Self { function_name: None, @@ -29,16 +30,19 @@ impl PathConverter { } } + #[must_use] pub const fn function(mut self, name: &'static str) -> Self { self.function_name = Some(name); self } + #[must_use] pub const fn argument(mut self, name: &'static str) -> Self { self.argument_name = Some(name); self } + #[must_use] pub const fn non_strict(mut self) -> Self { self.non_strict = true; self @@ -235,14 +239,17 @@ impl OsPath { Self::from_fspath(fspath, vm) } + #[must_use] pub fn as_path(&self) -> &Path { Path::new(&self.path) } + #[must_use] pub fn into_bytes(self) -> Vec { self.path.into_encoded_bytes() } + #[must_use] pub fn to_string_lossy(&self) -> alloc::borrow::Cow<'_, str> { self.path.to_string_lossy() } @@ -266,6 +273,7 @@ impl OsPath { } /// Get the output mode based on origin type (bytes -> Bytes, otherwise -> String) + #[must_use] pub fn mode(&self) -> OutputMode { match &self.origin { Some(obj) if obj.downcast_ref::().is_some() => OutputMode::Bytes, diff --git a/crates/vm/src/protocol/buffer.rs b/crates/vm/src/protocol/buffer.rs index 0fe4d15458b..8e7667241b3 100644 --- a/crates/vm/src/protocol/buffer.rs +++ b/crates/vm/src/protocol/buffer.rs @@ -42,6 +42,7 @@ pub struct PyBuffer { } impl PyBuffer { + #[must_use] pub fn new(obj: PyObjectRef, desc: BufferDescriptor, methods: &'static BufferMethods) -> Self { let zelf = Self { obj, @@ -52,12 +53,14 @@ impl PyBuffer { zelf } + #[must_use] pub fn as_contiguous(&self) -> Option> { self.desc .is_contiguous() .then(|| unsafe { self.contiguous_unchecked() }) } + #[must_use] pub fn as_contiguous_mut(&self) -> Option> { (!self.desc.readonly && self.desc.is_contiguous()) .then(|| unsafe { self.contiguous_mut_unchecked() }) @@ -74,12 +77,14 @@ impl PyBuffer { /// # Safety /// assume the buffer is contiguous + #[must_use] pub unsafe fn contiguous_unchecked(&self) -> BorrowedValue<'_, [u8]> { self.obj_bytes() } /// # Safety /// assume the buffer is contiguous and writable + #[must_use] pub unsafe fn contiguous_mut_unchecked(&self) -> BorrowedValueMut<'_, [u8]> { self.obj_bytes_mut() } @@ -109,14 +114,17 @@ impl PyBuffer { f(v) } + #[must_use] pub fn obj_as(&self) -> &Py { unsafe { self.obj.downcast_unchecked_ref() } } + #[must_use] pub fn obj_bytes(&self) -> BorrowedValue<'_, [u8]> { (self.methods.obj_bytes)(self) } + #[must_use] pub fn obj_bytes_mut(&self) -> BorrowedValueMut<'_, [u8]> { (self.methods.obj_bytes_mut)(self) } @@ -174,6 +182,7 @@ pub struct BufferDescriptor { } impl BufferDescriptor { + #[must_use] pub fn simple(bytes_len: usize, readonly: bool) -> Self { Self { len: bytes_len, @@ -184,6 +193,7 @@ impl BufferDescriptor { } } + #[must_use] pub fn format( bytes_len: usize, readonly: bool, @@ -200,6 +210,7 @@ impl BufferDescriptor { } #[cfg(debug_assertions)] + #[must_use] pub fn validate(self) -> Self { // ndim=0 is valid for scalar types (e.g., ctypes Structure) if self.ndim() == 0 { @@ -211,7 +222,7 @@ impl BufferDescriptor { } else { let mut shape_product = 1; let has_zero_dim = self.dim_desc.iter().any(|(s, _, _)| *s == 0); - for (shape, stride, suboffset) in self.dim_desc.iter().cloned() { + for (shape, stride, suboffset) in self.dim_desc.iter().copied() { shape_product *= shape; assert!(suboffset >= 0); // For empty arrays (any dimension is 0), strides can be 0 @@ -229,16 +240,18 @@ impl BufferDescriptor { self } + #[must_use] pub fn ndim(&self) -> usize { self.dim_desc.len() } + #[must_use] pub fn is_contiguous(&self) -> bool { if self.len == 0 { return true; } let mut sd = self.itemsize; - for (shape, stride, _) in self.dim_desc.iter().cloned().rev() { + for (shape, stride, _) in self.dim_desc.iter().copied().rev() { if shape > 1 && stride != sd as isize { return false; } @@ -249,12 +262,13 @@ impl BufferDescriptor { /// this function do not check the bound /// panic if indices.len() != ndim + #[must_use] pub fn fast_position(&self, indices: &[usize]) -> isize { let mut pos = 0; for (i, (_, stride, suboffset)) in indices .iter() - .cloned() - .zip_eq(self.dim_desc.iter().cloned()) + .copied() + .zip_eq(self.dim_desc.iter().copied()) { pos += i as isize * stride + suboffset; } @@ -266,8 +280,8 @@ impl BufferDescriptor { let mut pos = 0; for (i, (shape, stride, suboffset)) in indices .iter() - .cloned() - .zip_eq(self.dim_desc.iter().cloned()) + .copied() + .zip_eq(self.dim_desc.iter().copied()) { let i = i.wrapped_at(shape).ok_or_else(|| { vm.new_index_error(format!("index out of bounds on dimension {i}")) @@ -387,6 +401,7 @@ impl BufferDescriptor { suboffset == 0 && stride == self.itemsize as isize } + #[must_use] pub fn is_zero_in_shape(&self) -> bool { self.dim_desc.iter().any(|(shape, _, _)| *shape == 0) } @@ -428,6 +443,7 @@ impl From> for VecBuffer { } impl PyRef { + #[must_use] pub fn into_pybuffer(self, readonly: bool) -> PyBuffer { let len = self.data.lock().len(); PyBuffer::new( @@ -437,6 +453,7 @@ impl PyRef { ) } + #[must_use] pub fn into_pybuffer_with_descriptor(self, desc: BufferDescriptor) -> PyBuffer { PyBuffer::new(self.into(), desc, &VEC_BUFFER_METHODS) } diff --git a/crates/vm/src/protocol/mapping.rs b/crates/vm/src/protocol/mapping.rs index 6c200043e35..7d06c799153 100644 --- a/crates/vm/src/protocol/mapping.rs +++ b/crates/vm/src/protocol/mapping.rs @@ -105,11 +105,13 @@ impl AsRef for PyMapping<'_> { impl PyMapping<'_> { #[inline] + #[must_use] pub fn slots(&self) -> &PyMappingSlots { &self.obj.class().slots.as_mapping } #[inline] + #[must_use] pub fn check(&self) -> bool { self.slots().has_subscript() } diff --git a/crates/vm/src/protocol/number.rs b/crates/vm/src/protocol/number.rs index a5b35d88cb8..3f1a0cba18b 100644 --- a/crates/vm/src/protocol/number.rs +++ b/crates/vm/src/protocol/number.rs @@ -180,6 +180,7 @@ impl PyNumberMethods { inplace_matrix_multiply: None, }; + #[must_use] pub fn not_implemented() -> &'static Self { static GLOBAL_NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods::NOT_IMPLEMENTED; &GLOBAL_NOT_IMPLEMENTED @@ -612,6 +613,7 @@ impl<'a> PyNumber<'a> { impl PyNumber<'_> { // PyIndex_Check + #[must_use] pub fn is_index(self) -> bool { self.class().slots.as_number.index.load().is_some() } diff --git a/crates/vm/src/protocol/sequence.rs b/crates/vm/src/protocol/sequence.rs index b142e630042..8a77d5a901d 100644 --- a/crates/vm/src/protocol/sequence.rs +++ b/crates/vm/src/protocol/sequence.rs @@ -131,10 +131,12 @@ unsafe impl Traverse for PySequence<'_> { impl PySequence<'_> { #[inline] + #[must_use] pub fn slots(&self) -> &PySequenceSlots { &self.obj.class().slots.as_sequence } + #[must_use] pub fn check(&self) -> bool { self.slots().has_item() } diff --git a/crates/vm/src/scope.rs b/crates/vm/src/scope.rs index 5c6d92a8deb..966e953cdf3 100644 --- a/crates/vm/src/scope.rs +++ b/crates/vm/src/scope.rs @@ -16,6 +16,7 @@ impl fmt::Debug for Scope { impl Scope { #[inline] + #[must_use] pub fn new(locals: Option, globals: PyDictRef) -> Self { Self { locals, globals } } diff --git a/crates/vm/src/signal.rs b/crates/vm/src/signal.rs index 3caf8cb8e30..dbeeaeb4bf8 100644 --- a/crates/vm/src/signal.rs +++ b/crates/vm/src/signal.rs @@ -171,6 +171,7 @@ impl fmt::Display for UserSignalSendError { } } +#[must_use] pub fn user_signal_channel() -> (UserSignalSender, UserSignalReceiver) { let (tx, rx) = mpsc::channel(); (UserSignalSender { tx }, UserSignalReceiver { rx }) diff --git a/crates/vm/src/sliceable.rs b/crates/vm/src/sliceable.rs index e416f5a1b49..21fe6057e60 100644 --- a/crates/vm/src/sliceable.rs +++ b/crates/vm/src/sliceable.rs @@ -369,6 +369,7 @@ impl SaturatedSlice { // Equivalent to PySlice_AdjustIndices /// Convert for usage in indexing the underlying rust collections. Called *after* /// __index__ has been called on the Slice which might mutate the collection. + #[must_use] pub fn adjust_indices(&self, len: usize) -> (Range, isize, usize) { if len == 0 { return (0..0, self.step, 0); @@ -398,6 +399,7 @@ impl SaturatedSlice { (range, self.step, slice_len) } + #[must_use] pub fn iter(&self, len: usize) -> SaturatedSliceIter { SaturatedSliceIter::new(self, len) } @@ -410,11 +412,13 @@ pub struct SaturatedSliceIter { } impl SaturatedSliceIter { + #[must_use] pub fn new(slice: &SaturatedSlice, seq_len: usize) -> Self { let (range, step, len) = slice.adjust_indices(seq_len); Self::from_adjust_indices(range, step, len) } + #[must_use] pub const fn from_adjust_indices(range: Range, step: isize, len: usize) -> Self { let index = if step.is_negative() { range.end as isize - 1 @@ -424,6 +428,7 @@ impl SaturatedSliceIter { Self { index, step, len } } + #[must_use] pub const fn positive_order(mut self) -> Self { if self.step.is_negative() { self.index += self.step * self.len.saturating_sub(1) as isize; diff --git a/crates/vm/src/stdlib/_ctypes.rs b/crates/vm/src/stdlib/_ctypes.rs index 0ffcb1e01ab..17fa7868614 100644 --- a/crates/vm/src/stdlib/_ctypes.rs +++ b/crates/vm/src/stdlib/_ctypes.rs @@ -1300,13 +1300,13 @@ pub(crate) mod _ctypes { __module_exec(vm, module); let ctx = &vm.ctx; - PyCSimpleType::make_static_type(); - array::PyCArrayType::make_static_type(); - pointer::PyCPointerType::make_static_type(); - structure::PyCStructType::make_static_type(); - union::PyCUnionType::make_static_type(); - function::PyCFuncPtrType::make_static_type(); - function::RawMemoryBuffer::make_static_type(); + let _ = PyCSimpleType::make_static_type(); + let _ = array::PyCArrayType::make_static_type(); + let _ = pointer::PyCPointerType::make_static_type(); + let _ = structure::PyCStructType::make_static_type(); + let _ = union::PyCUnionType::make_static_type(); + let _ = function::PyCFuncPtrType::make_static_type(); + let _ = function::RawMemoryBuffer::make_static_type(); extend_module!(vm, module, { "_CData" => PyCData::make_static_type(), diff --git a/crates/vm/src/stdlib/_sre.rs b/crates/vm/src/stdlib/_sre.rs index 2aac4bd92cc..09de70b189e 100644 --- a/crates/vm/src/stdlib/_sre.rs +++ b/crates/vm/src/stdlib/_sre.rs @@ -66,7 +66,7 @@ mod _sre { impl SreStr for &[u8] { fn slice(&self, start: usize, end: usize, vm: &VirtualMachine) -> PyObjectRef { vm.ctx - .new_bytes(self.iter().take(end).skip(start).cloned().collect()) + .new_bytes(self.iter().take(end).skip(start).copied().collect()) .into() } } diff --git a/crates/vm/src/stdlib/_thread.rs b/crates/vm/src/stdlib/_thread.rs index 48e5a4a0823..609f0541357 100644 --- a/crates/vm/src/stdlib/_thread.rs +++ b/crates/vm/src/stdlib/_thread.rs @@ -315,6 +315,7 @@ pub(crate) mod _thread { /// Get thread identity - uses pthread_self() on Unix for fork compatibility #[pyfunction] + #[must_use] pub fn get_ident() -> u64 { current_thread_id() } diff --git a/crates/vm/src/stdlib/builtins.rs b/crates/vm/src/stdlib/builtins.rs index fd35b287211..9fdc88be5c9 100644 --- a/crates/vm/src/stdlib/builtins.rs +++ b/crates/vm/src/stdlib/builtins.rs @@ -1346,7 +1346,7 @@ mod builtins { pub fn init_module(vm: &VirtualMachine, module: &Py) { let ctx = &vm.ctx; - crate::protocol::VecBuffer::make_static_type(); + let _ = crate::protocol::VecBuffer::make_static_type(); module.__init_methods(vm).unwrap(); builtins::module_exec(vm, module).unwrap(); diff --git a/crates/vm/src/types/slot.rs b/crates/vm/src/types/slot.rs index 31a03094e8f..bfcd7a8798d 100644 --- a/crates/vm/src/types/slot.rs +++ b/crates/vm/src/types/slot.rs @@ -37,6 +37,7 @@ impl TypeDataSlot { } /// Get a reference to the data if the type matches. + #[must_use] pub fn get(&self) -> Option<&T> { if self.type_id == TypeId::of::() { self.data.downcast_ref() @@ -63,6 +64,7 @@ pub struct TypeDataRef<'a, T: 'static> { impl<'a, T: Any + 'static> TypeDataRef<'a, T> { /// Try to create a TypeDataRef from a read guard. /// Returns None if the slot is empty or contains a different type. + #[must_use] pub fn try_new(guard: PyRwLockReadGuard<'a, Option>) -> Option { PyRwLockReadGuard::try_map(guard, |opt| opt.as_ref().and_then(|slot| slot.get::())) .ok() @@ -86,6 +88,7 @@ pub struct TypeDataRefMut<'a, T: 'static> { impl<'a, T: Any + 'static> TypeDataRefMut<'a, T> { /// Try to create a TypeDataRefMut from a write guard. /// Returns None if the slot is empty or contains a different type. + #[must_use] pub fn try_new(guard: PyRwLockWriteGuard<'a, Option>) -> Option { PyRwLockWriteGuard::try_map(guard, |opt| { opt.as_mut().and_then(|slot| slot.get_mut::()) @@ -188,6 +191,7 @@ pub struct PyTypeSlots { } impl PyTypeSlots { + #[must_use] pub fn new(name: &'static str, flags: PyTypeFlags) -> Self { Self { name, @@ -196,6 +200,7 @@ impl PyTypeSlots { } } + #[must_use] pub fn heap_default() -> Self { Self { // init: AtomicCell::new(Some(init_wrapper)), @@ -243,6 +248,7 @@ impl PyTypeFlags { // CPython: See initialization of flags in type_new. /// Used for types created in Python. Subclassable and are a /// heaptype. + #[must_use] pub const fn heap_type_flags() -> Self { match Self::from_bits(Self::DEFAULT.bits() | Self::HEAPTYPE.bits() | Self::BASETYPE.bits()) { @@ -251,11 +257,13 @@ impl PyTypeFlags { } } + #[must_use] pub const fn has_feature(self, flag: Self) -> bool { self.contains(flag) } #[cfg(debug_assertions)] + #[must_use] pub const fn is_created_with_flags(self) -> bool { self.contains(Self::_CREATED_WITH_FLAGS) } @@ -1862,6 +1870,7 @@ impl PyComparisonOp { } } + #[must_use] pub fn eval_ord(self, ord: Ordering) -> bool { match self { Self::Lt => ord == Ordering::Less, @@ -1873,6 +1882,7 @@ impl PyComparisonOp { } } + #[must_use] pub const fn swapped(self) -> Self { match self { Self::Lt => Self::Gt, @@ -1895,6 +1905,7 @@ impl PyComparisonOp { } } + #[must_use] pub const fn operator_token(self) -> &'static str { match self { Self::Lt => "<", @@ -1987,6 +1998,7 @@ pub trait AsMapping: PyPayload { fn as_mapping() -> &'static PyMappingMethods; #[inline] + #[must_use] fn mapping_downcast(mapping: PyMapping<'_>) -> &Py { unsafe { mapping.obj.downcast_unchecked_ref() } } @@ -2001,6 +2013,7 @@ pub trait AsSequence: PyPayload { fn as_sequence() -> &'static PySequenceMethods; #[inline] + #[must_use] fn sequence_downcast(seq: PySequence<'_>) -> &Py { unsafe { seq.obj.downcast_unchecked_ref() } } @@ -2025,6 +2038,7 @@ pub trait AsNumber: PyPayload { } #[inline] + #[must_use] fn number_downcast(num: PyNumber<'_>) -> &Py { unsafe { num.obj.downcast_unchecked_ref() } } diff --git a/crates/vm/src/types/slot_defs.rs b/crates/vm/src/types/slot_defs.rs index efd1a8913f5..6ba5d1d6453 100644 --- a/crates/vm/src/types/slot_defs.rs +++ b/crates/vm/src/types/slot_defs.rs @@ -28,6 +28,7 @@ pub enum SlotOp { impl SlotOp { /// Convert to PyComparisonOp if this is a comparison operation + #[must_use] pub fn as_compare_op(&self) -> Option { match self { Self::Lt => Some(PyComparisonOp::Lt), @@ -41,6 +42,7 @@ impl SlotOp { } /// Check if this is a right operation (__radd__, __rsub__, etc.) + #[must_use] pub fn is_right(&self) -> bool { matches!(self, Self::Right) } @@ -167,6 +169,7 @@ pub enum SlotAccessor { impl SlotAccessor { /// Check if this accessor is for a reserved/unused slot + #[must_use] pub fn is_reserved(&self) -> bool { matches!( self, @@ -195,6 +198,7 @@ impl SlotAccessor { } /// Check if this is a number binary operation slot + #[must_use] pub fn is_number_binary(&self) -> bool { matches!( self, @@ -223,6 +227,7 @@ impl SlotAccessor { /// - TpDescrSet: __set__ and __delete__ /// - SqAssItem/MpAssSubscript: __setitem__ and __delitem__ /// - Number binaries: __add__ and __radd__, etc. + #[must_use] pub fn is_shared_slot(&self) -> bool { matches!( self, @@ -235,6 +240,7 @@ impl SlotAccessor { } /// Get underlying slot field name for debugging + #[must_use] pub fn slot_name(&self) -> &'static str { match self { Self::BfGetBuffer => "bf_getbuffer", @@ -322,6 +328,7 @@ impl SlotAccessor { } /// Extract the raw function pointer from a SlotFunc if it matches this accessor's type + #[must_use] pub fn extract_from_slot_func(&self, slot_func: &SlotFunc) -> bool { match self { // Type slots diff --git a/crates/vm/src/version.rs b/crates/vm/src/version.rs index 5b80a33322b..9e70b0a0b25 100644 --- a/crates/vm/src/version.rs +++ b/crates/vm/src/version.rs @@ -15,6 +15,7 @@ pub const SERIAL: usize = 0; pub const VERSION_HEX: usize = (MAJOR << 24) | (MINOR << 16) | (MICRO << 8) | (RELEASELEVEL_N << 4) | SERIAL; +#[must_use] pub fn get_version() -> String { // Windows: include MSC v. for compatibility with ctypes.util.find_library // MSC v.1929 = VS 2019, version 14+ makes find_msvcrt() return None @@ -42,16 +43,19 @@ pub fn get_version() -> String { ) } +#[must_use] pub fn get_version_number() -> String { format!("{MAJOR}.{MINOR}.{MICRO}{RELEASELEVEL}") } +#[must_use] pub fn get_winver_number() -> String { format!("{MAJOR}.{MINOR}") } const COMPILER: &str = env!("RUSTC_VERSION"); +#[must_use] pub fn get_build_info() -> String { // See: https://reproducible-builds.org/docs/timestamps/ let git_revision = get_git_revision(); @@ -73,20 +77,24 @@ pub fn get_build_info() -> String { ) } +#[must_use] pub fn get_git_revision() -> String { option_env!("RUSTPYTHON_GIT_HASH").unwrap_or("").to_owned() } +#[must_use] pub fn get_git_tag() -> String { option_env!("RUSTPYTHON_GIT_TAG").unwrap_or("").to_owned() } +#[must_use] pub fn get_git_branch() -> String { option_env!("RUSTPYTHON_GIT_BRANCH") .unwrap_or("") .to_owned() } +#[must_use] pub fn get_git_identifier() -> String { let git_tag = get_git_tag(); let git_branch = get_git_branch(); @@ -109,18 +117,21 @@ fn get_git_timestamp_datetime() -> DateTime { datetime.into() } +#[must_use] pub fn get_git_date() -> String { let datetime = get_git_timestamp_datetime(); datetime.format("%b %e %Y").to_string() } +#[must_use] pub fn get_git_time() -> String { let datetime = get_git_timestamp_datetime(); datetime.format("%H:%M:%S").to_string() } +#[must_use] pub fn get_git_datetime() -> String { let date = get_git_date(); let time = get_git_time(); diff --git a/crates/vm/src/vm/context.rs b/crates/vm/src/vm/context.rs index 14c510fd28c..2d03199f772 100644 --- a/crates/vm/src/vm/context.rs +++ b/crates/vm/src/vm/context.rs @@ -288,6 +288,7 @@ impl Context { pub const INT_CACHE_POOL_RANGE: core::ops::RangeInclusive = (-5)..=256; const INT_CACHE_POOL_MIN: i32 = *Self::INT_CACHE_POOL_RANGE.start(); + #[must_use] pub fn genesis() -> &'static PyRc { rustpython_common::static_cell! { static CONTEXT: PyRc; diff --git a/crates/vm/src/vm/interpreter.rs b/crates/vm/src/vm/interpreter.rs index 57f3d406461..505986acae0 100644 --- a/crates/vm/src/vm/interpreter.rs +++ b/crates/vm/src/vm/interpreter.rs @@ -155,6 +155,7 @@ where impl InterpreterBuilder { /// Create a new interpreter configuration with default settings. + #[must_use] pub fn new() -> Self { Self { settings: Settings::default(), @@ -168,6 +169,7 @@ impl InterpreterBuilder { /// Set custom settings for the interpreter. /// /// If called multiple times, only the last settings will be used. + #[must_use] pub fn settings(mut self, settings: Settings) -> Self { self.settings = settings; self @@ -185,6 +187,7 @@ impl InterpreterBuilder { /// // let interp = builder.add_native_module(def).build(); /// let interp = builder.build(); /// ``` + #[must_use] pub fn add_native_module(self, def: &'static builtins::PyModuleDef) -> Self { self.add_native_modules(&[def]) } @@ -201,6 +204,7 @@ impl InterpreterBuilder { /// // let interp = builder.add_native_modules(&defs).build(); /// let interp = builder.build(); /// ``` + #[must_use] pub fn add_native_modules(mut self, defs: &[&'static builtins::PyModuleDef]) -> Self { self.module_defs.extend_from_slice(defs); self @@ -254,6 +258,7 @@ impl InterpreterBuilder { /// Build the interpreter. /// /// This consumes the configuration and returns a fully initialized Interpreter. + #[must_use] pub fn build(self) -> Interpreter { let (vm, global_state) = initialize_main_vm( self.settings, @@ -267,6 +272,7 @@ impl InterpreterBuilder { } /// Alias for `build()` for compatibility with the `interpreter()` pattern. + #[must_use] pub fn interpreter(self) -> Interpreter { self.build() } @@ -312,6 +318,7 @@ impl Interpreter { /// // In practice, add stdlib: builder.add_native_modules(&stdlib_module_defs(&builder.ctx)) /// let interp = builder.build(); /// ``` + #[must_use] pub fn builder(settings: Settings) -> InterpreterBuilder { InterpreterBuilder::new().settings(settings) } @@ -320,6 +327,7 @@ impl Interpreter { /// To create an interpreter with the standard library with the `rustpython` crate, use `rustpython::InterpreterBuilder`. /// To create an interpreter without the `rustpython` crate, but only with `rustpython-vm`, /// try to build one from the source code of `InterpreterBuilder`. It will not be a one-liner but it also will not be too hard. + #[must_use] pub fn without_stdlib(settings: Settings) -> Self { Self::with_init(settings, |_| {}) } diff --git a/crates/vm/src/vm/mod.rs b/crates/vm/src/vm/mod.rs index 4106908ea1a..5e57998cd21 100644 --- a/crates/vm/src/vm/mod.rs +++ b/crates/vm/src/vm/mod.rs @@ -115,6 +115,7 @@ pub struct FramePtr(NonNull>); impl FramePtr { /// # Safety /// The pointed-to frame must still be alive. + #[must_use] pub unsafe fn as_ref(&self) -> &Py { unsafe { self.0.as_ref() } } @@ -201,6 +202,7 @@ impl Default for StopTheWorldState { #[cfg(all(unix, feature = "threading"))] impl StopTheWorldState { + #[must_use] pub const fn new() -> Self { Self { requested: AtomicBool::new(false), @@ -2273,6 +2275,7 @@ impl AsRef for VirtualMachine { /// Resolve frozen module alias to its original name. /// Returns the original module name if an alias exists, otherwise returns the input name. +#[must_use] pub fn resolve_frozen_alias(name: &str) -> &str { match name { "_frozen_importlib" => "importlib._bootstrap", diff --git a/crates/vm/src/vm/setting.rs b/crates/vm/src/vm/setting.rs index 0563e7131ac..7298c95ab08 100644 --- a/crates/vm/src/vm/setting.rs +++ b/crates/vm/src/vm/setting.rs @@ -31,6 +31,7 @@ pub struct PyConfig { } impl PyConfig { + #[must_use] pub fn new(settings: Settings, paths: Paths) -> Self { Self { settings, paths } } @@ -171,6 +172,7 @@ pub enum CheckHashPycsMode { } impl Settings { + #[must_use] pub fn with_path(mut self, path: String) -> Self { self.path_list.push(path); self diff --git a/crates/vm/src/vm/thread.rs b/crates/vm/src/vm/thread.rs index e5a961e1cad..de6e2962ffd 100644 --- a/crates/vm/src/vm/thread.rs +++ b/crates/vm/src/vm/thread.rs @@ -345,6 +345,7 @@ fn do_suspend(stw: &super::StopTheWorldState) { #[cfg(all(unix, feature = "threading"))] #[inline] +#[must_use] pub fn stop_requested_for_current_thread() -> bool { CURRENT_THREAD_SLOT.with(|slot| { slot.borrow() @@ -393,6 +394,7 @@ pub fn set_current_frame(frame: *const Frame) -> *const Frame { /// Get the current thread's top frame pointer. /// Used by faulthandler's signal handler to start traceback walking. +#[must_use] pub fn get_current_frame() -> *const Frame { CURRENT_FRAME.with(|c| c.load(Ordering::Relaxed) as *const Frame) } diff --git a/crates/wasm/src/convert.rs b/crates/wasm/src/convert.rs index aaf0e6e2549..17ad5b62946 100644 --- a/crates/wasm/src/convert.rs +++ b/crates/wasm/src/convert.rs @@ -254,6 +254,7 @@ pub fn js_to_py(vm: &VirtualMachine, js_val: JsValue) -> PyObjectRef { } } +#[must_use] pub fn syntax_err(err: CompileError) -> SyntaxError { let js_err = SyntaxError::new(&format!("Error parsing Python code: {err}")); let _ = Reflect::set( diff --git a/crates/wasm/src/vm_class.rs b/crates/wasm/src/vm_class.rs index 0657b0bc08e..96b1b2a17fd 100644 --- a/crates/wasm/src/vm_class.rs +++ b/crates/wasm/src/vm_class.rs @@ -108,6 +108,7 @@ pub struct VMStore; #[wasm_bindgen(js_class = vmStore)] impl VMStore { + #[must_use] pub fn init(id: String, inject_browser_module: Option) -> WASMVirtualMachine { STORED_VMS.with_borrow_mut(|vms| { if !vms.contains_key(&id) { @@ -123,6 +124,7 @@ impl VMStore { STORED_VMS.with_borrow(|vms| vms.contains_key(&id).then_some(WASMVirtualMachine { id })) } + #[must_use] pub fn get(id: String) -> JsValue { match Self::_get(id) { Some(wasm_vm) => wasm_vm.into(), @@ -142,6 +144,7 @@ impl VMStore { }); } + #[must_use] pub fn ids() -> Vec { STORED_VMS.with_borrow(|vms| vms.keys().map(|k| k.into()).collect()) } @@ -178,6 +181,7 @@ impl WASMVirtualMachine { self.with(|stored| stored.interp.enter(|vm| f(vm, stored))) } + #[must_use] pub fn valid(&self) -> bool { STORED_VMS.with_borrow(|vms| vms.contains_key(&self.id)) }