diff --git a/compiler/noirc_evaluator/src/acir/call/mod.rs b/compiler/noirc_evaluator/src/acir/call/mod.rs index 33768130027..2b398404ec3 100644 --- a/compiler/noirc_evaluator/src/acir/call/mod.rs +++ b/compiler/noirc_evaluator/src/acir/call/mod.rs @@ -188,8 +188,19 @@ impl Context<'_> { .get(&value_id) .expect("ICE: Unknown slice input to brillig") { - AcirValue::DynamicArray(AcirDynamicArray { len, .. }) => *len, - AcirValue::Array(array) => array.len(), + AcirValue::DynamicArray(AcirDynamicArray { len, .. }) => { + // len holds the flattened length of all elements in the slice, + // so to get the no-flattened length we need to divide by the flattened + // length of a single slice entry + let sum: u32 = item_types.iter().map(|typ| typ.flattened_size()).sum(); + if sum == 0 { 0 } else { *len / sum as usize } + } + AcirValue::Array(array) => { + // len holds the non-flattened length of all elements in the slice, + // so here we need to divide by the non-flattened length of a single + // slice entry + if item_types.len() == 0 { 0 } else { array.len() / item_types.len() } + } _ => unreachable!("ICE: Slice value is not an array"), }; @@ -198,7 +209,7 @@ impl Context<'_> { .iter() .map(BrilligFunctionContext::ssa_type_to_parameter) .collect(), - len / item_types.len(), + len, ) } else { BrilligFunctionContext::ssa_type_to_parameter(&typ) diff --git a/compiler/noirc_evaluator/src/acir/types.rs b/compiler/noirc_evaluator/src/acir/types.rs index 943b4b3372e..2b2a13b38cf 100644 --- a/compiler/noirc_evaluator/src/acir/types.rs +++ b/compiler/noirc_evaluator/src/acir/types.rs @@ -87,7 +87,7 @@ pub(super) struct AcirDynamicArray { /// Identification for the Acir dynamic array /// This is essentially a ACIR pointer to the array pub(super) block_id: BlockId, - /// Length of the array + /// Flattened length of the elements in the array pub(super) len: usize, /// An ACIR dynamic array is a flat structure, so we use /// the inner structure of an `AcirType::NumericType` directly. diff --git a/compiler/noirc_evaluator/src/ssa/parser/mod.rs b/compiler/noirc_evaluator/src/ssa/parser/mod.rs index 8b9e8eaf163..a795352b528 100644 --- a/compiler/noirc_evaluator/src/ssa/parser/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/parser/mod.rs @@ -928,8 +928,13 @@ impl<'a> Parser<'a> { fn parse_types(&mut self) -> ParseResult> { if self.eat(Token::LeftParen)? { - let types = self.parse_comma_separated_types()?; - self.eat_or_error(Token::RightParen)?; + let types = if self.eat(Token::RightParen)? { + Vec::new() + } else { + let types = self.parse_comma_separated_types()?; + self.eat_or_error(Token::RightParen)?; + types + }; Ok(types) } else { Ok(vec![self.parse_type()?]) diff --git a/compiler/noirc_evaluator/src/ssa/parser/tests.rs b/compiler/noirc_evaluator/src/ssa/parser/tests.rs index 2e9d246278f..7801fcb6c55 100644 --- a/compiler/noirc_evaluator/src/ssa/parser/tests.rs +++ b/compiler/noirc_evaluator/src/ssa/parser/tests.rs @@ -113,6 +113,18 @@ fn test_make_composite_slice() { assert_ssa_roundtrip(src); } +#[test] +fn test_make_empty_composite_array() { + let src = " + acir(inline) fn main f0 { + b0(): + v0 = make_array [] : [(); 1] + return v0 + } + "; + assert_ssa_roundtrip(src); +} + #[test] fn test_make_byte_array_with_string_literal() { let src = " diff --git a/compiler/noirc_evaluator/src/ssa/validation/mod.rs b/compiler/noirc_evaluator/src/ssa/validation/mod.rs index 31bd3456978..8455baba338 100644 --- a/compiler/noirc_evaluator/src/ssa/validation/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/validation/mod.rs @@ -220,7 +220,14 @@ impl<'f> Validator<'f> { composite_type } Type::Slice(composite_type) => { - if elements.len() % composite_type.len() != 0 { + if composite_type.is_empty() { + if !elements.is_empty() { + panic!( + "MakeArray slice has non-zero {} elements but composite type is empty", + elements.len(), + ); + } + } else if elements.len() % composite_type.len() != 0 { panic!( "MakeArray slice has {} elements but composite type has {} types which don't divide the number of elements", elements.len(), @@ -1543,6 +1550,18 @@ mod tests { let _ = Ssa::from_str(src).unwrap(); } + #[test] + fn make_array_slice_empty_composite_type() { + let src = " + acir(inline) fn main f0 { + b0(): + v0 = make_array [] : [()] + return v0 + } + "; + let _ = Ssa::from_str(src).unwrap(); + } + #[test] #[should_panic( expected = "MakeArray has incorrect element type at index 1: expected u8, got Field" diff --git a/test_programs/execution_success/regression_10197/Nargo.toml b/test_programs/execution_success/regression_10197/Nargo.toml new file mode 100644 index 00000000000..9f67a8d37b2 --- /dev/null +++ b/test_programs/execution_success/regression_10197/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "regression_10197" +type = "bin" +authors = [""] + +[dependencies] diff --git a/test_programs/execution_success/regression_10197/Prover.toml b/test_programs/execution_success/regression_10197/Prover.toml new file mode 100644 index 00000000000..77cf1bb2681 --- /dev/null +++ b/test_programs/execution_success/regression_10197/Prover.toml @@ -0,0 +1 @@ +index = 1 diff --git a/test_programs/execution_success/regression_10197/src/main.nr b/test_programs/execution_success/regression_10197/src/main.nr new file mode 100644 index 00000000000..d7a2a805f0e --- /dev/null +++ b/test_programs/execution_success/regression_10197/src/main.nr @@ -0,0 +1,5 @@ +fn main(index: u32) { + let mut slice = &[(0, [1, 2]), (3, [4, 5])]; + slice[index] = (6, [7, 8]); + println(slice); +} diff --git a/test_programs/execution_success/regression_10198/Nargo.toml b/test_programs/execution_success/regression_10198/Nargo.toml new file mode 100644 index 00000000000..e0df1050bb5 --- /dev/null +++ b/test_programs/execution_success/regression_10198/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "regression_10198" +type = "bin" +authors = [""] + +[dependencies] diff --git a/test_programs/execution_success/regression_10198/Prover.toml b/test_programs/execution_success/regression_10198/Prover.toml new file mode 100644 index 00000000000..77cf1bb2681 --- /dev/null +++ b/test_programs/execution_success/regression_10198/Prover.toml @@ -0,0 +1 @@ +index = 1 diff --git a/test_programs/execution_success/regression_10198/src/main.nr b/test_programs/execution_success/regression_10198/src/main.nr new file mode 100644 index 00000000000..eefe044b24d --- /dev/null +++ b/test_programs/execution_success/regression_10198/src/main.nr @@ -0,0 +1,8 @@ +fn main(index: u32) { + let slice: [()] = &[(), (), ()]; + println(slice); + + let mut slice: [()] = &[(), (), ()]; + slice[index] = (); + println(slice); +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/regression_10197/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/regression_10197/execute__tests__expanded.snap new file mode 100644 index 00000000000..b40e7b5ca01 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/regression_10197/execute__tests__expanded.snap @@ -0,0 +1,10 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: expanded_code +--- +fn main(index: u32) { + let mut slice: [(Field, [Field; 2])] = + &[(0_Field, [1_Field, 2_Field]), (3_Field, [4_Field, 5_Field])]; + slice[index] = (6_Field, [7_Field, 8_Field]); + println(slice); +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/regression_10197/execute__tests__stdout.snap b/tooling/nargo_cli/tests/snapshots/execution_success/regression_10197/execute__tests__stdout.snap new file mode 100644 index 00000000000..0ec21e2fb9c --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/regression_10197/execute__tests__stdout.snap @@ -0,0 +1,5 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: stdout +--- +&[(0x00, [0x01, 0x02]), (0x06, [0x07, 0x08])] diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/regression_10198/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/regression_10198/execute__tests__expanded.snap new file mode 100644 index 00000000000..8b6f9b4c3a4 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/regression_10198/execute__tests__expanded.snap @@ -0,0 +1,11 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: expanded_code +--- +fn main(index: u32) { + let slice: [()] = &[(), (), ()]; + println(slice); + let mut slice: [()] = &[(), (), ()]; + slice[index] = (); + println(slice); +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/regression_10198/execute__tests__stdout.snap b/tooling/nargo_cli/tests/snapshots/execution_success/regression_10198/execute__tests__stdout.snap new file mode 100644 index 00000000000..5187244f9c6 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/regression_10198/execute__tests__stdout.snap @@ -0,0 +1,6 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: stdout +--- +&[(), (), ()] +&[(), (), ()]