[ty] Simplify lifetime requirements for PySlice trait (#19687)

This commit is contained in:
Alex Waygood 2025-08-01 15:13:47 +01:00 committed by GitHub
parent 18aae21b9a
commit 57e2e8664f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 22 additions and 21 deletions

View file

@ -8520,7 +8520,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
}; };
if let Ok(new_elements) = tuple.py_slice(db, start, stop, step) { if let Ok(new_elements) = tuple.py_slice(db, start, stop, step) {
TupleType::from_elements(db, new_elements.copied()) TupleType::from_elements(db, new_elements)
} else { } else {
report_slice_step_size_zero(context, value_node.into()); report_slice_step_size_zero(context, value_node.into());
Type::unknown() Type::unknown()
@ -8599,7 +8599,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
let literal_value = literal_ty.value(db); let literal_value = literal_ty.value(db);
if let Ok(new_bytes) = literal_value.py_slice(db, start, stop, step) { if let Ok(new_bytes) = literal_value.py_slice(db, start, stop, step) {
let new_bytes: Vec<u8> = new_bytes.copied().collect(); let new_bytes: Vec<u8> = new_bytes.collect();
Type::bytes_literal(db, &new_bytes) Type::bytes_literal(db, &new_bytes)
} else { } else {
report_slice_step_size_zero(context, value_node.into()); report_slice_step_size_zero(context, value_node.into());

View file

@ -500,12 +500,12 @@ impl<'db> PySlice<'db> for FixedLengthTuple<Type<'db>> {
type Item = Type<'db>; type Item = Type<'db>;
fn py_slice( fn py_slice(
&'db self, &self,
db: &'db dyn Db, db: &'db dyn Db,
start: Option<i32>, start: Option<i32>,
stop: Option<i32>, stop: Option<i32>,
step: Option<i32>, step: Option<i32>,
) -> Result<impl Iterator<Item = &'db Self::Item>, StepSizeZeroError> { ) -> Result<impl Iterator<Item = Self::Item>, StepSizeZeroError> {
self.0.py_slice(db, start, stop, step) self.0.py_slice(db, start, stop, step)
} }
} }

View file

@ -111,24 +111,27 @@ pub(crate) trait PySlice<'db> {
type Item: 'db; type Item: 'db;
fn py_slice( fn py_slice(
&'db self, &self,
db: &'db dyn Db, db: &'db dyn Db,
start: Option<i32>, start: Option<i32>,
stop: Option<i32>, stop: Option<i32>,
step: Option<i32>, step: Option<i32>,
) -> Result<impl Iterator<Item = &'db Self::Item>, StepSizeZeroError>; ) -> Result<impl Iterator<Item = Self::Item>, StepSizeZeroError>;
} }
impl<'db, T: 'db> PySlice<'db> for [T] { impl<'db, T> PySlice<'db> for [T]
where
T: Copy + 'db,
{
type Item = T; type Item = T;
fn py_slice( fn py_slice(
&'db self, &self,
_db: &'db dyn Db, _db: &'db dyn Db,
start: Option<i32>, start: Option<i32>,
stop: Option<i32>, stop: Option<i32>,
step_int: Option<i32>, step_int: Option<i32>,
) -> Result<impl Iterator<Item = &'db Self::Item>, StepSizeZeroError> { ) -> Result<impl Iterator<Item = Self::Item>, StepSizeZeroError> {
let step_int = step_int.unwrap_or(1); let step_int = step_int.unwrap_or(1);
if step_int == 0 { if step_int == 0 {
return Err(StepSizeZeroError); return Err(StepSizeZeroError);
@ -139,12 +142,12 @@ impl<'db, T: 'db> PySlice<'db> for [T] {
// The iterator needs to have the same type as the step>0 case below, // The iterator needs to have the same type as the step>0 case below,
// so we need to use `.skip(0)`. // so we need to use `.skip(0)`.
#[expect(clippy::iter_skip_zero)] #[expect(clippy::iter_skip_zero)]
return Ok(Either::Left(self.iter().skip(0).take(0).step_by(1))); return Ok(Either::Left(self.iter().skip(0).take(0).step_by(1)).copied());
} }
let to_position = |index| Nth::from_index(index).to_position(len); let to_position = |index| Nth::from_index(index).to_position(len);
if step_int.is_positive() { let iter = if step_int.is_positive() {
let step = from_nonnegative_i32(step_int); let step = from_nonnegative_i32(step_int);
let start = start.map(to_position).unwrap_or(Position::BeforeStart); let start = start.map(to_position).unwrap_or(Position::BeforeStart);
@ -168,9 +171,7 @@ impl<'db, T: 'db> PySlice<'db> for [T] {
(0, 0, step) (0, 0, step)
}; };
Ok(Either::Left( Either::Left(self.iter().skip(skip).take(take).step_by(step))
self.iter().skip(skip).take(take).step_by(step),
))
} else { } else {
let step = from_negative_i32(step_int); let step = from_negative_i32(step_int);
@ -195,10 +196,10 @@ impl<'db, T: 'db> PySlice<'db> for [T] {
(skip, take, step) (skip, take, step)
}; };
Ok(Either::Right( Either::Right(self.iter().rev().skip(skip).take(take).step_by(step))
self.iter().rev().skip(skip).take(take).step_by(step), };
))
} Ok(iter.copied())
} }
} }
@ -210,7 +211,7 @@ mod tests {
use crate::util::subscript::{OutOfBoundsError, StepSizeZeroError}; use crate::util::subscript::{OutOfBoundsError, StepSizeZeroError};
use super::{PyIndex, PySlice}; use super::{PyIndex, PySlice};
use itertools::assert_equal; use itertools::{Itertools, assert_equal};
#[test] #[test]
fn py_index_empty() { fn py_index_empty() {
@ -276,8 +277,8 @@ mod tests {
expected: &[char; M], expected: &[char; M],
) { ) {
assert_equal( assert_equal(
input.py_slice(db, start, stop, step).unwrap(), input.py_slice(db, start, stop, step).unwrap().collect_vec(),
expected.iter(), expected.iter().copied().collect_vec(),
); );
} }