diff --git a/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs b/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs index c23b232ef2c..1ec45b37bc6 100644 --- a/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs +++ b/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs @@ -142,7 +142,12 @@ impl FunctionBuilder { assert!(databus.databus.is_none(), "initializing finalized call data"); let typ = self.current_function.dfg[value].get_type().into_owned(); match typ { - Type::Numeric(_) => { + Type::Numeric(numeric_type) => { + let value = if matches!(numeric_type, NumericType::NativeField) { + value + } else { + self.insert_cast(value, NumericType::NativeField) + }; databus.values.push_back(value); databus.index += 1; } diff --git a/compiler/noirc_evaluator/src/ssa/interpreter/errors.rs b/compiler/noirc_evaluator/src/ssa/interpreter/errors.rs index 381c647bc7f..6a075586965 100644 --- a/compiler/noirc_evaluator/src/ssa/interpreter/errors.rs +++ b/compiler/noirc_evaluator/src/ssa/interpreter/errors.rs @@ -182,6 +182,19 @@ pub enum InternalError { actual_length: usize, instruction: &'static str, }, + #[error( + "make_array with {elements_count} elements and {types_count} types but {elements_count} % {types_count} != 0" + )] + MakeArrayElementCountMismatch { result: ValueId, elements_count: usize, types_count: usize }, + #[error( + "make_array element at index `{index}` has type `{actual_type}` but the expected type is `{expected_type}`" + )] + MakeArrayElementTypeMismatch { + result: ValueId, + index: usize, + expected_type: String, + actual_type: String, + }, #[error("Expected input to be `{expected_type}` for `{name}` but it was `{value}`")] UnexpectedInput { name: &'static str, expected_type: &'static str, value: String }, #[error("Error parsing `{name}` into `{expected_type}` from `{value}`: {error}")] diff --git a/compiler/noirc_evaluator/src/ssa/interpreter/mod.rs b/compiler/noirc_evaluator/src/ssa/interpreter/mod.rs index f56e583c51b..9db539d9a0c 100644 --- a/compiler/noirc_evaluator/src/ssa/interpreter/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/interpreter/mod.rs @@ -150,13 +150,11 @@ impl<'ssa, W: Write> Interpreter<'ssa, W> { let actual_type = value.get_type(); if expected_type != actual_type { - return Err(InterpreterError::Internal( - InternalError::ValueTypeDoesNotMatchReturnType { - value_id: id, - expected_type: expected_type.to_string(), - actual_type: actual_type.to_string(), - }, - )); + return Err(internal(InternalError::ValueTypeDoesNotMatchReturnType { + value_id: id, + expected_type: expected_type.to_string(), + actual_type: actual_type.to_string(), + })); } } @@ -1012,10 +1010,43 @@ impl<'ssa, W: Write> Interpreter<'ssa, W> { let elements = try_vecmap(elements, |element| self.lookup(*element))?; let is_slice = matches!(&result_type, Type::Slice(..)); + // The number of elements in the array must be a multiple of the number of element types + let element_types = result_type.clone().element_types(); + if element_types.is_empty() { + if !elements.is_empty() { + return Err(internal(InternalError::MakeArrayElementCountMismatch { + result, + elements_count: elements.len(), + types_count: element_types.len(), + })); + } + } else if elements.len() % element_types.len() != 0 { + return Err(internal(InternalError::MakeArrayElementCountMismatch { + result, + elements_count: elements.len(), + types_count: element_types.len(), + })); + } + + // Make sure each element's type matches the one in element_types + for (index, (element, expected_type)) in + elements.iter().zip(element_types.iter().cycle()).enumerate() + { + let actual_type = element.get_type(); + if &actual_type != expected_type { + return Err(internal(InternalError::MakeArrayElementTypeMismatch { + result, + index, + actual_type: actual_type.to_string(), + expected_type: expected_type.to_string(), + })); + } + } + let array = Value::ArrayOrSlice(ArrayValue { elements: Shared::new(elements), rc: Shared::new(1), - element_types: result_type.clone().element_types(), + element_types, is_slice, }); self.define(result, array) diff --git a/compiler/noirc_evaluator/src/ssa/interpreter/value.rs b/compiler/noirc_evaluator/src/ssa/interpreter/value.rs index 5ef006dbe8e..c9f8d4d30bf 100644 --- a/compiler/noirc_evaluator/src/ssa/interpreter/value.rs +++ b/compiler/noirc_evaluator/src/ssa/interpreter/value.rs @@ -352,7 +352,7 @@ impl NumericValue { } } - pub(crate) fn convert_to_field(&self) -> FieldElement { + pub fn convert_to_field(&self) -> FieldElement { match self { NumericValue::Field(field) => *field, NumericValue::U1(boolean) if *boolean => FieldElement::one(), diff --git a/tooling/nargo_cli/src/cli/interpret_cmd.rs b/tooling/nargo_cli/src/cli/interpret_cmd.rs index 0ccd03225a3..f7ceefb523f 100644 --- a/tooling/nargo_cli/src/cli/interpret_cmd.rs +++ b/tooling/nargo_cli/src/cli/interpret_cmd.rs @@ -16,7 +16,7 @@ use noirc_driver::{CompilationResult, CompileOptions, gen_abi}; use clap::Args; use noirc_errors::CustomDiagnostic; use noirc_evaluator::ssa::interpreter::InterpreterOptions; -use noirc_evaluator::ssa::interpreter::value::Value; +use noirc_evaluator::ssa::interpreter::value::{NumericValue, Value}; use noirc_evaluator::ssa::ir::types::{NumericType, Type}; use noirc_evaluator::ssa::ssa_gen::{Ssa, generate_ssa}; use noirc_evaluator::ssa::{SsaEvaluatorOptions, SsaLogging, primary_passes}; @@ -121,7 +121,7 @@ pub(crate) fn run(args: InterpretCommand, workspace: Workspace) -> Result<(), Cl let ssa_return = ssa_return.map(|ssa_return| { let main_function = &ssa.functions[&ssa.main_id]; if main_function.has_data_bus_return_data() { - let values = flatten_values(ssa_return); + let values = flatten_databus_values(ssa_return); vec![Value::array(values, vec![Type::Numeric(NumericType::NativeField)])] } else { ssa_return @@ -289,23 +289,25 @@ fn print_and_interpret_ssa( interpret_ssa(passes_to_interpret, ssa, msg, args, return_value, interpreter_options) } -fn flatten_values(values: Vec) -> Vec { +fn flatten_databus_values(values: Vec) -> Vec { let mut flattened_values = Vec::new(); for value in values { - flatten_value(value, &mut flattened_values); + flatten_databus_value(value, &mut flattened_values); } flattened_values } -fn flatten_value(value: Value, flattened_values: &mut Vec) { +fn flatten_databus_value(value: Value, flattened_values: &mut Vec) { match value { Value::ArrayOrSlice(array_value) => { for value in array_value.elements.borrow().iter() { - flatten_value(value.clone(), flattened_values); + flatten_databus_value(value.clone(), flattened_values); } } - Value::Numeric(..) - | Value::Reference(..) + Value::Numeric(value) => { + flattened_values.push(Value::Numeric(NumericValue::Field(value.convert_to_field()))); + } + Value::Reference(..) | Value::Function(..) | Value::Intrinsic(..) | Value::ForeignFunction(..) => flattened_values.push(value),