1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
//! Definitions for index bounds checking.
use super::ProcError;
impl crate::TypeInner {
/// Return the length of a subscriptable type.
///
/// The `self` parameter should be a handle to a vector, matrix, or array
/// type, a pointer to one of those, or a value pointer. Arrays may be
/// fixed-size, dynamically sized, or sized by a specializable constant.
///
/// The value returned is appropriate for bounds checks on subscripting.
///
/// Return an error if `self` does not describe a subscriptable type at all.
pub fn indexable_length(&self, module: &crate::Module) -> Result<IndexableLength, ProcError> {
use crate::TypeInner as Ti;
let known_length = match *self {
Ti::Vector { size, .. } => size as _,
Ti::Matrix { columns, .. } => columns as _,
Ti::Array { size, .. } => {
return size.to_indexable_length(module);
}
Ti::ValuePointer {
size: Some(size), ..
} => size as _,
Ti::Pointer { base, .. } => {
// When assigning types to expressions, ResolveContext::Resolve
// does a separate sub-match here instead of a full recursion,
// so we'll do the same.
let base_inner = &module.types[base].inner;
match *base_inner {
Ti::Vector { size, .. } => size as _,
Ti::Matrix { columns, .. } => columns as _,
Ti::Array { size, .. } => return size.to_indexable_length(module),
_ => return Err(ProcError::TypeNotIndexable),
}
}
_ => return Err(ProcError::TypeNotIndexable),
};
Ok(IndexableLength::Known(known_length))
}
}
/// The number of elements in an indexable type.
///
/// This summarizes the length of vectors, matrices, and arrays in a way that is
/// convenient for indexing and bounds-checking code.
pub enum IndexableLength {
/// Values of this type always have the given number of elements.
Known(u32),
/// The value of the given specializable constant is the number of elements.
/// (Non-specializable constants are reported as `Known`.)
Specializable(crate::Handle<crate::Constant>),
/// The number of elements is determined at runtime.
Dynamic,
}
impl crate::ArraySize {
pub fn to_indexable_length(self, module: &crate::Module) -> Result<IndexableLength, ProcError> {
use crate::Constant as K;
Ok(match self {
Self::Constant(k) => match module.constants[k] {
K {
specialization: Some(_),
..
} => IndexableLength::Specializable(k),
ref unspecialized => {
let length = unspecialized
.to_array_length()
.ok_or(ProcError::InvalidArraySizeConstant(k))?;
IndexableLength::Known(length)
}
},
Self::Dynamic => IndexableLength::Dynamic,
})
}
}