|
| 1 | +//! After instantiation, we preform a few final checks of each module. |
| 2 | +
|
| 3 | +use num::BigInt; |
| 4 | + |
| 5 | +use crate::{typing::concrete_type::ConcreteType, value::Value}; |
| 6 | + |
| 7 | +use super::{InstantiationContext, RealWireDataSource, RealWirePathElem}; |
| 8 | +impl InstantiationContext<'_, '_> { |
| 9 | + fn check_array_accesses_in(&self, path: &[RealWirePathElem], mut arr_typ: &ConcreteType) { |
| 10 | + for elem in path { |
| 11 | + match elem { |
| 12 | + RealWirePathElem::ArrayAccess { span, idx_wire } => { |
| 13 | + let ConcreteType::Array(arr) = arr_typ else { |
| 14 | + break; |
| 15 | + }; // May still contain unknowns |
| 16 | + let ConcreteType::Value(Value::Integer(arr_sz)) = &arr.1 else { |
| 17 | + break; |
| 18 | + }; // May still contain unknowns |
| 19 | + arr_typ = &arr.0; |
| 20 | + |
| 21 | + let idx_wire_wire = &self.wires[*idx_wire]; |
| 22 | + if let RealWireDataSource::Constant { value } = &idx_wire_wire.source { |
| 23 | + // Constant access into array! We can check. |
| 24 | + let integer_value = value.unwrap_integer(); |
| 25 | + if integer_value >= arr_sz || integer_value < &BigInt::ZERO { |
| 26 | + self.errors |
| 27 | + .error(span.inner_span(), format!("Index out of bounds. Array is of size {arr_sz}, but the index is {integer_value}.")); |
| 28 | + } |
| 29 | + } |
| 30 | + } |
| 31 | + } |
| 32 | + } |
| 33 | + } |
| 34 | + pub fn check_array_accesses(&self) { |
| 35 | + for (_id, w) in &self.wires { |
| 36 | + match &w.source { |
| 37 | + RealWireDataSource::Select { root, path } => { |
| 38 | + let from = &self.wires[*root]; |
| 39 | + self.check_array_accesses_in(path, &from.typ); |
| 40 | + } |
| 41 | + RealWireDataSource::Multiplexer { |
| 42 | + is_state: _, |
| 43 | + sources, |
| 44 | + } => { |
| 45 | + for s in sources { |
| 46 | + self.check_array_accesses_in(&s.to_path, &w.typ); |
| 47 | + } |
| 48 | + } |
| 49 | + _ => {} |
| 50 | + } |
| 51 | + } |
| 52 | + } |
| 53 | +} |
0 commit comments