Skip to content

Commit 5f34c4a

Browse files
committed
FIX: Add extra information to errors where possible
Where possible, add expected/actual information to the ShapeError. In many places it is identified new places where more specific ErrorKinds and error messages are needed. These are not updated here - a comment is inserted - this will be updated in a future version, when we can accept breaking changes.
1 parent 3a59caa commit 5f34c4a

File tree

5 files changed

+40
-17
lines changed

5 files changed

+40
-17
lines changed

src/dimension/broadcast.rs

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ where
2727
if *out == 1 {
2828
*out = *s2
2929
} else if *s2 != 1 {
30+
// TODO More specific error axis length mismatch
3031
return Err(from_kind(ErrorKind::IncompatibleShape));
3132
}
3233
}

src/dimension/mod.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ pub fn size_of_shape_checked<D: Dimension>(dim: &D) -> Result<usize, ShapeError>
8989
.try_fold(1usize, |acc, &d| acc.checked_mul(d))
9090
.ok_or_else(|| from_kind(ErrorKind::Overflow))?;
9191
if size_nonzero > ::std::isize::MAX as usize {
92+
// TODO More specific error
9293
Err(from_kind(ErrorKind::Overflow))
9394
} else {
9495
Ok(dim.size())
@@ -137,7 +138,7 @@ pub(crate) fn can_index_slice_not_custom<D: Dimension>(data_len: usize, dim: &D)
137138
let len = size_of_shape_checked(dim)?;
138139
// Condition 2.
139140
if len > data_len {
140-
return Err(from_kind(ErrorKind::OutOfBounds));
141+
return Err(ShapeError::shape_length_exceeds_data_length(data_len, len));
141142
}
142143
Ok(())
143144
}
@@ -170,6 +171,7 @@ where
170171
{
171172
// Condition 1.
172173
if dim.ndim() != strides.ndim() {
174+
// TODO More specific error for dimension stride dimensionality mismatch
173175
return Err(from_kind(ErrorKind::IncompatibleLayout));
174176
}
175177

@@ -185,19 +187,23 @@ where
185187
let off = d.saturating_sub(1).checked_mul(s.abs() as usize)?;
186188
acc.checked_add(off)
187189
})
190+
// TODO More specific error
188191
.ok_or_else(|| from_kind(ErrorKind::Overflow))?;
189192
// Condition 2a.
190193
if max_offset > isize::MAX as usize {
194+
// TODO More specific error
191195
return Err(from_kind(ErrorKind::Overflow));
192196
}
193197

194198
// Determine absolute difference in units of bytes between least and
195199
// greatest address accessible by moving along all axes
196200
let max_offset_bytes = max_offset
197201
.checked_mul(elem_size)
202+
// TODO More specific error
198203
.ok_or_else(|| from_kind(ErrorKind::Overflow))?;
199204
// Condition 2b.
200205
if max_offset_bytes > isize::MAX as usize {
206+
// TODO More specific error
201207
return Err(from_kind(ErrorKind::Overflow));
202208
}
203209

@@ -256,15 +262,16 @@ fn can_index_slice_impl<D: Dimension>(
256262
// Check condition 3.
257263
let is_empty = dim.slice().iter().any(|&d| d == 0);
258264
if is_empty && max_offset > data_len {
259-
return Err(from_kind(ErrorKind::OutOfBounds));
265+
return Err(ShapeError::shape_length_exceeds_data_length(data_len, max_offset));
260266
}
261267
if !is_empty && max_offset >= data_len {
262-
return Err(from_kind(ErrorKind::OutOfBounds));
268+
return Err(ShapeError::shape_length_exceeds_data_length(data_len.wrapping_sub(1), max_offset));
263269
}
264270

265271
// Check condition 4.
266272
if !is_empty && dim_stride_overlap(dim, strides) {
267-
return Err(from_kind(ErrorKind::Unsupported));
273+
// TODO: More specific error kind Strides result in overlapping elements
274+
return Err(ShapeError::from_kind(ErrorKind::Unsupported));
268275
}
269276

270277
Ok(())
@@ -293,6 +300,7 @@ where
293300
{
294301
for &stride in strides.slice() {
295302
if (stride as isize) < 0 {
303+
// TODO: More specific error kind Non-negative strides required
296304
return Err(from_kind(ErrorKind::Unsupported));
297305
}
298306
}

src/impl_methods.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::dimension::{
2323
offset_from_ptr_to_memory, size_of_shape_checked, stride_offset, Axes,
2424
};
2525
use crate::dimension::broadcast::co_broadcast;
26-
use crate::error::{self, ErrorKind, ShapeError, from_kind};
26+
use crate::error::{self, ErrorKind, ShapeError};
2727
use crate::math_cell::MathCell;
2828
use crate::itertools::zip;
2929
use crate::zip::{IntoNdProducer, Zip};
@@ -1588,7 +1588,7 @@ where
15881588
} else if self.ndim() > 1 && self.raw_view().reversed_axes().is_standard_layout() {
15891589
Ok(self.with_strides_dim(shape.fortran_strides(), shape))
15901590
} else {
1591-
Err(error::from_kind(error::ErrorKind::IncompatibleLayout))
1591+
Err(ShapeError::incompatible_layout(error::ExpectedLayout::ContiguousCF))
15921592
}
15931593
}
15941594
}
@@ -1693,6 +1693,7 @@ where
16931693
}
16941694
}
16951695
}
1696+
// TODO More specific error incompatible ndim
16961697
Err(ShapeError::from_kind(ErrorKind::IncompatibleShape))
16971698
}
16981699

