From 04734976e92475b1ab94257e30bc3438c7358681 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Thu, 21 Mar 2024 15:18:51 +0000 Subject: [PATCH] fix(ssa): Use accurate type during SSA AsSlice simplficiation (#4610) # Description ## Problem\* Resolves #4609 ## Summary\* We were not accurately converting the type from an array to a slice during `AsSlice` SSA simplification. This led to the slice capacity tracker not accurately tracking the slice size. ## Additional Context ## Documentation\* Check one: - [ ] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[Exceptional Case]** Documentation to be submitted in a separate PR. # PR Checklist\* - [ ] I have tested the changes locally. - [ ] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. --- .../src/ssa/ir/instruction/call.rs | 9 ++++---- compiler/noirc_evaluator/src/ssa/ir/types.rs | 7 ++++++ .../array_to_slice/src/main.nr | 23 +++++++++++++++++++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index 8b800e0db5..5b268de239 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -85,10 +85,11 @@ pub(super) fn simplify_call( } } Intrinsic::AsSlice => { - let slice = dfg.get_array_constant(arguments[0]); - if let Some((slice, element_type)) = slice { - let slice_length = dfg.make_constant(slice.len().into(), Type::length_type()); - let new_slice = dfg.make_array(slice, element_type); + let array = dfg.get_array_constant(arguments[0]); + if let Some((array, array_type)) = array { + let slice_length = dfg.make_constant(array.len().into(), Type::length_type()); + let inner_element_types = array_type.element_types(); + let new_slice = dfg.make_array(array, Type::Slice(inner_element_types)); SimplifyResult::SimplifiedToMultiple(vec![slice_length, new_slice]) } else { SimplifyResult::None diff --git a/compiler/noirc_evaluator/src/ssa/ir/types.rs b/compiler/noirc_evaluator/src/ssa/ir/types.rs index ea3f539324..48036580d2 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/types.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/types.rs @@ -159,6 +159,13 @@ impl Type { Type::Reference(element) => element.contains_an_array(), } } + + pub(crate) fn element_types(self) -> Rc> { + match self { + Type::Array(element_types, _) | Type::Slice(element_types) => element_types, + other => panic!("element_types: Expected array or slice, found {other}"), + } + } } /// Composite Types are essentially flattened struct or tuple types. diff --git a/test_programs/execution_success/array_to_slice/src/main.nr b/test_programs/execution_success/array_to_slice/src/main.nr index b97f68fc28..0d0f9562d7 100644 --- a/test_programs/execution_success/array_to_slice/src/main.nr +++ b/test_programs/execution_success/array_to_slice/src/main.nr @@ -7,6 +7,7 @@ fn as_slice_push(xs: [T; N]) -> [T] { slice } +// Expected that x == 0 and y == 1 fn main(x: Field, y: pub Field) { let xs: [Field; 0] = []; let ys: [Field; 1] = [1]; @@ -30,4 +31,26 @@ fn main(x: Field, y: pub Field) { assert(dynamic.as_slice()[2] == dynamic_expected[2]); assert(dynamic.as_slice()[3] == dynamic_expected[3]); assert(dynamic.as_slice().len() == 4); + + regression_4609_append_slices(x, y); + regression_4609_append_dynamic_slices(x, y); +} + +fn regression_4609_append_slices(x: Field, y: Field) { + let sl = [x, 1, 2, 3].as_slice(); + let sl2 = [y, 5, 6].as_slice(); + let sl3 = sl.append(sl2); + assert(sl3[0] == x); + assert(sl3[4] == y); +} + +fn regression_4609_append_dynamic_slices(x: Field, y: Field) { + let mut sl = [x, 1, 2, 3].as_slice(); + sl[x] = x + 10; + let mut sl2 = [y, 5, 6].as_slice(); + sl2[y] = y + 5; + let sl3 = sl.append(sl2); + assert(sl3[0] == 10); + assert(sl3[4] == y); + assert(sl3[5] == 6); }