diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index 7c098e1a5d1..6c28a4e4af6 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -687,6 +687,7 @@ pub fn compile_no_check( force_compile: bool, ) -> Result { let force_unconstrained = options.force_brillig; + let experimental_ownership = options.unstable_features.contains(&UnstableFeature::Ownership); let program = if options.instrument_debug { monomorphize_debug( @@ -694,9 +695,15 @@ pub fn compile_no_check( &mut context.def_interner, &context.debug_instrumenter, force_unconstrained, + experimental_ownership, )? } else { - monomorphize(main_function, &mut context.def_interner, force_unconstrained)? + monomorphize( + main_function, + &mut context.def_interner, + force_unconstrained, + experimental_ownership, + )? }; if options.show_monomorphized { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop_front.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop_front.rs index 8df8f1c6b12..834a3b3ce37 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop_front.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop_front.rs @@ -68,60 +68,27 @@ pub(super) fn compile_vector_pop_front_procedure( BrilligBinaryOp::Sub, ); - let is_rc_one = brillig_context.allocate_register(); - brillig_context.codegen_usize_op( - source_rc.address, - is_rc_one, - BrilligBinaryOp::Equals, - 1_usize, + // FIXME: https://github.com/noir-lang/noir/issues/7976 + // There used to be a branch here for `if is_rc_one` but it was removed due to issues with + // mutating the reference count while popping from the front of the vector. + brillig_context.codegen_initialize_vector(target_vector, target_size, None); + + let target_vector_items_pointer = + brillig_context.codegen_make_vector_items_pointer(target_vector); + + let source_copy_pointer = brillig_context.allocate_register(); + brillig_context.memory_op_instruction( + source_items_pointer.address, + item_pop_count_arg, + source_copy_pointer, + BrilligBinaryOp::Add, ); + // Now we copy the source vector starting at index removed_items.len() into the target vector + brillig_context.codegen_mem_copy(source_copy_pointer, target_vector_items_pointer, target_size); + + brillig_context.deallocate_register(source_copy_pointer); + brillig_context.deallocate_register(target_vector_items_pointer); - brillig_context.codegen_branch(is_rc_one, |brillig_context, is_rc_one| { - if is_rc_one { - // We reuse the source vector, moving the metadata to the right (decreasing capacity) - brillig_context.memory_op_instruction( - source_vector.pointer, - item_pop_count_arg, - target_vector.pointer, - BrilligBinaryOp::Add, - ); - brillig_context.memory_op_instruction( - source_capacity.address, - item_pop_count_arg, - source_capacity.address, - BrilligBinaryOp::Sub, - ); - brillig_context.codegen_initialize_vector_metadata( - target_vector, - target_size, - Some(source_capacity), - ); - } else { - brillig_context.codegen_initialize_vector(target_vector, target_size, None); - - let target_vector_items_pointer = - brillig_context.codegen_make_vector_items_pointer(target_vector); - - let source_copy_pointer = brillig_context.allocate_register(); - brillig_context.memory_op_instruction( - source_items_pointer.address, - item_pop_count_arg, - source_copy_pointer, - BrilligBinaryOp::Add, - ); - // Now we copy the source vector starting at index removed_items.len() into the target vector - brillig_context.codegen_mem_copy( - source_copy_pointer, - target_vector_items_pointer, - target_size, - ); - - brillig_context.deallocate_register(source_copy_pointer); - brillig_context.deallocate_register(target_vector_items_pointer); - } - }); - - brillig_context.deallocate_register(is_rc_one); brillig_context.deallocate_single_addr(target_size); brillig_context.deallocate_single_addr(source_rc); brillig_context.deallocate_single_addr(source_size); diff --git a/compiler/noirc_evaluator/src/ssa/ssa_gen/tests.rs b/compiler/noirc_evaluator/src/ssa/ssa_gen/tests.rs index 50f913105fc..65ba5e11fe8 100644 --- a/compiler/noirc_evaluator/src/ssa/ssa_gen/tests.rs +++ b/compiler/noirc_evaluator/src/ssa/ssa_gen/tests.rs @@ -10,7 +10,7 @@ use noirc_frontend::function_path; use noirc_frontend::test_utils::{Expect, get_monomorphized}; fn get_initial_ssa(src: &str, test_path: &str) -> Result { - let program = match get_monomorphized(src, test_path, Expect::Success) { + let program = match get_monomorphized(src, Some(test_path), Expect::Success) { Ok(program) => program, Err(errors) => { panic!( diff --git a/compiler/noirc_frontend/src/monomorphization/ast.rs b/compiler/noirc_frontend/src/monomorphization/ast.rs index 02b9347af4b..1e8749e88c7 100644 --- a/compiler/noirc_frontend/src/monomorphization/ast.rs +++ b/compiler/noirc_frontend/src/monomorphization/ast.rs @@ -88,6 +88,12 @@ pub struct GlobalId(pub u32); #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct FuncId(pub u32); +/// Each identifier is given a unique ID to distinguish different uses of identifiers. +/// This is used, for example, in last use analysis to determine which identifiers represent +/// the last use of their definition and can thus be moved instead of cloned. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct IdentId(pub u32); + impl Display for FuncId { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.0) @@ -101,6 +107,7 @@ pub struct Ident { pub mutable: bool, pub name: String, pub typ: Type, + pub id: IdentId, } #[derive(Debug, Clone, Hash)] diff --git a/compiler/noirc_frontend/src/monomorphization/mod.rs b/compiler/noirc_frontend/src/monomorphization/mod.rs index db379ae91a5..423ab6e472a 100644 --- a/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -28,7 +28,7 @@ use crate::{ node_interner::{self, DefinitionKind, NodeInterner, StmtId, TraitImplKind, TraitMethodId}, }; use acvm::{FieldElement, acir::AcirField}; -use ast::{GlobalId, While}; +use ast::{GlobalId, IdentId, While}; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; use iter_extended::{btree_map, try_vecmap, vecmap}; use noirc_errors::Location; @@ -61,7 +61,7 @@ struct LambdaContext { /// /// This struct holds the FIFO queue of functions to monomorphize, which is added to /// whenever a new (function, type) combination is encountered. -struct Monomorphizer<'interner> { +pub(super) struct Monomorphizer<'interner> { /// Functions are keyed by their unique ID, whether they're unconstrained, their expected type, /// and any generics they have so that we can monomorphize a new version of the function for each type. /// @@ -103,6 +103,7 @@ struct Monomorphizer<'interner> { next_local_id: u32, next_global_id: u32, next_function_id: u32, + next_ident_id: u32, is_range_loop: bool, @@ -137,8 +138,15 @@ pub fn monomorphize( main: node_interner::FuncId, interner: &mut NodeInterner, force_unconstrained: bool, + enable_ownership: bool, ) -> Result { - monomorphize_debug(main, interner, &DebugInstrumenter::default(), force_unconstrained) + monomorphize_debug( + main, + interner, + &DebugInstrumenter::default(), + force_unconstrained, + enable_ownership, + ) } pub fn monomorphize_debug( @@ -146,6 +154,7 @@ pub fn monomorphize_debug( interner: &mut NodeInterner, debug_instrumenter: &DebugInstrumenter, force_unconstrained: bool, + experimental_ownership: bool, ) -> Result { let debug_type_tracker = DebugTypeTracker::build_from_debug_instrumenter(debug_instrumenter); let mut monomorphizer = Monomorphizer::new(interner, debug_type_tracker); @@ -202,7 +211,11 @@ pub fn monomorphize_debug( debug_functions, debug_types, ); - Ok(program.handle_ownership(monomorphizer.next_local_id)) + Ok(program.handle_ownership( + monomorphizer.next_local_id, + monomorphizer.next_ident_id, + experimental_ownership, + )) } impl<'interner> Monomorphizer<'interner> { @@ -217,6 +230,7 @@ impl<'interner> Monomorphizer<'interner> { next_local_id: 0, next_global_id: 0, next_function_id: 0, + next_ident_id: 0, interner, lambda_envs_stack: Vec::new(), is_range_loop: false, @@ -226,7 +240,7 @@ impl<'interner> Monomorphizer<'interner> { } } - fn next_local_id(&mut self) -> LocalId { + pub(super) fn next_local_id(&mut self) -> LocalId { let id = self.next_local_id; self.next_local_id += 1; LocalId(id) @@ -244,6 +258,12 @@ impl<'interner> Monomorphizer<'interner> { GlobalId(id) } + pub(super) fn next_ident_id(&mut self) -> IdentId { + let id = self.next_ident_id; + self.next_ident_id += 1; + IdentId(id) + } + fn lookup_local(&mut self, id: node_interner::DefinitionId) -> Option { self.locals.get(&id).copied().map(Definition::Local) } @@ -776,7 +796,14 @@ impl<'interner> Monomorphizer<'interner> { let definition = Definition::Local(id); let mutable = false; - ast::Expression::Ident(ast::Ident { definition, mutable, location: None, name, typ }) + ast::Expression::Ident(ast::Ident { + definition, + mutable, + location: None, + name, + typ, + id: self.next_ident_id(), + }) }); // Finally we can return the created Tuple from the new block @@ -899,8 +926,9 @@ impl<'interner> Monomorphizer<'interner> { let typ = Self::convert_type(tuple_type, location)?; let location = Some(location); + let id = self.next_ident_id(); let new_rhs = - ast::Expression::Ident(ast::Ident { location, mutable, definition, name, typ }); + ast::Expression::Ident(ast::Ident { location, mutable, definition, name, typ, id }); let new_rhs = ast::Expression::ExtractTupleField(Box::new(new_rhs), i); let new_expr = self.unpack_pattern(field_pattern, new_rhs, &field_type)?; @@ -947,7 +975,8 @@ impl<'interner> Monomorphizer<'interner> { }; let typ = Self::convert_type(typ, ident.location)?; - Ok(Some(ast::Ident { location: Some(ident.location), mutable, definition, name, typ })) + let id = self.next_ident_id(); + Ok(Some(ast::Ident { location: Some(ident.location), mutable, definition, name, typ, id })) } fn ident( @@ -996,7 +1025,9 @@ impl<'interner> Monomorphizer<'interner> { None, ); let typ = Self::convert_type(&typ, ident.location)?; - let ident = ast::Ident { location, mutable, definition, name, typ: typ.clone() }; + let id = self.next_ident_id(); + let ident = + ast::Ident { location, mutable, definition, name, typ: typ.clone(), id }; let ident_expression = ast::Expression::Ident(ident); if self.is_function_closure_type(&typ) { ast::Expression::Tuple(vec![ @@ -1076,6 +1107,7 @@ impl<'interner> Monomorphizer<'interner> { mutable: false, name, typ, + id: self.next_ident_id(), }; ast::Expression::Ident(ident) } else { @@ -1111,6 +1143,7 @@ impl<'interner> Monomorphizer<'interner> { mutable: false, name, typ, + id: self.next_ident_id(), }; ast::Expression::Ident(ident) } else { @@ -1593,6 +1626,7 @@ impl<'interner> Monomorphizer<'interner> { location: None, name: the_trait.methods[method.method_index].name.to_string(), typ: Self::convert_type(&function_type, location)?, + id: self.next_ident_id(), })) } @@ -1649,6 +1683,7 @@ impl<'interner> Monomorphizer<'interner> { mutable: false, name: "tmp".to_string(), typ: Self::convert_type(&self.interner.id_type(call.func), location)?, + id: self.next_ident_id(), }); let env_argument = @@ -1966,6 +2001,7 @@ impl<'interner> Monomorphizer<'interner> { location: None, name, typ, + id: self.next_ident_id(), })) } @@ -2049,6 +2085,7 @@ impl<'interner> Monomorphizer<'interner> { definition, name: env_name.to_string(), typ: env_typ.clone(), + id: self.next_ident_id(), }; self.lambda_envs_stack @@ -2068,6 +2105,7 @@ impl<'interner> Monomorphizer<'interner> { location: None, // TODO: This should match the location of the lambda expression name: name.clone(), typ: lambda_fn_typ.clone(), + id: self.next_ident_id(), }); let mut parameters = vec![(env_local_id, true, env_name.to_string(), env_typ.clone())]; @@ -2104,6 +2142,7 @@ impl<'interner> Monomorphizer<'interner> { definition: closure_definition, name: block_ident_name.to_string(), typ: ast::Type::Tuple(vec![env_typ, lambda_fn_typ]), + id: self.next_ident_id(), }); Ok((block_let_stmt, closure_ident)) @@ -2285,6 +2324,7 @@ impl<'interner> Monomorphizer<'interner> { Box::new(env_type.clone()), unconstrained, ), + id: self.next_ident_id(), }) } diff --git a/compiler/noirc_frontend/src/monomorphization/printer.rs b/compiler/noirc_frontend/src/monomorphization/printer.rs index 29d3eaed0fd..bf625abc29c 100644 --- a/compiler/noirc_frontend/src/monomorphization/printer.rs +++ b/compiler/noirc_frontend/src/monomorphization/printer.rs @@ -81,15 +81,11 @@ impl AstPrinter { }) .unwrap_or_default(); - write!( - f, - "{}fn {}({}) -> {}{} {{", - if function.unconstrained { "unconstrained " } else { "" }, - self.fmt_func(&function.name, function.id), - params, - vis, - function.return_type, - )?; + let unconstrained = if function.unconstrained { "unconstrained " } else { "" }; + let name = self.fmt_func(&function.name, function.id); + let return_type = &function.return_type; + + write!(f, "{unconstrained}fn {name}({params}) -> {vis}{return_type} {{",)?; self.in_unconstrained = function.unconstrained; self.indent_level += 1; self.print_expr_expect_block(&function.body, f)?; diff --git a/compiler/noirc_frontend/src/monomorphization/tests.rs b/compiler/noirc_frontend/src/monomorphization/tests.rs index b6495df0d20..cb9e712f278 100644 --- a/compiler/noirc_frontend/src/monomorphization/tests.rs +++ b/compiler/noirc_frontend/src/monomorphization/tests.rs @@ -7,7 +7,7 @@ use crate::{ #[macro_export] macro_rules! get_monomorphized { ($src:expr, $expect:expr) => { - $crate::test_utils::get_monomorphized($src, $crate::function_path!(), $expect) + $crate::test_utils::get_monomorphized($src, Some($crate::function_path!()), $expect) }; } diff --git a/compiler/noirc_frontend/src/ownership/last_uses.rs b/compiler/noirc_frontend/src/ownership/last_uses.rs new file mode 100644 index 00000000000..810924c92ac --- /dev/null +++ b/compiler/noirc_frontend/src/ownership/last_uses.rs @@ -0,0 +1,473 @@ +//! This module contains the last use analysis pass which is run on each function before +//! the ownership pass when the experimental ownership scheme is enabled. This pass does +//! not run without this experimental flag - and if it did its results would go unused. +//! +//! The purpose of this pass is to find which instance of a variable is the variable's +//! last use. Note that a variable may have multiple last uses. This can happen if the +//! variable's last use is within an `if` expression or similar. It could be last used +//! in one place in the `then` branch and in another place in the `else` branch as long +//! as no code after the `if` expression uses the same variable. +//! +//! This pass works by tracking the last use location for each variable with a +//! "loop index" and a `Branches` enumeration. +//! - The loop index tracks the loop level the variable was declared in. A variable +//! must be cloned in any loop with an index greater than the variable's own loop index. +//! Note that "loop index" refers to how nested we are within loops. A function starts +//! in index 0, and when we enter the body of a `loop {}` or `for _ in a..b {}`, the index +//! increments by 1. So `b` in `loop { for _ in 0..1 { b } }` would have index `2`. +//! - The `Branches` enumeration holds each current last use of a variable. +//! - In the common case this will be `Branches::Direct(ident_id)` indicating that `ident_id` +//! is the last use of its variable and it was not moved into an `if` or `match`. +//! - When the variable is used within an `if` or `match` its last use will have a value of +//! `Branches::IfOrMatch(cases)` with the given nested last uses in each case of the if/match. +//! - This pass is not sophisticated with regard to struct and tuple fields. It currently +//! ignores these entirely and counts each use as a use of the entire variable. This is an +//! area for future optimization. E.g. the program `a.b.c; a.e.f` will result in `a` being +//! cloned in its entirety in the first statement. Note that this is lessened in the overall +//! ownership pass such that only `.c` is cloned but it is still an area for improvement. +use crate::monomorphization::ast::{self, IdentId, LocalId}; +use crate::monomorphization::ast::{Expression, Function, Literal}; +use fxhash::FxHashMap as HashMap; + +use super::Context; + +/// A variable's last use may be split into several branches. E.g: +/// ```noir +/// if d.len() == 2 { // use 1 of d +/// if d.len() == 2 { // use 2 of d +/// assert_eq(d, [5, 6]); // use 3 of d +/// } +/// } else { +/// assert_eq(d, [5, 6]); // use 4 of d +/// } +/// ``` +/// d's last uses in the above snippet would be: +/// ```noir +/// Branches::IfOrMatch(vec![ +/// Branches::IfOrMatch(vec![ +/// Branches::Direct(3), +/// Branches::None, +/// ]), +/// Branches::Direct(4), +/// ]) +/// ``` +#[derive(Debug, Clone)] +pub(super) enum Branches { + /// No use in this branch or there is no branch + None, + Direct(IdentId), + IfOrMatch(Vec), +} + +impl Branches { + /// Collect all IdentIds from this tree + fn flatten_uses(self) -> Vec { + match self { + Branches::None => Vec::new(), + Branches::Direct(ident_id) => vec![ident_id], + Branches::IfOrMatch(cases) => cases.into_iter().flat_map(Self::flatten_uses).collect(), + } + } +} + +/// A single path through a `Branches` enum. +/// +/// This is used by the context to keep track of where we currently are within a function. +#[derive(Debug)] +enum BranchesPath { + /// We've reached our destination + Here, + /// We're in a fork in the road, take the branch at the given index + IfOrMatch { branch_index: usize, rest: Box }, +} + +struct LastUseContext { + /// The outer `Vec` is each loop we're currently in, while the `BranchPath` contains + /// the path to overwrite the last use in any `Branches` enums of the variables we find. + /// As a whole, this tracks the current control-flow of the function we're in. + current_loop_and_branch: Vec, + + /// Stores the location of each variable's last use + /// + /// Map from each local variable to the last instance of that variable. Separate uses of + /// the same variable are differentiated by that identifier's `IdentId` which is always + /// different on separate identifiers, unlike the `LocalId` which is the same for any + /// identifier referring to the same underlying definition. + /// + /// Each definition is mapped to a loop index and a Branches enumeration. + /// - The loop index tracks how many loops the variable was declared within. It may be moved + /// within the same loop but cannot be moved within a nested loop. E.g: + /// ```noir + /// fn foo() { + /// let x = 2; + /// for _ in 0 .. 2 { + /// let b = true; + /// println((x, b)); + /// } + /// } + /// ``` + /// In the snippet above, `x` will have loop index 0 which does not match its last use + /// within the for loop (1 loop deep = loop index of 1). However, `b` has loop index 1 + /// and thus can be moved into its last use in the loop, in this case the `println` call. + /// - The Branches enumeration holds each last use of the variable. This is usually only + /// one use but can be multiple if the last use is spread across several `if` or `match` + /// branches. E.g: + /// ```noir + /// fn bar() { + /// let x = 2; + /// if true { + /// println(x); + /// } else { + /// assert(x < 5); + /// } + /// } + /// ``` + /// `x` above has two last uses, one in each if branch. + last_uses: HashMap, +} + +impl Context { + /// Traverse the given function and return the last use(s) of each local variable. + /// A variable may have multiple last uses if it was last used within a conditional expression. + pub(super) fn find_last_uses_of_variables( + function: &Function, + ) -> HashMap> { + let mut context = + LastUseContext { current_loop_and_branch: Vec::new(), last_uses: HashMap::default() }; + context.push_loop_scope(); + for (parameter, ..) in &function.parameters { + context.declare_variable(*parameter); + } + context.track_variables_in_expression(&function.body); + context.get_variables_to_move() + } +} + +impl LastUseContext { + fn push_loop_scope(&mut self) { + self.current_loop_and_branch.push(BranchesPath::Here); + } + + fn pop_loop_scope(&mut self) { + self.current_loop_and_branch.pop(); + } + + fn branch(&mut self, branch_index: usize) { + let path = + self.current_loop_and_branch.last_mut().expect("We should always have at least 1 path"); + let rest = Box::new(std::mem::replace(path, BranchesPath::Here)); + *path = BranchesPath::IfOrMatch { branch_index, rest }; + } + + fn unbranch(&mut self) { + let path = + self.current_loop_and_branch.last_mut().expect("We should always have at least 1 path"); + let rest = std::mem::replace(path, BranchesPath::Here); + + match rest { + BranchesPath::Here => panic!("unbranch called without any branches"), + BranchesPath::IfOrMatch { branch_index: _, rest } => *path = *rest, + } + } + + fn loop_index(&self) -> usize { + self.current_loop_and_branch.len() - 1 + } + + fn declare_variable(&mut self, id: LocalId) { + let loop_index = self.loop_index(); + self.last_uses.insert(id, (loop_index, Branches::None)); + } + + /// Remember a new use of the given variable, possibly overwriting or + /// adding to the previous last use depending on the current position + /// in if/match branches or the loop index. + /// + /// If the loop index is equal to the variable's when it was defined we can + /// overwrite the last use, but if it is greater we have to set the last use to None. + /// This is because variable's cannot be moved within loops unless it was defined + /// within the same loop. + fn remember_use_of_variable(&mut self, id: LocalId, variable: IdentId) { + let path = + self.current_loop_and_branch.last().expect("We should always have at least 1 scope"); + let loop_index = self.loop_index(); + + if let Some((variable_loop_index, uses)) = self.last_uses.get_mut(&id) { + if *variable_loop_index == loop_index { + Self::remember_use_of_variable_rec(uses, path, variable); + } else { + *uses = Branches::None; + } + } + } + + fn remember_use_of_variable_rec( + branches: &mut Branches, + path: &BranchesPath, + variable: IdentId, + ) { + match (branches, path) { + // Path is direct, overwrite the last use entirely + (branch, BranchesPath::Here) => { + *branch = Branches::Direct(variable); + } + // Our path says we need to enter an if or match but the variable's last + // use was direct. So we need to overwrite the last use with an empty IfOrMatch + // and write to the relevant branch of that + ( + branch @ (Branches::None | Branches::Direct { .. }), + BranchesPath::IfOrMatch { branch_index, rest: _ }, + ) => { + // The branch doesn't exist for this variable; create it + let empty_branches = + std::iter::repeat_n(Branches::None, *branch_index + 1).collect(); + *branch = Branches::IfOrMatch(empty_branches); + Self::remember_use_of_variable_rec(branch, path, variable); + } + // The variable's last use was in an if or match, and our current path is in one + // as well so just follow to the relevant branch in both. We just need to possibly + // resize the variable's branches count in case it was created with fewer than we + // know we currently have. + (Branches::IfOrMatch(branches), BranchesPath::IfOrMatch { branch_index, rest }) => { + let required_len = *branch_index + 1; + if branches.len() < required_len { + branches.resize(required_len, Branches::None); + } + Self::remember_use_of_variable_rec(&mut branches[*branch_index], rest, variable); + } + } + } + + fn get_variables_to_move(self) -> HashMap> { + self.last_uses + .into_iter() + .map(|(definition, (_, last_uses))| (definition, last_uses.flatten_uses())) + .collect() + } + + fn track_variables_in_expression(&mut self, expr: &Expression) { + match expr { + Expression::Ident(ident) => self.track_variables_in_ident(ident), + Expression::Literal(literal) => self.track_variables_in_literal(literal), + Expression::Block(exprs) => { + exprs.iter().for_each(|expr| self.track_variables_in_expression(expr)); + } + Expression::Unary(unary) => self.track_variables_in_unary(unary), + Expression::Binary(binary) => self.track_variables_in_binary(binary), + Expression::Index(index) => self.track_variables_in_index(index), + Expression::Cast(cast) => self.track_variables_in_cast(cast), + Expression::For(for_expr) => self.track_variables_in_for(for_expr), + Expression::Loop(loop_expr) => self.track_variables_in_loop(loop_expr), + Expression::While(while_expr) => self.track_variables_in_while(while_expr), + Expression::If(if_expr) => self.track_variables_in_if(if_expr), + Expression::Match(match_expr) => self.track_variables_in_match(match_expr), + Expression::Tuple(elems) => self.track_variables_in_tuple(elems), + Expression::ExtractTupleField(tuple, _index) => { + self.track_variables_in_expression(tuple); + } + Expression::Call(call) => self.track_variables_in_call(call), + Expression::Let(let_expr) => self.track_variables_in_let(let_expr), + Expression::Constrain(boolean, _location, msg) => { + self.track_variables_in_constrain(boolean, msg); + } + Expression::Assign(assign) => self.track_variables_in_assign(assign), + Expression::Semi(expr) => self.track_variables_in_expression(expr), + Expression::Clone(_) => unreachable!("last_uses is called before clones are inserted"), + Expression::Drop(_) => unreachable!("last_uses is called before drops are inserted"), + Expression::Break => (), + Expression::Continue => (), + } + } + + fn track_variables_in_ident(&mut self, ident: &ast::Ident) { + // We only track last uses for local variables, globals are always cloned + if let ast::Definition::Local(local_id) = &ident.definition { + self.remember_use_of_variable(*local_id, ident.id); + } + } + + fn track_variables_in_literal(&mut self, literal: &Literal) { + match literal { + Literal::Integer(..) | Literal::Bool(_) | Literal::Unit | Literal::Str(_) => (), + + Literal::FmtStr(_, _, captures) => self.track_variables_in_expression(captures), + + Literal::Array(array) | Literal::Slice(array) => { + for element in array.contents.iter() { + self.track_variables_in_expression(element); + } + } + } + } + + fn track_variables_in_unary(&mut self, unary: &ast::Unary) { + self.track_variables_in_expression(&unary.rhs); + } + + fn track_variables_in_binary(&mut self, binary: &ast::Binary) { + self.track_variables_in_expression(&binary.lhs); + self.track_variables_in_expression(&binary.rhs); + } + + fn track_variables_in_index(&mut self, index: &ast::Index) { + self.track_variables_in_expression(&index.collection); + self.track_variables_in_expression(&index.index); + } + + fn track_variables_in_cast(&mut self, cast: &ast::Cast) { + self.track_variables_in_expression(&cast.lhs); + } + + fn track_variables_in_for(&mut self, for_expr: &ast::For) { + self.track_variables_in_expression(&for_expr.start_range); + self.track_variables_in_expression(&for_expr.end_range); + self.track_variables_in_loop(&for_expr.block); + } + + fn track_variables_in_while(&mut self, while_expr: &ast::While) { + self.track_variables_in_expression(&while_expr.condition); + self.track_variables_in_loop(&while_expr.body); + } + + fn track_variables_in_loop(&mut self, loop_body: &Expression) { + self.push_loop_scope(); + self.track_variables_in_expression(loop_body); + self.pop_loop_scope(); + } + + fn track_variables_in_if(&mut self, if_expr: &ast::If) { + self.track_variables_in_expression(&if_expr.condition); + + self.branch(0); + self.track_variables_in_expression(&if_expr.consequence); + self.unbranch(); + + if let Some(alt) = &if_expr.alternative { + self.branch(1); + self.track_variables_in_expression(alt); + self.unbranch(); + } + } + + fn track_variables_in_match(&mut self, match_expr: &ast::Match) { + for (i, case) in match_expr.cases.iter().enumerate() { + for argument in &case.arguments { + self.declare_variable(*argument); + } + + self.branch(i); + self.track_variables_in_expression(&case.branch); + self.unbranch(); + } + + if let Some(default_case) = &match_expr.default_case { + self.branch(match_expr.cases.len()); + self.track_variables_in_expression(default_case); + self.unbranch(); + } + } + + fn track_variables_in_tuple(&mut self, elems: &[Expression]) { + for elem in elems { + self.track_variables_in_expression(elem); + } + } + + fn track_variables_in_call(&mut self, call: &ast::Call) { + self.track_variables_in_expression(&call.func); + for arg in &call.arguments { + self.track_variables_in_expression(arg); + } + } + + fn track_variables_in_let(&mut self, let_expr: &ast::Let) { + self.track_variables_in_expression(&let_expr.expression); + self.declare_variable(let_expr.id); + } + + fn track_variables_in_constrain( + &mut self, + boolean: &Expression, + msg: &Option>, + ) { + self.track_variables_in_expression(boolean); + + if let Some(msg) = msg { + self.track_variables_in_expression(&msg.0); + } + } + + fn track_variables_in_assign(&mut self, assign: &ast::Assign) { + self.track_variables_in_lvalue(&assign.lvalue); + self.track_variables_in_expression(&assign.expression); + } + + /// A variable in an lvalue position is never moved (otherwise you wouldn't + /// be able to access the variable you assigned to afterward). However, the + /// index in an array expression `a[i] = ...` is an arbitrary expression that + /// is actually in an rvalue position and can thus be moved. + /// + /// Subtle point: since we don't track identifier uses here at all this means + /// if the last use of one was just before it is assigned, it can actually be + /// moved before it is assigned. This should be fine because we move out of the + /// binding, and the binding isn't used until it is set to a new value. + fn track_variables_in_lvalue(&mut self, lvalue: &ast::LValue) { + match lvalue { + // All identifiers in lvalues are implicitly `&mut ident` and thus aren't moved + ast::LValue::Ident(_) => (), + ast::LValue::Index { array, index, element_type: _, location: _ } => { + self.track_variables_in_expression(index); + self.track_variables_in_lvalue(array); + } + ast::LValue::MemberAccess { object, field_index: _ } => { + self.track_variables_in_lvalue(object); + } + ast::LValue::Dereference { reference, element_type: _ } => { + self.track_variables_in_lvalue(reference); + } + } + } +} + +#[cfg(test)] +mod test { + use crate::{ + monomorphization::ast::{IdentId, LocalId}, + test_utils::get_monomorphized, + }; + + #[test] + fn smoke_test() { + let src = " + fn main(d: [Field; 2]) { + if len(d) == 2 { // use 1 of d + if len(d) == 2 { // use 2 of d + assert(eq(d, [5, 6])); // use 3 of d + } + } else { + assert(eq(d, [5, 6])); // use 4 of d + } + } + + fn eq(lhs: [Field; 2], rhs: [Field; 2]) -> bool { + (lhs[0] == rhs[0]) & (lhs[1] == rhs[1]) + } + + fn len(arr: [Field; 2]) -> u32 { + 2 + } + "; + + let program = get_monomorphized(src, None, crate::test_utils::Expect::Success).unwrap(); + + let function = program.main(); + let last_uses = super::Context::find_last_uses_of_variables(function); + + let d_local_id = LocalId(0); + let d_last_uses = &last_uses[&d_local_id]; + + // We should improve testing of this pass so that it is more clear where these ids + // correspond to. + assert_eq!(*d_last_uses, &[IdentId(7), IdentId(10)]); + } +} diff --git a/compiler/noirc_frontend/src/ownership/mod.rs b/compiler/noirc_frontend/src/ownership/mod.rs index edb8c44523d..4a5377ca455 100644 --- a/compiler/noirc_frontend/src/ownership/mod.rs +++ b/compiler/noirc_frontend/src/ownership/mod.rs @@ -43,147 +43,231 @@ //! Additionally we currently only decrement reference counts at the end of the function when //! a parameter goes out of scope. These means reference counts likely trend upward over time //! until the array is eventually mutated and it is reset back to 1. +//! +//! --------------------------------- EXPERIMENTAL OWNERSHIP RULES --------------------------------- +//! +//! This pass currently contains two sets of ownership rules. There is the current default set of +//! rules described above, and there is the set of rules enabled by `Context::experimental_ownership_feature`. +//! The experimental ownership rules aim to be less ad-hoc than the current rules with the goal of +//! making it easier for users to see where clones occur - and possibly forcing users to write +//! their own clones manually. These rules treat each variable roughly as a variable in Rust which +//! implements `Copy`: +//! - Variables are copied on each use, except for the last use where they are moved. +//! - If a variable's last use is in a loop that it was not defined in, it is copied instead of moved. +//! - The last use analysis isn't sophisticated on struct fields. It will count `a.b` and `a.c` +//! both as uses of `a`. Even if both could conceptually be moved, only the last usage will be +//! moved and the first (say `a.b`) will still be cloned. +//! - Dereferences always clone. +//! - Certain expressions will avoid cloning or delay where clones are performed: +//! - Reference expressions `&e` will not clone `e` but may still clone variables used within. +//! - E.g. `&foo.bar` will not clone but `&foo(bar)` may still clone `foo` or `bar`. +//! - Dereferences will attempt to extract a field first if possible. +//! - E.g. `(*self).b.c` is transformed to `*(self.b.c)` where the `*` operation also clones. +//! - Ordinary member access will also delay clones. +//! - E.g. `self.b.c` is compiled as `self.b.c.clone()` over `self.clone().b.c` +//! - Array indexing `a[i]` will avoid cloning `a`. The extracted element is always cloned. +//! +//! Most of this logic is contained in this file except for the last use analysis which is in the +//! `last_uses` module. That module contains a separate pass run on each function before this pass +//! to find the last use of each local variable to identify where moves can occur. use crate::{ ast::UnaryOp, monomorphization::ast::{ - Definition, Expression, Function, Ident, LValue, Let, Literal, LocalId, Parameters, - Program, Type, Unary, + Definition, Expression, Function, Ident, IdentId, LValue, Let, Literal, LocalId, + Parameters, Program, Type, Unary, }, }; +use fxhash::FxHashMap as HashMap; use fxhash::FxHashSet as HashSet; use noirc_errors::Location; +mod last_uses; + impl Program { - pub(crate) fn handle_ownership(mut self, mut next_local_id: u32) -> Self { + pub(crate) fn handle_ownership( + mut self, + next_local_id: u32, + next_ident_id: u32, + experimental_ownership_feature: bool, + ) -> Self { + let mut context = Context { + experimental_ownership_feature, + next_ident_id, + next_local_id, + variables_to_move: Default::default(), + }; + for function in self.functions.iter_mut() { - handle_ownership_in_function(function, &mut next_local_id); + context.handle_ownership_in_function(function); } - self } } -fn handle_ownership_in_function(function: &mut Function, local_id: &mut u32) { - if !function.unconstrained { - return; +struct Context { + experimental_ownership_feature: bool, + + /// If `experimental_ownership_feature` is enabled, this contains each instance of a variable + /// we should move instead of cloning. + variables_to_move: HashMap>, + + next_ident_id: u32, + next_local_id: u32, +} + +impl Context { + fn next_ident_id(&mut self) -> IdentId { + let id = self.next_ident_id; + self.next_ident_id += 1; + IdentId(id) } - let new_bindings = collect_parameters_to_clone(&function.parameters); - handle_expression(&mut function.body); + fn next_local_id(&mut self) -> LocalId { + let id = self.next_local_id; + self.next_local_id += 1; + LocalId(id) + } - // Prepend new_bindings to the function body and insert drops for them at the end. - if !new_bindings.is_empty() { - let unit = Expression::Literal(Literal::Unit); - let old_body = std::mem::replace(&mut function.body, unit); + fn should_move(&self, definition: LocalId, variable: IdentId) -> bool { + self.variables_to_move + .get(&definition) + .is_some_and(|instances_to_move| instances_to_move.contains(&variable)) + } - // Store anything we want to clone in let bindings first so when we later drop - // them we know we're dropping the same instance rather than a fresh copy. - let (mut new_body, new_idents) = create_let_bindings(new_bindings, local_id); + fn handle_ownership_in_function(&mut self, function: &mut Function) { + if !function.unconstrained { + return; + } - // Now push the clones for each parameter - for new_ident in &new_idents { - new_body.push(Expression::Clone(Box::new(new_ident.clone()))); + if self.experimental_ownership_feature { + self.variables_to_move = Self::find_last_uses_of_variables(function); } - // Insert a `let` for the returned value so we can insert drops after it - let return_id = next_local_id(local_id); - let return_let = Expression::Let(Let { - id: return_id, - mutable: false, - name: "return".to_string(), - expression: Box::new(old_body), - }); + self.handle_expression(&mut function.body); - new_body.push(return_let); + if !self.experimental_ownership_feature { + let new_bindings = self.collect_parameters_to_clone(&function.parameters); - // Now drop each parameter we cloned - for new_ident in new_idents { - new_body.push(Expression::Drop(Box::new(new_ident))); - } + // Prepend new_bindings to the function body and insert drops for them at the end. + if !new_bindings.is_empty() { + let unit = Expression::Literal(Literal::Unit); + let old_body = std::mem::replace(&mut function.body, unit); - // Finally, return the original return value we held on to - new_body.push(Expression::Ident(Ident { - location: None, - definition: Definition::Local(return_id), - mutable: false, - name: "return".to_string(), - typ: function.return_type.clone(), - })); + // Store anything we want to clone in let bindings first so when we later drop + // them we know we're dropping the same instance rather than a fresh copy. + let (mut new_body, new_idents) = self.create_let_bindings(new_bindings); - function.body = Expression::Block(new_body); - } -} + // Now push the clones for each parameter + for new_ident in &new_idents { + new_body.push(Expression::Clone(Box::new(new_ident.clone()))); + } + + // Insert a `let` for the returned value so we can insert drops after it + let return_id = self.next_local_id(); + let return_let = Expression::Let(Let { + id: return_id, + mutable: false, + name: "return".to_string(), + expression: Box::new(old_body), + }); -fn create_let_bindings( - bindings_to_create: Vec<(String, Type, Expression)>, - current_local_id: &mut u32, -) -> (Vec, Vec) { - let mut bindings = Vec::with_capacity(bindings_to_create.len()); - let mut idents = Vec::with_capacity(bindings_to_create.len()); + new_body.push(return_let); - for (name, typ, expression) in bindings_to_create { - let id = next_local_id(current_local_id); - let expression = Box::new(expression); - bindings.push(Expression::Let(Let { id, mutable: false, name: String::new(), expression })); + // Now drop each parameter we cloned + for new_ident in new_idents { + new_body.push(Expression::Drop(Box::new(new_ident))); + } - idents.push(Expression::Ident(Ident { - location: None, - definition: Definition::Local(id), - mutable: false, - name, - typ, - })); + // Finally, return the original return value we held on to + new_body.push(Expression::Ident(Ident { + location: None, + definition: Definition::Local(return_id), + mutable: false, + name: "return".to_string(), + typ: function.return_type.clone(), + id: self.next_ident_id(), + })); + + function.body = Expression::Block(new_body); + } + } } - (bindings, idents) -} + fn create_let_bindings( + &mut self, + bindings_to_create: Vec<(String, Type, Expression)>, + ) -> (Vec, Vec) { + let mut bindings = Vec::with_capacity(bindings_to_create.len()); + let mut idents = Vec::with_capacity(bindings_to_create.len()); + + for (name, typ, expression) in bindings_to_create { + let id = self.next_local_id(); + let expression = Box::new(expression); + bindings.push(Expression::Let(Let { + id, + mutable: false, + name: String::new(), + expression, + })); + + idents.push(Expression::Ident(Ident { + location: None, + definition: Definition::Local(id), + mutable: false, + name, + typ, + id: self.next_ident_id(), + })); + } -fn next_local_id(current_local_id: &mut u32) -> LocalId { - let next = *current_local_id; - *current_local_id += 1; - LocalId(next) -} + (bindings, idents) + } -/// Returns a vector of new parameters to prepend clones to a function - if any. -/// Note that these may be full expressions e.g. `*param.field` so they should -/// be stored in a let binding before being cloned to ensure that a later drop -/// would be to the same value. -fn collect_parameters_to_clone(parameters: &Parameters) -> Vec<(String, Type, Expression)> { - let mut seen_array_types = HashSet::default(); - let mut new_bindings = Vec::new(); - - for (parameter_id, mutable, name, parameter_type) in parameters { - let parameter = Expression::Ident(Ident { - location: None, - definition: Definition::Local(*parameter_id), - mutable: *mutable, - name: name.clone(), - typ: parameter_type.clone(), - }); - - // (by-value) Mutable parameters are always cloned. Otherwise, we have to recur on the type - // to find a duplicate array types behind mutable references. - let parameter = if *mutable { - let name = name.clone(); - new_bindings.push((name, parameter_type.clone(), parameter)); - // disable cloning in recur_on_parameter, we already cloned - None - } else { - Some(parameter) - }; + /// Returns a vector of new parameters to prepend clones to a function - if any. + /// Note that these may be full expressions e.g. `*param.field` so they should + /// be stored in a let binding before being cloned to ensure that a later drop + /// would be to the same value. + fn collect_parameters_to_clone( + &mut self, + parameters: &Parameters, + ) -> Vec<(String, Type, Expression)> { + let mut seen_array_types = HashSet::default(); + let mut new_bindings = Vec::new(); + + for (parameter_id, mutable, name, parameter_type) in parameters { + let parameter = Expression::Ident(Ident { + location: None, + definition: Definition::Local(*parameter_id), + mutable: *mutable, + name: name.clone(), + typ: parameter_type.clone(), + id: self.next_ident_id(), + }); - recur_on_parameter( - parameter, - parameter_type, - name, - &mut seen_array_types, - &mut new_bindings, - false, - ); - } + // (by-value) Mutable parameters are always cloned. Otherwise, we have to recur on the type + // to find a duplicate array types behind mutable references. + let parameter = if *mutable { + let name = name.clone(); + new_bindings.push((name, parameter_type.clone(), parameter)); + // disable cloning in recur_on_parameter, we already cloned + None + } else { + Some(parameter) + }; + + recur_on_parameter( + parameter, + parameter_type, + name, + &mut seen_array_types, + &mut new_bindings, + false, + ); + } - new_bindings + new_bindings + } } /// Recur on a parameter's type, digging into any struct fields, looking for references to arrays. @@ -260,180 +344,318 @@ fn recur_on_parameter<'typ>( } } -fn handle_expression(expr: &mut Expression) { - match expr { - Expression::Ident(_) => (), - Expression::Literal(literal) => handle_literal(literal), - Expression::Block(exprs) => { - exprs.iter_mut().for_each(handle_expression); +impl Context { + fn handle_expression(&mut self, expr: &mut Expression) { + match expr { + Expression::Ident(_) => self.handle_ident(expr), + Expression::Literal(literal) => self.handle_literal(literal), + Expression::Block(exprs) => { + exprs.iter_mut().for_each(|expr| self.handle_expression(expr)); + } + Expression::Unary(_) => self.handle_unary(expr), + Expression::Binary(binary) => self.handle_binary(binary), + Expression::Index(_) => self.handle_index(expr), + Expression::Cast(cast) => self.handle_cast(cast), + Expression::For(for_expr) => self.handle_for(for_expr), + Expression::Loop(loop_expr) => self.handle_expression(loop_expr), + Expression::While(while_expr) => self.handle_while(while_expr), + Expression::If(if_expr) => self.handle_if(if_expr), + Expression::Match(match_expr) => self.handle_match(match_expr), + Expression::Tuple(elements) => self.handle_tuple(elements), + Expression::ExtractTupleField(..) => self.handle_extract_expression(expr), + Expression::Call(call) => self.handle_call(call), + Expression::Let(let_expr) => self.handle_let(let_expr), + Expression::Constrain(boolean, _location, msg) => self.handle_constrain(boolean, msg), + Expression::Assign(assign) => self.handle_assign(assign), + Expression::Semi(expr) => self.handle_expression(expr), + // Clones & Drops are only inserted by this pass so we can assume any code they + // contain is already handled + Expression::Clone(_) => (), + Expression::Drop(_) => (), + Expression::Break => (), + Expression::Continue => (), } - Expression::Unary(unary) => handle_unary(unary), - Expression::Binary(binary) => handle_binary(binary), - Expression::Index(_) => handle_index(expr), - Expression::Cast(cast) => handle_cast(cast), - Expression::For(for_expr) => handle_for(for_expr), - Expression::Loop(loop_expr) => handle_expression(loop_expr), - Expression::While(while_expr) => handle_while(while_expr), - Expression::If(if_expr) => handle_if(if_expr), - Expression::Match(match_expr) => handle_match(match_expr), - Expression::Tuple(elements) => handle_tuple(elements), - Expression::ExtractTupleField(tuple, _index) => handle_expression(tuple), - Expression::Call(call) => handle_call(call), - Expression::Let(let_expr) => handle_let(let_expr), - Expression::Constrain(boolean, _location, msg) => handle_constrain(boolean, msg), - Expression::Assign(assign) => handle_assign(assign), - Expression::Semi(expr) => handle_expression(expr), - // Clones & Drops are only inserted by this pass so we can assume any code they - // contain is already handled - Expression::Clone(_) => (), - Expression::Drop(_) => (), - Expression::Break => (), - Expression::Continue => (), } -} -/// - Array literals: -/// - Arrays stored inside a nested array literal (e.g. both variables in `[array1, array2]` -/// have their reference count incremented). -/// - This does not apply to nested array literals since we know they are not referenced elsewhere. -fn handle_literal(literal: &mut Literal) { - match literal { - Literal::Integer(..) | Literal::Bool(_) | Literal::Unit | Literal::Str(_) => (), - - Literal::FmtStr(_, _, captures) => handle_expression(captures), - - Literal::Array(array) | Literal::Slice(array) => { - let element_type = - array.typ.array_element_type().expect("Array literal should have an array type"); - if contains_array_or_str_type(element_type) { - // We have to clone nested arrays unless they are array literals - for element in array.contents.iter_mut() { - if !is_array_or_str_literal(element) { - clone_expr(element); - } + /// Handle the rhs of a `&expr` unary expression. + /// When the experimental ownership flag is enabled variables and field accesses + /// in these expressions are exempt from clones. + fn handle_reference_expression(&mut self, expr: &mut Expression) { + match expr { + Expression::Ident(_) => (), + Expression::Block(exprs) => { + let len_minus_one = exprs.len().saturating_sub(1); + for expr in exprs.iter_mut().take(len_minus_one) { + // In `&{ a; b; ...; z }` we're only taking the reference of `z`. + self.handle_expression(expr); + } + if let Some(expr) = exprs.last_mut() { + self.handle_reference_expression(expr); } } + Expression::Unary(Unary { rhs, operator: UnaryOp::Dereference { .. }, .. }) => { + self.handle_reference_expression(rhs); + } + Expression::ExtractTupleField(tuple, _index) => self.handle_reference_expression(tuple), + + // If we have something like `f(arg)` then we want to treat those variables normally + // rather than avoid cloning them. So we shouldn't recur in `handle_reference_expression`. + other => self.handle_expression(other), } } -} -fn handle_unary(unary: &mut Unary) { - handle_expression(&mut unary.rhs); -} + fn handle_extract_expression(&mut self, expr: &mut Expression) { + let Expression::ExtractTupleField(tuple, index) = expr else { + panic!("handle_extract_expression given non-extract expression {expr}"); + }; -fn handle_binary(binary: &mut crate::monomorphization::ast::Binary) { - handle_expression(&mut binary.lhs); - handle_expression(&mut binary.rhs); -} + if !self.experimental_ownership_feature { + return self.handle_expression(tuple); + } -/// - Extracting an array from another array (`let inner: [_; _] = array[0];`): -/// - Extracting a nested array from its outer array will always increment the reference count -/// of the nested array. -fn handle_index(index_expr: &mut Expression) { - let crate::monomorphization::ast::Expression::Index(index) = index_expr else { - panic!("handle_index should only be called with Index nodes"); - }; + // When experimental ownership is enabled, we may clone identifiers. We want to avoid + // cloning the entire object though if we're only accessing one field of it so we check + // here to move the clone to the outermost extract expression instead. + // E.g. we want to change `a.clone().b.c` to `a.b.c.clone()`. + if let Some((should_clone, tuple_type)) = self.handle_extract_expression_rec(tuple) { + if let Some(elements) = unwrap_tuple_type(tuple_type) { + if should_clone && contains_array_or_str_type(&elements[*index]) { + clone_expr(expr); + } + } + } else { + self.handle_expression(tuple); + } + } - handle_expression(&mut index.collection); - handle_expression(&mut index.index); + /// Traverse an expression comprised of only identifiers, tuple field extractions, and + /// dereferences returning whether we should clone the result and the type of that result. + /// Returns None if a different expression variant was found. + fn handle_extract_expression_rec(&mut self, expr: &mut Expression) -> Option<(bool, Type)> { + match expr { + Expression::Ident(ident) => { + let should_clone = self.should_clone_ident(ident); + Some((should_clone, ident.typ.clone())) + } + // Delay dereferences as well so we change `(*self).foo.bar` to `*(self.foo.bar)` + Expression::Unary(Unary { + rhs, + operator: UnaryOp::Dereference { .. }, + result_type, + .. + }) => { + self.handle_reference_expression(rhs); + Some((true, result_type.clone())) + } + Expression::ExtractTupleField(tuple, index) => { + let (should_clone, typ) = self.handle_extract_expression_rec(tuple)?; + let mut elements = unwrap_tuple_type(typ)?; + Some((should_clone, elements.swap_remove(*index))) + } + _ => None, + } + } - if contains_array_or_str_type(&index.element_type) { - clone_expr(index_expr); + /// Under the experimental alternate ownership scheme, whenever an ident is used it is + /// always cloned unless it is the last use of the ident (not in a loop). + fn should_clone_ident(&self, ident: &Ident) -> bool { + if self.experimental_ownership_feature { + if let Definition::Local(local_id) = &ident.definition { + if contains_array_or_str_type(&ident.typ) && !self.should_move(*local_id, ident.id) + { + return true; + } + } + } + false } -} -fn handle_cast(cast: &mut crate::monomorphization::ast::Cast) { - handle_expression(&mut cast.lhs); -} + fn handle_ident(&self, expr: &mut Expression) { + let ident = match expr { + Expression::Ident(ident) => ident, + other => panic!("handle_ident given non-ident expr: {other}"), + }; -fn handle_for(for_expr: &mut crate::monomorphization::ast::For) { - handle_expression(&mut for_expr.start_range); - handle_expression(&mut for_expr.end_range); - handle_expression(&mut for_expr.block); -} + if self.should_clone_ident(ident) { + clone_expr(expr); + } + } -fn handle_while(while_expr: &mut crate::monomorphization::ast::While) { - handle_expression(&mut while_expr.condition); - handle_expression(&mut while_expr.body); -} + /// - Array literals: + /// - Arrays stored inside a nested array literal (e.g. both variables in `[array1, array2]` + /// have their reference count incremented). + /// - This does not apply to nested array literals since we know they are not referenced elsewhere. + fn handle_literal(&mut self, literal: &mut Literal) { + match literal { + Literal::Integer(..) | Literal::Bool(_) | Literal::Unit | Literal::Str(_) => (), + + Literal::FmtStr(_, _, captures) => self.handle_expression(captures), + + Literal::Array(array) | Literal::Slice(array) => { + let element_type = array + .typ + .array_element_type() + .expect("Array literal should have an array type"); + + if !self.experimental_ownership_feature && contains_array_or_str_type(element_type) + { + // We have to clone nested arrays unless they are array literals + for element in array.contents.iter_mut() { + if !is_array_or_str_literal(element) { + clone_expr(element); + } + } + } + } + } + } + + fn handle_unary(&mut self, expr: &mut Expression) { + let unary = match expr { + Expression::Unary(unary) => unary, + other => panic!("handle_unary given non-unary expression: {other}"), + }; + + // Don't clone `rhs` if this is a reference or dereference expression. + // - If this is a reference expression `&rhs`, `rhs` by definition shouldn't be cloned + // - If this is `*rhs` we're going to clone the extracted element instead + if self.experimental_ownership_feature + && matches!(unary.operator, UnaryOp::Reference { .. } | UnaryOp::Dereference { .. }) + { + self.handle_reference_expression(&mut unary.rhs); + } else { + self.handle_expression(&mut unary.rhs); + } -fn handle_if(if_expr: &mut crate::monomorphization::ast::If) { - handle_expression(&mut if_expr.condition); - handle_expression(&mut if_expr.consequence); - if let Some(alt) = &mut if_expr.alternative { - handle_expression(alt); + if self.experimental_ownership_feature + && matches!(unary.operator, UnaryOp::Dereference { .. }) + && contains_array_or_str_type(&unary.result_type) + { + clone_expr(expr); + } } -} -fn handle_match(match_expr: &mut crate::monomorphization::ast::Match) { - for case in &mut match_expr.cases { - handle_expression(&mut case.branch); + fn handle_binary(&mut self, binary: &mut crate::monomorphization::ast::Binary) { + self.handle_expression(&mut binary.lhs); + self.handle_expression(&mut binary.rhs); } - if let Some(default_case) = &mut match_expr.default_case { - handle_expression(default_case); + /// - Extracting an array from another array (`let inner: [_; _] = array[0];`): + /// - Extracting a nested array from its outer array will always increment the reference count + /// of the nested array. + fn handle_index(&mut self, index_expr: &mut Expression) { + let crate::monomorphization::ast::Expression::Index(index) = index_expr else { + panic!("handle_index should only be called with Index nodes"); + }; + + if self.experimental_ownership_feature { + // Don't clone the collection, cloning only the resulting element is cheaper + self.handle_reference_expression(&mut index.collection); + } else { + self.handle_expression(&mut index.collection); + } + + self.handle_expression(&mut index.index); + + if contains_array_or_str_type(&index.element_type) { + clone_expr(index_expr); + } } -} -fn handle_tuple(elems: &mut [Expression]) { - for elem in elems { - handle_expression(elem); + fn handle_cast(&mut self, cast: &mut crate::monomorphization::ast::Cast) { + self.handle_expression(&mut cast.lhs); } -} -fn handle_call(call: &mut crate::monomorphization::ast::Call) { - handle_expression(&mut call.func); - for arg in &mut call.arguments { - handle_expression(arg); + fn handle_for(&mut self, for_expr: &mut crate::monomorphization::ast::For) { + self.handle_expression(&mut for_expr.start_range); + self.handle_expression(&mut for_expr.end_range); + self.handle_expression(&mut for_expr.block); } -} -/// - Let bindings (`let _ = ;`): -/// - Binding an array to a let binding increments the reference count of the array unless -/// the expression is an array literal in which case it is considered to be moved. -fn handle_let(let_expr: &mut crate::monomorphization::ast::Let) { - handle_expression(&mut let_expr.expression); + fn handle_while(&mut self, while_expr: &mut crate::monomorphization::ast::While) { + self.handle_expression(&mut while_expr.condition); + self.handle_expression(&mut while_expr.body); + } - if !is_array_or_str_literal(&let_expr.expression) { - clone_expr(&mut let_expr.expression); + fn handle_if(&mut self, if_expr: &mut crate::monomorphization::ast::If) { + self.handle_expression(&mut if_expr.condition); + self.handle_expression(&mut if_expr.consequence); + if let Some(alt) = &mut if_expr.alternative { + self.handle_expression(alt); + } } -} -fn handle_constrain( - boolean: &mut Expression, - msg: &mut Option>, -) { - handle_expression(boolean); + fn handle_match(&mut self, match_expr: &mut crate::monomorphization::ast::Match) { + for case in &mut match_expr.cases { + self.handle_expression(&mut case.branch); + } - if let Some(msg) = msg { - handle_expression(&mut msg.0); + if let Some(default_case) = &mut match_expr.default_case { + self.handle_expression(default_case); + } } -} -/// - Assignments (`x = ;`): -/// - Assigning an array to an existing variable will also increment the reference -/// count of the array unless it is an array literal. -fn handle_assign(assign: &mut crate::monomorphization::ast::Assign) { - handle_lvalue(&mut assign.lvalue); - handle_expression(&mut assign.expression); + fn handle_tuple(&mut self, elements: &mut [Expression]) { + for elem in elements { + self.handle_expression(elem); + } + } - if !is_array_or_str_literal(&assign.expression) { - clone_expr(&mut assign.expression); + fn handle_call(&mut self, call: &mut crate::monomorphization::ast::Call) { + self.handle_expression(&mut call.func); + for arg in &mut call.arguments { + self.handle_expression(arg); + } } -} -fn handle_lvalue(lvalue: &mut LValue) { - match lvalue { - LValue::Ident(_) => (), - LValue::Index { array, index, element_type: _, location: _ } => { - handle_expression(index); - handle_lvalue(array); + /// - Let bindings (`let _ = ;`): + /// - Binding an array to a let binding increments the reference count of the array unless + /// the expression is an array literal in which case it is considered to be moved. + fn handle_let(&mut self, let_expr: &mut crate::monomorphization::ast::Let) { + self.handle_expression(&mut let_expr.expression); + + if !self.experimental_ownership_feature && !is_array_or_str_literal(&let_expr.expression) { + clone_expr(&mut let_expr.expression); } - LValue::MemberAccess { object, field_index: _ } => { - handle_lvalue(object); + } + + fn handle_constrain( + &mut self, + boolean: &mut Expression, + msg: &mut Option>, + ) { + self.handle_expression(boolean); + + if let Some(msg) = msg { + self.handle_expression(&mut msg.0); } - LValue::Dereference { reference, element_type: _ } => { - handle_lvalue(reference); + } + + /// - Assignments (`x = ;`): + /// - Assigning an array to an existing variable will also increment the reference + /// count of the array unless it is an array literal. + fn handle_assign(&mut self, assign: &mut crate::monomorphization::ast::Assign) { + self.handle_lvalue(&mut assign.lvalue); + self.handle_expression(&mut assign.expression); + + if !self.experimental_ownership_feature && !is_array_or_str_literal(&assign.expression) { + clone_expr(&mut assign.expression); + } + } + + fn handle_lvalue(&mut self, lvalue: &mut LValue) { + match lvalue { + LValue::Ident(_) => (), + LValue::Index { array, index, element_type: _, location: _ } => { + self.handle_expression(index); + self.handle_lvalue(array); + } + LValue::MemberAccess { object, field_index: _ } => { + self.handle_lvalue(object); + } + LValue::Dereference { reference, element_type: _ } => { + self.handle_lvalue(reference); + } } } } @@ -488,11 +710,24 @@ fn is_array_or_str_literal(expr: &Expression) -> bool { fn contains_array_or_str_type(typ: &Type) -> bool { match typ { - Type::Field | Type::Integer(..) | Type::Bool | Type::Unit | Type::Function(..) => false, + Type::Field + | Type::Integer(..) + | Type::Bool + | Type::Unit + | Type::Function(..) + | Type::Reference(..) => false, Type::Array(_, _) | Type::String(_) | Type::FmtString(_, _) | Type::Slice(_) => true, Type::Tuple(elems) => elems.iter().any(contains_array_or_str_type), - Type::Reference(elem, _) => contains_array_or_str_type(elem), + } +} + +fn unwrap_tuple_type(typ: Type) -> Option> { + match typ { + Type::Tuple(elements) => Some(elements), + // array accesses will automatically dereference so we do too + Type::Reference(element, _) => unwrap_tuple_type(*element), + _ => None, } } diff --git a/compiler/noirc_frontend/src/test_utils.rs b/compiler/noirc_frontend/src/test_utils.rs index bbe4c530e88..2baceffc24e 100644 --- a/compiler/noirc_frontend/src/test_utils.rs +++ b/compiler/noirc_frontend/src/test_utils.rs @@ -29,7 +29,7 @@ use crate::monomorphization::{ast::Program, errors::MonomorphizationError, monom pub fn get_monomorphized( src: &str, - test_path: &str, + test_path: Option<&str>, expect: Expect, ) -> Result { let (_parsed_module, mut context, errors) = get_program(src, test_path, expect); @@ -42,7 +42,7 @@ pub fn get_monomorphized( .get_main_function(context.root_crate_id()) .unwrap_or_else(|| panic!("get_monomorphized: test program contains no 'main' function")); - monomorphize(main, &mut context.def_interner, false) + monomorphize(main, &mut context.def_interner, false, false) } pub(crate) fn has_parser_error(errors: &[CompilationError]) -> bool { @@ -60,13 +60,13 @@ pub(crate) fn remove_experimental_warnings(errors: &mut Vec) { pub(crate) fn get_program<'a, 'b>( src: &'a str, - test_path: &'b str, + test_path: Option<&'b str>, expect: Expect, ) -> (ParsedModule, Context<'a, 'b>, Vec) { let allow_parser_errors = false; get_program_with_options( src, - Some(test_path), + test_path, expect, allow_parser_errors, FrontendOptions::test_default(), diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 2fafe0911b9..635caa64a39 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -48,11 +48,11 @@ pub(crate) fn get_program_using_features( } pub(crate) fn get_program_errors(src: &str, test_path: &str) -> Vec { - get_program(src, test_path, Expect::Error).2 + get_program(src, Some(test_path), Expect::Error).2 } fn assert_no_errors(src: &str, test_path: &str) { - let (_, context, errors) = get_program(src, test_path, Expect::Success); + let (_, context, errors) = get_program(src, Some(test_path), Expect::Success); if !errors.is_empty() { let errors = errors.iter().map(CustomDiagnostic::from).collect::>(); report_all(context.file_manager.as_file_map(), &errors, false, false); @@ -181,7 +181,13 @@ fn check_errors_with_options( panic!("get_monomorphized: test program contains no 'main' function") }); - let result = crate::monomorphization::monomorphize(main, &mut context.def_interner, false); + let ownership = options.enabled_unstable_features.contains(&UnstableFeature::Ownership); + let result = crate::monomorphization::monomorphize( + main, + &mut context.def_interner, + false, + ownership, + ); match result { Ok(_) => { if primary_spans_with_errors.is_empty() { @@ -933,7 +939,7 @@ fn check_trait_as_type_as_two_fn_parameters() { } fn get_program_captures(src: &str, test_path: &str) -> Vec> { - let (program, context, _errors) = get_program(src, test_path, Expect::Success); + let (program, context, _errors) = get_program(src, Some(test_path), Expect::Success); let interner = context.def_interner; let mut all_captures: Vec> = Vec::new(); for func in program.into_sorted().functions { diff --git a/test_programs/execution_success/mutate_array_copy/Nargo.toml b/test_programs/execution_success/mutate_array_copy/Nargo.toml new file mode 100644 index 00000000000..b642ec6e830 --- /dev/null +++ b/test_programs/execution_success/mutate_array_copy/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "mutate_array_copy" +type = "bin" +authors = [""] + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/mutate_array_copy/src/main.nr b/test_programs/execution_success/mutate_array_copy/src/main.nr new file mode 100644 index 00000000000..0d112b69995 --- /dev/null +++ b/test_programs/execution_success/mutate_array_copy/src/main.nr @@ -0,0 +1,11 @@ +unconstrained fn main() { + let mut a = [1, 2]; + foo(&mut a); +} + +unconstrained fn foo(a: &mut [Field; 2]) { + let a_copy = *a; + a[0] = 100; + assert_eq(a_copy, [1, 2]); + assert_eq(*a, [100, 2]); +} diff --git a/tooling/ast_fuzzer/src/program/expr.rs b/tooling/ast_fuzzer/src/program/expr.rs index 25092e753a1..33b94517009 100644 --- a/tooling/ast_fuzzer/src/program/expr.rs +++ b/tooling/ast_fuzzer/src/program/expr.rs @@ -5,8 +5,8 @@ use arbitrary::{Arbitrary, Unstructured}; use noirc_frontend::{ ast::{BinaryOpKind, IntegerBitSize, UnaryOp}, monomorphization::ast::{ - ArrayLiteral, Assign, Binary, BinaryOp, Cast, Definition, Expression, Ident, If, LValue, - Let, Literal, LocalId, Type, Unary, + ArrayLiteral, Assign, Binary, BinaryOp, Cast, Definition, Expression, Ident, IdentId, If, + LValue, Let, Literal, LocalId, Type, Unary, }, signed_field::SignedField, }; @@ -191,21 +191,34 @@ pub(crate) fn gen_range( } /// Make an `Ident` expression out of a variable. -pub(crate) fn ident(id: VariableId, mutable: bool, name: Name, typ: Type) -> Expression { - Expression::Ident(ident_inner(id, mutable, name, typ)) +pub(crate) fn ident( + variable_id: VariableId, + id: IdentId, + mutable: bool, + name: Name, + typ: Type, +) -> Expression { + Expression::Ident(ident_inner(variable_id, id, mutable, name, typ)) } /// Make an `Ident` out of a variable. -pub(crate) fn ident_inner(id: VariableId, mutable: bool, name: Name, typ: Type) -> Ident { +pub(crate) fn ident_inner( + variable_id: VariableId, + id: IdentId, + mutable: bool, + name: Name, + typ: Type, +) -> Ident { Ident { location: None, - definition: match id { + definition: match variable_id { VariableId::Global(id) => Definition::Global(id), VariableId::Local(id) => Definition::Local(id), }, mutable, name, typ, + id, } } diff --git a/tooling/ast_fuzzer/src/program/func.rs b/tooling/ast_fuzzer/src/program/func.rs index 3593b160269..70d4595bc04 100644 --- a/tooling/ast_fuzzer/src/program/func.rs +++ b/tooling/ast_fuzzer/src/program/func.rs @@ -10,9 +10,9 @@ use noirc_frontend::{ ast::{IntegerBitSize, UnaryOp}, hir_def::{self, expr::HirIdent, stmt::HirPattern}, monomorphization::ast::{ - ArrayLiteral, Assign, BinaryOp, Call, Definition, Expression, For, FuncId, Function, - GlobalId, Ident, Index, InlineType, LValue, Let, Literal, LocalId, Parameters, Program, - Type, While, + ArrayLiteral, Assign, BinaryOp, Call, Definition, Expression, For, FuncId, GlobalId, Ident, + IdentId, Index, InlineType, LValue, Let, Literal, LocalId, Parameters, Program, Type, + While, }, node_interner::DefinitionId, shared::{Signedness, Visibility}, @@ -24,7 +24,6 @@ use super::{ make_name, scope::{Scope, ScopeStack, Variable}, types, - visitor::visit_expr, }; /// Something akin to a forward declaration of a function, capturing the details required to: @@ -111,6 +110,9 @@ pub(super) struct FunctionContext<'a> { /// Every variable created in the function will have an increasing ID, /// which does not reset when variables go out of scope. next_local_id: u32, + /// Every identifier created in the function will have an increasing ID, + /// which does not reset when variables go out of scope. + next_ident_id: u32, /// Number of statements remaining to be generated in the function. budget: usize, /// Global variables. @@ -165,7 +167,17 @@ impl<'a> FunctionContext<'a> { }) .collect(); - Self { ctx, id, next_local_id, budget, globals, locals, in_loop: false, call_targets } + Self { + ctx, + id, + next_local_id, + budget, + globals, + locals, + in_loop: false, + call_targets, + next_ident_id: 0, + } } /// Generate the function body. @@ -200,6 +212,13 @@ impl<'a> FunctionContext<'a> { id } + /// Get and increment the next ident ID. + fn next_ident_id(&mut self) -> IdentId { + let id = IdentId(self.next_ident_id); + self.next_ident_id += 1; + id + } + /// Choose a producer for a type, preferring local variables over global ones. fn choose_producer( &self, @@ -307,7 +326,8 @@ impl<'a> FunctionContext<'a> { ) -> arbitrary::Result> { if let Some(id) = self.choose_producer(u, typ)? { let (mutable, src_name, src_type) = self.get_variable(&id).clone(); - let src_expr = expr::ident(id, mutable, src_name, src_type.clone()); + let ident_id = self.next_ident_id(); + let src_expr = expr::ident(id, ident_id, mutable, src_name, src_type.clone()); if let Some(expr) = self.gen_expr_from_source(u, src_expr, &src_type, typ, max_depth)? { return Ok(Some(expr)); } @@ -671,7 +691,14 @@ impl<'a> FunctionContext<'a> { // Remove variable so we stop using it. self.locals.remove(&id); - Ok(Some(Expression::Drop(Box::new(expr::ident(VariableId::Local(id), mutable, name, typ))))) + let ident_id = self.next_ident_id(); + Ok(Some(Expression::Drop(Box::new(expr::ident( + VariableId::Local(id), + ident_id, + mutable, + name, + typ, + ))))) } /// Assign to a mutable variable, if we have one in scope. @@ -689,7 +716,8 @@ impl<'a> FunctionContext<'a> { let id = *u.choose_iter(opts)?; let (mutable, name, typ) = self.locals.current().get_variable(&id).clone(); - let ident = expr::ident_inner(VariableId::Local(id), mutable, name, typ.clone()); + let ident_id = self.next_ident_id(); + let ident = expr::ident_inner(VariableId::Local(id), ident_id, mutable, name, typ.clone()); let ident = LValue::Ident(ident); // For arrays and tuples we can consider assigning to their items. @@ -858,6 +886,7 @@ impl<'a> FunctionContext<'a> { Box::new(Type::Unit), callee.unconstrained, ), + id: self.next_ident_id(), })), arguments: args, return_type: callee.return_type.clone(), @@ -874,17 +903,19 @@ impl<'a> FunctionContext<'a> { // in the locals the generator would be able to manipulate, as it could // lead to the loop becoming infinite. let idx_type = types::U32; - let idx_id = self.next_local_id(); - let idx_name = format!("idx_{}", make_name(idx_id.0 as usize, false)); + let idx_local_id = self.next_local_id(); + let idx_id = self.next_ident_id(); + let idx_name = format!("idx_{}", make_name(idx_local_id.0 as usize, false)); + let idx_variable_id = VariableId::Local(idx_local_id); let idx_ident = - expr::ident_inner(VariableId::Local(idx_id), true, idx_name.clone(), idx_type); + expr::ident_inner(idx_variable_id, idx_id, true, idx_name.clone(), idx_type); let idx_expr = Expression::Ident(idx_ident.clone()); // Decrease budget so we don't nest endlessly. self.decrease_budget(1); // Start building the loop harness, initialize index to 0 - let let_idx = expr::let_var(idx_id, true, idx_name, expr::u32_literal(0)); + let let_idx = expr::let_var(idx_local_id, true, idx_name, expr::u32_literal(0)); // Get the randomized loop body let was_in_loop = std::mem::replace(&mut self.in_loop, true); @@ -921,10 +952,12 @@ impl<'a> FunctionContext<'a> { // in the locals the generator would be able to manipulate, as it could // lead to the loop becoming infinite. let idx_type = types::U32; - let idx_id = self.next_local_id(); - let idx_name = format!("idx_{}", make_name(idx_id.0 as usize, false)); + let idx_local_id = self.next_local_id(); + let idx_id = self.next_ident_id(); + let idx_name = format!("idx_{}", make_name(idx_local_id.0 as usize, false)); + let idx_variable_id = VariableId::Local(idx_local_id); let idx_ident = - expr::ident_inner(VariableId::Local(idx_id), true, idx_name.clone(), idx_type); + expr::ident_inner(idx_variable_id, idx_id, true, idx_name.clone(), idx_type); let idx_expr = Expression::Ident(idx_ident.clone()); // Decrease budget so we don't nest endlessly. @@ -932,7 +965,7 @@ impl<'a> FunctionContext<'a> { // Start building the loop harness, initialize index to 0 let mut stmts = vec![Expression::Let(Let { - id: idx_id, + id: idx_local_id, mutable: true, name: idx_name, expression: Box::new(expr::u32_literal(0)), @@ -976,23 +1009,6 @@ impl<'a> FunctionContext<'a> { } } -/// Find the next local ID we can use to add variables to a [Function] during mutations. -pub(crate) fn next_local_id(func: &Function) -> u32 { - let mut next = func.parameters.iter().map(|p| p.0.0 + 1).max().unwrap_or_default(); - visit_expr(&func.body, &mut |expr| { - let id = match expr { - Expression::Let(let_) => Some(let_.id), - Expression::For(for_) => Some(for_.index_variable), - _ => None, - }; - if let Some(id) = id { - next = next.max(id.0 + 1); - } - true - }); - next -} - #[test] fn test_loop() { let mut u = Unstructured::new(&[0u8; 1]); diff --git a/tooling/ast_fuzzer/src/program/rewrite.rs b/tooling/ast_fuzzer/src/program/rewrite.rs index 43473a13a39..f7daefbc875 100644 --- a/tooling/ast_fuzzer/src/program/rewrite.rs +++ b/tooling/ast_fuzzer/src/program/rewrite.rs @@ -3,11 +3,14 @@ use std::collections::HashSet; use arbitrary::Unstructured; use noirc_frontend::{ ast::BinaryOpKind, - monomorphization::ast::{Definition, Expression, LocalId, Program, Type}, + monomorphization::ast::{Definition, Expression, Function, IdentId, LocalId, Program, Type}, shared::Visibility, }; -use super::{Context, VariableId, expr, func, types, visitor::visit_expr_mut}; +use super::{ + Context, VariableId, expr, func, types, + visitor::{visit_expr, visit_expr_mut}, +}; /// Find recursive functions and add a `ctx_depth` parameter to them. pub(crate) fn add_recursion_depth( @@ -29,10 +32,13 @@ pub(crate) fn add_recursion_depth( // 1) caching this value in a "function meta" construct, or // 2) using `u32::MAX`, but we wouldn't be able to add caching to `Program`, // so eventually we'll need to look at the values to do random mutations. - let depth_id = LocalId(func::next_local_id(func)); + let (next_local_id, next_ident_id) = next_local_and_ident_id(func); + let depth_id = LocalId(next_local_id); let depth_name = "ctx_depth".to_string(); + let depth_ident_id = IdentId(next_ident_id); let depth_ident = expr::ident_inner( VariableId::Local(depth_id), + depth_ident_id, !is_main, depth_name.clone(), types::U32, @@ -96,3 +102,27 @@ pub(crate) fn add_recursion_depth( Ok(()) } + +/// Find the next local ID and ident IDs (in that order) that we can use to add +/// variables to a [Function] during mutations. +fn next_local_and_ident_id(func: &Function) -> (u32, u32) { + let mut next_local_id = func.parameters.iter().map(|p| p.0.0 + 1).max().unwrap_or_default(); + let mut next_ident_id = 0; + + visit_expr(&func.body, &mut |expr| { + let local_id = match expr { + Expression::Let(let_) => Some(let_.id), + Expression::For(for_) => Some(for_.index_variable), + Expression::Ident(ident) => { + next_ident_id = next_ident_id.max(ident.id.0 + 1); + None + } + _ => None, + }; + if let Some(id) = local_id { + next_local_id = next_local_id.max(id.0 + 1); + } + true + }); + (next_local_id, next_ident_id) +} diff --git a/tooling/debugger/ignored-tests.txt b/tooling/debugger/ignored-tests.txt index 4f41902d832..224431f4c90 100644 --- a/tooling/debugger/ignored-tests.txt +++ b/tooling/debugger/ignored-tests.txt @@ -11,3 +11,4 @@ regression_7323 reference_only_used_as_alias brillig_rc_regression_6123 array_rc_regression_7842 +mutate_array_copy diff --git a/tooling/nargo_cli/src/cli/check_cmd.rs b/tooling/nargo_cli/src/cli/check_cmd.rs index f4c0a8e260f..48ace1646ed 100644 --- a/tooling/nargo_cli/src/cli/check_cmd.rs +++ b/tooling/nargo_cli/src/cli/check_cmd.rs @@ -59,7 +59,9 @@ pub(crate) fn run(args: CheckCommand, workspace: Workspace) -> Result<(), CliErr let Some(main) = context.get_main_function(&crate_id) else { continue; }; - let program = monomorphize(main, &mut context.def_interner, false).unwrap(); + use noirc_frontend::elaborator::UnstableFeature::Ownership; + let ownership = args.compile_options.unstable_features.contains(&Ownership); + let program = monomorphize(main, &mut context.def_interner, false, ownership).unwrap(); let hash = fxhash::hash64(&program); println!("{}: {:x}", package.name, hash); continue; diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap b/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap new file mode 100644 index 00000000000..1ab830e97d9 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap @@ -0,0 +1,40 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [], + "return_type": null, + "error_types": { + "12049594436772143978": { + "error_kind": "string", + "string": "array ref-count underflow detected" + }, + "17843811134343075018": { + "error_kind": "string", + "string": "Stack too deep" + } + } + }, + "bytecode": "H4sIAAAAAAAA/81XS47TQBBtx3YSTxgSwQ3YwNKJk0mWkQgH4AgmQyQWiA07JPAJODPpUVX88lz2hIkbpiSrf+VX//5ErqZI2sRdQQryW9pM2gGsx8dvK+P8OppnJLdP/E2+XGWGfT3qX2SCGYXBzxU/kP/zkeB8qGp8tEXljo/fBPovXZ0foezX+IW0/3WHzZo77yt3op7knvJ+1z/2YiIxeiN4t2Sjg35g/xYRyXOC71p8fuOC1tM8InmqD/tnQL6LDV1ntOZJcyUy1mJjrgtrV53rgDpHLa1zTf9acjDenAuBfF+wL5F0LQHZqCMTY6DePvffAS7zKU1cXeNJ1b/N602eq7xY8FNn25/AOvK/lfEN6a++2j5Rz8O6nB+K8lCuyvv75b58RfieBuAn3E+mrj2Hpq69XjLXjHGfe7nqoT5MXF1zLFPtQ37sO+njXC6t98WBbP/bOuf9Fv0TB/JPZtjYD/bdUutM89Y6R5MqiF2Fj8cXwdJ9ZAg2piDXfyNYiw1+zuuxwT9y57Z4mhE/+nrmmnvrkHTG2uM9OVBOXHw+69y/Op+teuo6n7vigfHm89nKhZEhx8LaCVbWosO2H59s1EbMQ0f24zuKfYNnhxVvtB8JbfKyfwEu87E+mEOqm3W/8LSVNr+O5inJ/khyQ70h+Oy0YmDd3Z5rbYd663fVNvrnKbXN53jftZ2G8cn61pDtyH48T/jMsOr+0tpWm66pbdWNa++ztP+z9vy9te97c7kuNvvFcr/+tCrK4u7Re/NU+sOqXsc7kqeRjPW+yvyKlxL/V+U9ft+kr/FLDXme72cHX9TSPmAYc0l1PpdVTf64avKr7JuqqaOuTWAN72+eXsgY/YVYqkdK/D9krDEZwz/6/8yQPyb5Z3obc1yHE4N/YvD7+HxXPGnR9r734geZhI9zrJvmDr8HA59jp3MD3y18J0T5+gbFNx+fDUMDa9CBhf/jv8ibdsgN/PZddNnFe99jdl3qI8aKDCxH/6XOjgf2dWzFg/f3PxUgg+4BGQAA", + "debug_symbols": "tdjdqtpAFIbhe8lxDmbWrPnzVkrZ+BM3gRAlaqGI997EpmrTyOYN9EQc/Z4ZzVoZyFyLXbW5fH7U7f5wKlbfrkVz2K7P9aHtR9dbWWy6umnqz4/XjwszvFh/z5+O63YYns7r7lysNJRF1e76N7HX+7qpipU3t+9lYQPMR5hPMJ9ZXgzMW5gXmHcwrzAP6yuwvjJbX69jPvhpPsF8ZnlnYN7CvLC8wvmVzu9gXmHew3yAedg/CvtHYf/42f6xLo3AqkyFxUKwcFgoFh6LgEXEImGRqQjzNY9/Nj0bp7tesFgIFg4LxcJjEbCIWCQs5mse9CHSRESDhcVCsHBYKBYei4BFxCJhgWuecM3TbM3F+FGICVMhWDgsFAuPRcAiYpGwyFTk+Zrnp5juJdliIVg4LBQLj0XAImKRsMhUWIOLbuVNL5rwMNY90W+TuZl/PvnCvNmFbHwY8VMjC4z7+re93F+38p9sjG6MxhSms+uCf+4XmLDAxAVXKy0w+X9eYX3T9vk5u/xlbv3gx7qr15umGk+K9pd2+3JwdP55rCZnSMfusK12l64aTpOeB0nD2rbfiK2E+y3YD52WLg8De/9OSmu0X7Nf9xc=", + "file_map": { + "5": { + "source": "use crate::meta::derive_via;\n\n#[derive_via(derive_eq)]\n// docs:start:eq-trait\npub trait Eq {\n fn eq(self, other: Self) -> bool;\n}\n// docs:end:eq-trait\n\n// docs:start:derive_eq\ncomptime fn derive_eq(s: TypeDefinition) -> Quoted {\n let signature = quote { fn eq(_self: Self, _other: Self) -> bool };\n let for_each_field = |name| quote { (_self.$name == _other.$name) };\n let body = |fields| {\n if s.fields_as_written().len() == 0 {\n quote { true }\n } else {\n fields\n }\n };\n crate::meta::make_trait_impl(\n s,\n quote { Eq },\n signature,\n for_each_field,\n quote { & },\n body,\n )\n}\n// docs:end:derive_eq\n\nimpl Eq for Field {\n fn eq(self, other: Field) -> bool {\n self == other\n }\n}\n\nimpl Eq for u128 {\n fn eq(self, other: u128) -> bool {\n self == other\n }\n}\nimpl Eq for u64 {\n fn eq(self, other: u64) -> bool {\n self == other\n }\n}\nimpl Eq for u32 {\n fn eq(self, other: u32) -> bool {\n self == other\n }\n}\nimpl Eq for u16 {\n fn eq(self, other: u16) -> bool {\n self == other\n }\n}\nimpl Eq for u8 {\n fn eq(self, other: u8) -> bool {\n self == other\n }\n}\nimpl Eq for u1 {\n fn eq(self, other: u1) -> bool {\n self == other\n }\n}\n\nimpl Eq for i8 {\n fn eq(self, other: i8) -> bool {\n self == other\n }\n}\nimpl Eq for i16 {\n fn eq(self, other: i16) -> bool {\n self == other\n }\n}\nimpl Eq for i32 {\n fn eq(self, other: i32) -> bool {\n self == other\n }\n}\nimpl Eq for i64 {\n fn eq(self, other: i64) -> bool {\n self == other\n }\n}\n\nimpl Eq for () {\n fn eq(_self: Self, _other: ()) -> bool {\n true\n }\n}\nimpl Eq for bool {\n fn eq(self, other: bool) -> bool {\n self == other\n }\n}\n\nimpl Eq for [T; N]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T; N]) -> bool {\n let mut result = true;\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for [T]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T]) -> bool {\n let mut result = self.len() == other.len();\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for str {\n fn eq(self, other: str) -> bool {\n let self_bytes = self.as_bytes();\n let other_bytes = other.as_bytes();\n self_bytes == other_bytes\n }\n}\n\nimpl Eq for (A, B)\nwhere\n A: Eq,\n B: Eq,\n{\n fn eq(self, other: (A, B)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1)\n }\n}\n\nimpl Eq for (A, B, C)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n{\n fn eq(self, other: (A, B, C)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2)\n }\n}\n\nimpl Eq for (A, B, C, D)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n D: Eq,\n{\n fn eq(self, other: (A, B, C, D)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2) & self.3.eq(other.3)\n }\n}\n\nimpl Eq for (A, B, C, D, E)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n D: Eq,\n E: Eq,\n{\n fn eq(self, other: (A, B, C, D, E)) -> bool {\n self.0.eq(other.0)\n & self.1.eq(other.1)\n & self.2.eq(other.2)\n & self.3.eq(other.3)\n & self.4.eq(other.4)\n }\n}\n\nimpl Eq for Ordering {\n fn eq(self, other: Ordering) -> bool {\n self.result == other.result\n }\n}\n\n// Noir doesn't have enums yet so we emulate (Lt | Eq | Gt) with a struct\n// that has 3 public functions for constructing the struct.\npub struct Ordering {\n result: Field,\n}\n\nimpl Ordering {\n // Implementation note: 0, 1, and 2 for Lt, Eq, and Gt are built\n // into the compiler, do not change these without also updating\n // the compiler itself!\n pub fn less() -> Ordering {\n Ordering { result: 0 }\n }\n\n pub fn equal() -> Ordering {\n Ordering { result: 1 }\n }\n\n pub fn greater() -> Ordering {\n Ordering { result: 2 }\n }\n}\n\n#[derive_via(derive_ord)]\n// docs:start:ord-trait\npub trait Ord {\n fn cmp(self, other: Self) -> Ordering;\n}\n// docs:end:ord-trait\n\n// docs:start:derive_ord\ncomptime fn derive_ord(s: TypeDefinition) -> Quoted {\n let signature = quote { fn cmp(_self: Self, _other: Self) -> std::cmp::Ordering };\n let for_each_field = |name| quote {\n if result == std::cmp::Ordering::equal() {\n result = _self.$name.cmp(_other.$name);\n }\n };\n let body = |fields| quote {\n let mut result = std::cmp::Ordering::equal();\n $fields\n result\n };\n crate::meta::make_trait_impl(s, quote { Ord }, signature, for_each_field, quote {}, body)\n}\n// docs:end:derive_ord\n\n// Note: Field deliberately does not implement Ord\n\nimpl Ord for u128 {\n fn cmp(self, other: u128) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\nimpl Ord for u64 {\n fn cmp(self, other: u64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u32 {\n fn cmp(self, other: u32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u16 {\n fn cmp(self, other: u16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u8 {\n fn cmp(self, other: u8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i8 {\n fn cmp(self, other: i8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i16 {\n fn cmp(self, other: i16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i32 {\n fn cmp(self, other: i32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i64 {\n fn cmp(self, other: i64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for () {\n fn cmp(_self: Self, _other: ()) -> Ordering {\n Ordering::equal()\n }\n}\n\nimpl Ord for bool {\n fn cmp(self, other: bool) -> Ordering {\n if self {\n if other {\n Ordering::equal()\n } else {\n Ordering::greater()\n }\n } else if other {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for [T; N]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T; N]) -> Ordering {\n let mut result = Ordering::equal();\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for [T]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T]) -> Ordering {\n let mut result = self.len().cmp(other.len());\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for (A, B)\nwhere\n A: Ord,\n B: Ord,\n{\n fn cmp(self, other: (A, B)) -> Ordering {\n let result = self.0.cmp(other.0);\n\n if result != Ordering::equal() {\n result\n } else {\n self.1.cmp(other.1)\n }\n }\n}\n\nimpl Ord for (A, B, C)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n{\n fn cmp(self, other: (A, B, C)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n D: Ord,\n{\n fn cmp(self, other: (A, B, C, D)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D, E)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n D: Ord,\n E: Ord,\n{\n fn cmp(self, other: (A, B, C, D, E)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n if result == Ordering::equal() {\n result = self.4.cmp(other.4);\n }\n\n result\n }\n}\n\n// Compares and returns the maximum of two values.\n//\n// Returns the second argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::max(1, 2), 2);\n// assert_eq(cmp::max(2, 2), 2);\n// ```\npub fn max(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v1\n } else {\n v2\n }\n}\n\n// Compares and returns the minimum of two values.\n//\n// Returns the first argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::min(1, 2), 1);\n// assert_eq(cmp::min(2, 2), 2);\n// ```\npub fn min(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v2\n } else {\n v1\n }\n}\n\nmod cmp_tests {\n use crate::cmp::{max, min};\n\n #[test]\n fn sanity_check_min() {\n assert_eq(min(0 as u64, 1 as u64), 0);\n assert_eq(min(0 as u64, 0 as u64), 0);\n assert_eq(min(1 as u64, 1 as u64), 1);\n assert_eq(min(255 as u8, 0 as u8), 0);\n }\n\n #[test]\n fn sanity_check_max() {\n assert_eq(max(0 as u64, 1 as u64), 1);\n assert_eq(max(0 as u64, 0 as u64), 0);\n assert_eq(max(1 as u64, 1 as u64), 1);\n assert_eq(max(255 as u8, 0 as u8), 255);\n }\n}\n", + "path": "std/cmp.nr" + }, + "50": { + "source": "unconstrained fn main() {\n let mut a = [1, 2];\n foo(&mut a);\n}\n\nunconstrained fn foo(a: &mut [Field; 2]) {\n let a_copy = *a;\n a[0] = 100;\n assert_eq(a_copy, [1, 2]);\n assert_eq(*a, [100, 2]);\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "main" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_false_inliner_0.snap b/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_false_inliner_0.snap new file mode 100644 index 00000000000..1c79f212c85 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_false_inliner_0.snap @@ -0,0 +1,40 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [], + "return_type": null, + "error_types": { + "12049594436772143978": { + "error_kind": "string", + "string": "array ref-count underflow detected" + }, + "17843811134343075018": { + "error_kind": "string", + "string": "Stack too deep" + } + } + }, + "bytecode": "H4sIAAAAAAAA/8VXQW7CMBB0QgwEWoHae98QSCCcKg58oL20Uk8piENfwdNLVK8yGjaBKnZrCS3xJjs76x0njkwzImcT02NIkC9nU2dj8A/Ov627zvqNRUq4PuNvsqJIFX4e889TFzMKEz+T+IHqn41cnN2piY9cBHd8/k3h/51p+iMUf1m/kPwfOzhPHdfXFq7G+NUBYnuMvbyHuhngiZySMPXNI8IzkAf6BH9CufrebyLCk3y4PrIOUjur5DpXfBH9twqOVXC0WOKbGV1j9Qi8fhnzSIBHovCOFR7I19Lck7O1zt4pHvcMz3HtBko+4TS7Lrg3jII7hPn/0JXgT8zluoTQ1ZDyaet3qd1IyXWu+FhXIwVnpOBosX6jq1DvHa4X6ipWeMfmsp+w1pbmMmdD6ypQf5fcHzjENyZs9KWKL1JiDegaOdXxPyAu38f5YB9JbmlLDltns35jYQn7mXADrU/2QHwQS9OV/aO8eH9AXSEm6wr3B+w5S3M7Z33oSvtuSJV8PNZnw9rBoWnHkm+i+G7VlXDqoyvJjfv+xdnUBH3PqX0vWFPILzn5xy83P/1dj8GpqQPXGvEt3f/mrnEdxSY98jyW1eKYV8dqVR0Oxb7iOtUDz1W+8asy3+yXxb78XOVVvr6Kr53rQp85tLOA9u0xg3oYo+8V2ndW3BELn8dn8V7bgRv4nLHs4sU9co3XrTXiWNq7zNBz1rTv3fwe0NYDY9V9+A030yzdwRMAAA==", + "debug_symbols": "tdnNboJAFAXgd5k1i7nzc++Mr9I0DSoaEgIGsUljfPeCoUoJSTuSszFizvnAwSuLuap9sb0cP8r60JzV5u2qqmaXd2VT90fXW6a2bVlV5fFj+rHSwwvZe/58yuvh8Nzlbac2jjNV1Pv+jfTtQ1kVauP17T1T5BLzPjHPiXlJzIfEfEzLG52Yp8S8Scwn3l+zeH+9G/Psp/nsv8EB9iiYUbCg4ICCIwi2GgUTCjarYLJhTJIzc9riaIejPY5mHC04OuDoCKOdxtGEo1dOo/w8r0jmDyxncbTD0R5HM44WHB1wdITRfuU0snvQYU4TjjY42uJoh6M9jmYcLTg64OgIoxk3jYybRl43jUb7MWk0z2mLox2O9jiacbTg6ICjI4yWldMYn/T8sSuEow2Otjja4WiPoxlHC44OODrC6ICbxrg4MkZrflTIPjv3ik2vuPSKX66QPCrGzyqcXpG/L2zy37iwuCJ2jErgGR7Sv3VMrpDWL3QoealImxc6Fri+pBd/VhTjUze/Orf+4DNvy3xbFePuyuFS7yabLd3XqZjtu5zaZlfsL20x7MBMNl+GZQ8mCzJcyrCeIWRR9+foz/MN", + "file_map": { + "5": { + "source": "use crate::meta::derive_via;\n\n#[derive_via(derive_eq)]\n// docs:start:eq-trait\npub trait Eq {\n fn eq(self, other: Self) -> bool;\n}\n// docs:end:eq-trait\n\n// docs:start:derive_eq\ncomptime fn derive_eq(s: TypeDefinition) -> Quoted {\n let signature = quote { fn eq(_self: Self, _other: Self) -> bool };\n let for_each_field = |name| quote { (_self.$name == _other.$name) };\n let body = |fields| {\n if s.fields_as_written().len() == 0 {\n quote { true }\n } else {\n fields\n }\n };\n crate::meta::make_trait_impl(\n s,\n quote { Eq },\n signature,\n for_each_field,\n quote { & },\n body,\n )\n}\n// docs:end:derive_eq\n\nimpl Eq for Field {\n fn eq(self, other: Field) -> bool {\n self == other\n }\n}\n\nimpl Eq for u128 {\n fn eq(self, other: u128) -> bool {\n self == other\n }\n}\nimpl Eq for u64 {\n fn eq(self, other: u64) -> bool {\n self == other\n }\n}\nimpl Eq for u32 {\n fn eq(self, other: u32) -> bool {\n self == other\n }\n}\nimpl Eq for u16 {\n fn eq(self, other: u16) -> bool {\n self == other\n }\n}\nimpl Eq for u8 {\n fn eq(self, other: u8) -> bool {\n self == other\n }\n}\nimpl Eq for u1 {\n fn eq(self, other: u1) -> bool {\n self == other\n }\n}\n\nimpl Eq for i8 {\n fn eq(self, other: i8) -> bool {\n self == other\n }\n}\nimpl Eq for i16 {\n fn eq(self, other: i16) -> bool {\n self == other\n }\n}\nimpl Eq for i32 {\n fn eq(self, other: i32) -> bool {\n self == other\n }\n}\nimpl Eq for i64 {\n fn eq(self, other: i64) -> bool {\n self == other\n }\n}\n\nimpl Eq for () {\n fn eq(_self: Self, _other: ()) -> bool {\n true\n }\n}\nimpl Eq for bool {\n fn eq(self, other: bool) -> bool {\n self == other\n }\n}\n\nimpl Eq for [T; N]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T; N]) -> bool {\n let mut result = true;\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for [T]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T]) -> bool {\n let mut result = self.len() == other.len();\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for str {\n fn eq(self, other: str) -> bool {\n let self_bytes = self.as_bytes();\n let other_bytes = other.as_bytes();\n self_bytes == other_bytes\n }\n}\n\nimpl Eq for (A, B)\nwhere\n A: Eq,\n B: Eq,\n{\n fn eq(self, other: (A, B)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1)\n }\n}\n\nimpl Eq for (A, B, C)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n{\n fn eq(self, other: (A, B, C)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2)\n }\n}\n\nimpl Eq for (A, B, C, D)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n D: Eq,\n{\n fn eq(self, other: (A, B, C, D)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2) & self.3.eq(other.3)\n }\n}\n\nimpl Eq for (A, B, C, D, E)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n D: Eq,\n E: Eq,\n{\n fn eq(self, other: (A, B, C, D, E)) -> bool {\n self.0.eq(other.0)\n & self.1.eq(other.1)\n & self.2.eq(other.2)\n & self.3.eq(other.3)\n & self.4.eq(other.4)\n }\n}\n\nimpl Eq for Ordering {\n fn eq(self, other: Ordering) -> bool {\n self.result == other.result\n }\n}\n\n// Noir doesn't have enums yet so we emulate (Lt | Eq | Gt) with a struct\n// that has 3 public functions for constructing the struct.\npub struct Ordering {\n result: Field,\n}\n\nimpl Ordering {\n // Implementation note: 0, 1, and 2 for Lt, Eq, and Gt are built\n // into the compiler, do not change these without also updating\n // the compiler itself!\n pub fn less() -> Ordering {\n Ordering { result: 0 }\n }\n\n pub fn equal() -> Ordering {\n Ordering { result: 1 }\n }\n\n pub fn greater() -> Ordering {\n Ordering { result: 2 }\n }\n}\n\n#[derive_via(derive_ord)]\n// docs:start:ord-trait\npub trait Ord {\n fn cmp(self, other: Self) -> Ordering;\n}\n// docs:end:ord-trait\n\n// docs:start:derive_ord\ncomptime fn derive_ord(s: TypeDefinition) -> Quoted {\n let signature = quote { fn cmp(_self: Self, _other: Self) -> std::cmp::Ordering };\n let for_each_field = |name| quote {\n if result == std::cmp::Ordering::equal() {\n result = _self.$name.cmp(_other.$name);\n }\n };\n let body = |fields| quote {\n let mut result = std::cmp::Ordering::equal();\n $fields\n result\n };\n crate::meta::make_trait_impl(s, quote { Ord }, signature, for_each_field, quote {}, body)\n}\n// docs:end:derive_ord\n\n// Note: Field deliberately does not implement Ord\n\nimpl Ord for u128 {\n fn cmp(self, other: u128) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\nimpl Ord for u64 {\n fn cmp(self, other: u64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u32 {\n fn cmp(self, other: u32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u16 {\n fn cmp(self, other: u16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u8 {\n fn cmp(self, other: u8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i8 {\n fn cmp(self, other: i8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i16 {\n fn cmp(self, other: i16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i32 {\n fn cmp(self, other: i32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i64 {\n fn cmp(self, other: i64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for () {\n fn cmp(_self: Self, _other: ()) -> Ordering {\n Ordering::equal()\n }\n}\n\nimpl Ord for bool {\n fn cmp(self, other: bool) -> Ordering {\n if self {\n if other {\n Ordering::equal()\n } else {\n Ordering::greater()\n }\n } else if other {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for [T; N]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T; N]) -> Ordering {\n let mut result = Ordering::equal();\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for [T]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T]) -> Ordering {\n let mut result = self.len().cmp(other.len());\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for (A, B)\nwhere\n A: Ord,\n B: Ord,\n{\n fn cmp(self, other: (A, B)) -> Ordering {\n let result = self.0.cmp(other.0);\n\n if result != Ordering::equal() {\n result\n } else {\n self.1.cmp(other.1)\n }\n }\n}\n\nimpl Ord for (A, B, C)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n{\n fn cmp(self, other: (A, B, C)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n D: Ord,\n{\n fn cmp(self, other: (A, B, C, D)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D, E)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n D: Ord,\n E: Ord,\n{\n fn cmp(self, other: (A, B, C, D, E)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n if result == Ordering::equal() {\n result = self.4.cmp(other.4);\n }\n\n result\n }\n}\n\n// Compares and returns the maximum of two values.\n//\n// Returns the second argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::max(1, 2), 2);\n// assert_eq(cmp::max(2, 2), 2);\n// ```\npub fn max(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v1\n } else {\n v2\n }\n}\n\n// Compares and returns the minimum of two values.\n//\n// Returns the first argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::min(1, 2), 1);\n// assert_eq(cmp::min(2, 2), 2);\n// ```\npub fn min(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v2\n } else {\n v1\n }\n}\n\nmod cmp_tests {\n use crate::cmp::{max, min};\n\n #[test]\n fn sanity_check_min() {\n assert_eq(min(0 as u64, 1 as u64), 0);\n assert_eq(min(0 as u64, 0 as u64), 0);\n assert_eq(min(1 as u64, 1 as u64), 1);\n assert_eq(min(255 as u8, 0 as u8), 0);\n }\n\n #[test]\n fn sanity_check_max() {\n assert_eq(max(0 as u64, 1 as u64), 1);\n assert_eq(max(0 as u64, 0 as u64), 0);\n assert_eq(max(1 as u64, 1 as u64), 1);\n assert_eq(max(255 as u8, 0 as u8), 255);\n }\n}\n", + "path": "std/cmp.nr" + }, + "50": { + "source": "unconstrained fn main() {\n let mut a = [1, 2];\n foo(&mut a);\n}\n\nunconstrained fn foo(a: &mut [Field; 2]) {\n let a_copy = *a;\n a[0] = 100;\n assert_eq(a_copy, [1, 2]);\n assert_eq(*a, [100, 2]);\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "main" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_false_inliner_9223372036854775807.snap b/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_false_inliner_9223372036854775807.snap new file mode 100644 index 00000000000..96af34a1a5b --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_false_inliner_9223372036854775807.snap @@ -0,0 +1,27 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [], + "return_type": null, + "error_types": { + "17843811134343075018": { + "error_kind": "string", + "string": "Stack too deep" + } + } + }, + "bytecode": "H4sIAAAAAAAA/7WSwQ7CIAyGwWEUZzw4H6TLMNvRgy/SuPAce3R3+BsaYrwATUhpSr72L7UmmYV3psAE8oD38AeV7/bzQkxlNvqsbk3+QiH4H/oq9j95MG0bPgm/0fzpBM57S3ytReqe99Or+9Wk/WilX/6vpf7hj+YeWm8qln1yW/1+5oVI+ujAP4Kfm1N5/X5AfFF6xLuCPuPMY5w48pPXNXz4nvFNNrcvgErvAJkEAAA=", + "debug_symbols": "XYzBCoAgEET/Zc8dErrUr0SE2iYLomIahOy/p9AhvAy8ecwUOFBls5M7/QXLWsB6LRN5V6nwACqStWT2rr5lJKksfnhmp382PQG7fYhe45EjtqfmYGwhaq5iGsS8MfPGLw==", + "file_map": {}, + "names": [ + "main" + ], + "brillig_names": [ + "main" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap b/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap new file mode 100644 index 00000000000..1ab830e97d9 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap @@ -0,0 +1,40 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [], + "return_type": null, + "error_types": { + "12049594436772143978": { + "error_kind": "string", + "string": "array ref-count underflow detected" + }, + "17843811134343075018": { + "error_kind": "string", + "string": "Stack too deep" + } + } + }, + "bytecode": "H4sIAAAAAAAA/81XS47TQBBtx3YSTxgSwQ3YwNKJk0mWkQgH4AgmQyQWiA07JPAJODPpUVX88lz2hIkbpiSrf+VX//5ErqZI2sRdQQryW9pM2gGsx8dvK+P8OppnJLdP/E2+XGWGfT3qX2SCGYXBzxU/kP/zkeB8qGp8tEXljo/fBPovXZ0foezX+IW0/3WHzZo77yt3op7knvJ+1z/2YiIxeiN4t2Sjg35g/xYRyXOC71p8fuOC1tM8InmqD/tnQL6LDV1ntOZJcyUy1mJjrgtrV53rgDpHLa1zTf9acjDenAuBfF+wL5F0LQHZqCMTY6DePvffAS7zKU1cXeNJ1b/N602eq7xY8FNn25/AOvK/lfEN6a++2j5Rz8O6nB+K8lCuyvv75b58RfieBuAn3E+mrj2Hpq69XjLXjHGfe7nqoT5MXF1zLFPtQ37sO+njXC6t98WBbP/bOuf9Fv0TB/JPZtjYD/bdUutM89Y6R5MqiF2Fj8cXwdJ9ZAg2piDXfyNYiw1+zuuxwT9y57Z4mhE/+nrmmnvrkHTG2uM9OVBOXHw+69y/Op+teuo6n7vigfHm89nKhZEhx8LaCVbWosO2H59s1EbMQ0f24zuKfYNnhxVvtB8JbfKyfwEu87E+mEOqm3W/8LSVNr+O5inJ/khyQ70h+Oy0YmDd3Z5rbYd663fVNvrnKbXN53jftZ2G8cn61pDtyH48T/jMsOr+0tpWm66pbdWNa++ztP+z9vy9te97c7kuNvvFcr/+tCrK4u7Re/NU+sOqXsc7kqeRjPW+yvyKlxL/V+U9ft+kr/FLDXme72cHX9TSPmAYc0l1PpdVTf64avKr7JuqqaOuTWAN72+eXsgY/YVYqkdK/D9krDEZwz/6/8yQPyb5Z3obc1yHE4N/YvD7+HxXPGnR9r734geZhI9zrJvmDr8HA59jp3MD3y18J0T5+gbFNx+fDUMDa9CBhf/jv8ibdsgN/PZddNnFe99jdl3qI8aKDCxH/6XOjgf2dWzFg/f3PxUgg+4BGQAA", + "debug_symbols": "tdjdqtpAFIbhe8lxDmbWrPnzVkrZ+BM3gRAlaqGI997EpmrTyOYN9EQc/Z4ZzVoZyFyLXbW5fH7U7f5wKlbfrkVz2K7P9aHtR9dbWWy6umnqz4/XjwszvFh/z5+O63YYns7r7lysNJRF1e76N7HX+7qpipU3t+9lYQPMR5hPMJ9ZXgzMW5gXmHcwrzAP6yuwvjJbX69jPvhpPsF8ZnlnYN7CvLC8wvmVzu9gXmHew3yAedg/CvtHYf/42f6xLo3AqkyFxUKwcFgoFh6LgEXEImGRqQjzNY9/Nj0bp7tesFgIFg4LxcJjEbCIWCQs5mse9CHSRESDhcVCsHBYKBYei4BFxCJhgWuecM3TbM3F+FGICVMhWDgsFAuPRcAiYpGwyFTk+Zrnp5juJdliIVg4LBQLj0XAImKRsMhUWIOLbuVNL5rwMNY90W+TuZl/PvnCvNmFbHwY8VMjC4z7+re93F+38p9sjG6MxhSms+uCf+4XmLDAxAVXKy0w+X9eYX3T9vk5u/xlbv3gx7qr15umGk+K9pd2+3JwdP55rCZnSMfusK12l64aTpOeB0nD2rbfiK2E+y3YD52WLg8De/9OSmu0X7Nf9xc=", + "file_map": { + "5": { + "source": "use crate::meta::derive_via;\n\n#[derive_via(derive_eq)]\n// docs:start:eq-trait\npub trait Eq {\n fn eq(self, other: Self) -> bool;\n}\n// docs:end:eq-trait\n\n// docs:start:derive_eq\ncomptime fn derive_eq(s: TypeDefinition) -> Quoted {\n let signature = quote { fn eq(_self: Self, _other: Self) -> bool };\n let for_each_field = |name| quote { (_self.$name == _other.$name) };\n let body = |fields| {\n if s.fields_as_written().len() == 0 {\n quote { true }\n } else {\n fields\n }\n };\n crate::meta::make_trait_impl(\n s,\n quote { Eq },\n signature,\n for_each_field,\n quote { & },\n body,\n )\n}\n// docs:end:derive_eq\n\nimpl Eq for Field {\n fn eq(self, other: Field) -> bool {\n self == other\n }\n}\n\nimpl Eq for u128 {\n fn eq(self, other: u128) -> bool {\n self == other\n }\n}\nimpl Eq for u64 {\n fn eq(self, other: u64) -> bool {\n self == other\n }\n}\nimpl Eq for u32 {\n fn eq(self, other: u32) -> bool {\n self == other\n }\n}\nimpl Eq for u16 {\n fn eq(self, other: u16) -> bool {\n self == other\n }\n}\nimpl Eq for u8 {\n fn eq(self, other: u8) -> bool {\n self == other\n }\n}\nimpl Eq for u1 {\n fn eq(self, other: u1) -> bool {\n self == other\n }\n}\n\nimpl Eq for i8 {\n fn eq(self, other: i8) -> bool {\n self == other\n }\n}\nimpl Eq for i16 {\n fn eq(self, other: i16) -> bool {\n self == other\n }\n}\nimpl Eq for i32 {\n fn eq(self, other: i32) -> bool {\n self == other\n }\n}\nimpl Eq for i64 {\n fn eq(self, other: i64) -> bool {\n self == other\n }\n}\n\nimpl Eq for () {\n fn eq(_self: Self, _other: ()) -> bool {\n true\n }\n}\nimpl Eq for bool {\n fn eq(self, other: bool) -> bool {\n self == other\n }\n}\n\nimpl Eq for [T; N]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T; N]) -> bool {\n let mut result = true;\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for [T]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T]) -> bool {\n let mut result = self.len() == other.len();\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for str {\n fn eq(self, other: str) -> bool {\n let self_bytes = self.as_bytes();\n let other_bytes = other.as_bytes();\n self_bytes == other_bytes\n }\n}\n\nimpl Eq for (A, B)\nwhere\n A: Eq,\n B: Eq,\n{\n fn eq(self, other: (A, B)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1)\n }\n}\n\nimpl Eq for (A, B, C)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n{\n fn eq(self, other: (A, B, C)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2)\n }\n}\n\nimpl Eq for (A, B, C, D)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n D: Eq,\n{\n fn eq(self, other: (A, B, C, D)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2) & self.3.eq(other.3)\n }\n}\n\nimpl Eq for (A, B, C, D, E)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n D: Eq,\n E: Eq,\n{\n fn eq(self, other: (A, B, C, D, E)) -> bool {\n self.0.eq(other.0)\n & self.1.eq(other.1)\n & self.2.eq(other.2)\n & self.3.eq(other.3)\n & self.4.eq(other.4)\n }\n}\n\nimpl Eq for Ordering {\n fn eq(self, other: Ordering) -> bool {\n self.result == other.result\n }\n}\n\n// Noir doesn't have enums yet so we emulate (Lt | Eq | Gt) with a struct\n// that has 3 public functions for constructing the struct.\npub struct Ordering {\n result: Field,\n}\n\nimpl Ordering {\n // Implementation note: 0, 1, and 2 for Lt, Eq, and Gt are built\n // into the compiler, do not change these without also updating\n // the compiler itself!\n pub fn less() -> Ordering {\n Ordering { result: 0 }\n }\n\n pub fn equal() -> Ordering {\n Ordering { result: 1 }\n }\n\n pub fn greater() -> Ordering {\n Ordering { result: 2 }\n }\n}\n\n#[derive_via(derive_ord)]\n// docs:start:ord-trait\npub trait Ord {\n fn cmp(self, other: Self) -> Ordering;\n}\n// docs:end:ord-trait\n\n// docs:start:derive_ord\ncomptime fn derive_ord(s: TypeDefinition) -> Quoted {\n let signature = quote { fn cmp(_self: Self, _other: Self) -> std::cmp::Ordering };\n let for_each_field = |name| quote {\n if result == std::cmp::Ordering::equal() {\n result = _self.$name.cmp(_other.$name);\n }\n };\n let body = |fields| quote {\n let mut result = std::cmp::Ordering::equal();\n $fields\n result\n };\n crate::meta::make_trait_impl(s, quote { Ord }, signature, for_each_field, quote {}, body)\n}\n// docs:end:derive_ord\n\n// Note: Field deliberately does not implement Ord\n\nimpl Ord for u128 {\n fn cmp(self, other: u128) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\nimpl Ord for u64 {\n fn cmp(self, other: u64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u32 {\n fn cmp(self, other: u32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u16 {\n fn cmp(self, other: u16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u8 {\n fn cmp(self, other: u8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i8 {\n fn cmp(self, other: i8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i16 {\n fn cmp(self, other: i16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i32 {\n fn cmp(self, other: i32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i64 {\n fn cmp(self, other: i64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for () {\n fn cmp(_self: Self, _other: ()) -> Ordering {\n Ordering::equal()\n }\n}\n\nimpl Ord for bool {\n fn cmp(self, other: bool) -> Ordering {\n if self {\n if other {\n Ordering::equal()\n } else {\n Ordering::greater()\n }\n } else if other {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for [T; N]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T; N]) -> Ordering {\n let mut result = Ordering::equal();\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for [T]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T]) -> Ordering {\n let mut result = self.len().cmp(other.len());\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for (A, B)\nwhere\n A: Ord,\n B: Ord,\n{\n fn cmp(self, other: (A, B)) -> Ordering {\n let result = self.0.cmp(other.0);\n\n if result != Ordering::equal() {\n result\n } else {\n self.1.cmp(other.1)\n }\n }\n}\n\nimpl Ord for (A, B, C)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n{\n fn cmp(self, other: (A, B, C)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n D: Ord,\n{\n fn cmp(self, other: (A, B, C, D)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D, E)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n D: Ord,\n E: Ord,\n{\n fn cmp(self, other: (A, B, C, D, E)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n if result == Ordering::equal() {\n result = self.4.cmp(other.4);\n }\n\n result\n }\n}\n\n// Compares and returns the maximum of two values.\n//\n// Returns the second argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::max(1, 2), 2);\n// assert_eq(cmp::max(2, 2), 2);\n// ```\npub fn max(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v1\n } else {\n v2\n }\n}\n\n// Compares and returns the minimum of two values.\n//\n// Returns the first argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::min(1, 2), 1);\n// assert_eq(cmp::min(2, 2), 2);\n// ```\npub fn min(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v2\n } else {\n v1\n }\n}\n\nmod cmp_tests {\n use crate::cmp::{max, min};\n\n #[test]\n fn sanity_check_min() {\n assert_eq(min(0 as u64, 1 as u64), 0);\n assert_eq(min(0 as u64, 0 as u64), 0);\n assert_eq(min(1 as u64, 1 as u64), 1);\n assert_eq(min(255 as u8, 0 as u8), 0);\n }\n\n #[test]\n fn sanity_check_max() {\n assert_eq(max(0 as u64, 1 as u64), 1);\n assert_eq(max(0 as u64, 0 as u64), 0);\n assert_eq(max(1 as u64, 1 as u64), 1);\n assert_eq(max(255 as u8, 0 as u8), 255);\n }\n}\n", + "path": "std/cmp.nr" + }, + "50": { + "source": "unconstrained fn main() {\n let mut a = [1, 2];\n foo(&mut a);\n}\n\nunconstrained fn foo(a: &mut [Field; 2]) {\n let a_copy = *a;\n a[0] = 100;\n assert_eq(a_copy, [1, 2]);\n assert_eq(*a, [100, 2]);\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "main" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_true_inliner_0.snap b/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_true_inliner_0.snap new file mode 100644 index 00000000000..1c79f212c85 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_true_inliner_0.snap @@ -0,0 +1,40 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [], + "return_type": null, + "error_types": { + "12049594436772143978": { + "error_kind": "string", + "string": "array ref-count underflow detected" + }, + "17843811134343075018": { + "error_kind": "string", + "string": "Stack too deep" + } + } + }, + "bytecode": "H4sIAAAAAAAA/8VXQW7CMBB0QgwEWoHae98QSCCcKg58oL20Uk8piENfwdNLVK8yGjaBKnZrCS3xJjs76x0njkwzImcT02NIkC9nU2dj8A/Ov627zvqNRUq4PuNvsqJIFX4e889TFzMKEz+T+IHqn41cnN2piY9cBHd8/k3h/51p+iMUf1m/kPwfOzhPHdfXFq7G+NUBYnuMvbyHuhngiZySMPXNI8IzkAf6BH9CufrebyLCk3y4PrIOUjur5DpXfBH9twqOVXC0WOKbGV1j9Qi8fhnzSIBHovCOFR7I19Lck7O1zt4pHvcMz3HtBko+4TS7Lrg3jII7hPn/0JXgT8zluoTQ1ZDyaet3qd1IyXWu+FhXIwVnpOBosX6jq1DvHa4X6ipWeMfmsp+w1pbmMmdD6ypQf5fcHzjENyZs9KWKL1JiDegaOdXxPyAu38f5YB9JbmlLDltns35jYQn7mXADrU/2QHwQS9OV/aO8eH9AXSEm6wr3B+w5S3M7Z33oSvtuSJV8PNZnw9rBoWnHkm+i+G7VlXDqoyvJjfv+xdnUBH3PqX0vWFPILzn5xy83P/1dj8GpqQPXGvEt3f/mrnEdxSY98jyW1eKYV8dqVR0Oxb7iOtUDz1W+8asy3+yXxb78XOVVvr6Kr53rQp85tLOA9u0xg3oYo+8V2ndW3BELn8dn8V7bgRv4nLHs4sU9co3XrTXiWNq7zNBz1rTv3fwe0NYDY9V9+A030yzdwRMAAA==", + "debug_symbols": "tdnNboJAFAXgd5k1i7nzc++Mr9I0DSoaEgIGsUljfPeCoUoJSTuSszFizvnAwSuLuap9sb0cP8r60JzV5u2qqmaXd2VT90fXW6a2bVlV5fFj+rHSwwvZe/58yuvh8Nzlbac2jjNV1Pv+jfTtQ1kVauP17T1T5BLzPjHPiXlJzIfEfEzLG52Yp8S8Scwn3l+zeH+9G/Psp/nsv8EB9iiYUbCg4ICCIwi2GgUTCjarYLJhTJIzc9riaIejPY5mHC04OuDoCKOdxtGEo1dOo/w8r0jmDyxncbTD0R5HM44WHB1wdITRfuU0snvQYU4TjjY42uJoh6M9jmYcLTg64OgIoxk3jYybRl43jUb7MWk0z2mLox2O9jiacbTg6ICjI4yWldMYn/T8sSuEow2Otjja4WiPoxlHC44OODrC6ICbxrg4MkZrflTIPjv3ik2vuPSKX66QPCrGzyqcXpG/L2zy37iwuCJ2jErgGR7Sv3VMrpDWL3QoealImxc6Fri+pBd/VhTjUze/Orf+4DNvy3xbFePuyuFS7yabLd3XqZjtu5zaZlfsL20x7MBMNl+GZQ8mCzJcyrCeIWRR9+foz/MN", + "file_map": { + "5": { + "source": "use crate::meta::derive_via;\n\n#[derive_via(derive_eq)]\n// docs:start:eq-trait\npub trait Eq {\n fn eq(self, other: Self) -> bool;\n}\n// docs:end:eq-trait\n\n// docs:start:derive_eq\ncomptime fn derive_eq(s: TypeDefinition) -> Quoted {\n let signature = quote { fn eq(_self: Self, _other: Self) -> bool };\n let for_each_field = |name| quote { (_self.$name == _other.$name) };\n let body = |fields| {\n if s.fields_as_written().len() == 0 {\n quote { true }\n } else {\n fields\n }\n };\n crate::meta::make_trait_impl(\n s,\n quote { Eq },\n signature,\n for_each_field,\n quote { & },\n body,\n )\n}\n// docs:end:derive_eq\n\nimpl Eq for Field {\n fn eq(self, other: Field) -> bool {\n self == other\n }\n}\n\nimpl Eq for u128 {\n fn eq(self, other: u128) -> bool {\n self == other\n }\n}\nimpl Eq for u64 {\n fn eq(self, other: u64) -> bool {\n self == other\n }\n}\nimpl Eq for u32 {\n fn eq(self, other: u32) -> bool {\n self == other\n }\n}\nimpl Eq for u16 {\n fn eq(self, other: u16) -> bool {\n self == other\n }\n}\nimpl Eq for u8 {\n fn eq(self, other: u8) -> bool {\n self == other\n }\n}\nimpl Eq for u1 {\n fn eq(self, other: u1) -> bool {\n self == other\n }\n}\n\nimpl Eq for i8 {\n fn eq(self, other: i8) -> bool {\n self == other\n }\n}\nimpl Eq for i16 {\n fn eq(self, other: i16) -> bool {\n self == other\n }\n}\nimpl Eq for i32 {\n fn eq(self, other: i32) -> bool {\n self == other\n }\n}\nimpl Eq for i64 {\n fn eq(self, other: i64) -> bool {\n self == other\n }\n}\n\nimpl Eq for () {\n fn eq(_self: Self, _other: ()) -> bool {\n true\n }\n}\nimpl Eq for bool {\n fn eq(self, other: bool) -> bool {\n self == other\n }\n}\n\nimpl Eq for [T; N]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T; N]) -> bool {\n let mut result = true;\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for [T]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T]) -> bool {\n let mut result = self.len() == other.len();\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for str {\n fn eq(self, other: str) -> bool {\n let self_bytes = self.as_bytes();\n let other_bytes = other.as_bytes();\n self_bytes == other_bytes\n }\n}\n\nimpl Eq for (A, B)\nwhere\n A: Eq,\n B: Eq,\n{\n fn eq(self, other: (A, B)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1)\n }\n}\n\nimpl Eq for (A, B, C)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n{\n fn eq(self, other: (A, B, C)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2)\n }\n}\n\nimpl Eq for (A, B, C, D)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n D: Eq,\n{\n fn eq(self, other: (A, B, C, D)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2) & self.3.eq(other.3)\n }\n}\n\nimpl Eq for (A, B, C, D, E)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n D: Eq,\n E: Eq,\n{\n fn eq(self, other: (A, B, C, D, E)) -> bool {\n self.0.eq(other.0)\n & self.1.eq(other.1)\n & self.2.eq(other.2)\n & self.3.eq(other.3)\n & self.4.eq(other.4)\n }\n}\n\nimpl Eq for Ordering {\n fn eq(self, other: Ordering) -> bool {\n self.result == other.result\n }\n}\n\n// Noir doesn't have enums yet so we emulate (Lt | Eq | Gt) with a struct\n// that has 3 public functions for constructing the struct.\npub struct Ordering {\n result: Field,\n}\n\nimpl Ordering {\n // Implementation note: 0, 1, and 2 for Lt, Eq, and Gt are built\n // into the compiler, do not change these without also updating\n // the compiler itself!\n pub fn less() -> Ordering {\n Ordering { result: 0 }\n }\n\n pub fn equal() -> Ordering {\n Ordering { result: 1 }\n }\n\n pub fn greater() -> Ordering {\n Ordering { result: 2 }\n }\n}\n\n#[derive_via(derive_ord)]\n// docs:start:ord-trait\npub trait Ord {\n fn cmp(self, other: Self) -> Ordering;\n}\n// docs:end:ord-trait\n\n// docs:start:derive_ord\ncomptime fn derive_ord(s: TypeDefinition) -> Quoted {\n let signature = quote { fn cmp(_self: Self, _other: Self) -> std::cmp::Ordering };\n let for_each_field = |name| quote {\n if result == std::cmp::Ordering::equal() {\n result = _self.$name.cmp(_other.$name);\n }\n };\n let body = |fields| quote {\n let mut result = std::cmp::Ordering::equal();\n $fields\n result\n };\n crate::meta::make_trait_impl(s, quote { Ord }, signature, for_each_field, quote {}, body)\n}\n// docs:end:derive_ord\n\n// Note: Field deliberately does not implement Ord\n\nimpl Ord for u128 {\n fn cmp(self, other: u128) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\nimpl Ord for u64 {\n fn cmp(self, other: u64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u32 {\n fn cmp(self, other: u32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u16 {\n fn cmp(self, other: u16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u8 {\n fn cmp(self, other: u8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i8 {\n fn cmp(self, other: i8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i16 {\n fn cmp(self, other: i16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i32 {\n fn cmp(self, other: i32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i64 {\n fn cmp(self, other: i64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for () {\n fn cmp(_self: Self, _other: ()) -> Ordering {\n Ordering::equal()\n }\n}\n\nimpl Ord for bool {\n fn cmp(self, other: bool) -> Ordering {\n if self {\n if other {\n Ordering::equal()\n } else {\n Ordering::greater()\n }\n } else if other {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for [T; N]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T; N]) -> Ordering {\n let mut result = Ordering::equal();\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for [T]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T]) -> Ordering {\n let mut result = self.len().cmp(other.len());\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for (A, B)\nwhere\n A: Ord,\n B: Ord,\n{\n fn cmp(self, other: (A, B)) -> Ordering {\n let result = self.0.cmp(other.0);\n\n if result != Ordering::equal() {\n result\n } else {\n self.1.cmp(other.1)\n }\n }\n}\n\nimpl Ord for (A, B, C)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n{\n fn cmp(self, other: (A, B, C)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n D: Ord,\n{\n fn cmp(self, other: (A, B, C, D)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D, E)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n D: Ord,\n E: Ord,\n{\n fn cmp(self, other: (A, B, C, D, E)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n if result == Ordering::equal() {\n result = self.4.cmp(other.4);\n }\n\n result\n }\n}\n\n// Compares and returns the maximum of two values.\n//\n// Returns the second argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::max(1, 2), 2);\n// assert_eq(cmp::max(2, 2), 2);\n// ```\npub fn max(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v1\n } else {\n v2\n }\n}\n\n// Compares and returns the minimum of two values.\n//\n// Returns the first argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::min(1, 2), 1);\n// assert_eq(cmp::min(2, 2), 2);\n// ```\npub fn min(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v2\n } else {\n v1\n }\n}\n\nmod cmp_tests {\n use crate::cmp::{max, min};\n\n #[test]\n fn sanity_check_min() {\n assert_eq(min(0 as u64, 1 as u64), 0);\n assert_eq(min(0 as u64, 0 as u64), 0);\n assert_eq(min(1 as u64, 1 as u64), 1);\n assert_eq(min(255 as u8, 0 as u8), 0);\n }\n\n #[test]\n fn sanity_check_max() {\n assert_eq(max(0 as u64, 1 as u64), 1);\n assert_eq(max(0 as u64, 0 as u64), 0);\n assert_eq(max(1 as u64, 1 as u64), 1);\n assert_eq(max(255 as u8, 0 as u8), 255);\n }\n}\n", + "path": "std/cmp.nr" + }, + "50": { + "source": "unconstrained fn main() {\n let mut a = [1, 2];\n foo(&mut a);\n}\n\nunconstrained fn foo(a: &mut [Field; 2]) {\n let a_copy = *a;\n a[0] = 100;\n assert_eq(a_copy, [1, 2]);\n assert_eq(*a, [100, 2]);\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "main" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_true_inliner_9223372036854775807.snap b/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_true_inliner_9223372036854775807.snap new file mode 100644 index 00000000000..96af34a1a5b --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/mutate_array_copy/execute__tests__force_brillig_true_inliner_9223372036854775807.snap @@ -0,0 +1,27 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [], + "return_type": null, + "error_types": { + "17843811134343075018": { + "error_kind": "string", + "string": "Stack too deep" + } + } + }, + "bytecode": "H4sIAAAAAAAA/7WSwQ7CIAyGwWEUZzw4H6TLMNvRgy/SuPAce3R3+BsaYrwATUhpSr72L7UmmYV3psAE8oD38AeV7/bzQkxlNvqsbk3+QiH4H/oq9j95MG0bPgm/0fzpBM57S3ytReqe99Or+9Wk/WilX/6vpf7hj+YeWm8qln1yW/1+5oVI+ujAP4Kfm1N5/X5AfFF6xLuCPuPMY5w48pPXNXz4nvFNNrcvgErvAJkEAAA=", + "debug_symbols": "XYzBCoAgEET/Zc8dErrUr0SE2iYLomIahOy/p9AhvAy8ecwUOFBls5M7/QXLWsB6LRN5V6nwACqStWT2rr5lJKksfnhmp382PQG7fYhe45EjtqfmYGwhaq5iGsS8MfPGLw==", + "file_map": {}, + "names": [ + "main" + ], + "brillig_names": [ + "main" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/slice_dynamic_index/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap b/tooling/nargo_cli/tests/snapshots/execution_success/slice_dynamic_index/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap index 053cfd987d8..c01d2b56795 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/slice_dynamic_index/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/slice_dynamic_index/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap @@ -35,8 +35,8 @@ expression: artifact } } }, - "bytecode": "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", - "debug_symbols": "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", + "bytecode": "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", + "debug_symbols": "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", "file_map": { "50": { "source": "fn main(x: Field) {\n // The parameters to this function must come directly from witness values (inputs to main).\n regression_dynamic_slice_index(x - 1, x - 4);\n}\n\nfn regression_dynamic_slice_index(x: Field, y: Field) {\n let mut slice = &[];\n for i in 0..5 {\n slice = slice.push_back(i as Field);\n }\n assert(slice.len() == 5);\n\n dynamic_slice_index_set_if(slice, x, y);\n dynamic_slice_index_set_else(slice, x, y);\n dynamic_slice_index_set_nested_if_else_else(slice, x, y);\n dynamic_slice_index_set_nested_if_else_if(slice, x, y + 1);\n dynamic_slice_index_if(slice, x);\n dynamic_array_index_if([0, 1, 2, 3, 4], x);\n dynamic_slice_index_else(slice, x);\n\n dynamic_slice_merge_if(slice, x);\n dynamic_slice_merge_else(slice, x);\n dynamic_slice_merge_two_ifs(slice, x);\n dynamic_slice_merge_mutate_between_ifs(slice, x, y);\n dynamic_slice_merge_push_then_pop(slice, x, y);\n}\n\nfn dynamic_slice_index_set_if(mut slice: [Field], x: Field, y: Field) {\n assert(slice[x] == 4);\n assert(slice[y] == 1);\n slice[y] = 0;\n assert(slice[x] == 4);\n assert(slice[1] == 0);\n if x as u32 < 10 {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n slice[x - 1] = slice[x];\n } else {\n slice[x] = 0;\n }\n assert(slice[3] == 2);\n assert(slice[4] == 2);\n}\n\nfn dynamic_slice_index_set_else(mut slice: [Field], x: Field, y: Field) {\n assert(slice[x] == 4);\n assert(slice[y] == 1);\n slice[y] = 0;\n assert(slice[x] == 4);\n assert(slice[1] == 0);\n if x as u32 > 10 {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n slice[x - 1] = slice[x];\n } else {\n slice[x] = 0;\n }\n assert(slice[4] == 0);\n}\n// This tests the case of missing a store instruction in the else branch\n// of merging slices\nfn dynamic_slice_index_if(mut slice: [Field], x: Field) {\n if x as u32 < 10 {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n } else {\n assert(slice[x] == 0);\n }\n assert(slice[4] == 2);\n}\n\nfn dynamic_array_index_if(mut array: [Field; 5], x: Field) {\n if x as u32 < 10 {\n assert(array[x] == 4);\n array[x] = array[x] - 2;\n } else {\n assert(array[x] == 0);\n }\n assert(array[4] == 2);\n}\n// This tests the case of missing a store instruction in the then branch\n// of merging slices\nfn dynamic_slice_index_else(mut slice: [Field], x: Field) {\n if x as u32 > 10 {\n assert(slice[x] == 0);\n } else {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n }\n assert(slice[4] == 2);\n}\n\nfn dynamic_slice_merge_if(mut slice: [Field], x: Field) {\n if x as u32 < 10 {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n\n slice = slice.push_back(10);\n // Having an array set here checks whether we appropriately\n // handle a slice length that is not yet resolving to a constant\n // during flattening\n slice[x] = 10;\n assert(slice[slice.len() - 1] == 10);\n assert(slice.len() == 6);\n\n slice[x] = 20;\n slice[x] = slice[x] + 10;\n\n slice = slice.push_front(11);\n assert(slice[0] == 11);\n assert(slice.len() == 7);\n assert(slice[5] == 30);\n\n slice = slice.push_front(12);\n assert(slice[0] == 12);\n assert(slice.len() == 8);\n assert(slice[6] == 30);\n\n let (popped_slice, last_elem) = slice.pop_back();\n assert(last_elem == 10);\n assert(popped_slice.len() == 7);\n\n let (first_elem, rest_of_slice) = popped_slice.pop_front();\n assert(first_elem == 12);\n assert(rest_of_slice.len() == 6);\n\n slice = rest_of_slice.insert(x as u32 - 2, 20);\n assert(slice[2] == 20);\n assert(slice[6] == 30);\n assert(slice.len() == 7);\n\n let (removed_slice, removed_elem) = slice.remove(x as u32 - 1);\n // The deconstructed tuple assigns to the slice but is not seen outside of the if statement\n // without a direct assignment\n slice = removed_slice;\n\n assert(removed_elem == 1);\n assert(slice.len() == 6);\n } else {\n assert(slice[x] == 0);\n slice = slice.push_back(20);\n }\n\n assert(slice.len() == 6);\n assert(slice[slice.len() - 1] == 30);\n}\n\nfn dynamic_slice_merge_else(mut slice: [Field], x: Field) {\n if x as u32 > 10 {\n assert(slice[x] == 0);\n slice[x] = 2;\n } else {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n slice = slice.push_back(10);\n }\n assert(slice.len() == 6);\n assert(slice[slice.len() - 1] == 10);\n\n slice = slice.push_back(20);\n assert(slice.len() == 7);\n assert(slice[slice.len() - 1] == 20);\n}\n\nfn dynamic_slice_index_set_nested_if_else_else(mut slice: [Field], x: Field, y: Field) {\n assert(slice[x] == 4);\n assert(slice[y] == 1);\n slice[y] = 0;\n assert(slice[x] == 4);\n assert(slice[1] == 0);\n if x as u32 < 10 {\n slice[x] = slice[x] - 2;\n if y != 1 {\n slice[x] = slice[x] + 20;\n } else {\n if x == 5 {\n // We should not hit this case\n assert(slice[x] == 22);\n } else {\n slice[x] = 10;\n slice = slice.push_back(15);\n assert(slice.len() == 6);\n }\n assert(slice[4] == 10);\n }\n } else {\n slice[x] = 0;\n }\n assert(slice[4] == 10);\n assert(slice.len() == 6);\n assert(slice[slice.len() - 1] == 15);\n\n slice = slice.push_back(20);\n assert(slice.len() == 7);\n assert(slice[slice.len() - 1] == 20);\n}\n\nfn dynamic_slice_index_set_nested_if_else_if(mut slice: [Field], x: Field, y: Field) {\n assert(slice[x] == 4);\n assert(slice[y] == 2);\n slice[y] = 0;\n assert(slice[x] == 4);\n assert(slice[2] == 0);\n if x as u32 < 10 {\n slice[x] = slice[x] - 2;\n // TODO: this panics as we have a load for the slice in flattening\n if y == 1 {\n slice[x] = slice[x] + 20;\n } else {\n if x == 4 {\n slice[x] = 5;\n }\n assert(slice[4] == 5);\n }\n } else {\n slice[x] = 0;\n }\n assert(slice[4] == 5);\n}\n\nfn dynamic_slice_merge_two_ifs(mut slice: [Field], x: Field) {\n if x as u32 > 10 {\n assert(slice[x] == 0);\n slice[x] = 2;\n } else {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n slice = slice.push_back(10);\n }\n\n assert(slice.len() == 6);\n assert(slice[slice.len() - 1] == 10);\n\n if x == 20 {\n slice = slice.push_back(20);\n }\n\n slice = slice.push_back(15);\n\n assert(slice.len() == 7);\n assert(slice[slice.len() - 1] == 15);\n\n slice = slice.push_back(20);\n assert(slice.len() == 8);\n assert(slice[slice.len() - 1] == 20);\n}\n\nfn dynamic_slice_merge_mutate_between_ifs(mut slice: [Field], x: Field, y: Field) {\n if x != y {\n slice[x] = 50;\n slice = slice.push_back(y);\n slice = slice.push_back(x);\n } else {\n slice[x] = slice[x] - 2;\n slice = slice.push_back(x);\n }\n\n slice = slice.push_back(30);\n assert(slice.len() == 8);\n\n if x == 20 {\n slice = slice.push_back(20);\n }\n\n slice = slice.push_back(15);\n\n if x != 20 {\n slice = slice.push_back(50);\n }\n\n slice = slice.push_back(60);\n assert(slice.len() == 11);\n assert(slice[x] == 50);\n assert(slice[slice.len() - 4] == 30);\n assert(slice[slice.len() - 3] == 15);\n assert(slice[slice.len() - 2] == 50);\n assert(slice[slice.len() - 1] == 60);\n}\n\nfn dynamic_slice_merge_push_then_pop(mut slice: [Field], x: Field, y: Field) {\n if x != y {\n slice[x] = 5;\n slice = slice.push_back(y);\n slice = slice.push_back(x);\n assert(slice.len() == 7);\n\n let (popped_slice, elem) = slice.pop_back();\n assert(slice.len() == 7);\n assert(elem == x);\n slice = popped_slice;\n } else {\n slice = slice.push_back(x);\n }\n\n slice = slice.push_back(30);\n assert(slice.len() == 7);\n\n if x == 20 {\n slice = slice.push_back(20);\n }\n\n let (slice, elem) = slice.pop_back();\n assert(elem == 30);\n\n let (_, elem) = slice.pop_back();\n assert(elem == y);\n}\n", diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/slice_dynamic_index/execute__tests__force_brillig_true_inliner_0.snap b/tooling/nargo_cli/tests/snapshots/execution_success/slice_dynamic_index/execute__tests__force_brillig_true_inliner_0.snap index 0fbf0466d13..f0ae528f8fa 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/slice_dynamic_index/execute__tests__force_brillig_true_inliner_0.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/slice_dynamic_index/execute__tests__force_brillig_true_inliner_0.snap @@ -35,8 +35,8 @@ expression: artifact } } }, - "bytecode": "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", - "debug_symbols": "zd3fjuPGlYDxd5lrX1Sd/5VXCRaB7TjBAIYd2M4CiyDvvpqxRRlTDXOzah59N0a3R13zc1v8RFI81L8+/PW7b/759798/OFvP/784U9//teH73/89utfPv74w+27f/37qw/f/PTx++8//v0vv//XH8anf0z7/Pif//H1D5++/fmXr3/65cOfps+vPnz3w18/fRW3n//bx++/+/AnH//+r68+TP+PfyLe/om6/0Tolz+R//FP1Js/IeP4Cfv9T3z1f3/op8XXhYvLuHLxeeXicuXieuXiduXifuXiceXieeXiV26hcuUWqlduoXrlFqpXbqF65RaqV26heuUWqlduofbss0UifnuoRH65+LO/c6n74jrml4v7lYs/+ztXlfviVl8unlcuXlcuvi5c3J+tovrxP3T5ySaR89j1S/3y/75PjEQwEsVIDCNxjCQwksRICiNZFElgGhuYxgamsYFpbGAaG52NHVPvyw7ZJIGRJEZSGMl6leTLs5M5MJKJkQhGohiJYSSOkQRG0tpYO5Yd23FxFkayKJIaGMl8kcS/fMeqBCNRjMQwktbGxkMS2zM2MJLESAojWRTJGhjJxEgEI1GMpLWx5YdkfdnY5RhJYCSJkdSrJNszdlEkcwwOZXIonZmd8/6e5O2rsVGUQzEOxV9F8Y0SHEpyKMWhdNZ26tGVads1nXNwKJNDkVdRtvBP5VA6N2aJdV9WMjdKcSgLQ5HBoUwORTgU5VCMQ2ndX1nHsnPfzZbkUIpDWRiKDg5lcijCobQmTh5d0W2kSFsTp8clO2LbeJY6hxIcSnIorTuUoo+n7XZ0qAtDscGhTA5FOBTlUIxDcQ6Fc8xsnYnTcSyrY9tJsIWhtM7YnFDmiyhzOwHWOmVzQlEOxTiUzsSp5EHZE9c6aXNCSQ6lXkSx7a2p1mGbP6a0TtucUCaHIhyKcijGoTiHEhxKciic2ganttfN3XxefV66+rNNtHG/XZKZ/PFDPcb9wMlDtwOnpwdk3pFiHIpzKMGhJIdSHMrCUJ6ek3lHyuRQOLUtTm2LU9tqrO3trPJxp0HTtVGCQ0kOpTiU9SKKbW/BrsGhTA5FOBTlUIxDcQ6ltbaP279abO+Rr+RQikNZFIqM8SJKzo0yORThUJRDaa1tPii1P22dQwkOJTmU4lAWhjIHhzI5lM7a+jiuvfG5JW4qh2IcinMo8SrK/rRNDqU4lIWhSGdtXeOgbOfiRCaHIhxKa211PCi1UYxD8RdRtqFWkeBQkkMpDqW1tv6o7X4mQTu7EnVcxBDbhQCiyqEYh+IcSnAoyaEUh7IwFOvcdYrx+DCzfYfShENRDsU4FOdQgkNJDqU1cfboistGaU3ccd3ijPjyDTvxwaFMDkU4lNba2nw8bbc9fjcOxTmU4FCSQykOZWEoMTgUzjFzdCYuxe7LpuwU41CcQ+lM3O8/TWj7VAeJ5FDqRZTtM5YkFoaSg0OZHIpwKMqhGIfiHEpwKMmhcGqbnNpeNx/0efV56epPN9HuvxofJw8NOUZPQ7bRU3l+iuf9KMahOIcSHEpyKMWhLAzl+Sme96NMDoVT28Wp7eLUdnFquzi1XY21tdI7xcq2syCrOJRFoegYHMp8EcXHRhEORTkU41CcQwkOJTmU1tqGHZSUjbIwlDk4lMmhyKsouVGUQzEOxTmU1trWg7L2p21yKMWhLAxFBocyORThUJRDMQ6ls7bruBGUrbnVVoJDSQ6lOJT1IopsT1sdHMrkUIRD6aztMjko2/CZqnEozqG01vaYr71RbKMkh1KvoqyNsjAUGxzK5FAanytu874X57bX1haG4oNDmRyKcCjKoRiH4hxKcCitL4elR23X3CgLQ4nBoUwORTgU5VCMQ3EOJTiUxoMPH/O4E/rYRmc0O3edho3HY2ujTA5FOBTlUIxDcQ4lOJTkUApDqdbEreOxc2ynejqv43c57oR++3I7k9B5Hf8ZxTmU4FCSQykOZWEondfxu+SROKltL67zOv4zinAoyqEYh+IcSnAoyaEUh7IoFBuY2trA1NYGprY2MLW1gamtDUxtbWBqa53X8bs+3m5QHRulOJSFoXRex39G6UzczDwO37fzttZ58fwZxTgU51A4XZmcrszWrqQclPzyCjCTwaFMDqUzcbc3wh4U2yjKodiLKLVtQZ1XrJ9RgkNJDgVzMZop5mI009aL0fw4WWq+U4RDUQ6lM3Fm/qBsr0HqHEq8irI2SnIoxaEsDMVaa5t6UGqnTA5FOBTlUDpr+/j8Pfftsisz51CCQ8kXUbYbV1rroMUJZWEorYMWJ5TO2vrxcSnuse3FtQ5anFCUQzEOxTmU4FCSQykOZWEoMTgUTm2DU9vg1DY4tQ1ObYNT2+DUNji1jdba5jEJ49un/FjrJMwJZXIowqF01jaOO4147AcfrZMwJxTnUOJVlNwoyaEUh7IwlNahnBPK5FCEQ1EOxTgU51A4tS1Oba8bVfq8+rpy9acHim472MevZvvNPD0j5PO4pDfqjx8q47iLkYztLkb29IzQO1KUQzEOxTmU4FCSQykOZVEo/vSM0DtSMLX1gamtD0xtby+/fRTP46Oub1/uFOdQgkNJDqVeRHHbKAtDmYNDmRyKcCjKoRiH4hxKa23jOPTMjI2SHEpxKAtDkfEiSs2NMjkU4VCUQ2mtbT0oa3/aOocSHEpyKMWhLAxFB4cyOZTO2tY8Lv8t2RKnyqEYh+IcSryKsj9tk0MpDmVhKNZZ27JjkLgsN8rkUIRDUQ6ltbaPG8vWdmNZN+dQ4kWUbXrXLTmU4lAWhuKNtY3p9+nd25db+F07KevelZDt4gt341CcQwkOJTmU4lAWhhKDQ2nddapjwqG2q9Y9lEMxDsU5lOBQkkMpDmVhKNl5oLqOj5KIsScuO3edxnHXxRi17VBm607CkGOHco6NkhxKcSgLQ6nBoUwORTgU5VCcQwnMMXMlh9KaOFsPynZasBaGssaLKNt4ta/JoQiHohxKZ+IenwQZQ/anbXAoyaEUh7IolOgctDijTA5FOBSjnIuLzumGENWDojslOJTOxInkg+IbpTiU9SKKfbnHH53TDWeUyaEIh6IcinEozqEEh5IcSnEonNoKp7bXTTd8Xl0uXf3pJqYde5Xxxw8Viftjb7/QbQ/0+RmE96M4hxIcSnIoxaEsDOX5GYT3o0wORTgUTm21sbZz+bHs8u01SJNDKQ6lsyvjuHO+jPnlZEbY4FAmhyIcir6KEhvFOBTnUIJD6UxcLT8SN7bE2cJQfHSGX+Kg7Cd6fXIowqEoh2KvoqyN4hxKcCjJoXB2KH1hKDE4lMmhCIeiHIpxKM6hJGaHMjrPxQ2Tg2K6URaGkoNDaT1m/v09NLddpxQORV9F2XYS0jgU51CCQ0kOpTiUhaHU4FAmhyIcCqe2xant0/MqcXw6RLyxely6el66el26+rpy9afHOf549Xnp6nLp6nrp6nbp6pduq+vSbXVduq2uS7fVdeW2mmNcuvrT2+o8Zgz95KHidbzf7ys3inAoyqEYh+IcSnAoyaEUh7IwlKenHt6Rwqnt7OyK6P0jA25fbq9B0zmU4FDyRZTtRGTO4lAWhiKDQ+ncdZp+dGWf/k5RDsU4FH8VZQu/BIeSHEpxKJ2Jm1kHpb584zR1cCiTQxEORTkU41CcQwkOhbMXp617cb+fMtlemW1wKPNVlO01yIRDUQ7FOBTnUIJDSQ6lOJSFofjgUDi1dU5t/bLafl7dLl396SbG/aG3d2r/+KEmcb9swmTtlOBQkkMpDmVhKE+PGrwjZXIowqEoh2IcCqe20VhbsePaOrHaXj9jYSg5OJTGrojP4yyIb5/LlykcinIoxqH4iyg6N0pwKMmhFIfSWVv3Y8bMY6PU4FAmhyIcir6K4hultbaPyTv/9IgvKM6hBIeSHEpxKAtDWYNDmRxKZ+LMjsTZ9jEquYxD8VcdB23v8K3gUJJDKQ4Fc/heA3P4XmNyKMKhYPbiarTuxa1xUNbcKMGhJIfSuhf3+wv/ZaMsDGWOV1G2jXlODkU4FOVQjENxDiU4lORQikNZGIpwaiuc2spltf28ul66+rNNzHG/SjdV//ihlsct1iy3M/H19IDLO1KCQ0kOpTiUhaE8PeDyjpTJoQiHohwKp7bKqa1yaquc2mpnbefxHrnN7V7gZcKhKIfSuTHP8IOSulGcQwkOJTmUehWlNsrCUHxwKJNDaa3tun/oo8nczq66cijGoTiHEhxKcijFoSwMJQaHMjkUTm2DU9vg1DY4tQ1ObYNT2+DUNhsTJxHHdeVR2+F7Tg5FOilr3Sk5trdKUjkU41CcQ4kXUd7YmJNDKQ5lYSjVWduU4wLdN06W1uRQhENRDsU4FOdQgkPprG0eJ8Aka2yU4lAWhrIGhzI5FOFQlEMxDsU5lOBQOLVdnNouTG3XwNR2DUxt1+is7cqDsra7jK2hHIpxKJ21XY/bwK3tVqRrBIeSHEpxKAtDmYNDmRxKY211jPuyOqZvFOVQjENxDiU4lORQikNpre2yB+XLuxksGRzK5FCEQ9EXUWR7DeqcDzqjOIcSHEprbe2RON+ftsWhLAylcz7ojDI7Kcc1CTpypwiHohyKcSjOoQSHkhxKa23XPChrbZSFodjgUCaHIhyKcijGoXTWduqxQzl9O8ffOcB1RkkOpTiUhaF0DnCdUSaHIhyKcijGoXBq65zaOqe2zqmtc2obnNpGa20zD8o2LrtCOBTlUFprm/NB2fZtwzmU4FDyRZTa3pqK4lAWhpKDQ+msrRx3pVGZ29O2c5bsjKIcinEonbUVPV6DxPanbXAo+SKKz41SHMrCUDpnyc4orbV9hF+2+8OvEg5FORTjUJxDCQ4lOZTiUBaGsgaHwqnt4tR2cWq7OLVdnNouTm07Z8lU53FaUPeLXDtnyc4oi0KZo3OYTHXUwxK7ZYIs8iLLdhnlzaIgi4EsDrJ0Rlcfl1Kqv/HcTZClQJbFsczW7ubjNaD25+6cIIu8ylK7RUEWA1kcZOnsrun9YwrV7I1tOkGWAlkWx9I5YHZqmSCLgCwKshjI4iALqLsC6q6Auiug7iqou62zZnbctUZtu2vNzSIgi4IsBrK0dncd5xlc5m4JkCVBlgJZOrvrcVww4LU2S+vQ2ZllgiwCsijIYiCLgywBsiTIUiALqLsO6q6Duuug7jqouw7qbusMWjzeVwux3RIgS4IsBbJ0djfsOLaP2I/tWwfRziwTZBGQpbO7OY7W5dxb1zqMdmZxkCVAltbuVhyW8cZzt0CWxbG0jqSdWSbIIiCLgiwGsjjIEiALqLsJ6m6Culug7haouwXqboG6W6DuFqi7BepugbrbOqSW9jgOsP1av9YptRNL65jamWW2WubDsh+rtQ6qnVn0RRbf52xaR9XOLA6yBMjS2d3MdVjeuOakdVztzLIwltk6r5apD8vcLRNkkVdZcrcoyGIgi4Msnd2tcVxfV/LGczdBlgJZFsfSOq9Wdbx/VMt2ywRZBGRRkKWzuxXHPkO98drYOq92ZgmQJUGWAlkWx9I6r3ZmmSCLgCwKsoC6K6DuCqi7AuqugLoroO4qqLsK6q6Cuqug7iqouwrqroK6q6DuKqi7nfNqdns3/LfH2u1k7mbpnFc7tUyQRUCWxu7a7cjwsOh+nqFzXu3U4iBLgCzVaVn398pNpuyWxbF0zoiZaBwWf8MyQRYBWRRk6WydxMOy33drds6InVriRZY3znt3zoidWgpkWRxLDJBlgiwCsijIYiCLgyyg7gaou9fNiP26/Lp0+ecnufR+tiHz5DcZJXdK1H4F53x+kusdLQKyKMhiIIuDLAGyJMhSIMviWArU3QJ1t0DdLVB3q7G7ZnK/2stM9zPClSBLgSyr0xJ2WHI/e7QGyDJBFgFZ9FWW/QrxZSCLgywBsrR2d90faz7esBTIsjAWGQNkmS+yzLlbWrtbxzuUtmK3KMhiIIuDLAGyJMhSIEtnd10efbHtLKzMAbJMkEVAFgVZDGRxkCVAlgRZCmQBdVdA3RVQdwXUXQF1V0DdFVB3pbN1etwR3HS/64ZIgSydrdP12N/d744lOkCWCbIIyKIvsrxxzkMNZHGQJUAWzntZopz3skQXx2IDZJkgi4AsCrIYyOIgC+h42kDH09Z6PP3Y3/XarscUHyDLBFkEZGk9nn5MlcX+aRniBrL4iyziuyVAlgRZCmTp7G4cd4O18P24MQbIMkEWAVkUZDGQxUGWAFkSZCmQBdTdBHU3Qd1NUHcT1N0EdTdB3c3W7h53m7bYP1FWMkGWAlkWx9I5f2Q5Dku+cRzQOX90apEXWXR/b6Jz/ujUYiCLgywBsiTIUiDL4ljWAFkmyALq7gJ197q5rF+X92uXf7qOx+cD1YyTh/pxtXrG3PeQn5+eekdLgSwLY9Hnp6fe0TJBFgFZFGQxkMVBFk53dXC6q4PTXR2g7s7G7obmcacLzbVbFGQxkKWxL7eTjfe90rD988F0BsiSIEuBLOtVlr0vMkCWCbIIyNLZXbM6LP6GxUAWB1kCZMkXWWLsltbuah4W892yOBYdIMsEWQRkUZDFQJbW7uajL0t3S4AsCbIUyLI4FhsgywRZBGRRkMVAFlB3DdRdA3XXQN01UHcd1F0Hdddbz6nOOM5jyn4e0w1k6WzdrSCHxff9XQ+QJUGWAlnWiyxvnPOIAbJMkEVAFtB7WWEgi4MsAbIkyFIgy+JYEvReeU6QBXQ8nQaydLbO5/F65PqGJUCWBFkKZOlsnT/2Xzz2bboGyDJfZMn9OKAEZFGQxUCW1u7WcZ7B33gNqAJZFseyOvsS8353rAjJ3TJBFgFZFGQxkMVBlgBZEmQpkGVhLDY43bXB6a4NTndtcLprg9NdG5zu2uB01wandTZArWudbQl/WOINywRZBGRRkMVAFgdZAmRJkKVAlsWxCKi7AuqugLoroO4KqLutMz9RfrfkmLslQJYEWQpk6exuzodF9+du68zPmWW+yGK6WwRkUZDFQJbO7qavw5K2WwJkSZClQJbFsbTO/JxZJsgiIIuCLAaygLproO4aqLsG6q6Buuug7jqou97a3XVcG1pjPw5onT86sxjI4iBLZ3dLHpY3jgNa54/OLPUqy9oti2NpnT86s0yQRUAWBVkMZHGQJUCWBFlA3Q1Qd6+bP/p1+Xnt8s/WsY7PuK2ze6uX1P0K8ZL1hkVBFgNZHGQJkCVBlgJZFsfy9MTSe1omyALqboG6W6DuFqi71djdWHZMCS2X3ZKdlrTDkvvvZU2QRUAW7bSEPiz71RjLQBYHWQJkSZClQJaFsfgYnZZ170uOsXbLBFkEZFGQxUAWB1kCZEmQpUCWxbFMUHcnqLsT1N0J6u4EdXc2djeHjsOy30HeZ4AsCbIUyLI4FhkgywRZBGRRkMVAFlB3BdRdAXVXQN0VUHcV1F0FdVdBrVNQ67S1dSWHZY3dEiBLgiwFsqxXWWyzWGvrjjv23r7cj9VsgiwCsijIYiCLgywBsnR2dx53O8q53+3IrUCWxbH4AFkmyCIgi4IsBrI4yBIgC6i7Duqug7oboO4GqLsB6m6Auhug1gWoddHaOj/2d2fEbimQZXEsOUCWCbIIyKIgi4EsDrIEyALqboK6m6DuFqi7BepugbpboO5Wa3dLD8vazx2WgywBsiTHsjr7InqfhUrx/Zr8zvmjU4uALAqyGMjiIEuALAmyFMiyMJYYnO7G4HQ3Bqe7MTjdjcHpbgxOd2NwuhuD07oYoNbN1tblw7LesEyQRUAWBVkMZHGQJUCWBFkKZFkci4C6K6DuCqi7AuqugLoroO4KqLutsy2qx7lmte1cc7TOtpxZJsgiIIuCLAayOMgSIEuCLAWygLproO4aqLsG6q6Bumug7hqouwZqnYFa1zrboo/5I63d0jrbcmaZIIuALAqyGMjiIEuALAmyFMgC6m6Auhug7gaouwHqboC6G6DuBqi7rXM2No7rDk3GbimQZXEsrXM2Z5YJsgjIoiCLgSyd3TU97tVpJrslQJYEWQpkWa+y1GZpnbM5s0yQRUCW1u7GMbNsZbvFQBZ/kWW/H1m0ztmcWRJkKZCls7s+jm3aZT8maZ0/OrPMF1l0f21snT86syjIYiBLZ3f9+Byx9NhfG1vnj84sCbLUiyy5v063zh/9sSVb54/OLBNkae1u1d0Sc+wWBVkMZPFXWWK3BMiSIEuBLItjaZ2FOrNMkEVAFgVZDGQBdXeCunvdLNSvy9e1yz9dx1y/PXSJ/z8f+lny/LzSu0kmRiIYiWIkhpE4RhIYSWIkhZFgGquYxiqmsYpprDb2JPNx14bU3C0BsiTIUp0W8Ydl33fTxbHYAFkmyCIgi4IsBrK0dtcfltzPblqALAmyFMiyOBYfIMsEWQRkUZDFQBZQdx3UXQd110HddVB3o7W765jsqLGfgY4JsgjIoiCLgSwOsgTIkiBLgSyLY0lQdxPU3QR1N0HdTVB3s7O7Jcd5zNqnbzIDZEmQpUCWzu5WPZ67a39vogbIMkEWAVkUZDGQxUGWAFkSZCmQBdTdBeruAnV3gbq7QN1dnd1ddlwZuXx/r3w5yBIgS4IsBbIsjKXGAFkmyCIgi4IsnO7W4HS3Bqe7NTjdrdF5TeiY98fetplt6rHmAFkmyCIgi4IsBrI4yBIgS4IsBbKAuiug7gqouwLqroC6K6DuCqi7AmqdgFrXOnc0vA7LPmdarZNHZ5YJsgjIoiCLgSwOsgTIkiBLgSyg7hqouwbqroG6a6DuGqi7BuqutXZ33Ze9nZuL3ZIgS4Esi2PpnD+6nZDTw+K1WxRkMZDFQZYAWRJkKZBlcSyd80enlgmygLoboO4GqLsB6m6Auhug7gaouwlqXYJal62tW/d52Nv7Vmu3KMhiIIuDLAGyJMhSIMviWGqALBNkAXW3QN0tUHcL1N0Cdbdz5qdE7LC88f5058zPqWVxLJ0zP6eWzu7K4xy8pOwWAVkUZDGQxUGWAFkSZGntbuVhWfv7JGthLGsMkGWCLAKyKMhiIIuDLAGyJMjC6e4aoO4+PfMjcb+PikTuy8u1yz9bJB33D2jRKfvyz0ZG6q7XMffl/drl49rl89rl69rl16XLPz1ecrL8vHZ5uXZ5vXb5a7dauXarlWu3Wrl2q5Vrt1q5dqvVa7davW6r/fftu//++qePX3/z/Xc/337i0x/+84dvf/n44w+/ffvL//zj/iff/PTx++8//v0v//jpx2+/++s/f/ruL9//+O2nP/swfvvHn2VIfSXD1g3+KQZzWXw1V87b9/b5+5Tbn0vevvfPj3f9Sub49P2nJ7BM89v3Fbfv8/P347beNLt9X5+/v+2WiLjfvv/0//T2ZXwlOurTL2p8/gvUbn+hfgJ83ke5/Q3j9je63P5bb/+9/ws=", + "bytecode": "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", + "debug_symbols": "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", "file_map": { "50": { "source": "fn main(x: Field) {\n // The parameters to this function must come directly from witness values (inputs to main).\n regression_dynamic_slice_index(x - 1, x - 4);\n}\n\nfn regression_dynamic_slice_index(x: Field, y: Field) {\n let mut slice = &[];\n for i in 0..5 {\n slice = slice.push_back(i as Field);\n }\n assert(slice.len() == 5);\n\n dynamic_slice_index_set_if(slice, x, y);\n dynamic_slice_index_set_else(slice, x, y);\n dynamic_slice_index_set_nested_if_else_else(slice, x, y);\n dynamic_slice_index_set_nested_if_else_if(slice, x, y + 1);\n dynamic_slice_index_if(slice, x);\n dynamic_array_index_if([0, 1, 2, 3, 4], x);\n dynamic_slice_index_else(slice, x);\n\n dynamic_slice_merge_if(slice, x);\n dynamic_slice_merge_else(slice, x);\n dynamic_slice_merge_two_ifs(slice, x);\n dynamic_slice_merge_mutate_between_ifs(slice, x, y);\n dynamic_slice_merge_push_then_pop(slice, x, y);\n}\n\nfn dynamic_slice_index_set_if(mut slice: [Field], x: Field, y: Field) {\n assert(slice[x] == 4);\n assert(slice[y] == 1);\n slice[y] = 0;\n assert(slice[x] == 4);\n assert(slice[1] == 0);\n if x as u32 < 10 {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n slice[x - 1] = slice[x];\n } else {\n slice[x] = 0;\n }\n assert(slice[3] == 2);\n assert(slice[4] == 2);\n}\n\nfn dynamic_slice_index_set_else(mut slice: [Field], x: Field, y: Field) {\n assert(slice[x] == 4);\n assert(slice[y] == 1);\n slice[y] = 0;\n assert(slice[x] == 4);\n assert(slice[1] == 0);\n if x as u32 > 10 {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n slice[x - 1] = slice[x];\n } else {\n slice[x] = 0;\n }\n assert(slice[4] == 0);\n}\n// This tests the case of missing a store instruction in the else branch\n// of merging slices\nfn dynamic_slice_index_if(mut slice: [Field], x: Field) {\n if x as u32 < 10 {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n } else {\n assert(slice[x] == 0);\n }\n assert(slice[4] == 2);\n}\n\nfn dynamic_array_index_if(mut array: [Field; 5], x: Field) {\n if x as u32 < 10 {\n assert(array[x] == 4);\n array[x] = array[x] - 2;\n } else {\n assert(array[x] == 0);\n }\n assert(array[4] == 2);\n}\n// This tests the case of missing a store instruction in the then branch\n// of merging slices\nfn dynamic_slice_index_else(mut slice: [Field], x: Field) {\n if x as u32 > 10 {\n assert(slice[x] == 0);\n } else {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n }\n assert(slice[4] == 2);\n}\n\nfn dynamic_slice_merge_if(mut slice: [Field], x: Field) {\n if x as u32 < 10 {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n\n slice = slice.push_back(10);\n // Having an array set here checks whether we appropriately\n // handle a slice length that is not yet resolving to a constant\n // during flattening\n slice[x] = 10;\n assert(slice[slice.len() - 1] == 10);\n assert(slice.len() == 6);\n\n slice[x] = 20;\n slice[x] = slice[x] + 10;\n\n slice = slice.push_front(11);\n assert(slice[0] == 11);\n assert(slice.len() == 7);\n assert(slice[5] == 30);\n\n slice = slice.push_front(12);\n assert(slice[0] == 12);\n assert(slice.len() == 8);\n assert(slice[6] == 30);\n\n let (popped_slice, last_elem) = slice.pop_back();\n assert(last_elem == 10);\n assert(popped_slice.len() == 7);\n\n let (first_elem, rest_of_slice) = popped_slice.pop_front();\n assert(first_elem == 12);\n assert(rest_of_slice.len() == 6);\n\n slice = rest_of_slice.insert(x as u32 - 2, 20);\n assert(slice[2] == 20);\n assert(slice[6] == 30);\n assert(slice.len() == 7);\n\n let (removed_slice, removed_elem) = slice.remove(x as u32 - 1);\n // The deconstructed tuple assigns to the slice but is not seen outside of the if statement\n // without a direct assignment\n slice = removed_slice;\n\n assert(removed_elem == 1);\n assert(slice.len() == 6);\n } else {\n assert(slice[x] == 0);\n slice = slice.push_back(20);\n }\n\n assert(slice.len() == 6);\n assert(slice[slice.len() - 1] == 30);\n}\n\nfn dynamic_slice_merge_else(mut slice: [Field], x: Field) {\n if x as u32 > 10 {\n assert(slice[x] == 0);\n slice[x] = 2;\n } else {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n slice = slice.push_back(10);\n }\n assert(slice.len() == 6);\n assert(slice[slice.len() - 1] == 10);\n\n slice = slice.push_back(20);\n assert(slice.len() == 7);\n assert(slice[slice.len() - 1] == 20);\n}\n\nfn dynamic_slice_index_set_nested_if_else_else(mut slice: [Field], x: Field, y: Field) {\n assert(slice[x] == 4);\n assert(slice[y] == 1);\n slice[y] = 0;\n assert(slice[x] == 4);\n assert(slice[1] == 0);\n if x as u32 < 10 {\n slice[x] = slice[x] - 2;\n if y != 1 {\n slice[x] = slice[x] + 20;\n } else {\n if x == 5 {\n // We should not hit this case\n assert(slice[x] == 22);\n } else {\n slice[x] = 10;\n slice = slice.push_back(15);\n assert(slice.len() == 6);\n }\n assert(slice[4] == 10);\n }\n } else {\n slice[x] = 0;\n }\n assert(slice[4] == 10);\n assert(slice.len() == 6);\n assert(slice[slice.len() - 1] == 15);\n\n slice = slice.push_back(20);\n assert(slice.len() == 7);\n assert(slice[slice.len() - 1] == 20);\n}\n\nfn dynamic_slice_index_set_nested_if_else_if(mut slice: [Field], x: Field, y: Field) {\n assert(slice[x] == 4);\n assert(slice[y] == 2);\n slice[y] = 0;\n assert(slice[x] == 4);\n assert(slice[2] == 0);\n if x as u32 < 10 {\n slice[x] = slice[x] - 2;\n // TODO: this panics as we have a load for the slice in flattening\n if y == 1 {\n slice[x] = slice[x] + 20;\n } else {\n if x == 4 {\n slice[x] = 5;\n }\n assert(slice[4] == 5);\n }\n } else {\n slice[x] = 0;\n }\n assert(slice[4] == 5);\n}\n\nfn dynamic_slice_merge_two_ifs(mut slice: [Field], x: Field) {\n if x as u32 > 10 {\n assert(slice[x] == 0);\n slice[x] = 2;\n } else {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n slice = slice.push_back(10);\n }\n\n assert(slice.len() == 6);\n assert(slice[slice.len() - 1] == 10);\n\n if x == 20 {\n slice = slice.push_back(20);\n }\n\n slice = slice.push_back(15);\n\n assert(slice.len() == 7);\n assert(slice[slice.len() - 1] == 15);\n\n slice = slice.push_back(20);\n assert(slice.len() == 8);\n assert(slice[slice.len() - 1] == 20);\n}\n\nfn dynamic_slice_merge_mutate_between_ifs(mut slice: [Field], x: Field, y: Field) {\n if x != y {\n slice[x] = 50;\n slice = slice.push_back(y);\n slice = slice.push_back(x);\n } else {\n slice[x] = slice[x] - 2;\n slice = slice.push_back(x);\n }\n\n slice = slice.push_back(30);\n assert(slice.len() == 8);\n\n if x == 20 {\n slice = slice.push_back(20);\n }\n\n slice = slice.push_back(15);\n\n if x != 20 {\n slice = slice.push_back(50);\n }\n\n slice = slice.push_back(60);\n assert(slice.len() == 11);\n assert(slice[x] == 50);\n assert(slice[slice.len() - 4] == 30);\n assert(slice[slice.len() - 3] == 15);\n assert(slice[slice.len() - 2] == 50);\n assert(slice[slice.len() - 1] == 60);\n}\n\nfn dynamic_slice_merge_push_then_pop(mut slice: [Field], x: Field, y: Field) {\n if x != y {\n slice[x] = 5;\n slice = slice.push_back(y);\n slice = slice.push_back(x);\n assert(slice.len() == 7);\n\n let (popped_slice, elem) = slice.pop_back();\n assert(slice.len() == 7);\n assert(elem == x);\n slice = popped_slice;\n } else {\n slice = slice.push_back(x);\n }\n\n slice = slice.push_back(30);\n assert(slice.len() == 7);\n\n if x == 20 {\n slice = slice.push_back(20);\n }\n\n let (slice, elem) = slice.pop_back();\n assert(elem == 30);\n\n let (_, elem) = slice.pop_back();\n assert(elem == y);\n}\n", diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/slice_dynamic_index/execute__tests__force_brillig_true_inliner_9223372036854775807.snap b/tooling/nargo_cli/tests/snapshots/execution_success/slice_dynamic_index/execute__tests__force_brillig_true_inliner_9223372036854775807.snap index 0fbf0466d13..f0ae528f8fa 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/slice_dynamic_index/execute__tests__force_brillig_true_inliner_9223372036854775807.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/slice_dynamic_index/execute__tests__force_brillig_true_inliner_9223372036854775807.snap @@ -35,8 +35,8 @@ expression: artifact } } }, - "bytecode": "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", - "debug_symbols": "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", + "bytecode": "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", + "debug_symbols": "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", "file_map": { "50": { "source": "fn main(x: Field) {\n // The parameters to this function must come directly from witness values (inputs to main).\n regression_dynamic_slice_index(x - 1, x - 4);\n}\n\nfn regression_dynamic_slice_index(x: Field, y: Field) {\n let mut slice = &[];\n for i in 0..5 {\n slice = slice.push_back(i as Field);\n }\n assert(slice.len() == 5);\n\n dynamic_slice_index_set_if(slice, x, y);\n dynamic_slice_index_set_else(slice, x, y);\n dynamic_slice_index_set_nested_if_else_else(slice, x, y);\n dynamic_slice_index_set_nested_if_else_if(slice, x, y + 1);\n dynamic_slice_index_if(slice, x);\n dynamic_array_index_if([0, 1, 2, 3, 4], x);\n dynamic_slice_index_else(slice, x);\n\n dynamic_slice_merge_if(slice, x);\n dynamic_slice_merge_else(slice, x);\n dynamic_slice_merge_two_ifs(slice, x);\n dynamic_slice_merge_mutate_between_ifs(slice, x, y);\n dynamic_slice_merge_push_then_pop(slice, x, y);\n}\n\nfn dynamic_slice_index_set_if(mut slice: [Field], x: Field, y: Field) {\n assert(slice[x] == 4);\n assert(slice[y] == 1);\n slice[y] = 0;\n assert(slice[x] == 4);\n assert(slice[1] == 0);\n if x as u32 < 10 {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n slice[x - 1] = slice[x];\n } else {\n slice[x] = 0;\n }\n assert(slice[3] == 2);\n assert(slice[4] == 2);\n}\n\nfn dynamic_slice_index_set_else(mut slice: [Field], x: Field, y: Field) {\n assert(slice[x] == 4);\n assert(slice[y] == 1);\n slice[y] = 0;\n assert(slice[x] == 4);\n assert(slice[1] == 0);\n if x as u32 > 10 {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n slice[x - 1] = slice[x];\n } else {\n slice[x] = 0;\n }\n assert(slice[4] == 0);\n}\n// This tests the case of missing a store instruction in the else branch\n// of merging slices\nfn dynamic_slice_index_if(mut slice: [Field], x: Field) {\n if x as u32 < 10 {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n } else {\n assert(slice[x] == 0);\n }\n assert(slice[4] == 2);\n}\n\nfn dynamic_array_index_if(mut array: [Field; 5], x: Field) {\n if x as u32 < 10 {\n assert(array[x] == 4);\n array[x] = array[x] - 2;\n } else {\n assert(array[x] == 0);\n }\n assert(array[4] == 2);\n}\n// This tests the case of missing a store instruction in the then branch\n// of merging slices\nfn dynamic_slice_index_else(mut slice: [Field], x: Field) {\n if x as u32 > 10 {\n assert(slice[x] == 0);\n } else {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n }\n assert(slice[4] == 2);\n}\n\nfn dynamic_slice_merge_if(mut slice: [Field], x: Field) {\n if x as u32 < 10 {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n\n slice = slice.push_back(10);\n // Having an array set here checks whether we appropriately\n // handle a slice length that is not yet resolving to a constant\n // during flattening\n slice[x] = 10;\n assert(slice[slice.len() - 1] == 10);\n assert(slice.len() == 6);\n\n slice[x] = 20;\n slice[x] = slice[x] + 10;\n\n slice = slice.push_front(11);\n assert(slice[0] == 11);\n assert(slice.len() == 7);\n assert(slice[5] == 30);\n\n slice = slice.push_front(12);\n assert(slice[0] == 12);\n assert(slice.len() == 8);\n assert(slice[6] == 30);\n\n let (popped_slice, last_elem) = slice.pop_back();\n assert(last_elem == 10);\n assert(popped_slice.len() == 7);\n\n let (first_elem, rest_of_slice) = popped_slice.pop_front();\n assert(first_elem == 12);\n assert(rest_of_slice.len() == 6);\n\n slice = rest_of_slice.insert(x as u32 - 2, 20);\n assert(slice[2] == 20);\n assert(slice[6] == 30);\n assert(slice.len() == 7);\n\n let (removed_slice, removed_elem) = slice.remove(x as u32 - 1);\n // The deconstructed tuple assigns to the slice but is not seen outside of the if statement\n // without a direct assignment\n slice = removed_slice;\n\n assert(removed_elem == 1);\n assert(slice.len() == 6);\n } else {\n assert(slice[x] == 0);\n slice = slice.push_back(20);\n }\n\n assert(slice.len() == 6);\n assert(slice[slice.len() - 1] == 30);\n}\n\nfn dynamic_slice_merge_else(mut slice: [Field], x: Field) {\n if x as u32 > 10 {\n assert(slice[x] == 0);\n slice[x] = 2;\n } else {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n slice = slice.push_back(10);\n }\n assert(slice.len() == 6);\n assert(slice[slice.len() - 1] == 10);\n\n slice = slice.push_back(20);\n assert(slice.len() == 7);\n assert(slice[slice.len() - 1] == 20);\n}\n\nfn dynamic_slice_index_set_nested_if_else_else(mut slice: [Field], x: Field, y: Field) {\n assert(slice[x] == 4);\n assert(slice[y] == 1);\n slice[y] = 0;\n assert(slice[x] == 4);\n assert(slice[1] == 0);\n if x as u32 < 10 {\n slice[x] = slice[x] - 2;\n if y != 1 {\n slice[x] = slice[x] + 20;\n } else {\n if x == 5 {\n // We should not hit this case\n assert(slice[x] == 22);\n } else {\n slice[x] = 10;\n slice = slice.push_back(15);\n assert(slice.len() == 6);\n }\n assert(slice[4] == 10);\n }\n } else {\n slice[x] = 0;\n }\n assert(slice[4] == 10);\n assert(slice.len() == 6);\n assert(slice[slice.len() - 1] == 15);\n\n slice = slice.push_back(20);\n assert(slice.len() == 7);\n assert(slice[slice.len() - 1] == 20);\n}\n\nfn dynamic_slice_index_set_nested_if_else_if(mut slice: [Field], x: Field, y: Field) {\n assert(slice[x] == 4);\n assert(slice[y] == 2);\n slice[y] = 0;\n assert(slice[x] == 4);\n assert(slice[2] == 0);\n if x as u32 < 10 {\n slice[x] = slice[x] - 2;\n // TODO: this panics as we have a load for the slice in flattening\n if y == 1 {\n slice[x] = slice[x] + 20;\n } else {\n if x == 4 {\n slice[x] = 5;\n }\n assert(slice[4] == 5);\n }\n } else {\n slice[x] = 0;\n }\n assert(slice[4] == 5);\n}\n\nfn dynamic_slice_merge_two_ifs(mut slice: [Field], x: Field) {\n if x as u32 > 10 {\n assert(slice[x] == 0);\n slice[x] = 2;\n } else {\n assert(slice[x] == 4);\n slice[x] = slice[x] - 2;\n slice = slice.push_back(10);\n }\n\n assert(slice.len() == 6);\n assert(slice[slice.len() - 1] == 10);\n\n if x == 20 {\n slice = slice.push_back(20);\n }\n\n slice = slice.push_back(15);\n\n assert(slice.len() == 7);\n assert(slice[slice.len() - 1] == 15);\n\n slice = slice.push_back(20);\n assert(slice.len() == 8);\n assert(slice[slice.len() - 1] == 20);\n}\n\nfn dynamic_slice_merge_mutate_between_ifs(mut slice: [Field], x: Field, y: Field) {\n if x != y {\n slice[x] = 50;\n slice = slice.push_back(y);\n slice = slice.push_back(x);\n } else {\n slice[x] = slice[x] - 2;\n slice = slice.push_back(x);\n }\n\n slice = slice.push_back(30);\n assert(slice.len() == 8);\n\n if x == 20 {\n slice = slice.push_back(20);\n }\n\n slice = slice.push_back(15);\n\n if x != 20 {\n slice = slice.push_back(50);\n }\n\n slice = slice.push_back(60);\n assert(slice.len() == 11);\n assert(slice[x] == 50);\n assert(slice[slice.len() - 4] == 30);\n assert(slice[slice.len() - 3] == 15);\n assert(slice[slice.len() - 2] == 50);\n assert(slice[slice.len() - 1] == 60);\n}\n\nfn dynamic_slice_merge_push_then_pop(mut slice: [Field], x: Field, y: Field) {\n if x != y {\n slice[x] = 5;\n slice = slice.push_back(y);\n slice = slice.push_back(x);\n assert(slice.len() == 7);\n\n let (popped_slice, elem) = slice.pop_back();\n assert(slice.len() == 7);\n assert(elem == x);\n slice = popped_slice;\n } else {\n slice = slice.push_back(x);\n }\n\n slice = slice.push_back(30);\n assert(slice.len() == 7);\n\n if x == 20 {\n slice = slice.push_back(20);\n }\n\n let (slice, elem) = slice.pop_back();\n assert(elem == 30);\n\n let (_, elem) = slice.pop_back();\n assert(elem == y);\n}\n", diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/slice_regex/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap b/tooling/nargo_cli/tests/snapshots/execution_success/slice_regex/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap index 77961801bfb..5e306356553 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/slice_regex/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/slice_regex/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap @@ -23,8 +23,8 @@ expression: artifact } } }, - "bytecode": "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", - "debug_symbols": "zZ3bjtXWlkD/hWcePO9z5ldarSi3EyEhiEjSUivKvx9XTmoTsF2Wx8ESLwhCjZVdrLFtr7Fc3n+8+vGn73//+ds37/71/tdX3/zPH6/evv/hu9/evH+3/umPP1+/+v7Dm7dv3/z87T//86vl6ZeRv77+11++e/f0x19/++7Db6++cc3l9auf3v349NvOdYR/vXn706tvYvnzf1+/GgWMAcYBE4BJwBRgGjBznZFlIZAQSAlkBHICBYGSQEWgJhAxQogRcmCE1QOK2UBKICOQEygIlAQqAjWBBkC6EIgYocQIJUYoMUKJEUqMUGKEEiOUGGHECCNGGDHCiBF2YMTEM2Sy/BN6vfniHvn7a0ft8aWq/xk/bh4/bx6/bh6/bx5/7h3fl5vHl5vH15vHt5vH33//Wslj/NLP3/QeBEoCFYGaQAOgWAgkBFICGYGIEUGMiAMjNB9Qb044UQRqAg2AciGQEEgJZARyAgWBiBFJjEhiRBIjihhRxIgiRtS+EV4PKJbNO7ecQEGgJFARqAk0AOqFQEIgJRAxookRTYxoYkQTI5oY0cSIIUYMMWKIEQdt2cOeIa/YQE6gIFASqAjUBJrrkB4U5hNICKQEMgI5gYJASaAiUBOIGCHECCFGCDFCiBFCjBBixEFhDnksUEI/6fPX1tF6EKO/3Ph98/hz7/gHNfzLjS83j683j283j+83jx83j3/w/u1HnI7uz9/0B/sBJ1ATaAB0sB9wAgmBlEBGoAPPXJ+hXDYH54PIfwIlgYpATaAB0EENP4GEQEogIxAxwokRToxwYoQTI5wYEcSIIEYEMSKIEUGMCGJEECOCGBHEiCBGJDEiiRFJjEhiRBIjkhiRxIgkRiQxIokRRYwoYkQRI4oYUcSIIkYUMaKIEUWMKGJEEyOaGNHEiCZGNDGiiRFNjGhiRBMjmhgxxIghRgwxYogRQ4wYYsQQI4YYMcSIAUbYshBICLRvRNmjDVT0BjICOYGCQEmgIlATaAB0UJhPICEQMUKIEUKMEGKEECOEGCHECCFGKDFCiRFKjFBixEEJreWRtcqWDRQESgIVgZpAA6CDZnkCCYGUQEYgYoQRI4wYYcQII0YYMcKJEU6McGKEEyOcGOHECCdGHDTLyo9Qf3ITx7XNFjvIm19u/Ll3/INo+uXGl5vH15vHt5vH95vHj5vHz5vH33//tj/uYGj3z9/0B4X5BBoAHRTmE0gIpAQyAjmBDjybfkApGygJVARqAg2ADgrzCSQEUgIZgZxAxIgiRhQxoogRRYxoYkQTIw4K8yyPO1bHNu/cg8J8AjmBgkBJoCJQE2gAdFCYTyAhEDFiiBFDjBhixBAjhhgxxIgBRviyEEgIpAQyAjmBgkD7RnQ/UvtsUrsfFOYTqAk0ADoozCeQEEgJZARyAgWBiBFCjBBihBAjlBihxAglRigxQokRSoxQYoQSI5QYcVCY5+Oiaz7t89fW0X4Qo7/c+HLz+Hrz+Hbz+H7z+HHz+Hnz+HXz+H3z+Lvv31hk/mZi0c/jtO/vB5xBQiAlkBHICRQESgIdeFb+gKw2UBNoAHSQ408gIZASyAjkBAoCJYGIEUGMCGJEEiOSGJHEiCRG7Bfm0I/vXN0UZt8vzGdQEqgI1AQaAO0X5jNICKQEMgIRI4oYUcSIIkYUMaKIEU2MaGJEEyP2C3NI9wOS3kBOoCBQEqgI1AQaAO0X5jNICKQEIkYMMWKIEUOMGGLEECMGGBHLQiAh0MEx4vHQgdD8L5ZasdjN4/vN48fN4+fN49fN4/fN48+948ty8/hy8/j771/TxzneNvfZxf5+wBnkBAoCJYGKQE2gAZAeeNaPpZd5bSAhkBLICOQECgIlgYpATaABkBEjjBhhxAgjRhgxwogRRowwYoQRI4wY4cQIJ0Y4McKJEU6McGKEEyOcGOHECCdGBDEiiBH7hXn9Vp8/52N9LbGBjEBOoCBQEqgI1AQaAO0X5vj4kLhV6dlAQiAlkBHICRQESgIVgZpAA6AiRhQxoogRRYwoYkQRI4oYUcSIIkYUMeKgMK8ruMeBRT+BLq45D2L0lxtfbx7fbh7fbx4/bh4/bx6/bh6/bx5/7h3/YD9g/e+P8efzHyeIg/2AE0gJZARyAgWBkkBFoAPP/PkzbNartU1wP9gPeBHKg/2AE0gIpAQyAjmBgkBJoCJQE4gYIcQIIUYIMUKIEUKMEGKEECOEGCHECCFGKDFCiRFKjDgozGWPal7pG8gJFARKAhWBmkADoIPCfALtG1HyWHGUbSb3oDCfQEYgJ1AQKAlUBGoCDYAOCvMJRIxwYoQTI5wY4cQIJ0Y4McKJEU6MCGLEQWGu+gj1f7GpnQcx+suNbzeP7zePHzePnzePXzeP3zePP/eOfxD5v9z4++/f9seFQcfndzDkwX7ACWQEcgIFgZJARaAm0L5nvTxCU+fnO3l5sB9wAgmBlEBGICdQECgJVARqAhEjmhjRxIgmRjQxookRTYxoYkQTI5oY0cSIIUYMMWKIEUOMOCjM83gIz9o2bQMFgZJARaAm0FyH6qAwn0BCoH0jpp5/4n7lawMZgZxAQaAkUBGoCTQAOijMJ5AQiBghxAghRggxQogRQowQYoQQI5QYocSI/cK87jPp48Dy6S1s1xZAtR+jv+D4fvP4cfP4efP4dfP4ffP4c+/4++X+C44vN4+///6V5XFhIMvnty3V/n7AGeQECgIlgYpATaABkB94lvaAPv10078gIZASyAjkBAoCJYGKQE2gAVAQI4IYEcSIIEYEMSKIEUGMCGJEECOCGJHEiCRGJDEiiRFJjNgvzKn5fCJct/Y3V7L7hfkMKgI1gQZA+4X5DBICKYGMQE4gYkQRI4oYUcSIIkY0MaKJEU2MaGJEEyP6wAh7HFg0lw2UBCoCNYEGQLMQSAikBDICOYGIEUOMGGLEECMGGNHLQiAhkBLICOQEOjBinp+anSaf3Gt+bfHdS948ft08ft88/tw7viw3jy83j683j283j+83j7///rVH0V5/+/muV+/vB5xBRaAm0ABofz/gDBICKYH2PTOtBzSbg/NBuT+BgkBJoCJQE2gAdNCtTyAhkBKIGGHECCNGGDHCiBFGjDBixH4alHg8cla2P1jX+2nwDDICOYGCQEmgIlATaAC0nwbPIGJEEiOSGJHEiCRGJDEiiRFJjEhiRBEj9oOdyuPAsv62N5ATKAiUBCoCNYEGQPvB7gzaFzYf1VyyNyeA/U51BjWBBkD7neoMEgIpgYxATqAgEDFiiBFDjBhgxCwLgYRASiAjkBMoCJQEAkbMfmbRRZ9/Cnn9bW4gIZASyAjkBAoCJYEKQPvLcFnXVc+T25tHGM3+MvwMCgIlgYpATaAB0P4y/AwSAimBiBFGjNhffb5U92Z/7fkyYtcRv47EdSSvI3Ud6evIXEb215ovI9dnP6/Pfl6f/bw++3l99vP67Of12c/rs5/XZ7+uz35dn/26Pvt1ffbr+uzX9dmv67Nf12e/rs9+XZ/9vj77fX32+/rs9/XZ7+uz39dnv6/Pfl+f/b4++3199uf67M/12Z/rsz/XZ3+uz/5cn/25Pvtzffbn+uzP5dmXZVkAI4BRwBhgHDABmARMAaYBAzwQ4IEADwR4IMADAR4I8ECABwI8EOCBAA8UeKDAAwUeKPBAgQcKPFDggQIPFHigwAMDHhjwwIAHBjww4IEBDwx4YMADAx4Y8MCBBw48cOCBAw8ceODAAwceOPDAgQcOPAjgQQAPAngQwIMAHgTwIIAHATwI4EEADxJ4kMCDBB4k8CCBBwk8SOBBAg8SeJDAgwIeFPCggAcFPCjgQQEPCnhQwIMCHhTwoIEHDTxo4EEDDxp40MCDBh408KCBBw08GODBAA8GeDDAgwEeDPBggAcDPBjgAeiJAnqigJ4ooCcK6InrxTJgAjAJmAJMAwZ4AHqigJ4ooCcK6IkCeqKAniigJwroiQJ6ooCeKKAnCuiJAnqigJ4ooCcK6IkCeqKAniigJwroiQJ6ooCeKKAnCuiJAnqigJ4ooCcK6IkCeqKAniigJwroiQJ6ooCeKKAnCuiJAnqigJ4ooCcK6IkCeqKAniigJwroiQJ6ooCeKKAnCuiJAnqigJ4ooCcK6IkCeqKAniigJwroiQJ6ooCeKKAnCuiJAnqigJ4ooCcK6IkCeqKAniigJwroiQJ6ooCeKKAnCuiJAnqigJ4ooCcK6IkCeqKAniigJwroiQJ6ooCeKKAnCuiJAnqigJ4ooCcK6IkCeqKAnqigJyroiQp6ooKeqKAnKuiJCnqigp6ooCcq6IkKeqKCnqigJyroiQp6ooKeqKAnKuiJCnqigp6ooCcq6IkKeqKCnqigJyroiQp6ooKeqKAnKuiJCnqigp6ooCcq6IkKeqKCnqigJyroiQp6ooKeqKAnKuiJCnqigp6ooCcq6IkKeqKCnqigJyroiQp6ooKeqKAnKuiJCnqigp6ooCcq6IkKeqKCnqigJyroiQp6ooKeqKAnKuiJCnqigp6ooCcq6IkKeqKCnqigJyroiQp6ooKeqKAnKuiJCnqigp6ooCcq6IkKeqKCnqigJyroiQp6ooKeqKAnKuiJCnqigp6ooCcq6IkKeqKCnqigJyroiQp6ooKeaKAnGuiJBnqigZ5ooCca6IkGeqKBnmigJxroiQZ6ooGeaKAnGuiJBnqigZ5ooCca6IkGeqKBnmigJxroiQZ6ooGeaKAnGuiJBnqigZ5ooCca6IkGeqKBnmigJxroiQZ6ooGeaKAnGuiJBnqigZ5ooCca6IkGeqKBnmigJxroiQZ6ooGeaKAnGuiJBnqigZ5ooCca6IkGeqKBnmigJxroiQZ6ooGeaKAnGuiJBnqigZ5ooCca6IkGeqKBnmigJxroiQZ6ooGeaKAnGuiJBnqigZ5ooCca6IkGeqKBnmigJxroiQZ6ooGeaKAnGuiJBnqi7ffE8udPUah/PLb8wTRg5jqz3xNPGAGMAmb/keX5/Fn1a9B6MP95lPPK7M7Pmn2eGd9h9h9YnvVg9HPGF/D5NCuliDJEOaICUYmoQlQjagglC6KQG4LcEOSGIDcEuSHIDUFuCHJDkBuK3FDwKUYr5YgKRCWiClGNqCGULYgCn1SyUoWoRtQQyhdECaIUUYYoR1QgCrnhyA1HbjhyI5AbgdwI5EYgNwK5EciNQG7sl52XPzpHPBdECaIUUYYoR1QgKglV4INtVsoQ5YgKRCWiClGNqCFUL4gSRCE3mrgR+3eD6FpFnu1dF5FbShCliDJEOaICUYmoQlQjagglyA1BbghyQ5AbgtwQ5IYgNwS5IcgNQW7s382h/vGs59uzXhysKzOeI5vm9JZKRBWimlD79xqc/Wvsr/VOqUbUEGp/rXf2r7G/1julFFGGKEcUsteRvY7sdWTv/lrvjArkRiA3As1yoKNooKNooKNoojNsojNsojNsojNsojNsoe+r0PdV6Psq9n2hK4dCVw6FnC/k/MEnw/s8uuh6SbKhDj4a/owSRCmiDFGOqEBUIqoQ1YhCbgxyY9A5ZdD1xqAz0aDrjUHXG4OuNwZdbwy53ki0yk60yk60yk60yk60yk60yk60yk60yk60yk60yk60yk60yk60yk60yk60yk5Fbig5V6YqogxRjqhAVCKqENWIIufKtAVRyA1Dbhg5V6Y5ogJRiahCFDpXGlmbJ+o2ibpNom6TqNsk6jbp6L3s6L3s6L0c6L0c6L0c6L0c6Dgf6Dgf6Dgf6DgfyI1AbgRyI5EbidxI5EYiNxK5kciNRG4kOs4nOs4nOs4XOs4XOs4XOs4XOs4XOs4XugYodA1QyI1CbhRyo5Ebjdxo5EajWW40y41mudEsD1q1DVrRD1rRD1rRD1rRD1rRD1rRD1rRD1rRD1nRF7rfptD9NoXutyl0v00tjqhAVCKqENWIQm4IuaeihBwPSxJRhShy1qujsvTyv8ZR7TmhClGNKLIKKFR7CtWeQrWnzBDliApEJaIKUY0o5IYjNxy54cgNR244csORG47cQGWpUFkqdJdOobt0Ct2lU6GIMkQ5otC5MtC5MtC5MtC5MpAbidxI5EYiNxK5kciNRLO8X2BM5PEj4GLba4D9AnNKKaIMUY6oQFQiqhDViBpCNXKjkRuN3GjkRiM3GrnRyI2D5/C2/g31xJZpwMx15uA5vC8zAhgFjAHGAbM7PyPPh9rRzU8q9X45keVx1fT0scxbav+nomyWZ8q2P2vf+zXjlApEJaIKUY2oIdTBEzDOqP1/DX08JufpAblbqhDViBpCHTzz4YwSRCmiDFGOqCDU/qr/5aPG/pr/hAFHp/31/gmza9I8nmw0uTmz9f76+4QxwOzP6yLPj1CSxXaoQFQiqhDViBpCHTwN4YwSRCmiDFHIjUBuBHIjkBuB3AjkRiI3ErmRyI39tbeI+EvXW+nkKi0DUYWoIVSRp2X1wZMXzqhAVCKqENWIIk/L6l4QJYhSRCE3GrnRyI1GbjRyo5EbjdwY5MYgNwa5MciNIU9S6ylENaLIk9RmWRAliFJEGaLI07JGFkQJohRRhihHVCAqEVWIakQhNxS5ocgNRW4ockORG4rcUOSGIjcUuWHkSWpjiihDlCMqEJWIKkQ1oQ6qyMvP2BoPRCWiClGNKPIktYkFUYIoRZQhCrkRyA20zzpon3XQPuugfdZB+6yD9lkH7bMO2mcdtM86aJ910D7roH3WaeRGIzcauTHIjUFugB3XATuuA3Zc5+CTT19mEjAFmAbM5Z13XfZXhC/t0awMKJMrBfZZV2oIRfZZV0oQpYgyRDmiglBkn3WlFFGGKEdUICoRVYhqRA2hbCHU/t3VLx819u+tPmHA0elgZ/dlZtekl3aDV6YA04ABe2m6kH3WlRJEKaIMUY6oQFQiqhDViEJuJHIjkRuJ3EjkRiI3ErmRyI1Ebuz/9PzLu84rBfZ0dakFUYooRxTYS1upIRTZZ10pQZQiyhDliApEJaIKUciNRm4McmOQG4PcGOTGIDcGuTHIjSFuCNlnXSlBlCLKEOWICkQloopQZJ91pRxRgahEVCGqETWEIvusKyWIUkQhNxS5ocgNRW4ockORG4rcMOSGITcMuUH2WVcqEVWIakQNoXxBlCBKEQX2WVdqCEX2WVdKEKWIMkQ5ogJRiahCFHIjkBvkmWcrVYhqRA2hyDPPVkoQpYgyRDmiAlHIjUZuNHKjkRuD3BjkxiA3ru8Fr4wDJgCTgCnANGCu7wXrsgDm+q6Ogj1nXS7/vN7KkEarSyGqEUX6vcqCKEGUIsoQ5YgKRCE3BLkhyA1BbihyQ5EbitxQ5MbB2v3lPRBVcqeKaiGK7LeokbtH1AxRjqhAVCKqENWIIncWqZO7R9QTUYWoRhS5e0RjQZQgShFliHJA2f6Vgy3Lc6+yRXVLNaKGUPtXDqeUIEoRZYhyRAWiElHIDUFuCHJDkRuK3FDkhiI3FLmhyA1Fbii4i3u9BFgQJYhSRBmiHFGBqERUIaoRhdxw5EaQfVqLRtQQKhdECaIUUYYoR9S+8+u1wfMsW8iWSkQVohpRQ6iDp46eUYIoRZQhyhGF3CjkRqPzcqPzcqPzcqPzcqNrtkbXbI2u2QZdsw26Zht0zTbIjUFuDHJjkBuD3BjkxhA3fFkQJYhSRBmirl4fvt58ceZz48lPN4K3X7pu8D4v+au3ryW+oteSX9Frqa/otfRX9Frm63ktsnxFr0W+oteCjmWoWznqVo66laNu5ahbOepWjrqVo27lqFv59W715/qn//vuw5vvvn/7068r8/SXv7/74bc379/9/cff/v+X57/5/sObt2/f/PztLx/e//DTj79/+Onbt+9/ePq7V8vTL0//8/U19Ot1F8LW1/M0oarpr9ccHOuf/3pHt8vr9nz649O3KFPyev3F1leyvpp/Aw==", + "bytecode": "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", + "debug_symbols": "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", "file_map": { "22": { "source": "pub mod hash;\npub mod aes128;\npub mod array;\npub mod slice;\npub mod ecdsa_secp256k1;\npub mod ecdsa_secp256r1;\npub mod embedded_curve_ops;\npub mod field;\npub mod collections;\npub mod compat;\npub mod convert;\npub mod option;\npub mod string;\npub mod test;\npub mod cmp;\npub mod ops;\npub mod default;\npub mod prelude;\npub mod runtime;\npub mod meta;\npub mod append;\npub mod mem;\npub mod panic;\npub mod hint;\n\nuse convert::AsPrimitive;\n\n// Oracle calls are required to be wrapped in an unconstrained function\n// Thus, the only argument to the `println` oracle is expected to always be an ident\n#[oracle(print)]\nunconstrained fn print_oracle(with_newline: bool, input: T) {}\n\nunconstrained fn print_unconstrained(with_newline: bool, input: T) {\n print_oracle(with_newline, input);\n}\n\npub fn println(input: T) {\n // Safety: a print statement cannot be constrained\n unsafe {\n print_unconstrained(true, input);\n }\n}\n\npub fn print(input: T) {\n // Safety: a print statement cannot be constrained\n unsafe {\n print_unconstrained(false, input);\n }\n}\n\npub fn verify_proof(\n verification_key: [Field; N],\n proof: [Field; M],\n public_inputs: [Field; K],\n key_hash: Field,\n) {\n verify_proof_internal(verification_key, proof, public_inputs, key_hash, 0);\n}\n\npub fn verify_proof_with_type(\n verification_key: [Field; N],\n proof: [Field; M],\n public_inputs: [Field; K],\n key_hash: Field,\n proof_type: u32,\n) {\n if !crate::runtime::is_unconstrained() {\n crate::assert_constant(proof_type);\n }\n verify_proof_internal(verification_key, proof, public_inputs, key_hash, proof_type);\n}\n\n#[foreign(recursive_aggregation)]\nfn verify_proof_internal(\n verification_key: [Field; N],\n proof: [Field; M],\n public_inputs: [Field; K],\n key_hash: Field,\n proof_type: u32,\n) {}\n\n// Asserts that the given value is known at compile-time.\n// Useful for debugging for-loop bounds.\n#[builtin(assert_constant)]\npub fn assert_constant(x: T) {}\n\n// Asserts that the given value is both true and known at compile-time\n#[builtin(static_assert)]\npub fn static_assert(predicate: bool, message: str) {}\n\npub fn wrapping_add(x: T, y: T) -> T\nwhere\n T: AsPrimitive,\n Field: AsPrimitive,\n{\n AsPrimitive::as_(x.as_() + y.as_())\n}\n\npub fn wrapping_sub(x: T, y: T) -> T\nwhere\n T: AsPrimitive,\n Field: AsPrimitive,\n{\n //340282366920938463463374607431768211456 is 2^128, it is used to avoid underflow\n AsPrimitive::as_(x.as_() + 340282366920938463463374607431768211456 - y.as_())\n}\n\npub fn wrapping_mul(x: T, y: T) -> T\nwhere\n T: AsPrimitive,\n Field: AsPrimitive,\n{\n AsPrimitive::as_(x.as_() * y.as_())\n}\n\n#[builtin(as_witness)]\npub fn as_witness(x: Field) {}\n\nmod tests {\n use super::wrapping_mul;\n\n #[test(should_fail_with = \"custom message\")]\n fn test_static_assert_custom_message() {\n super::static_assert(1 == 2, \"custom message\");\n }\n\n #[test(should_fail)]\n fn test_wrapping_mul() {\n // This currently fails.\n // See: https://github.com/noir-lang/noir/issues/7528\n let zero: u128 = 0;\n let one: u128 = 1;\n let two_pow_64: u128 = 0x10000000000000000;\n let u128_max: u128 = 0xffffffffffffffffffffffffffffffff;\n\n // 1*0==0\n assert_eq(zero, wrapping_mul(zero, one));\n\n // 0*1==0\n assert_eq(zero, wrapping_mul(one, zero));\n\n // 1*1==1\n assert_eq(one, wrapping_mul(one, one));\n\n // 0 * ( 1 << 64 ) == 0\n assert_eq(zero, wrapping_mul(zero, two_pow_64));\n\n // ( 1 << 64 ) * 0 == 0\n assert_eq(zero, wrapping_mul(two_pow_64, zero));\n\n // 1 * ( 1 << 64 ) == 1 << 64\n assert_eq(two_pow_64, wrapping_mul(two_pow_64, one));\n\n // ( 1 << 64 ) * 1 == 1 << 64\n assert_eq(two_pow_64, wrapping_mul(one, two_pow_64));\n\n // ( 1 << 64 ) * ( 1 << 64 ) == 1 << 64\n assert_eq(zero, wrapping_mul(two_pow_64, two_pow_64));\n // -1 * -1 == 1\n assert_eq(one, wrapping_mul(u128_max, u128_max));\n }\n}\n", diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/slice_regex/execute__tests__force_brillig_true_inliner_0.snap b/tooling/nargo_cli/tests/snapshots/execution_success/slice_regex/execute__tests__force_brillig_true_inliner_0.snap index 8c772363593..7e835c29c42 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/slice_regex/execute__tests__force_brillig_true_inliner_0.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/slice_regex/execute__tests__force_brillig_true_inliner_0.snap @@ -23,8 +23,8 @@ expression: artifact } } }, - "bytecode": "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", - "debug_symbols": "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", + "bytecode": "H4sIAAAAAAAA/+1dXYhl2VU+5/7WvVW36lZ19e9093T1z8xkJpPcqls/PUxCmrG6x0DeVEYDQmq6M0EfEgkSEdS5KA74IPgQ9EEHhYBCICioqCAoDvgXlLwE8ckf1CDEhxhwNDFiTvdd93711Xd2ndO1dtWp6buhqHPP2mf97b3XXnvtdfZJk2lJx/8byRGKIfl2+9H/zvh3DeD17/7dGf8eHK2sd4iuJ/7bg82XOkI+R/6HnTHONA7+geGPpP/BuJmTj46m+FEWozv33b95uF5Jpv0jlvzWfjHlPxOQ2frO94ymsMS5bbOyO4ojm+G/G4f/ydi9F4f/Cf5X4+DfMPzfGwf/ZjZesrHybmPan7ivpW70tnfUWPHDv7PRAx0lQANlayRRdDlMiV4CfCDM6HeJV+++mRI944f1Y21humsKXvsCxn2kKeg0BR2FC+0Zt5Fj/1vvCb64f7TgvudYLto/jH5X6ClG/2gRP3ntZrprC177AtYI6NWxTbeYL6OBtOfi6LBwmxr9rtBTjDadI35YP9ymHcFrX8BaAb062vGXmC+jgbS7cXRYuE2NflfoKUabdokf1g+36bzgtS9g1oZLOXpFnc/HkXFgMi6M8TVARiVHjerjdVaadO9D4/+ZrN9pTJ/J0yve43mrLvhRumuS7hYi664ndLcQ0F0PYHaNurN7u4mf7poFddcm3fUi624xOai7XkB3iwCza9Sd3ftY4qe7dkHddUh3i5F1tyR0txjQ3RLA7Bp1Z/e+P/HTXUfw0xH8eK6tDP9yHPxD00Vf6AJlMvo9oac057/hYpjR6iZR5+D1kGyhdu4DP6iDPFz9krg6AhajTZcCciP9XoBXJUfqqJOaI66GIy7zZ6ytzgDMr63WN033q8nBYrCzRBth5wDWJNh5gLUJdgFgHYJdBB4sZmSwS/Ac9iUudfqNOnyo2+YUL9dLiB8cg2cJhm12jmBoM88TbAVgpgs1D3L8N04/mM6D1g9wHkSaPA+uAgz7UJPuvTn+7zEPrgh+1HoqddPPzusdIa8f/o0Nw382Cv7tCf/n4uCf7B+cj4P/k4b/Qhz8Ez/nYhT8wz3DfylO/5zsjz0VB/9EP5fj4N8y/FfitO9EP1ej4N+4b/ifjsP/A8N/LQr+zQn+tTj83zb81+Pg3zb8N+Lgn7TvzSj4tyb2+VYc/ifzyzNx8L9h+J+Ngn9n0j+fi6P/Cf73xcE/0c/zcfQz2ZN8IQr+4cR+vj8O/kn/fDGOfib24QNx8E/yRz4YRz+3bd0wSKbF1ipGex3u+60N7t9PiV6S6LiK0e8Sr85rlUlcZZ34Yf3wXsKG4LUvYLyG2BB0NgQdhWvVEddZR1znHHGdd8R1wRGXp+4vVpSvS464nnLEVXPEddkR1xVHXJ768uwTVyvKl6edaDjietoRV8sR15Ngv6454vLsE55j29PmrDniehJsznVHXJ4+k6eduOGIy9P/8vRNqmoLb1YUV1V9zKr6cp64PMe2Jy7PsV1Vvqo6p81iCuVwzWIKJ8fXLUdcz1QUl6fP5GkLPdcwnmPIs38964jrOUdcnva+qr6cZ6xjtt4uh+t9jrg8bU5V59qqrh9nfmE5XDO/sByuqvqFnmt3z3b0tBOefTV1xOWpr6qu3atqJzx9E0/de/YvT748936fhD2K5x1xeY4hz7HtOYbWHHFVdd5+wRHX+x1xzdbuJ9e/bjji8rT31x1xedoJz3jhi464ZnNtOVyzNXI5XLM18snx5bkW9bT3nv2rqnvlT8JawXN+nHPE9QFHXE9CDuVsTpvNaadlTpvFfcvhSh1xzeK+J6evWdy3HK5Z3LccrlnctxyuNUdcVZ23P+iIyzNWW9W4ryculnFV4FoRuNS5TfasOtcnw3Vn/HtwtLJhvKrzsbGPny0g20DIlp29aed6/dhnf+TTP55QadPvu6PpdZrsPwQu+92n38tAEAVhhSLTX95PcvLhAHV4srqu03VN1ME/vv9lgZsPfnxlrMHIB7YPVogPpoW/8VAvbAc7ZK1J9e+RDJEOSpQyhA72cqS9WdXDEHFApzn/DRfDjFY3idr31kOyIf9sdPFAPR7jCtdSSVyRD0WdtGk3IDfS7wV4VXKkjjqpOeJqOeLiAy7jtNVw8rEEPCzEijoYpE6wIcD4gMtNgPEBl1sA4wMut4EHPuByB57DvsSlTr9Rh2UPuMT+tkEwbPMhwTCAvEkwHNemC3OU0GbxmI01T5qc1oY4FzLNrNSoPl4nyXSutHufGXd2dcAltlVd3ONxog6vV7obkO4ifWRjoru20F0zydcdHvbdFrqzez/hqLuB4MdwdQQuddDokuCfDySPNLdshOTGA8CXCsgWxaFHA4IGwn7PAUFuhHYO01V26O33z5IzzDTvjH8PjliUM1wXcmQFByK2Azv0Vv+tCsjAkw7Wi8zXVkr0kkQ70HavS7w687MeGuzIY4101xK89gWMd+rVV5Jago7C9YwjrhsR+Cry1bSqfRUrUj8PfhVLTZ5lv4p1mZ7jOSABnUf6SlRhnbdJ55H6wDo7ScZPXl9WTnSbdI6wkHPCOo/0pbABz9s4/yg5alQfr7PSpHu/FXAElV7V18D6yUGb3Q7ork66i/QFrInuukJ3nYDucDHQFbqze7/tqLt6Qd3xl9RiBQhNDvWVnm5Ad0W/0vMHjrprCX4iLxq2qvqVHuW/F7XbRuu4vjaoZAu1MwaM32tf6UFdc2Ba8arkuOKok2cccd2oKF8GOy5bEWdHsnzANSXYkPhCGAZcWwTDgCsH3rcBhn2biwqqmp6yueHl1hQv10uIJrYtB1XRTnNQFdfOHFTFHV0OqqJcx7T7PJmXLfsE52WkyfMyZqvYdVaadO9fHOflVcGP0h0HVc9F1t15obtzAd1hhptdo+7s3tcddTcQ/BiuCwLXqsC1JPi3Z9XXd2IEVZXcmO10sYBsUYKqeVkR9nsFCHIjnM9huspBVZP3XQpIRnLyZECSO7La3UBDvUQyWP1vkwyRHDYpg9GK7DRszxYYj11mC4yA3Eh/tsCIy9dlR1y8WMEskxh2ZzUK/mosVjggfJTFiump7GIF7QsvVrDdebGC8wEvVnC+4sUK2mGrF3tT0uhaW+A8zxusWalRfbzOSpPuPTdGohxunov4Ho+1FcGP0h0vViJtbgQzQFpJvu6KZoAMHHU3EPzYddmU7tCiGv3uGIsVJTfawfMFZKtESjc2QjuH6dOQ0v3ymEgnOShXbEc/FXJkRaV046TCGSAfIRlOYsHVyZHJh/ZwPbJsw6o6zjWon+b8N1wM45TxSA5dMGUc+Q+lDrMNOUoa8jHt0A15AlVyI/1egNfYKeMxcKkJ9Zh2PCbOi42XRqKDCxxpxfGNcxwHsX4w4LyUjbTWBD9FotSxgk4mx7LQXT+gO1wYLAvd2b1POOpORaljzwXsxyCvyp5ZW+L8eNyO5bLg9cQdS/V7F34f1slWcpiuomPJq2eEdYQ83p0gSQ53CIx+Nzmo6xgOwQrxw/rhKMmq4FVt9fEEhHpdJp3HiTKFt/qUHGW3+j4XMKJKr2rF20/yx5TSHU/ekYzWRHcXhO7OB3SH23oXhO7s3s846q5WUHc8eV+IrLuLQncXArrDbVC7Rt3ZvbccdTcQ/BiuSwJXaHJF/u1Z0zUeSBFjclVy40FFTxWQrRKTKzbCxRymqzi5FjH0kfIMBqwfHHBIkwccdhDsEE269/kKGPpLkXX3lNDdpYDucEDZNerO7v1aZENv+rkaRT/lt6p4qxy3qvhlZdyqQtm4qC0nkzfT66faU7xcj3nFPsZbTtimvOWE25i85YRbwrzlhO1i9azN8KtYMfr0tTE+7NNI03irUX28zkqT7v1OoE9fhefq4h736SuCH6U7dl6uJXF1t5Yc1N21JF93awCza9Sd3ftDR90NBD+G67rAdUXgWhL827Om6xsAi+G8KLmvA80bBWSLsuWExpgNPRqFWnKwEdZymK7ylpPJ+w5t11wmmnfGvwdHLGq7hvNFrA4ORGyHeyMtw19UQIYiTmGklcHEkF0O6A95qwk92TXq1+79TQWcwlhtanJcEbq7HNAdTmZXhO7s3lcjO4W9RNsv9d/o8D2OfF1xxHXVEdeaAy7rT5j39iQ40SZvWScaJ2d2onGyZif6JsDYib4FMHaiUS6rF7fNpjbg2TE+tAFI03irUX28zkqT7n0jYAMwylRkm/qW4EfldF0nGNqrGwRDX+YmwdYAdovkMxr/M5Yvy9O6OpYvbr6Y7zi7SbBNIXPRcWbylh1n2O95nKE943GGJ0vxOMOTk3icYbtYvaq83G+81ag+XifJwZf758fKUOOs7AEgTcFPCBcvnLC+8dfKqd/KkWcZ5PnTcV9Sp3Rx+530AQN10CnWx2uU1+6dD7QfjrW6uBdqvzrBlJ+p7CQfUIJ2skGwNYAZbbSHan5j/xfb9ArBcJxz8ARlXSPYe3GcPxd5nCvdcVDqpMcY667oGBs46m4g+DFc8wJXU+BSR1vbs6brBYDFCEopueeB5kIB2aIEpdARRANhvxtAkBuhm8N0lYNSJu/L5ESe5NHWxpN6mSMrr460DB+pgAxq0uGgVD0SXynxkvcyDC+qGkIO1K/duxswZGUXVcuCn8jtthn5hZpJ3mBT6AJl4hfH2Oao/4aLYUbruHK8lWyhdsbJnse5wtUsiSvyMblDHlNKbqTfC/Cq5EgddVJ1XOplt2Ma+4WPik5BHpYjdFT0XsA28hjme6Ggs9ULnbBaxFYgHe6jHrhajri6DriqdgR9XjAsK3xc/FGCznhcfJlgGDrfHAxDZ5yDYT2AcTBsEWChoLPVq8o7I+wfFX1n5Kcd/aNFwU8f8BlsnmBorxYIhn5Pj2C4dlkk+YzGz49lyvB8kXztOItz36Bzj2CbQuai48zkrULQGQM8PM6wXfjzHDjmY4wz0weOM6RpvNWSg7YEddmke78SGGfqyHy8x2NpTvATwsWBEaxv/LVy6ndy5Hm7YNCZ2y9SkCbYfkr+su33BcegMwdUEYZ2MuSfdgiGdpJ9d7STRhvtoZrfUtKDwb4E9vSrgeeNV9UnOICKdoI/w4LtU1UbXScY2uiyn84xecvaaOxTbKPRRrCNRtvGNhrHTejTOVbvuNZDaowzzayUHeN/5jjGQzZX4cKxwzZd2eiawM/y/GXARuPz3H6xNy1U+yFN9mWLtt/fOvqyC4IfZaPnCBbaUEQbzT4w2mijfZiNNT5UjOKo9ldtGnL8KvYhP6bbvEN+jLdactAG2nWSTPuJ3fuHQD8pGzNqCH6U7nhj8KQ3VVl3RTdVv+aou4Hgx3CFPmmIuNSagX2ISGuGjZDcaqMyJNuxbAym9JsnSuVgMtOnYWPwP2mhH2vzqsgnstTGINZv58jwXxWQYT4BQzLyp79z+5HBykp9NNUDO8ZIv0n1/3esJxxw9r9xBD7f2Nlbf2O498be1t6DB5v391hPWamBnrzp7+0Mb9/f2Ly/8/rWcG+4fSj9zCC/S85C6BMpp/XTPO1xB4j1iZSjnuir6GA78KZbx5GOyvzx3KDoC1w251if48kuSaoT/JkHebA+XmeFFxYXAn1OZfnMB3SXCn5SwYPadLs3evRf6bqXgwt1gY7K7kjLujmulPWfp5v7cbLNYJzHs5E13eBeTA7qC8e00Td9YV+wZ01um0/YVmalMYoix3qmz3cgyHOgH472848B/97x6LrwBpTxVnYD6sXA2FLti/d4bPUEP8oG86Id7SaPI1yE2j1lUw4Ltm43db2smA+N9UL2BW2CJZYtJQfHqD2rAgR8eOE8yKno7I4e/ecNth8Ae/Gh5uH0lO3itQbPE8wL25mTOAAT+e+TbNiH8CDFh8+PpjDMYM1KYxRFDmlncByxncF2443u2Btw6tN6yqeoJQdtUOjTeh8L2BnsW0WSXRYFP8rO8GY29nPDoXTOSbmGB20Q9rE5qo+fvk4EfuYrz2a9VtBmvUbjvidkYT/jU2A3Pk7Ph9YtJ51R/7ifxfzEMa1bsN9aG/EmUVZ2CYZjjNcoaI+Ndvb/c9Ru6hOYqk07BFP6jbsBOG1vG4fY3j3Bay05OPb32VC695lAe5fd8Fe6U+19d7Qfhu39KsGwvbuEE9vbaKv2Rl3wJtJp9Ud/ytEfVeuNZrK/3X4R7OAo4D+xHYyUND3Rr8UBUL9qPqlRfbxGee3eW47zsPrig4rfsB3EsbZLMLRhbAfRLqAd3B7/sLaJ85nD9W3jAz9VmBCPeBYlJ6niWYvzBMNj4bDfcuHYLMpbNmkBX6g4TzCMd14g2BmAXSQYnmNqx7WpzdOqfZqSN72Lfpry1wPjqeym96rgx+hZW/0e2KsvNPfrMM65tetbPdIXFh4TRhthOCa43+OYKNvv8StHj5tQeY5gMcYEziNsE3AO5yQnnE/5JBmcT4121if+qJlPezlAeyVA+0yA9qqgvZQc1Ik9E7evTse79VUc76tCplpy0BZgP2/SvT8JjPcz8Fxd3OPxrtqQ/ZOvwHh/J+CfHHcSmPLbQy/FFPXb/8rRP+E3grPCNiAr7J+grdklGNoHtmVoHzCJqEP+SZyjU9dfNz7wNLaEeMTTshoEw1MV+AMkeKoC9lsuyk6bvGXtNM4plwmGc8oVguGccpVg6GfZ0ZsqEcvqVWU9xS+RF11P/XNgPKkXFFWST1/orkH0rK2+Cfbq38heoX7ZXqF9OK645qKQp2xc8+uO+l0Q/BSJK+Ecs0swnPPYXuGch/aq0TpcDtQdfyhkHnCFdM17Ge+CLjlhFuMlPDZj72uruS60r110rvuO4772RcFPkRgV+mjc57DvsL+LfcdoY99RvjbPwRizYB8T59lVguE8exZo2zyr4mN8PPdpjY8tjWX0iI+tCH44D+7amF727wzpF9uW42Ox8uVMVpWcjDR5PV80OfliQL9l1/MtwU8Re472dpdgj7NPsN46XA71UlRKdFo59TlWYfVvgi5DL6nx2OQk/jvj34MjlpR0o3JzkLdacrAd8aX1Jt17PtB30C+ui3uhscnxlJA9Rx+L+xz2HY4FYN8x2th3OK6r7DnuI/FcohKyVVwX/ZBtoo19hvdMUoDxnhzqpEcw9eJPkXxO6y+nPZ/zlUCfLbsv2hT8qP2ANOe/0eF7of047mex8jnZ1s7yOR8/n/P7An3OI5/T2ght9e7o0f+H+RI0H84Bn3XxrB22wb7CK+0pzo+Tb4R64hwMg/0o+FY/TM+HbM1pzcG4f0y2Bsca+1aqT/B+vbIryu/KcP0ktVuMHIyTHuePe+jCZwPtfVw5GGocq/ZmfwLbG3MwuL1RF3wi5knHtIy3sjGtNwPtpnLk8R63m8qR5z2OXwI7+HOkX7TvbAdPaw7GLwT0i325yB4Hv7iZFc8cDLaDaBfQDn6Y1ncYz+B84UjfkJ20m/pCDdI03mpUH6+TZNpudu+XA+2GMZu6uMftVhP8nKb8lTmCqfhjKuh45q9gH5vlrzwqZfNXvugY71oN8KP6e1aWBL88j570N4XPkSxFvyn8uwHdYpvUxb3QPIq6UuM5z/7WBf/87obVuSieT5P9c9Il4FXh5u/3rhxS/wzVPyPqI1+cd49tURc8GL5FQU/tk6F+zB7h+yP2fMbHP9H7HTiPNMbPhL4uEPldmklfNzmxr6u+UhN6WQWZmnTvzx3tiPryA9utvwOf8a8D+xJsS2LvS6h9n9C+RNF9n6846nde8FNk7Yxz8i7BcN3BvgGuO3BvuD8eM9Y2cT7HXD4vhuPtmBfDvgTmxagzAqwov8fkLev34JjkvBj0CTgvBucNzovB+Y7zYrD/Wj1rM96nuDP+PThiCc3Nam+k7Nz87457NeyfID1rq2+BvfoPsleoX7ZXsfWr5oOQfovOB9901C+/85iVInl8aE93CYbrQbZX6BegvZpvHy4H5vbhWEQ6rZz63Hes/v8F9lHRB+KxGftdUbXORpr4HiT3q9A6u9Geyst9B/fu6+JeaGxyO2PfuTvaD2M/DGHYdzh/HPuO0ca+o/YreQ7GmGKfYEXzxTEnvB+Izdgzpz02cy7QZ8rGZpYEPxyzfBb2fi6RfrFtOWYZ+9A+FctX72mVjeVfC+g3heeOGrMM2fNQXvbj7N3cbh8uhzoAPSU6rSSs6ybVfwF0yfYccxV4bJ50XgznyBbNi1kP9J2yObIqJ7qIPeecJoRh31kkGPYdo419R+XFsD3n/VqEqXf/Vawd/ZAPt/Nle9y8mAWC5eXFpMRPkoTHfEr4sT7qlg9FnRO8qZyIdg4d5ZNkZXf06D/vxb8O9vyj7cPpqX3+vIOD0yScyxB57h2G5kHkf5lkQ18jFAfDXP6sNEZR5JDnqOzbxxzt51+N3ePaU1dxoFDuTNE40A8FbGnZ3BkVl1H77T2CYT/nM77UuQY8HvAcFRU3Sum3iucpvvLOUXnQ1vWygueoPGhr+llReUH3xs9yrgHTfw3Wb5xTyO/pZeW0z/efdpzv64KfnnguzfmfEI48OqG82ZYjHfb/kU6MHMms3B09+q/mVsNRldwyjhkUzS170zFmkAp+UsGD8nvMJihdsz2051R+SVZ2R/tltfq/Cr7KWzlrmDQJ7wVEjhENQ/pS8U51aDv6sg+fH+3n1eTISmMURQ7pc+zLpx7t5x/buJMci64nYyvk+yJvNaqP1w9lonufD4wt1b54j8eWOihe2eCUYGg32c/GcWS/sR/xeZPqHYYM/9ttXS8r6Ce8TesDlfPJ9ulLMGZ/I7DmZx8gdryoDbpTMQz2AdpCVpTX7v3mMfkAKTzH8SJ13q5a8xdZr2c6+WNqt5rgq+wHP94r7f37J9De5teo9mbf/CjtreIlnIOMPOftMyCPMc6s39za27m/t7O+/tLm+ic317cOO7N+Es8aTeE4x2alizCqg/gMVxtg3QK4ugFccwFcnYK4UvF8XfDaGF9buy5Q/Tvj+4OjlaHxMz8K82/0JznTAEtz/iMuvGe0uoTL21cKyYb843jn+tzOCtd8SVwn2aYoN9LH31gf+3WD6i+K+gtCXuszS4L2JGYCsHmiszz+bXME4zI+mlT/H2F+fEgLnrHn+4J+j+gjLUWfx3Zf1O+L+plN//sxj2j/sI3Y/pltRF2ovtyk+v8K/t7XKLenIehl9b4F+VBZmQNeHPvrhsmG9k/ZdqOvbLtdR+Z1GOK1LXhVOi5rL9uj/ffUXIN6ahPtffMcwdBGNIiOjVHsa4jL+GhS/f+mcafmTWUfsc2YVpE5tahtzvr2N8Y8TuI/QNtzDsJxlI3x/wcKsS/JskUBAA==", + "debug_symbols": "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", "file_map": { "22": { "source": "pub mod hash;\npub mod aes128;\npub mod array;\npub mod slice;\npub mod ecdsa_secp256k1;\npub mod ecdsa_secp256r1;\npub mod embedded_curve_ops;\npub mod field;\npub mod collections;\npub mod compat;\npub mod convert;\npub mod option;\npub mod string;\npub mod test;\npub mod cmp;\npub mod ops;\npub mod default;\npub mod prelude;\npub mod runtime;\npub mod meta;\npub mod append;\npub mod mem;\npub mod panic;\npub mod hint;\n\nuse convert::AsPrimitive;\n\n// Oracle calls are required to be wrapped in an unconstrained function\n// Thus, the only argument to the `println` oracle is expected to always be an ident\n#[oracle(print)]\nunconstrained fn print_oracle(with_newline: bool, input: T) {}\n\nunconstrained fn print_unconstrained(with_newline: bool, input: T) {\n print_oracle(with_newline, input);\n}\n\npub fn println(input: T) {\n // Safety: a print statement cannot be constrained\n unsafe {\n print_unconstrained(true, input);\n }\n}\n\npub fn print(input: T) {\n // Safety: a print statement cannot be constrained\n unsafe {\n print_unconstrained(false, input);\n }\n}\n\npub fn verify_proof(\n verification_key: [Field; N],\n proof: [Field; M],\n public_inputs: [Field; K],\n key_hash: Field,\n) {\n verify_proof_internal(verification_key, proof, public_inputs, key_hash, 0);\n}\n\npub fn verify_proof_with_type(\n verification_key: [Field; N],\n proof: [Field; M],\n public_inputs: [Field; K],\n key_hash: Field,\n proof_type: u32,\n) {\n if !crate::runtime::is_unconstrained() {\n crate::assert_constant(proof_type);\n }\n verify_proof_internal(verification_key, proof, public_inputs, key_hash, proof_type);\n}\n\n#[foreign(recursive_aggregation)]\nfn verify_proof_internal(\n verification_key: [Field; N],\n proof: [Field; M],\n public_inputs: [Field; K],\n key_hash: Field,\n proof_type: u32,\n) {}\n\n// Asserts that the given value is known at compile-time.\n// Useful for debugging for-loop bounds.\n#[builtin(assert_constant)]\npub fn assert_constant(x: T) {}\n\n// Asserts that the given value is both true and known at compile-time\n#[builtin(static_assert)]\npub fn static_assert(predicate: bool, message: str) {}\n\npub fn wrapping_add(x: T, y: T) -> T\nwhere\n T: AsPrimitive,\n Field: AsPrimitive,\n{\n AsPrimitive::as_(x.as_() + y.as_())\n}\n\npub fn wrapping_sub(x: T, y: T) -> T\nwhere\n T: AsPrimitive,\n Field: AsPrimitive,\n{\n //340282366920938463463374607431768211456 is 2^128, it is used to avoid underflow\n AsPrimitive::as_(x.as_() + 340282366920938463463374607431768211456 - y.as_())\n}\n\npub fn wrapping_mul(x: T, y: T) -> T\nwhere\n T: AsPrimitive,\n Field: AsPrimitive,\n{\n AsPrimitive::as_(x.as_() * y.as_())\n}\n\n#[builtin(as_witness)]\npub fn as_witness(x: Field) {}\n\nmod tests {\n use super::wrapping_mul;\n\n #[test(should_fail_with = \"custom message\")]\n fn test_static_assert_custom_message() {\n super::static_assert(1 == 2, \"custom message\");\n }\n\n #[test(should_fail)]\n fn test_wrapping_mul() {\n // This currently fails.\n // See: https://github.com/noir-lang/noir/issues/7528\n let zero: u128 = 0;\n let one: u128 = 1;\n let two_pow_64: u128 = 0x10000000000000000;\n let u128_max: u128 = 0xffffffffffffffffffffffffffffffff;\n\n // 1*0==0\n assert_eq(zero, wrapping_mul(zero, one));\n\n // 0*1==0\n assert_eq(zero, wrapping_mul(one, zero));\n\n // 1*1==1\n assert_eq(one, wrapping_mul(one, one));\n\n // 0 * ( 1 << 64 ) == 0\n assert_eq(zero, wrapping_mul(zero, two_pow_64));\n\n // ( 1 << 64 ) * 0 == 0\n assert_eq(zero, wrapping_mul(two_pow_64, zero));\n\n // 1 * ( 1 << 64 ) == 1 << 64\n assert_eq(two_pow_64, wrapping_mul(two_pow_64, one));\n\n // ( 1 << 64 ) * 1 == 1 << 64\n assert_eq(two_pow_64, wrapping_mul(one, two_pow_64));\n\n // ( 1 << 64 ) * ( 1 << 64 ) == 1 << 64\n assert_eq(zero, wrapping_mul(two_pow_64, two_pow_64));\n // -1 * -1 == 1\n assert_eq(one, wrapping_mul(u128_max, u128_max));\n }\n}\n", diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/slice_regex/execute__tests__force_brillig_true_inliner_9223372036854775807.snap b/tooling/nargo_cli/tests/snapshots/execution_success/slice_regex/execute__tests__force_brillig_true_inliner_9223372036854775807.snap index 0a870567be1..cba92d0338c 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/slice_regex/execute__tests__force_brillig_true_inliner_9223372036854775807.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/slice_regex/execute__tests__force_brillig_true_inliner_9223372036854775807.snap @@ -23,8 +23,8 @@ expression: artifact } } }, - "bytecode": "H4sIAAAAAAAA/+1de4xkWVm/9bjdXd1d0zU73duPmempntldFhZ2+jEvhMhEMEYhBg0rkY2uw+yuGtDgCgZIiKUSMAiICasJqwGUuBFFQiKaGDCGKCFZUZdgNqDwByKGBIy4fwAmbuT23q/qV7/63W/unT6nqmanb1KpqnvO/d7nO993XreWDK5a/t1MDnAZkA8vPP3dyv/Xobzxvc/l/P/2wa6dFuENCf/S9rlzLcFfQPr3WjnMWhz42wY/kvy3Z3M4L+kN4CMvhnfue58F+L2YDOwjFv+mv5j8H3N4Xsh5fdVCMa+1YLRcuKh4DQf/4m4L5BeB/h2D34xD//MN/kwcW+jb2lwc+HsmD2tzSQ6feTL87fx/CvVrBd8Gi8sM1zzBCu3HPd6QfrPtDtVnGRTBmq0IqyXKYuh0xuEb8bcdWhUftYAyqQeE1QgIy/zFUjJqBybDyHrcNj6s7TUFH0hbPRn1FfY7yenGe3fl39n/n1kYPFNkOzOO7FJBT1s8V8VXIJ624OegsFoBYJkNLECdGLFcOxJ80/ci8cs8tUl289cpO8Q1T7Bi+X/FG9LPtrwI9KAMimAtVoTVEmUxdLrg8I342w6tio96QJk0AsJin426M74jy77vs629NAUfSFs9GW3f9ju7Urr30vxb+Wyl7wVHdvOCntj+zHDPCNxWhv0X6w1pTsLRtWO4Ww7udhzc/Xz6SByZ77INPZR/Zzr4CeIxUrvo53mdOPD7Pm8pGVyq3Rl+jnmtXH0bLC4zXPMEK1Y/pnjz4tkloAdlUARrqSKsligbV2yCsjb8bYfWTgGtoWTCfQ/Ke3Y88ur3PWbjTcEH0lZPRtuk/c6ulO69Nv9WfU/VfntW0KP6hiNUhn3DLJUp353Ber1Try3qmQ6PQj17piVgxBjvuSUO/O2UeHsb8P8m4t/LeSONR/Vt2OhDG0acnPOirux3kgxs2O79av4dO+dF++bcCX3DLVSG7bRFZdhODXeG9+H8t7LbGSpTY3pLSbF8Td/HoCyGvpdzeKjvY4LWOtXH30ky0Lfde3f+rfSNYwkNcY/17Y2Hor7nqQz1fYTKUN9HqQz1bbiVvlEW9ozpbQXKYujt1hwe6g1xLoMssT7+zq6U7j2Sfyu9ob4b4h7rrSPoaSWjsqsFk8+F8y3Bb8iY0ORldvfn+XdmHx/Mfy8lo7bJfjx2Hmz2XZQHz4LOuD1g7JXSvUfzb2UfVcd9vTFxbPPsx9Ffsh9XsYOVoV9DP97JCVN6G3e7Xs3hFbVr1tsqlNnvJBnoze79Rf4dQm8dQc9B8zqFx8s1VgPiQRlynroWEM8a1MHxlOyznv8vyh3MzlOq/0T+ndnxpwgm2yq3bR5LP0n1L+f/tw929fPJE8mwvNiWDL+1ww0os2fNFzR6gzJso9nV7EXhYydrO1cXBnRk8I8PWErS3jD9J4D+4+ORdd+PbJoskoGsTwp51qk+/t7nie79c/6t/IjSL97j9nBc0KPa/gqVYXtFGFi3CffQjhoEa03gydrSF5x6bVHPdI4ytmdSKvs6PP9v9LzX96wSH5fz/9sHvGpEL9oM4uS+Z03wivzava/k37H7HvR3HDOgDXDMgDbE/Qy2YcOd6e07+e+lZFQWs1SGOl2lMiXfafERRltVH/Gt/FvpG/vthrjnxQBWT+mbcz/U961UhvpeozLUt+FW+kZZ2DOmt1NQFkNv3Rwe6g1xboIssT7+zq6U7j2Vfyu9ob4b4h7r7YSgx/CZ3l5ee/o7k289/72UjOqW/SD788v5/+0DXsar2QfKF3GuAM9sT0PxAN2by3lU8l2B5xrinucHrV5bPFcr+DY8fI/xoB7YNx4PiAdlyDH4iYB40C7NZ3BM/Rywy5XaoD7WMdtDuSA+s9Uu1b+c/98+2NWPqU8R/2wbhl/F1PbstMXUQ31Lb5h+5eciy7rvF7ZMFslA1l0hzzrVx9/7PNG9M45fUPrFe2zfm4Ie1ZbXqQzbH8LAukUx9TLBOiHwZG3pubXiem1Rz3TehXr2DPddL4Q2e7ZCX4J8x7CZEyC7hsDJfckJwSvya/fOj6kvQX9XJaZGG+J+A9swxtQvJb2dEHQpnR6nMiXfafERRltVH/ESR9/YDzfEPa9Pt3pK31ViahUPK31jjm36VnM56wQD86QNKsPca5PKMJ85BbjvcXCvXCfu4w7uEwK3snN7ppWMyjWGvZpM0F6VLuvJqC6xH0rp3r2OvVYdJ1Jy5HmY14L/v4/k+0wcU3nAke+4xlTQV7D/R19RlDew//93R2/cLrDNjGtsRI0NVB0beSig3k4KemLPw/B4yWZAPCjDk4TnVEA86MN4Hqab/0e9Y5vkeRir/zD4n15tGCbbKrdtzhnPUP3L+f/tg139nPF0MiwvtiXDr+Jve1bljNhGs6vZi8KHzBm3ksGV9obpPw30b41H1n0/cpvJIhnI+oyQZ53q4+99nujeux0/ovSL97g9bAl6VNvnORpsrwgD62LO2IU6TYJ1SuDJ2tLv1YrrtUU90znK2J5JqexRaLPvq9D3TDom476nbEz2gTH1PSqvt7IulHHMgDbE/Qy2YcOd6e0vSW9l52E2qUzxMy36Ntqq6vujjr5PwnMNcc+LAbhvVmOqSt+cM5bVN87DsL5RFvbMtPh2Hg8s69s/4eit6njgaUEPjyV9Fvzg35J81dqYccXgql0gTp6fLNsuPu3It+r8ZEfQU2Ytsoop1bgB507oFzB3+nJtmI8lhw9ulwxL1Td4vDfhcZDlu3JZLiWjsuG2GTvvVuOuyparjrs+4dgO7uFoiHte2yzaH6V8KtoO2wfazhaVoe0YbrQdlfNz3445P/tszPm5j1DzCyrnV+Np4/I3RnORvzHa6smorLHvHFnv49gM5oFebqjmaXh9kentf8Gff5Pki2uAeU1y7LWtaiwMcfL+qLJjYU868q26PyoV9JTx52qtptpPwGuS0SfhmuSF+jAfqcMHt0uU60xBfYPHtvOU48/xeW6bN6rtNOsDfg9qO8cFPWX8OdpOSmVoOzz3oNZBou2otfTsz3EtPfcluJae+ydcS78KuHktPbYne2Zc57eYDorObzHa6smofaOeU7p3q2Mzqp16Zx6pPQmtZFR2tWDyufhqtQclHPzdXbXfNhz8C69We9oDwn++8mkB4T+gYuCA8Pt7WdeiwN+7YvDX49jnnlrnFxD+ObX2IyD88ypeDajfPbU+OGD7varGvQLSf79aJxsO/rn71VqPgPRfMvhbceBfMPin48C/qsbHwsE/3/fPt8Whv9+/3B4H/oMG/44o8C/27fNZceTfh39nHPh9+Tw7jnz6Z58+Jwr8vb7/vCsO/L59PjeOfPr+4Xlx4PfPRbo7jnwuWQ5xNhlctfzbcG/D/XC5wdWrNcKXJKNrBhD/PNEaOFfpnzG0TfSwfCxvMNntCFo7ooxziB2BZ0fgUbAWA8JaCgirExDWSkBYqwFhhZT92pTStR4Q1kZAWPWAsI4HhHUiIKyQ8gppEyenlK6QfqIRENZmQFjLAWHdDP7rVEBYIW0iZNsO6XO6AWHdDD5nKyCskDFTSD9xOiCskPFXyNhkWn3hmSmFNa0x5rTGciFhhWzbIWGFbNvTSte09mmHYwrVYB2OKUyOrtsCwrp9SmGFjJlC+sKQOUzINhTSvu4ICOtZAWGF9PfTGsuFHOs4zLerwbozIKyQPmda+9ppzR8P48JqsA7jwmqwpjUuDJm7h9RjSD8R0lZrAWGFlNe05u7T6idCxiYhZR/SvkLSFXLu92aYo3h2QFgh21DIth2yDXUDwprWfvs5AWHdFRDWYe4+Ofs6HRBWSH+/FRBWSD8RcrzwuQFhHfa11WAd5sjVYB3myJOjK2QuGtLfh7SvaZ0rvxlyhZD9YzMgrOcFhHUzrKE87NMO+7QbpU87HPetBqsWENbhuO/k5HU47lsN1uG4bzVYh+O+1WB1A8Ka1n777oCwQo7VTuu4b0hYzKM6D/KYgKXO+rJn1bk7GazL+f/tg127Rqs6Qwlj+U4J3tTe6UWA/bqHfv4XX5/QxYfmz9P/Gfo/R/+PAkJkRDVSI/oxgtEuoKXod4N+10Ud/PD9xwRsO/DK+P1CjkQdTBXQALZvIToYF/7HQ73wELMW8WD1v0Q8zIyRB8MVGfe5yC+X779AAO2+IXjiw++wQdcKvg0Wlxmu+SSq7e14vHkHuKHtoQyKYM1VhNUSZTF0OuPwjfjbDq2Kj1pAmdQDwloOCMsGH5eSUZ75UL9Yfof5QP/Idmn8MB/Ib0r3vp03TnXoIbdhvseyY5+eXe1E91Hq2/AkBXjYRkPAWgwAK3IA1T/Y6Fgk+Kafo8Qv83SMZLd0nbJDXPMEK5b/V7ypF7x2qD7LoAjW0YqwWqIshk47Dt+I3zscVvFRDyiT5YCw2Gej7jjhiST7vs+29tIUfCBt9WS0fWMSl9K91ZzJEIfVqwSsA/CsbIHK1AHDVoZxKr+M2fKg78t5yPqwzfx35AOEd2P76Voy6lcagifDzwc5W7n6NlhcZrjmCVYsP6p4Q/o9+0IZFMFaqghLHUocQ6ezDt+Iv+3QqvhYDigT9n0o75nxyGub/VAz0f0Ov+wK2yT6K34xyTnH91V92ZU6QF35viNU5uVIyvdldV7YLK7XFvVMh9hf2DMplb0MfOmL6Hnkg3OWSLmne1C7yiHrQibeQe0/6NhADZ47aM6C9sEvhsC2xS+GQDvnF0OgneOLIe4lvfG4IpahTueoTMl3WuIdo61qvPMKR99V83slO6VvfpkD6vsIlaG+eYyMc4ck0fpGWXCOEPslHDaZVvQSjmMgS6yPv7MrpXtXHL2hvr2Ji04yKsdjhM/09hD4wQdIvhg7sR/ERWYx5Gv0oXwZp/HMdoixFfP7Gke+DXiuIe55ftDq8diN8oPob9gPog9jP4h+Af3g5/M/S8moLLhdRBoP6evN2gDqDXHOgCy5zdjvJBl9Gc8bHb2p8Vovvu4Ieg6aVyg8Xqy7EhAPypDzpNWAeNCH8cui1UuJ1Iug+KVDj4D/eVtzGCbbKsJE+iK/nLSfz6gXhaIt8YtUcSEbvgRu//neoAzb6L4Me1H4kC+LtoUc2ZX2hunHBTYb45F19BfBvtfxI1VfBKte8qfa/jEqw/bKC2kwHrR7aEcNgrUq8GS4/6BZXK8t6imd2zP8Er+PQJv9AD3v9T2Tjsm47ykbk/3xmPoe9MEcM6Av5JgB7YP7GbQvw53h/QTpbVXQpXS6QmVKvuqlPDH0bf4A9X1S0FpPRv2H/c6ulO593NE39tsNcc+LAaye0jfnTqhvflk06ptftIv6NtxK3ygL9u3oS2PorZvDQ70hzk2QJdbH39mV0r1POXpDfTfEPc+3bxI+09tyHndn8v20kzuNOwY3+yiKwTl3Qnuy38iv3fuHgLkTzydkV1s8Vyv4TpJyMSvWYd+4HhAPypBj8I2AeNAueZ7IYur/gv75CweMqbtU/3L+f/tgVz+mVi9xR9sw/OqlyPbstMXUQ31Lb5h+5eciy7rvF7ZMFslA1l0hzzrVx9/7PNG9/3T8gtIv3mP73hT0qLbMMTW2Pz4MUcXUaEfLBGtD4Mna0n83i+u1RT2lc3uG85IE+pInK/QlnBtczv9vH/CqEb1oMyofqQuZDOWWdO+7Y+pL0N9xTI3ziBxTey+WR/vCmHqJxuE2BF1Kp+tUpuQ7LbGZ0VY1NpvLZaP0jf1wQ9zz+nSrp/TNMTXqm2Nq1De/XJrHOrIL9a3mQnjdF+ZJy1SGudcalWE+swm41x3cDQf3MQf3uoN7Q+D2xrnUi2vHlQNuCJ6q5oCnAtrrSUEPz0tsg/8/Q/LFeQ/2/7HX0KrxfMTZBJ7Z1rzx/Gc78m3Ccw1xz/P/Vu+gYyroK9j/o69A//+oMw/D7WLS/TaPhZXtty84eqs6FnZS0BN7HqZovCQEHjUerHKCg+JBH8bzMGrcHH08z8NY/Z8E//OSdBgm2yrCRPrUy5Rj5IxbybC82JYMv4q/7VmVM2Ib3ZdhLwofMmfsJoMr7Q3TvwX0d5OxyLrvR24zWSQDWZ8R8qxTffy9zxPd+3HHjyj94j1uD11Bj2r761SG7RVhYF3MGdGOmgRrU+DZX7OSFtdri3pK5zz+aGWvgTb70xX6nknHZNz3lI3J7h9T34PxFscM6As5ZkD74H6mC2WGO8P7ZtJb2XmYDSpT8p2WeRijraq+f9nRN/bbDXHPiwE4v0N9c86I+uacsay+cR6G9Y2ysGdMb1tQFkNv5sdRb8rv1JNRv2+/syulez1Hb1XnYbqCHsNnevsd8INvrZA7xZ6PVvMwiJNzp7LzMO8YU+7kreVVMaWag+TcCf0C5k5/mF6bD5QdHxK1BLA8WadU/2GQ5btyWS5RHdU2I+2HcfNutS+rat79iGM7VfdRdAU9ZdYFo+2wzaHtnKIytJ1u/httR+X83Ldjzs8+G3N+7iMw58f+m3N+1IM90xJ8j8vfIE5eD1HW33zEsZmq6yHWBD08r/434M8/RvL11iRH2gPnrtVnnMYz25q3Vv+vHPlWnQvx1iR7cS221xB7M/4pvTYfKDuUFcPyZM1nm3zK8ecoG26bk7Ydo62q7XzGsR11eJB3fseaoKdMjOzNPah9e8p2DDfajlpLz/2F2lem1tJz/6T2FKu19Mi3PRP77J8a8YM2kwpZVN0D8cWA8aO3jxxldzYZll3seYtZITtv3gLb4qyQnd37SkDZnRX0GCwVi6n9/Grf6rgPKVN8T8UhZTX6z4egLAJCVkLRxutpPqTM/n8zl1rszVrqgK+m4CNJyh9SZvW/NQU8cAeE9SLTdb5G+JJkdHII8c8TrYHp2fEaO9JYJ9nNClo7oozfPlB1YzrCuj0grNMR6IocdJ6f5OF3yBNv7EXbqRV8Gywu48PvIrU79/A7rzNHn8Z9x0EOVONDO2Iffjfr8I342w6tio8TAWVye0BYp6eULi/AM31My6EUfDBJ2UMpNvKIPMTBJCp2a4vnqvgdxBPZp55X/QX7z+s9PA758A7B4cQ8BB4M/nngAJ+3OCwziTtnBvezjyUBaTI6CJb9Ljro9vzCAOZdOUx1SEyHnreyF8wMnr+bnvfa4w17UNCY2qO3KA8HOHgg0jtYVx1CmtX/EdJbR9DlJdFqMoj75EkfEsOTQWUHD1/s6LvqZJCSXZmNjqhvHlxWm4m9uEPpG2Vhz5jecMJnXJN4iJMPiSk7ifdyR29VD4mZE/TwhMwV8IOvIPmibtkPTnqAlCdkyg6QvsqRb9UJGc5TskvlxuwH1eEZauCc/aAakM3Y+fUcmdIbt4vYG1StDZTdoIptxn5nV0r3fjag3jimzq7YG1R5AmM5IB6UIedwsQ6j4cXJ6oAGNfHIBzC8A/zPGyg2VBta1cK/yIsf+/mz2hyCtsQL94o24Ow/3xuUYRvdl2EvCh9ycbJNzmVX2humHxcRrI1H1n0/Ygsxym7+wQUkeLALH3DyG44fqbr5Z03QU2ZDK7ZXfhOR2tCKdnScYKkNYBmL75wprtcW9dRiU17EYWW/D232t52YYdpiMu57ysZkD4+p7/E2tHqL8tCGuJ/BNmy4szp/SnrjBZNYhjpdpjIl32nxEUZbVR/xIUff2G83xD0vBuBFEt6GVtS3t6GVD55RG4yVvtXGxRv9ALCPOXqregDYukMPyg7zL7UpiX1gF8piyHYrhxf6IIi/dmRb9SCIOUGPgmX3sZ2cJDxbBfUaUOeMeL6WDM9x3ga0Ktj8hsXVa9Tnfn1N1Ee6Zqg+6qIhaDB4R5LiWIRljRvE9+H2RuFl9d9DMSJuCGzmz6gxGKs3ro2wyv+vC36r+v/PBhyDUYf4sd/6MsRTj1cY44q96Fgd/Kn4qSejNjiUV9C9JyKPcZUZi/YOCFEH36lF7BhP3UNjMF67QDnF0JtaLL4m5FR1sfhXI7eLtniuVvBtePge40E9bBGeWIeE8eaDkwHxoA/jMRi1WW8L6vAYjNWfzW03U+//0BgM2yrCRPrGtUG8mwzLi23J8Hub8FT/h200u5q9KHzIMZihmLY3TH8X6D8FNEaUdd+P3GGySHTMYrTVqT7+3ueJ7+X2pvxIF55riHvcHk4JelTbX6MybK8cg2K/x22rlvhtEhe7t2aL67VFPdO5ild5I+Y6tNnFCn3PjRqT3eLYTMi+B/0dxwxoA94G8S0q60KZ4d5fC0F6U3QpnXqHilm9cW0QN16LNojzOO2WkFN2cb655ei76jitkp3SN4/BoL6vd4M4jsmyvlEW9sy0+PYtkCXWx9/Zxb79bkdvqG8vlvAO/+Bc4kXgB3dJvqhbzp0mPcaF4wFsT94Y1yVHvphzNcQ9L3fiw+mudyxaHUTFcTDizuq8fHaYjxnBx23wLB8CirBUfYOXUv0Xgyx5QyHKppv/Hlf+puJ4Zct1IQ/v0I0fdmyn6nrWrqCn6ri2N1dRdoO42Y7K+blvx5yffbY6gEDl/LhB/B7H3/DB65OOu9jflI277g3obzYEPbwe6bXgz+9z1rWMez2SWtfirUcqu67lAUe+VecWvfVI3oEf3kursC3zeiR12EOG5y2z1+YDZccv/URYnqz5sJjXOf4cZcNtc9K2wxtWy9rOrzi2U3XD6oagp8yBH2Xns3meEm0HD6B9C/lz9dJWtY6O+yBcR8f9AK6jw3yM19E9EzeI/2ZAm5nWDeJzQnbeBnG04TkhO7v3noCy8zaIq/EMb4O4mgOJvObG3SCO7X65BG9RNohzOW+w6QBCVsJcAdHTvEHcaHgk/zENG8Ttf9FmFn6Ds9V/P/EQ6wQXxQNvAImE+8LhRt7rvg438jp8q2DocCNvHLqOB4R1M2wK/qQTQN1km4IvHG4KfvrKAvPHaMDgejcFd2BT8D9SMof2y5uCrezLMPj0OD0/yfZouivbHlHXaEN8QuoTY2qPaEs8+KRsQm0g5bahErrs3jcdvYfaFBz7hFhL9sqeEIuJOCaKvOn9a46+Q24KRn17PoA3BaO+OYZBfeOmYNY3ysKemZbNj0dBllgffyfJ6EDfk47eUN/eYIE6Lf0o4TO9NXPhZ3W/TfJF3bIfrENZDPma7aB8EWcNeGZbw0FonnT4P0e+NXiuIe55ftDqldkU7A3Cq5xZDXSiH7w9b1xKb9wuJn3IAeut7CEH87nQQuiNF+BnV1s8Vyv4NjzJNfDgc3wSa6yFr+PafMwLUtWGPHUICG+4ex74n7W5YZhsqwgT6Ys88drPxdUkKNoSL9ZSp4irBanYRvdl2IvCh1yQihs+0t4w/TjJPe7Fhdd68xlPcpd989kdjh+pOsmtNumotn+UytSiTbZ5XJCKdsSbgpcFnsyezs4V12uLemqBoT3DmwNeBG12l573+p5Jx2Tc95SNyS6Nqe9Bf8cxA9oAxwxoQ9zPqA3D2fePkt548gbLUKfeYlWrNy0+ghcgl/URP+Tou+oCZCU7pW/OnVDfvCAV9c0bjXkzYnYpfasFOqY3HOuMoTcbe0a9IU5+0xSOVdvv7Erp3iscvVV909SaQw/KDvOvJUEv+8BJv8XrBPFSdkHhTzmyRZ00xD3PB/I8BD5n97GdbBCezYJ6Daij3txeS4b9dRdoVbBXiM6Va9Qvs4kY6UqpvnrD1oqAf0TgUz4f5eNtilKbgvHAjGb+jBqDsXrjWjyr/P+a4Leq/3+dY+tVx2BWBD3st34N4qnXk5/GMY9x5/Iqp0OcdeCZefUOWXmzI986PNcQ9zxfYmVlxqLLvjWa4ym16D37/g7pzWsXk97Mze2i7Gbut0duF23xXK3g2/DwPW/h2ibhWQuIxzuoJdbbqXkMxmKooo0oPAZj9T8M/udhGoNhW0WYSJ/Z9imqfzn/v32wqz8Gow53QVsy/EvEIz6r+j9so/sy7EXhQ47BDMW0vWH6VewWWdbuhr9TQp5VN/z9keNHqh7ec0LQo9r+KpVhe+UYFA845LZVS/w2iYuM/2yuuF5b1FM6t2d4s8YnoM1+tELfc6PGZB8fU9+D8VaVzXBoH9zPoH0Z7v21EKQ3RZfS6RqVKflOy8Fs17sZ6e8CjtMq2Sl9VzmYDfXN/T3qG8dkH3PaOfv2G/Vgtscj+3bDZ3W/An7wXyrkTrFjcBWLIU7OndCe7Dfya/f+dUy50/WORXtvn1Rvt8++n5y7Nh9deJbHVtRbRruCN15D9jWQpfeWUW6bsTe1XOuAZX7L6KqQDfJr977h2A7Oq3pzraptsp7LjmuzzaHtHKcytB3Djbajcn7u271NauqgXpXz4wa27zj9Nx+0Oemcn98aXTbnf8qxmapvjV4X9PB6pKU8AcvkW3fWtfB6JF7/czn/v33Ay/CqdS2IswY8s61561rmch5jr0fy4trrfVlL0UsKuq1r84Gy4zlEtSlYyZr3Eh0DWbI/x+e5bcbaN+XZDuPMrqq2s+7YDq6Ba4h7Xtu0emViZJ63wDK0HZ6nRNsx3Gg7ah0d9xe4jo77IFxHx2uicB0dxue8jg75tmfG5W/UfrqGkEU9GbUn3BfFbeQux2aqxo8dQY+S3dlkWHax21sqZNd0ZIc2nArZ2b29gLI7K+gxWDMCVkfAUrHqmOaIdj2+1Zyjx9tYNgXP0X9eWI9KSAuIvhE2BX9/bqSxF2qrDbVsyPa/aDMLbwq2+j9APMQ6gUHxYLhaBTyFwb23EzmZ3JvkBlXkiTd3oIOtFXwbLC4zXPNJVLvY8XjzkmJ1gokHq+wbp9mpR9qovuc5aZR10SZMfFbxUQ8okxiwlpJR3bE/iHVAgfGhTjRR8q0no+3bO9HkXid4UfqecWSnAg4lOw78Jr2ZmWVXdjPz1YCyOyvoMVhqY57yN0uCfns28sbFXY9vTLo6JXiLEvjx/1vo/wIgZCUsFhA9jYFfGWcVaUe7u1sZcXKDK7tb+ZemwFktRZZdR8huyZFd2dc/v2lMzkrNunvOSo26RN4Z4jorzEyPleBt6pxVp4DoG9VZTXqrPTe4slvt3x7ZWcUeyol8flw/q/DOukP8PHxs5erbYHFZf9twMmp3MTJFxZunZ3VUgAfrWEVYkR3rnucoUdZF7/vBZxUf9YAy4Y7omXhsxPsdHxTi2AglOw6YJv3OV5Zd2e0IjwaU3VlBj8FaFbCUj1DLCcb0XrFdj++iLUZFvI0lYLqV/h8BhKyElQKib9SAadL7fzhgKtvgPh45YDpoAKHweAdjrwTEU2afdwg82JgXCE+sfTE8R48w8Yy4v6f1I4YHz4jDZ49AOdb/0PwA5mdobh9p51EBnCteoTK0t1UqQxvhNdrecP6Nesbj55x2XHU4Xp35pWTHQcekR7iu9zy+LwaU3VlBj8HqCFhe0KGGcMe1lkDxrUaNPN6iBB0N+s8HJ/OCXHVgHhM9zWsJDPZ/TME8PHcCRYt6ijqBr0/RWoJIC5/OxV5LUCN+kgIdcADG7UZ9J4kewTFc84m298theNvxePMWTKo3dHiw0oqwIttrX6dNh2/E33ZoVXzUA8pk2mGpwNFkGNvvGB+x3iLTyDtDFahUfRNKQ9Bz0JcRKDyoB07WYiWFnKyFOJhcrVVpEZ5WQDwtqNMgPAgTk7Vj84P7+FxRsrYA5Vj/EiRrt+a/vY0f3iY/leRxUoE20qIyzx/H3vxldJbd/DUreEyS0XWhXacdV/WBTUGPkh0na5NeO8WyK7t26s6Asjsr6DFYLQFL+VN14Lk9Gzkx3vX4Rv+xWIK3KMlajf7X6X8DELIS5gqInuZkzf7v5YKIvUNFJToNwUd2FZ3evVDAw8Up4CGjTXUgTaLZyl4AHdcHqePyOiC0O+6A1M6mcY14WSJdNOJltNWpPv5GOdm9FztOFJ1vQ9zzgnBeYM4bPdS34eF7jIdHZhHPkYB4UIZFO9lC4MHBKD49Sq1HQ5h8epTVfxDs/8coGGRbRZhI3ySXoKAtGX61Zg2XMuw/3xuUYRvdl2EvCh/y9KihpUm9Yfq9pSGTnq7n03nLzh7e5/iRqstE1BpA1fYXqQzbK49K42wLt61a4rdJezZrSz83X1yvLeqpk5ztGV4u8kZos6+h572+B/ke12wL4uS+p/R64jH1PejveJc92gAPFvDMCpZhG8aTTt7uxBpGl4o1jlDZM1HfvQnomweaUN98elRoffOrgGMPNqpEOxU8VU203+XoDeOGMgP0vJSvSHa8rn3OwcN6RXstOq1ijni1+u8FXr3TKli3k26TrNuybfJ9kXWrBqe431YbU9UgKy9NxYENw435nsdHDZ5lP1ATfOCgqmevnIc+Cn1627EnXrWC8uJVK95A6I06mPfRyAOhB93orPAo3xo73+UJmsWAeFS/6fkfLw+1+p8D+/8ktUu21SL/Msll82hL/JYV9LHeKf7YRvdl2IvCh8xDh/ak9Ybpx3inMx5ZR19y/5jjR6ouG1ernFTb997ozXEJTiRx26olfpvEt25+fr64XlvUU2MPfNCHlX0V2uwT9LzX90x6xST3PWVXTH5pTH2P9/ZJtAHOQ3kLHpYVnfb2pBOr8OSgenP9M1nf35iAvjkPRX1z/Bla3zzGOOmTvry5PpR1Sve+GzBXUbm+kh3vTvEWpLFe0V6L8tCUeO3HjQsDXr08lHU76TbJui3bJmeA3xi69Va0q10eKZXhzowOlamT3jHf8/iowbNl81DeiTHjwM0uXlynxlJmBC7VB3D/oOTJeIoWzXDOYPW3Fwa8ri5cG58aM+V2qN5aq1bcRz4ZuJ9rqFN6kX4eDyg6JXn/+d6gbA74yK5mLwofMtcYist7w/SrU0fH5bPUnJd3AFHZOa9nOT6r6o65ZUFPmTEwtHOeJy1zLAXmIWqMm/s9tbBP0dURsLL6uwvF9dqiHuPPLtWPsu9sFOB/bHYY7jPNd94DvvOFh77z0Hde5xXbd77s0HcW0lXkO19Z0ne+MpLvvDMnOmb7uHjpadvbpzWHnybDsXNC+FOqf1/OP45h23fzAHQ+ePHKzoN7Vx68cv7K/fefu3qF1ytml+l4IQL+Kxf3Ll3dPXf14qvP713Zu3BN/GbfM71BOfq7fRlhGdVBeAZrFsrmS8Cad2DNObBaJWHVxPMNQWuzN1x/If/fhPozAn5K9X8B+tc3LAzDTHujNDccGuYEzXOi/jzBD90fGT2LvVH6kSf0u1yf9adgLZaEZTLIZPzOXMb9DTa9KDLY8+hGuzP85m9RPrWCb4SF9wzXzaZfgzVJnSLfiB//Y330R02qvyTqtwW/ZjMdgdvKjkLZIuG5Jf+PPgthGR0p1f8tyAOy6wg8Y893BP4jhB9xKfzsk4+K+kdF/aydvxX8qrX5GH3oufNXLl69cnFn5/nndh44t3O+bB865Nt7w89Yv4F6Ue0qpfrvBZ5/F/KBfVgCX1bvT8gfch9yOb+/fbBr13jDPlT1aYZfxQf2OzKtex6ts4JWJeOqvnu2N3xPxSsop1nCPRQrUdkClDUJj/kEtDWEZXSkVP9R8gEq9uoI/KgzxlUmLlsQ9RdE/cy2P0BxexNwh+wPsR1lX/8PsRcK6NLEAQA=", - "debug_symbols": "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", + "bytecode": "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", + "debug_symbols": "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", "file_map": { "22": { "source": "pub mod hash;\npub mod aes128;\npub mod array;\npub mod slice;\npub mod ecdsa_secp256k1;\npub mod ecdsa_secp256r1;\npub mod embedded_curve_ops;\npub mod field;\npub mod collections;\npub mod compat;\npub mod convert;\npub mod option;\npub mod string;\npub mod test;\npub mod cmp;\npub mod ops;\npub mod default;\npub mod prelude;\npub mod runtime;\npub mod meta;\npub mod append;\npub mod mem;\npub mod panic;\npub mod hint;\n\nuse convert::AsPrimitive;\n\n// Oracle calls are required to be wrapped in an unconstrained function\n// Thus, the only argument to the `println` oracle is expected to always be an ident\n#[oracle(print)]\nunconstrained fn print_oracle(with_newline: bool, input: T) {}\n\nunconstrained fn print_unconstrained(with_newline: bool, input: T) {\n print_oracle(with_newline, input);\n}\n\npub fn println(input: T) {\n // Safety: a print statement cannot be constrained\n unsafe {\n print_unconstrained(true, input);\n }\n}\n\npub fn print(input: T) {\n // Safety: a print statement cannot be constrained\n unsafe {\n print_unconstrained(false, input);\n }\n}\n\npub fn verify_proof(\n verification_key: [Field; N],\n proof: [Field; M],\n public_inputs: [Field; K],\n key_hash: Field,\n) {\n verify_proof_internal(verification_key, proof, public_inputs, key_hash, 0);\n}\n\npub fn verify_proof_with_type(\n verification_key: [Field; N],\n proof: [Field; M],\n public_inputs: [Field; K],\n key_hash: Field,\n proof_type: u32,\n) {\n if !crate::runtime::is_unconstrained() {\n crate::assert_constant(proof_type);\n }\n verify_proof_internal(verification_key, proof, public_inputs, key_hash, proof_type);\n}\n\n#[foreign(recursive_aggregation)]\nfn verify_proof_internal(\n verification_key: [Field; N],\n proof: [Field; M],\n public_inputs: [Field; K],\n key_hash: Field,\n proof_type: u32,\n) {}\n\n// Asserts that the given value is known at compile-time.\n// Useful for debugging for-loop bounds.\n#[builtin(assert_constant)]\npub fn assert_constant(x: T) {}\n\n// Asserts that the given value is both true and known at compile-time\n#[builtin(static_assert)]\npub fn static_assert(predicate: bool, message: str) {}\n\npub fn wrapping_add(x: T, y: T) -> T\nwhere\n T: AsPrimitive,\n Field: AsPrimitive,\n{\n AsPrimitive::as_(x.as_() + y.as_())\n}\n\npub fn wrapping_sub(x: T, y: T) -> T\nwhere\n T: AsPrimitive,\n Field: AsPrimitive,\n{\n //340282366920938463463374607431768211456 is 2^128, it is used to avoid underflow\n AsPrimitive::as_(x.as_() + 340282366920938463463374607431768211456 - y.as_())\n}\n\npub fn wrapping_mul(x: T, y: T) -> T\nwhere\n T: AsPrimitive,\n Field: AsPrimitive,\n{\n AsPrimitive::as_(x.as_() * y.as_())\n}\n\n#[builtin(as_witness)]\npub fn as_witness(x: Field) {}\n\nmod tests {\n use super::wrapping_mul;\n\n #[test(should_fail_with = \"custom message\")]\n fn test_static_assert_custom_message() {\n super::static_assert(1 == 2, \"custom message\");\n }\n\n #[test(should_fail)]\n fn test_wrapping_mul() {\n // This currently fails.\n // See: https://github.com/noir-lang/noir/issues/7528\n let zero: u128 = 0;\n let one: u128 = 1;\n let two_pow_64: u128 = 0x10000000000000000;\n let u128_max: u128 = 0xffffffffffffffffffffffffffffffff;\n\n // 1*0==0\n assert_eq(zero, wrapping_mul(zero, one));\n\n // 0*1==0\n assert_eq(zero, wrapping_mul(one, zero));\n\n // 1*1==1\n assert_eq(one, wrapping_mul(one, one));\n\n // 0 * ( 1 << 64 ) == 0\n assert_eq(zero, wrapping_mul(zero, two_pow_64));\n\n // ( 1 << 64 ) * 0 == 0\n assert_eq(zero, wrapping_mul(two_pow_64, zero));\n\n // 1 * ( 1 << 64 ) == 1 << 64\n assert_eq(two_pow_64, wrapping_mul(two_pow_64, one));\n\n // ( 1 << 64 ) * 1 == 1 << 64\n assert_eq(two_pow_64, wrapping_mul(one, two_pow_64));\n\n // ( 1 << 64 ) * ( 1 << 64 ) == 1 << 64\n assert_eq(zero, wrapping_mul(two_pow_64, two_pow_64));\n // -1 * -1 == 1\n assert_eq(one, wrapping_mul(u128_max, u128_max));\n }\n}\n",