[red-knot] Minor follow-up on slice expression inference (#13982)

## Summary

Minor follow-up to #13917 — thanks @AlexWaygood for the post-merge
review.

- Add
SliceLiteralType::as_tuple
- Use .expect() instead of SAFETY
comment
- Match on ::try_from
result
- Add TODO comment regarding raising a diagnostic for `"foo"["bar":"baz"]`
This commit is contained in:
David Peter 2024-10-29 20:40:57 +01:00 committed by GitHub
parent 60a2dc53e7
commit 96b3c400fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 25 additions and 14 deletions

View file

@ -1944,6 +1944,11 @@ pub struct SliceLiteralType<'db> {
step: Option<i32>,
}
impl<'db> SliceLiteralType<'db> {
fn as_tuple(self, db: &dyn Db) -> (Option<i32>, Option<i32>, Option<i32>) {
(self.start(db), self.stop(db), self.step(db))
}
}
#[salsa::interned]
pub struct TupleType<'db> {
#[return_ref]

View file

@ -3226,9 +3226,7 @@ impl<'db> TypeInferenceBuilder<'db> {
// Ex) Given `("a", 1, Null)[0:2]`, return `("a", 1)`
(Type::Tuple(tuple_ty), Type::SliceLiteral(slice_ty)) => {
let elements = tuple_ty.elements(self.db);
let start = slice_ty.start(self.db);
let stop = slice_ty.stop(self.db);
let step = slice_ty.step(self.db);
let (start, stop, step) = slice_ty.as_tuple(self.db);
if let Ok(new_elements) = elements.as_ref().py_slice(start, stop, step) {
let new_elements: Vec<_> = new_elements.copied().collect();
@ -3266,9 +3264,7 @@ impl<'db> TypeInferenceBuilder<'db> {
// Ex) Given `"value"[1:3]`, return `"al"`
(Type::StringLiteral(literal_ty), Type::SliceLiteral(slice_ty)) => {
let literal_value = literal_ty.value(self.db);
let start = slice_ty.start(self.db);
let stop = slice_ty.stop(self.db);
let step = slice_ty.step(self.db);
let (start, stop, step) = slice_ty.as_tuple(self.db);
let chars: Vec<_> = literal_value.chars().collect();
let result = if let Ok(new_chars) = chars.as_slice().py_slice(start, stop, step) {
@ -3305,9 +3301,7 @@ impl<'db> TypeInferenceBuilder<'db> {
// Ex) Given `b"value"[1:3]`, return `b"al"`
(Type::BytesLiteral(literal_ty), Type::SliceLiteral(slice_ty)) => {
let literal_value = literal_ty.value(self.db);
let start = slice_ty.start(self.db);
let stop = slice_ty.stop(self.db);
let step = slice_ty.step(self.db);
let (start, stop, step) = slice_ty.as_tuple(self.db);
if let Ok(new_bytes) = literal_value.as_ref().py_slice(start, stop, step) {
let new_bytes: Vec<u8> = new_bytes.copied().collect();
@ -3418,9 +3412,10 @@ impl<'db> TypeInferenceBuilder<'db> {
let ty_step = self.infer_optional_expression(step.as_deref());
let type_to_slice_argument = |ty: Option<Type<'db>>| match ty {
Some(Type::IntLiteral(n)) if i32::try_from(n).is_ok() => {
SliceArg::Arg(Some(i32::try_from(n).expect("checked in branch arm")))
}
Some(Type::IntLiteral(n)) => match i32::try_from(n) {
Ok(n) => SliceArg::Arg(Some(n)),
Err(_) => SliceArg::Unsupported,
},
Some(Type::BooleanLiteral(b)) => SliceArg::Arg(Some(i32::from(b))),
Some(Type::None) => SliceArg::Arg(None),
Some(Type::Instance(class)) if class.is_known(self.db, KnownClass::NoneType) => {

View file

@ -17,8 +17,8 @@ fn from_nonnegative_i32(index: i32) -> usize {
static_assertions::const_assert!(usize::BITS >= 32);
debug_assert!(index >= 0);
// SAFETY: `index` is non-negative, and `usize` is at least 32 bits.
usize::try_from(index).unwrap()
usize::try_from(index)
.expect("Should only ever pass a positive integer to `from_nonnegative_i32`")
}
fn from_negative_i32(index: i32) -> usize {