@@ -1805,11 +1806,14 @@ where
18051806
{
18061807
let shape = co_broadcast::<D, E, <D as DimMax<E>>::Output>(&self.dim, &other.dim)?;
18071808
if let Some(view1) = self.broadcast(shape.clone()) {
1808-
if let Some(view2) = other.broadcast(shape) {
1809-
return Ok((view1, view2));
1809+
if let Some(view2) = other.broadcast(shape.clone()) {
1810+
Ok((view1, view2))
1811+
} else {
1812+
Err(ShapeError::incompatible_shapes(&other.dim, &shape))
18101813
}
1814+
} else {
1815+
Err(ShapeError::incompatible_shapes(&other.dim, &shape))
18111816
}
1812-
Err(from_kind(ErrorKind::IncompatibleShape))
18131817
}
18141818

18151819
/// Swap axes `ax` and `bx`.

src/slice.rs

+2
Original file line numberDiff line numberDiff line change
@@ -415,11 +415,13 @@ where
415415
{
416416
if let Some(in_ndim) = Din::NDIM {
417417
if in_ndim != indices.in_ndim() {
418+
// TODO More specific error incompatible ndim
418419
return Err(ShapeError::from_kind(ErrorKind::IncompatibleShape));
419420
}
420421
}
421422
if let Some(out_ndim) = Dout::NDIM {
422423
if out_ndim != indices.out_ndim() {
424+
// TODO More specific error incompatible ndim
423425
return Err(ShapeError::from_kind(ErrorKind::IncompatibleShape));
424426
}
425427
}

src/stacking.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
use crate::error::{from_kind, ErrorKind, ShapeError};
1010
use crate::imp_prelude::*;
11+
use crate::NdProducer;
1112

1213
/// Stack arrays along the new axis.
1314
///
@@ -72,18 +73,22 @@ where
7273
D: RemoveAxis,
7374
{
7475
if arrays.is_empty() {
76+
// TODO More specific error for empty input not supported
7577
return Err(from_kind(ErrorKind::Unsupported));
7678
}
7779
let mut res_dim = arrays[0].raw_dim();
7880
if axis.index() >= res_dim.ndim() {
79-
return Err(from_kind(ErrorKind::OutOfBounds));
81+
return Err(ShapeError::invalid_axis(res_dim.ndim().wrapping_sub(1), axis.index()));
8082
}
8183
let common_dim = res_dim.remove_axis(axis);
82-
if arrays
83-
.iter()
84-
.any(|a| a.raw_dim().remove_axis(axis) != common_dim)
84+
if let Some(a) = arrays.iter().find_map(|a|
85+
if a.raw_dim().remove_axis(axis) != common_dim {
86+
Some(a)
87+
} else {
88+
None
89+
})
8590
{
86-
return Err(from_kind(ErrorKind::IncompatibleShape));
91+
return Err(ShapeError::incompatible_shapes(&common_dim, &a.dim));
8792
}
8893

8994
let stacked_dim = arrays.iter().fold(0, |acc, a| acc + a.len_of(axis));
@@ -143,17 +148,20 @@ where
143148
D::Larger: RemoveAxis,
144149
{
145150
if arrays.is_empty() {
151+
// TODO More specific error for empty input not supported
146152
return Err(from_kind(ErrorKind::Unsupported));
147153
}
148154
let common_dim = arrays[0].raw_dim();
149155
// Avoid panic on `insert_axis` call, return an Err instead of it.
150156
if axis.index() > common_dim.ndim() {
151-
return Err(from_kind(ErrorKind::OutOfBounds));
157+
return Err(ShapeError::invalid_axis(common_dim.ndim(), axis.index()));
152158
}
153159
let mut res_dim = common_dim.insert_axis(axis);
154160

155-
if arrays.iter().any(|a| a.raw_dim() != common_dim) {
156-
return Err(from_kind(ErrorKind::IncompatibleShape));
161+
if let Some(array) = arrays.iter().find_map(|array| if !array.equal_dim(&common_dim) {
162+
Some(array)
163+
} else { None }) {
164+
return Err(ShapeError::incompatible_shapes(&common_dim, &array.dim));
157165
}
158166

159167
res_dim.set_axis(axis, arrays.len());

0 commit comments

Comments
 (0)