diff --git a/compiler/noirc_evaluator/src/acir/acir_context/mod.rs b/compiler/noirc_evaluator/src/acir/acir_context/mod.rs index 2d92ab60ab0..962e3601243 100644 --- a/compiler/noirc_evaluator/src/acir/acir_context/mod.rs +++ b/compiler/noirc_evaluator/src/acir/acir_context/mod.rs @@ -1311,7 +1311,7 @@ impl AcirContext { Ok::<(AcirVar, AcirType), InternalError>(( self.read_from_memory(block_id, &index_var)?, - value_types[i].into(), + value_types[i % value_types.len()].into(), )) }) } diff --git a/compiler/noirc_evaluator/src/acir/arrays.rs b/compiler/noirc_evaluator/src/acir/arrays.rs index 1c9b649a753..d476c998263 100644 --- a/compiler/noirc_evaluator/src/acir/arrays.rs +++ b/compiler/noirc_evaluator/src/acir/arrays.rs @@ -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, @@ -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, diff --git a/compiler/noirc_evaluator/src/acir/call/intrinsics/slice_ops.rs b/compiler/noirc_evaluator/src/acir/call/intrinsics/slice_ops.rs index af3782171f2..b8a23b46d7c 100644 --- a/compiler/noirc_evaluator/src/acir/call/intrinsics/slice_ops.rs +++ b/compiler/noirc_evaluator/src/acir/call/intrinsics/slice_ops.rs @@ -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}; @@ -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, @@ -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, diff --git a/compiler/noirc_evaluator/src/acir/types.rs b/compiler/noirc_evaluator/src/acir/types.rs index 7ccbf09fdef..943b4b3372e 100644 --- a/compiler/noirc_evaluator/src/acir/types.rs +++ b/compiler/noirc_evaluator/src/acir/types.rs @@ -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, /// Identification for the ACIR dynamic array /// inner element type sizes array @@ -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 { - 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` @@ -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 { + 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) { + 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"), + } +}