diff --git a/Cargo.lock b/Cargo.lock index 6b81b673b42..6c98390a533 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "acir" -version = "0.19.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "269617cfc7050d47915308c2ae20c33642cbfbc5c25097ba10a522539556065b" +checksum = "bb6315da836487843323dc07343365167ca1c5d9005affa1e412a87b74a98ed6" dependencies = [ "acir_field", "bincode", @@ -18,9 +18,9 @@ dependencies = [ [[package]] name = "acir_field" -version = "0.19.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ace9d882b85479aa678c7272aa717acdcabe1f4d0cb6236cd17dcda8c4bb32" +checksum = "7aa14cddc3b16bf9e661d830f7209193b27c1b540f2d2d0249182b6436a963c6" dependencies = [ "ark-bn254", "ark-ff", @@ -32,9 +32,9 @@ dependencies = [ [[package]] name = "acvm" -version = "0.19.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5eeabcd9c38133eb860c1ad4c0ced8d0032f9f22b6de0699bddacb69bd772ec" +checksum = "48bed7a285c69be779c8e07e72e0b146326c4a23a0eaf03725fd089f1337d07c" dependencies = [ "acir", "acvm_blackbox_solver", @@ -50,9 +50,9 @@ dependencies = [ [[package]] name = "acvm-backend-barretenberg" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff47ff4fd4ae9c6a606f88f1f67a5b4e382313ae3e99edfdc7403bef4a49972" +checksum = "06094a352644202d2094d2221ae0ebc480af7a755dceb72e6ddda3cd69e406e2" dependencies = [ "acvm", "barretenberg-sys", @@ -70,9 +70,9 @@ dependencies = [ [[package]] name = "acvm_blackbox_solver" -version = "0.19.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e3636cfc0b6a6e6e02a5b813b12941ef0979ec532290ee83587f42d7610dae" +checksum = "76b6a5c28ccefa5b6e4162995c7b6e250c5e3ae5109b7e19738ae17a35cb545c" dependencies = [ "acir", "blake2", @@ -85,9 +85,9 @@ dependencies = [ [[package]] name = "acvm_stdlib" -version = "0.19.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fc3882d621cb13af2793e35fff3aa8ba34959c486808e665212d5423835386" +checksum = "31b5871d78fbaab07689caeb46f7128da17267d6b1775a831339bca86ca22ff0" dependencies = [ "acir", ] @@ -524,9 +524,9 @@ dependencies = [ [[package]] name = "brillig" -version = "0.19.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23339a18ea207882da08076a70564b5a44bad80ce2ebb3a46e89172979ae09fb" +checksum = "36139e8a7c0bcc1a5d7638a2851d1315d3256777f3c4f713b4ffd0ccd2770e60" dependencies = [ "acir_field", "serde", @@ -534,12 +534,14 @@ dependencies = [ [[package]] name = "brillig_vm" -version = "0.19.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "024f52eb86d8f320cbbf8c2f231acdd84fe2171d3d1926c4bc95d64e933aa23e" +checksum = "7a8b61359c74d9c1fd5dbb847a0e4950aa7cb8c2de284ab820f9dcffb6db9fd7" dependencies = [ "acir", "acvm_blackbox_solver", + "num-bigint", + "num-traits", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e272989b2aa..1584890c512 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ edition = "2021" rust-version = "1.66" [workspace.dependencies] -acvm = "0.19.1" +acvm = "0.20.0" arena = { path = "crates/arena" } fm = { path = "crates/fm" } iter-extended = { path = "crates/iter-extended" } diff --git a/crates/nargo_cli/Cargo.toml b/crates/nargo_cli/Cargo.toml index 0fd2ce19927..cfb1878be6a 100644 --- a/crates/nargo_cli/Cargo.toml +++ b/crates/nargo_cli/Cargo.toml @@ -48,7 +48,7 @@ color-eyre = "0.6.2" tokio = { version = "1.0", features = ["io-std"] } # Backends -acvm-backend-barretenberg = { version = "0.9.0", default-features = false } +acvm-backend-barretenberg = { version = "0.9.1", default-features = false } [dev-dependencies] tempdir = "0.3.7" @@ -62,3 +62,4 @@ default = ["plonk_bn254"] plonk_bn254 = ["acvm-backend-barretenberg/native"] plonk_bn254_wasm = ["acvm-backend-barretenberg/wasm"] flat_witness = ["acvm-backend-barretenberg/native"] + diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/array_dynamic/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/array_dynamic/Nargo.toml new file mode 100644 index 00000000000..e0b467ce5da --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/array_dynamic/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/array_dynamic/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/array_dynamic/Prover.toml new file mode 100644 index 00000000000..750b3129ec9 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/array_dynamic/Prover.toml @@ -0,0 +1,9 @@ +x = [104, 101, 108, 108, 111] +z = "59" +t = "10" +index = [0,1,2,3,4] +index2 = [0,1,2,3,4] +offset = 1 +sublen = 2 + + diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/array_dynamic/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/array_dynamic/src/main.nr new file mode 100644 index 00000000000..b27c96b30c3 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/array_dynamic/src/main.nr @@ -0,0 +1,32 @@ + +fn main(x: [u32; 5], mut z: u32, t: u32, index: [Field;5], index2: [Field;5], offset: Field, sublen: Field) { + let idx = (z - 5*t - 5) as Field; + //dynamic array test + dyn_array(x, idx, idx - 3); + + //regression for issue 1283 + let mut s = 0; + let x3 = [246,159,32,176,8]; + for i in 0..5 { + s += x3[index[i]]; + } + assert(s!=0); + + if 3 < (sublen as u32) { + assert(index[offset + 3] == index2[3]); + } +} + +fn dyn_array(mut x: [u32; 5], y: Field, z: Field) { + assert(x[y] == 111); + assert(x[z] == 101); + x[z] = 0; + assert(x[y] == 111); + assert(x[1] == 0); + if y as u32 < 10 { + x[y] = x[y] - 2; + } else { + x[y] = 0; + } + assert(x[4] == 109); +} \ No newline at end of file diff --git a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/acir_variable.rs b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/acir_variable.rs index 61c3386ccbd..843cb146f34 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/acir_variable.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/acir_variable.rs @@ -1,8 +1,10 @@ use super::{errors::AcirGenError, generated_acir::GeneratedAcir}; use crate::brillig::brillig_gen::brillig_directive; -use crate::ssa_refactor::acir_gen::AcirValue; +use crate::ssa_refactor::acir_gen::{AcirDynamicArray, AcirValue}; use crate::ssa_refactor::ir::types::Type as SsaType; use crate::ssa_refactor::ir::{instruction::Endian, types::NumericType}; +use acvm::acir::circuit::opcodes::{BlockId, MemOp}; +use acvm::acir::circuit::Opcode; use acvm::acir::{ brillig::Opcode as BrilligOpcode, circuit::brillig::{BrilligInputs, BrilligOutputs}, @@ -210,7 +212,9 @@ impl AcirContext { assert_eq!(results.len(), 1); match results[0] { AcirValue::Var(var, _) => var, - AcirValue::Array(_) => unreachable!("ICE - expected a variable"), + AcirValue::DynamicArray(_) | AcirValue::Array(_) => { + unreachable!("ICE - expected a variable") + } } } @@ -789,6 +793,7 @@ impl AcirContext { Self::flatten_value(acir_vars, value); } } + AcirValue::DynamicArray(_) => unreachable!("Cannot flatten a dynamic array"), } } @@ -826,6 +831,11 @@ impl AcirContext { } BrilligInputs::Array(var_expressions) } + AcirValue::DynamicArray(_) => { + let mut var_expressions = Vec::new(); + self.brillig_array_input(&mut var_expressions, i); + BrilligInputs::Array(var_expressions) + } }); let mut b_outputs = Vec::new(); @@ -857,7 +867,7 @@ impl AcirContext { outputs_var } - fn brillig_array_input(&self, var_expressions: &mut Vec, input: AcirValue) { + fn brillig_array_input(&mut self, var_expressions: &mut Vec, input: AcirValue) { match input { AcirValue::Var(var, _) => { var_expressions.push(self.vars[&var].to_expression().into_owned()); @@ -867,6 +877,24 @@ impl AcirContext { self.brillig_array_input(var_expressions, var); } } + AcirValue::DynamicArray(AcirDynamicArray { block_id, len }) => { + for i in 0..len { + // We generate witnesses corresponding to the array values + let index = AcirValue::Var( + self.add_constant(FieldElement::from(i as u128)), + AcirType::NumericType(NumericType::NativeField), + ); + let index_var = index.into_var(); + + let value_read_var = self.read_from_memory(block_id, &index_var); + let value_read = AcirValue::Var( + value_read_var, + AcirType::NumericType(NumericType::NativeField), + ); + + self.brillig_array_input(var_expressions, value_read); + } + } } } @@ -901,6 +929,11 @@ impl AcirContext { Ok(outputs_var) } + /// Converts an AcirVar to a Witness + fn var_to_witness(&mut self, var: AcirVar) -> Witness { + let var_data = self.vars.get(&var).expect("ICE: undeclared AcirVar"); + self.acir_ir.get_or_create_witness(&var_data.to_expression()) + } /// Constrain lhs to be less than rhs fn less_than_constrain( @@ -913,6 +946,72 @@ impl AcirContext { let lhs_less_than_rhs = self.more_than_eq_var(rhs, lhs, bit_size, predicate)?; self.maybe_eq_predicate(lhs_less_than_rhs, predicate) } + + /// Returns a Variable that is constrained to be the result of reading + /// from the memory `block_id` at the given `index`. + pub(crate) fn read_from_memory(&mut self, block_id: BlockId, index: &AcirVar) -> AcirVar { + // Fetch the witness corresponding to the index + let index_witness = self.var_to_witness(*index); + + // Create a Variable to hold the result of the read and extract the corresponding Witness + let value_read_var = self.add_variable(); + let value_read_witness = self.var_to_witness(value_read_var); + + // Add the memory read operation to the list of opcodes + let read_op = Expression::zero(); + let op = MemOp { + operation: read_op, + index: index_witness.into(), + value: value_read_witness.into(), + }; + self.acir_ir.opcodes.push(Opcode::MemoryOp { block_id, op }); + + value_read_var + } + + /// Constrains the Variable `value` to be the new value located at `index` in the memory `block_id`. + pub(crate) fn write_to_memory(&mut self, block_id: BlockId, index: &AcirVar, value: &AcirVar) { + // Fetch the witness corresponding to the index + // + let index_witness = self.var_to_witness(*index); + + // Fetch the witness corresponding to the value to be written + let value_write_witness = self.var_to_witness(*value); + + // Add the memory write operation to the list of opcodes + let write_op = Expression::one(); + let op = MemOp { + operation: write_op, + index: index_witness.into(), + value: value_write_witness.into(), + }; + self.acir_ir.opcodes.push(Opcode::MemoryOp { block_id, op }); + } + + /// Initializes an array in memory with the given values `optional_values`. + /// If `optional_values` is empty, then the array is initialized with zeros. + pub(crate) fn initialize_array( + &mut self, + block_id: BlockId, + len: usize, + optional_values: Option<&[AcirValue]>, + ) { + // If the optional values are supplied, then we fill the initialized + // array with those values. If not, then we fill it with zeros. + let initialized_values = match optional_values { + None => { + let zero = self.add_constant(FieldElement::zero()); + let zero_witness = self.var_to_witness(zero); + vec![zero_witness; len] + } + Some(optional_values) => vecmap(optional_values, |value| { + let value = value.clone().into_var(); + self.var_to_witness(value) + }), + }; + + self.acir_ir.opcodes.push(Opcode::MemoryInit { block_id, init: initialized_values }); + } } /// Enum representing the possible values that a diff --git a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs index 0e665466d42..311f7dca51e 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs @@ -1,6 +1,7 @@ //! This file holds the pass to convert from Noir's SSA IR to ACIR. -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; +use std::fmt::Debug; use crate::{ brillig::{ @@ -28,7 +29,7 @@ use super::{ ssa_gen::Ssa, }; use acvm::{ - acir::{brillig::Opcode, native_types::Expression}, + acir::{brillig::Opcode, circuit::opcodes::BlockId, native_types::Expression}, FieldElement, }; use iter_extended::{try_vecmap, vecmap}; @@ -55,19 +56,44 @@ struct Context { /// Manages and builds the `AcirVar`s to which the converted SSA values refer. acir_context: AcirContext, + + /// Track initialized acir dynamic arrays + /// + /// An acir array must start with a MemoryInit ACIR opcodes + /// and then have MemoryOp opcodes + /// This set is used to ensure that a MemoryOp opcode is only pushed to the circuit + /// if there is already a MemoryInit opcode. + initialized_arrays: HashSet, +} + +#[derive(Clone)] +pub(crate) struct AcirDynamicArray { + /// Identification for the Acir dynamic array + /// This is essentially a ACIR pointer to the array + block_id: BlockId, + /// Length of the array + len: usize, +} +impl Debug for AcirDynamicArray { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "id: {}, len: {}", self.block_id.0, self.len) + } } #[derive(Debug, Clone)] pub(crate) enum AcirValue { Var(AcirVar, AcirType), Array(im::Vector), + DynamicArray(AcirDynamicArray), } impl AcirValue { fn into_var(self) -> AcirVar { match self { AcirValue::Var(var, _) => var, - AcirValue::Array(_) => panic!("Called AcirValue::into_var on an array"), + AcirValue::DynamicArray(_) | AcirValue::Array(_) => { + panic!("Called AcirValue::into_var on an array") + } } } @@ -75,6 +101,7 @@ impl AcirValue { match self { AcirValue::Var(var, typ) => vec![(var, typ)], AcirValue::Array(array) => array.into_iter().flat_map(AcirValue::flatten).collect(), + AcirValue::DynamicArray(_) => unimplemented!("Cannot flatten a dynamic array"), } } } @@ -116,7 +143,12 @@ impl Context { let mut acir_context = AcirContext::default(); let current_side_effects_enabled_var = acir_context.add_constant(FieldElement::one()); - Context { ssa_values: HashMap::new(), current_side_effects_enabled_var, acir_context } + Context { + ssa_values: HashMap::new(), + current_side_effects_enabled_var, + acir_context, + initialized_arrays: HashSet::new(), + } } /// Converts SSA into ACIR @@ -194,6 +226,17 @@ impl Context { for param_id in params { let typ = dfg.type_of_value(*param_id); let value = self.convert_ssa_block_param(&typ)?; + match &value { + AcirValue::Var(_, _) => (), + AcirValue::Array(values) => { + let block_id = BlockId(param_id.to_usize() as u32); + let v = vecmap(values, |v| v.clone()); + self.initialize_array(block_id, values.len(), Some(&v)); + } + AcirValue::DynamicArray(_) => unreachable!( + "The dynamic array type is created in Acir gen and therefore cannot be a block parameter" + ), + } self.ssa_values.insert(*param_id, value); } Ok(()) @@ -384,36 +427,174 @@ impl Context { store_value: Option, dfg: &DataFlowGraph, ) -> Result<(), AcirGenError> { - let array = self.convert_array_value(array, dfg); - let index = dfg - .get_numeric_constant(index) - .expect("Expected array index to be a known constant") - .try_to_u64() - .expect("Expected array index to fit into a u64") as usize; - - let array_size = array.len(); - if index >= array_size { - // Ignore the error if side effects are disabled. - if self.acir_context.is_constant_one(&self.current_side_effects_enabled_var) { - let location = self.acir_context.get_location(); - return Err(AcirGenError::IndexOutOfBounds { index, array_size, location }); - } - let result_type = dfg.type_of_value(dfg.instruction_results(instruction)[0]); - let value = self.create_default_value(&result_type)?; - self.define_result(dfg, instruction, value); - return Ok(()); + let index_const = dfg.get_numeric_constant(index); + + match self.convert_value(array, dfg) { + AcirValue::Var(acir_var, _) => panic!("Expected an array value, found: {acir_var:?}"), + AcirValue::Array(array) => { + if let Some(index_const) = index_const { + let array_size = array.len(); + let index = + index_const.try_to_u64().expect("Expected array index to fit into a u64") + as usize; + if index >= array_size { + // Ignore the error if side effects are disabled. + if self.acir_context.is_constant_one(&self.current_side_effects_enabled_var) + { + let location = self.acir_context.get_location(); + return Err(AcirGenError::IndexOutOfBounds { + index, + array_size, + location, + }); + } + let result_type = + dfg.type_of_value(dfg.instruction_results(instruction)[0]); + let value = self.create_default_value(&result_type)?; + self.define_result(dfg, instruction, value); + return Ok(()); + } + + let value = match store_value { + Some(store_value) => { + let store_value = self.convert_value(store_value, dfg); + AcirValue::Array(array.update(index, store_value)) + } + None => array[index].clone(), + }; + + self.define_result(dfg, instruction, value); + return Ok(()); + } + } + AcirValue::DynamicArray(_) => (), + } + + if let Some(store) = store_value { + self.array_set(instruction, array, index, store, dfg); + } else { + self.array_get(instruction, array, index, dfg); + } + + Ok(()) + } + + /// Generates a read opcode for the array + fn array_get( + &mut self, + instruction: InstructionId, + array: ValueId, + index: ValueId, + dfg: &DataFlowGraph, + ) { + let array = dfg.resolve(array); + let block_id = BlockId(array.to_usize() as u32); + if !self.initialized_arrays.contains(&block_id) { + match &dfg[array] { + Value::Array { array, .. } => { + let values: Vec = + array.iter().map(|i| self.convert_value(*i, dfg)).collect(); + self.initialize_array(block_id, array.len(), Some(&values)); + } + _ => panic!("reading uninitialized array"), + } } - let value = match store_value { - Some(store_value) => { - let store_value = self.convert_value(store_value, dfg); - AcirValue::Array(array.update(index, store_value)) + let index_var = self.convert_value(index, dfg).into_var(); + let read = self.acir_context.read_from_memory(block_id, &index_var); + let typ = match dfg.type_of_value(array) { + Type::Array(typ, _) => { + if typ.len() != 1 { + unimplemented!( + "Non-const array indices is not implemented for non-homogenous array" + ); + } + typ[0].clone() } - None => array[index].clone(), + _ => unreachable!("ICE - expected an array"), }; + let typ = AcirType::from(typ); + self.define_result(dfg, instruction, AcirValue::Var(read, typ)); + } - self.define_result(dfg, instruction, value); - Ok(()) + /// Copy the array and generates a write opcode on the new array + /// + /// Note: Copying the array is inefficient and is not the way we want to do it in the end. + fn array_set( + &mut self, + instruction: InstructionId, + array: ValueId, + index: ValueId, + store_value: ValueId, + dfg: &DataFlowGraph, + ) { + // Fetch the internal SSA ID for the array + let array = dfg.resolve(array); + let array_ssa_id = array.to_usize() as u32; + + // Use the SSA ID to create a block ID + // There is currently a 1-1 mapping from array SSA ID to block ID + let block_id = BlockId(array_ssa_id); + + // Every array has a length in its type, so we fetch that from + // the SSA IR. + let len = match dfg.type_of_value(array) { + Type::Array(_, len) => len, + _ => unreachable!("ICE - expected an array"), + }; + + // Check if the array has already been initialized in ACIR gen + // if not, we initialize it using the values from SSA + let already_initialized = self.initialized_arrays.contains(&block_id); + if !already_initialized { + match &dfg[array] { + Value::Array { array, .. } => { + let values: Vec = + array.iter().map(|i| self.convert_value(*i, dfg)).collect(); + self.initialize_array(block_id, array.len(), Some(&values)); + } + _ => panic!("Array {} should be initialized", array), + } + } + + // Since array_set creates a new array, we create a new block ID for this + // array. + let result_id = dfg + .instruction_results(instruction) + .first() + .expect("Array set does not have one result"); + let result_array_id = result_id.to_usize() as u32; + let result_block_id = BlockId(result_array_id); + + // Initialize the new array with zero values + self.initialize_array(result_block_id, len, None); + + // Copy the values from the old array into the newly created zeroed array + for i in 0..len { + let index = AcirValue::Var( + self.acir_context.add_constant(FieldElement::from(i as u128)), + AcirType::NumericType(NumericType::NativeField), + ); + let var = index.into_var(); + let read = self.acir_context.read_from_memory(block_id, &var); + self.acir_context.write_to_memory(result_block_id, &var, &read); + } + + // Write the new value into the new array at the specified index + let index_var = self.convert_value(index, dfg).into_var(); + let value_var = self.convert_value(store_value, dfg).into_var(); + self.acir_context.write_to_memory(result_block_id, &index_var, &value_var); + + let result_value = + AcirValue::DynamicArray(AcirDynamicArray { block_id: result_block_id, len }); + self.define_result(dfg, instruction, result_value); + } + + /// Initializes an array with the given values and caches the fact that we + /// have initialized this array. + fn initialize_array(&mut self, array: BlockId, len: usize, values: Option<&[AcirValue]>) { + self.acir_context.initialize_array(array, len, values); + self.initialized_arrays.insert(array); } /// Remember the result of an instruction returning a single value @@ -495,21 +676,11 @@ impl Context { acir_value } - fn convert_array_value( - &mut self, - value_id: ValueId, - dfg: &DataFlowGraph, - ) -> im::Vector { - match self.convert_value(value_id, dfg) { - AcirValue::Var(acir_var, _) => panic!("Expected an array value, found: {acir_var:?}"), - AcirValue::Array(array) => array, - } - } - fn convert_numeric_value(&mut self, value_id: ValueId, dfg: &DataFlowGraph) -> AcirVar { match self.convert_value(value_id, dfg) { AcirValue::Var(acir_var, _) => acir_var, AcirValue::Array(array) => panic!("Expected a numeric value, found: {array:?}"), + AcirValue::DynamicArray(_) => panic!("Expected a numeric value, found an array"), } } @@ -642,7 +813,9 @@ impl Context { ) -> Result { let (variable, incoming_type) = match self.convert_value(*value_id, dfg) { AcirValue::Var(variable, typ) => (variable, typ), - AcirValue::Array(_) => unreachable!("Cast is only applied to numerics"), + AcirValue::DynamicArray(_) | AcirValue::Array(_) => { + unreachable!("Cast is only applied to numerics") + } }; let target_numeric = match typ { Type::Numeric(numeric) => numeric,