Skip to content
2 changes: 1 addition & 1 deletion compiler/noirc_evaluator/src/acir/acir_context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1311,7 +1311,7 @@ impl<F: AcirField> AcirContext<F> {

Ok::<(AcirVar, AcirType), InternalError>((
self.read_from_memory(block_id, &index_var)?,
value_types[i].into(),
value_types[i % value_types.len()].into(),
))
})
}
Expand Down
9 changes: 2 additions & 7 deletions compiler/noirc_evaluator/src/acir/arrays.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ use acvm::acir::{circuit::opcodes::BlockType, native_types::Witness};
use acvm::{FieldElement, acir::AcirField, acir::circuit::opcodes::BlockId};
use iter_extended::{try_vecmap, vecmap};

use crate::acir::types::flat_numeric_types;
use crate::errors::{InternalError, RuntimeError};
use crate::ssa::ir::{
dfg::DataFlowGraph,
Expand Down Expand Up @@ -777,13 +778,7 @@ impl Context<'_> {
None
};

let value_types = self.convert_value(array, dfg).flat_numeric_types();
// Compiler sanity check
assert_eq!(
value_types.len(),
len,
"ICE: The length of the flattened type array should match the length of the dynamic array"
);
let value_types = flat_numeric_types(&array_typ);

Ok(AcirValue::DynamicArray(AcirDynamicArray {
block_id,
Expand Down
20 changes: 3 additions & 17 deletions compiler/noirc_evaluator/src/acir/call/intrinsics/slice_ops.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::acir::types::flat_numeric_types;
use crate::acir::{AcirDynamicArray, AcirType, AcirValue};
use crate::errors::RuntimeError;
use crate::ssa::ir::{dfg::DataFlowGraph, value::ValueId};
Expand Down Expand Up @@ -380,14 +381,7 @@ impl Context<'_> {
None
};

let mut value_types = slice.flat_numeric_types();
// We can safely append the value types to the end as we expect the types to be the same for each element.
value_types.append(&mut new_value_types);
assert_eq!(
value_types.len(),
slice_size,
"ICE: Value types array must match new slice size"
);
let value_types = flat_numeric_types(&slice_typ);

let result = AcirValue::DynamicArray(AcirDynamicArray {
block_id: result_block_id,
Expand Down Expand Up @@ -532,15 +526,7 @@ impl Context<'_> {
None
};

let mut value_types = slice.flat_numeric_types();
// We can safely remove the value types based upon the popped elements size =
// as we expect the types to be the same for each element.
value_types.truncate(value_types.len() - popped_elements_size);
assert_eq!(
value_types.len(),
result_size,
"ICE: Value types array must match new slice size"
);
let value_types = flat_numeric_types(&slice_typ);

let result = AcirValue::DynamicArray(AcirDynamicArray {
block_id: result_block_id,
Expand Down
49 changes: 35 additions & 14 deletions compiler/noirc_evaluator/src/acir/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,10 @@ pub(super) struct AcirDynamicArray {
/// Thus, we store a vector of types rather than a single type, as a dynamic non-homogenous array
/// is still represented in ACIR by a single `AcirDynamicArray` structure.
///
/// The length of the value types vector must match the `len` field in this structure.
/// This vector only holds the numeric types for a single dynamic array element.
/// For example, if in Noir or SSA we have `[(u8, u32, Field); 3]` then `len` will be 3
/// and `value_types` will be `[u8, u32, Field]`. To know the type of the element at index `i`
/// we can fetch `value_types[i % value_types.len()]`.
pub(super) value_types: Vec<NumericType>,
/// Identification for the ACIR dynamic array
/// inner element type sizes array
Expand Down Expand Up @@ -161,19 +164,6 @@ impl AcirValue {
AcirValue::DynamicArray(_) => unimplemented!("Cannot flatten a dynamic array"),
}
}

/// Fetch a flat list of the [NumericType] contained within an array
/// An [AcirValue::DynamicArray] should already have a field representing
/// its types and should be supported here unlike [AcirValue::flatten]
pub(super) fn flat_numeric_types(self) -> Vec<NumericType> {
match self {
AcirValue::Array(array) => {
array.into_iter().flat_map(|elem| elem.flat_numeric_types()).collect()
}
AcirValue::DynamicArray(AcirDynamicArray { value_types, .. }) => value_types,
AcirValue::Var(_, typ) => vec![typ.to_numeric_type()],
}
}
}

/// A Reference to an `AcirVarData`
Expand All @@ -185,3 +175,34 @@ impl AcirVar {
AcirVar(var)
}
}

/// Assumes `typ` is an array or slice type with nested numeric types, arrays or slices
/// (recursively) and returns a flat list of all the contained numeric types.
/// Panics if `self` is not an array or slice type or if a function or reference type
/// is found along the way.
pub(crate) fn flat_numeric_types(typ: &SsaType) -> Vec<NumericType> {
match typ {
SsaType::Array(..) | SsaType::Slice(..) => {
let mut flat_types = Vec::new();
collect_flat_numeric_types(typ, &mut flat_types);
flat_types
}
_ => panic!("Called flat_numeric_types on a non-array/slice type"),
}
}

/// Helper function for `flat_numeric_types` that recursively collects all numeric types
/// into `flat_types`.
fn collect_flat_numeric_types(typ: &SsaType, flat_types: &mut Vec<NumericType>) {
match typ {
SsaType::Numeric(numeric_type) => {
flat_types.push(*numeric_type);
}
SsaType::Array(types, _) | SsaType::Slice(types) => {
for typ in types.iter() {
collect_flat_numeric_types(typ, flat_types);
}
}
_ => panic!("Called collect_flat_numeric_types on non-array/slice/number type"),
}
}
Loading