From aa39313e5ffcc9109856d12b7e741ffd0054b779 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Wed, 14 Aug 2024 08:02:03 +0000 Subject: [PATCH] [1 changes] feat: Sync from aztec-packages (https://github.com/noir-lang/noir/pull/5718) feat: LSP fields, functions and methods completion after "." and "::" (https://github.com/noir-lang/noir/pull/5714) fix: Replace unused ArrayGet/Set with constrain if possibly out of bounds (https://github.com/noir-lang/noir/pull/5691) feat: add `Type::get_trait_impl` (https://github.com/noir-lang/noir/pull/5716) --- .noir-sync-commit | 2 +- noir/noir-repo/acvm-repo/acvm_js/build.sh | 2 +- .../src/transforms/contract_interface.rs | 176 ++-- .../noirc_evaluator/src/ssa/opt/die.rs | 356 +++++++- .../src/hir/comptime/interpreter/builtin.rs | 25 +- .../noirc_frontend/src/hir/comptime/value.rs | 70 +- .../noirc_frontend/src/hir_def/types.rs | 6 +- .../noirc_frontend/src/lexer/token.rs | 3 + .../noirc_frontend/src/node_interner.rs | 68 +- .../noirc_frontend/src/parser/errors.rs | 2 + .../noirc_frontend/src/parser/parser.rs | 38 +- .../noirc_frontend/src/parser/parser/types.rs | 6 + .../noirc_frontend/src/resolve_locations.rs | 6 + .../reference/debugger/_category_.json | 2 +- noir/noir-repo/noir_stdlib/src/meta/typ.nr | 3 + noir/noir-repo/scripts/install_bb.sh | 2 +- .../comptime_type/src/main.nr | 4 + .../Nargo.toml | 7 + .../Prover.toml | 0 .../src/main.nr | 4 + .../Nargo.toml | 7 + .../Prover.toml | 1 + .../src/main.nr | 4 + .../Nargo.toml | 7 + .../Prover.toml | 0 .../src/main.nr | 4 + .../Nargo.toml | 7 + .../Prover.toml | 1 + .../src/main.nr | 4 + .../Nargo.toml | 7 + .../Prover.toml | 0 .../src/main.nr | 4 + .../Nargo.toml | 7 + .../Prover.toml | 1 + .../src/main.nr | 4 + .../verify_honk_proof/Nargo.toml | 6 - .../verify_honk_proof/Prover.toml | 537 ------------ .../verify_honk_proof/src/main.nr | 16 - .../tooling/lsp/src/requests/completion.rs | 764 +++++++++++++++++- .../lsp/src/requests/completion/builtins.rs | 2 + .../noir-repo/tooling/lsp/src/requests/mod.rs | 2 +- .../noir_js_backend_barretenberg/package.json | 2 +- .../noir-repo/tooling/noirc_abi_wasm/build.sh | 2 +- noir/noir-repo/yarn.lock | 13 +- 44 files changed, 1433 insertions(+), 751 deletions(-) create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_array_get_known_index_out_of_bounds/Nargo.toml create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_array_get_known_index_out_of_bounds/Prover.toml create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_array_get_known_index_out_of_bounds/src/main.nr create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_array_get_unknown_index_out_of_bounds/Nargo.toml create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_array_get_unknown_index_out_of_bounds/Prover.toml create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_array_get_unknown_index_out_of_bounds/src/main.nr create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_array_set_known_index_out_of_bounds/Nargo.toml create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_array_set_known_index_out_of_bounds/Prover.toml create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_array_set_known_index_out_of_bounds/src/main.nr create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_array_set_unknown_index_out_of_bounds/Nargo.toml create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_array_set_unknown_index_out_of_bounds/Prover.toml create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_array_set_unknown_index_out_of_bounds/src/main.nr create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_slice_get_known_index_out_of_bounds/Nargo.toml create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_slice_get_known_index_out_of_bounds/Prover.toml create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_slice_get_known_index_out_of_bounds/src/main.nr create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_slice_get_unknown_index_out_of_bounds/Nargo.toml create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_slice_get_unknown_index_out_of_bounds/Prover.toml create mode 100644 noir/noir-repo/test_programs/execution_failure/unused_slice_get_unknown_index_out_of_bounds/src/main.nr delete mode 100644 noir/noir-repo/test_programs/execution_success/verify_honk_proof/Nargo.toml delete mode 100644 noir/noir-repo/test_programs/execution_success/verify_honk_proof/Prover.toml delete mode 100644 noir/noir-repo/test_programs/execution_success/verify_honk_proof/src/main.nr diff --git a/.noir-sync-commit b/.noir-sync-commit index d575ffe3e8c..c3e164f0283 100644 --- a/.noir-sync-commit +++ b/.noir-sync-commit @@ -1 +1 @@ -0ebf1fee471641db0bffcc8307d20327613c78c1 +4ea25dbde87488e758139619a3ce4edf93c6ebd6 diff --git a/noir/noir-repo/acvm-repo/acvm_js/build.sh b/noir/noir-repo/acvm-repo/acvm_js/build.sh index c07d2d8a4c1..16fb26e55db 100755 --- a/noir/noir-repo/acvm-repo/acvm_js/build.sh +++ b/noir/noir-repo/acvm-repo/acvm_js/build.sh @@ -25,7 +25,7 @@ function run_if_available { require_command jq require_command cargo require_command wasm-bindgen -#require_command wasm-opt +require_command wasm-opt self_path=$(dirname "$(readlink -f "$0")") pname=$(cargo read-manifest | jq -r '.name') diff --git a/noir/noir-repo/aztec_macros/src/transforms/contract_interface.rs b/noir/noir-repo/aztec_macros/src/transforms/contract_interface.rs index dd3ec7f6a75..7a8a7187857 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/contract_interface.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/contract_interface.rs @@ -324,101 +324,105 @@ pub fn update_fn_signatures_in_contract_interface( }); if let Some(interface_struct) = maybe_interface_struct { - let methods = context.def_interner.get_struct_methods(interface_struct.borrow().id); - - for func_id in methods.iter().flat_map(|methods| methods.direct.iter()) { - let name = context.def_interner.function_name(func_id); - let fn_parameters = &context.def_interner.function_meta(func_id).parameters.clone(); - - if name == "at" || name == "interface" || name == "storage" { - continue; - } - - let fn_signature_hash = compute_fn_signature_hash( - name, - &fn_parameters - .iter() - .skip(1) - .map(|(_, typ, _)| typ.clone()) - .collect::>(), - ); - let hir_func = context.def_interner.function(func_id).block(&context.def_interner); - - let function_selector_statement = context.def_interner.statement( - hir_func.statements().get(hir_func.statements().len() - 2).ok_or(( - AztecMacroError::CouldNotGenerateContractInterface { - secondary_message: Some( - "Function signature statement not found, invalid body length" - .to_string(), - ), - }, - file_id, - ))?, - ); - let function_selector_expression_id = match function_selector_statement { - HirStatement::Let(let_statement) => Ok(let_statement.expression), - _ => Err(( - AztecMacroError::CouldNotGenerateContractInterface { - secondary_message: Some( - "Function selector statement must be an expression".to_string(), - ), - }, - file_id, - )), - }?; - let function_selector_expression = - context.def_interner.expression(&function_selector_expression_id); - - let current_fn_signature_expression_id = match function_selector_expression { - HirExpression::Call(call_expr) => Ok(call_expr.arguments[0]), - _ => Err(( - AztecMacroError::CouldNotGenerateContractInterface { - secondary_message: Some( - "Function selector argument expression must be call expression" - .to_string(), - ), - }, - file_id, - )), - }?; - - let current_fn_signature_expression = - context.def_interner.expression(¤t_fn_signature_expression_id); + if let Some(methods) = + context.def_interner.get_struct_methods(interface_struct.borrow().id).cloned() + { + for func_id in methods.iter().flat_map(|(_name, methods)| methods.direct.iter()) { + let name = context.def_interner.function_name(func_id); + let fn_parameters = + &context.def_interner.function_meta(func_id).parameters.clone(); + + if name == "at" || name == "interface" || name == "storage" { + continue; + } - match current_fn_signature_expression { - HirExpression::Literal(HirLiteral::Integer(value, _)) => { - if !value.is_zero() { - Err(( + let fn_signature_hash = compute_fn_signature_hash( + name, + &fn_parameters + .iter() + .skip(1) + .map(|(_, typ, _)| typ.clone()) + .collect::>(), + ); + let hir_func = + context.def_interner.function(func_id).block(&context.def_interner); + + let function_selector_statement = context.def_interner.statement( + hir_func.statements().get(hir_func.statements().len() - 2).ok_or(( + AztecMacroError::CouldNotGenerateContractInterface { + secondary_message: Some( + "Function signature statement not found, invalid body length" + .to_string(), + ), + }, + file_id, + ))?, + ); + let function_selector_expression_id = match function_selector_statement { + HirStatement::Let(let_statement) => Ok(let_statement.expression), + _ => Err(( + AztecMacroError::CouldNotGenerateContractInterface { + secondary_message: Some( + "Function selector statement must be an expression".to_string(), + ), + }, + file_id, + )), + }?; + let function_selector_expression = + context.def_interner.expression(&function_selector_expression_id); + + let current_fn_signature_expression_id = match function_selector_expression { + HirExpression::Call(call_expr) => Ok(call_expr.arguments[0]), + _ => Err(( + AztecMacroError::CouldNotGenerateContractInterface { + secondary_message: Some( + "Function selector argument expression must be call expression" + .to_string(), + ), + }, + file_id, + )), + }?; + + let current_fn_signature_expression = + context.def_interner.expression(¤t_fn_signature_expression_id); + + match current_fn_signature_expression { + HirExpression::Literal(HirLiteral::Integer(value, _)) => { + if !value.is_zero() { + Err(( AztecMacroError::CouldNotGenerateContractInterface { secondary_message: Some( "Function signature argument must be a placeholder with value 0".to_string()), }, file_id, )) - } else { - Ok(()) + } else { + Ok(()) + } } - } - _ => Err(( - AztecMacroError::CouldNotGenerateContractInterface { - secondary_message: Some( - "Function signature argument must be a literal field element" - .to_string(), - ), + _ => Err(( + AztecMacroError::CouldNotGenerateContractInterface { + secondary_message: Some( + "Function signature argument must be a literal field element" + .to_string(), + ), + }, + file_id, + )), + }?; + + context.def_interner.update_expression( + current_fn_signature_expression_id, + |expr| { + *expr = HirExpression::Literal(HirLiteral::Integer( + FieldElement::from(fn_signature_hash as u128), + false, + )) }, - file_id, - )), - }?; - - context.def_interner.update_expression( - current_fn_signature_expression_id, - |expr| { - *expr = HirExpression::Literal(HirLiteral::Integer( - FieldElement::from(fn_signature_hash as u128), - false, - )) - }, - ); + ); + } } } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/die.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/die.rs index 24519d530ee..1aa0c2efbd0 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/die.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/die.rs @@ -2,16 +2,20 @@ //! which the results are unused. use std::collections::HashSet; +use im::Vector; +use noirc_errors::Location; + use crate::ssa::{ ir::{ basic_block::{BasicBlock, BasicBlockId}, dfg::DataFlowGraph, function::Function, - instruction::{Instruction, InstructionId, Intrinsic}, + instruction::{BinaryOp, Instruction, InstructionId, Intrinsic}, post_order::PostOrder, + types::Type, value::{Value, ValueId}, }, - ssa_gen::Ssa, + ssa_gen::{Ssa, SSA_WORD_SIZE}, }; impl Ssa { @@ -20,7 +24,7 @@ impl Ssa { #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn dead_instruction_elimination(mut self) -> Ssa { for function in self.functions.values_mut() { - dead_instruction_elimination(function); + dead_instruction_elimination(function, true); } self } @@ -32,16 +36,29 @@ impl Ssa { /// instructions that reference results from an instruction in another block are evaluated first. /// If we did not iterate blocks in this order we could not safely say whether or not the results /// of its instructions are needed elsewhere. -fn dead_instruction_elimination(function: &mut Function) { +fn dead_instruction_elimination(function: &mut Function, insert_out_of_bounds_checks: bool) { let mut context = Context::default(); for call_data in &function.dfg.data_bus.call_data { context.mark_used_instruction_results(&function.dfg, call_data.array_id); } - let blocks = PostOrder::with_function(function); + let mut inserted_out_of_bounds_checks = false; + let blocks = PostOrder::with_function(function); for block in blocks.as_slice() { - context.remove_unused_instructions_in_block(function, *block); + inserted_out_of_bounds_checks |= context.remove_unused_instructions_in_block( + function, + *block, + insert_out_of_bounds_checks, + ); + } + + // If we inserted out of bounds check, let's run the pass again with those new + // instructions (we don't want to remove those checks, or instructions that are + // dependencies of those checks) + if inserted_out_of_bounds_checks { + dead_instruction_elimination(function, false); + return; } context.remove_rc_instructions(&mut function.dfg); @@ -71,20 +88,40 @@ impl Context { /// values set. This allows DIE to identify whole chains of unused instructions. (If the /// values referenced by an unused instruction were considered to be used, only the head of /// such chains would be removed.) + /// + /// If `insert_out_of_bounds_checks` is true and there are unused ArrayGet/ArraySet that + /// might be out of bounds, this method will insert out of bounds checks instead of + /// removing unused instructions and return `true`. The idea then is to later call this + /// function again with `insert_out_of_bounds_checks` set to false to effectively remove + /// unused instructions but leave the out of bounds checks. fn remove_unused_instructions_in_block( &mut self, function: &mut Function, block_id: BasicBlockId, - ) { + insert_out_of_bounds_checks: bool, + ) -> bool { let block = &function.dfg[block_id]; self.mark_terminator_values_as_used(function, block); - for instruction_id in block.instructions().iter().rev() { + let instructions_len = block.instructions().len(); + + // Indexes of instructions that might be out of bounds. + // We'll remove those, but before that we'll insert bounds checks for them. + let mut possible_index_out_of_bounds_indexes = Vec::new(); + + for (instruction_index, instruction_id) in block.instructions().iter().rev().enumerate() { + let instruction = &function.dfg[*instruction_id]; + if self.is_unused(*instruction_id, function) { self.instructions_to_remove.insert(*instruction_id); - } else { - let instruction = &function.dfg[*instruction_id]; + if insert_out_of_bounds_checks + && instruction_might_result_in_out_of_bounds(function, instruction) + { + possible_index_out_of_bounds_indexes + .push(instructions_len - instruction_index - 1); + } + } else { use Instruction::*; if matches!(instruction, IncrementRc { .. } | DecrementRc { .. }) { self.rc_instructions.push((*instruction_id, block_id)); @@ -96,9 +133,26 @@ impl Context { } } + // If there are some instructions that might trigger an out of bounds error, + // first add constrain checks. Then run the DIE pass again, which will remove those + // but leave the constrains (any any value needed by those constrains) + if !possible_index_out_of_bounds_indexes.is_empty() { + let inserted_check = self.replace_array_instructions_with_out_of_bounds_checks( + function, + block_id, + &mut possible_index_out_of_bounds_indexes, + ); + // There's a slight chance we didn't insert any checks, so we could proceed with DIE. + if inserted_check { + return true; + } + } + function.dfg[block_id] .instructions_mut() .retain(|instruction| !self.instructions_to_remove.contains(instruction)); + + false } /// Returns true if an instruction can be removed. @@ -166,6 +220,288 @@ impl Context { } } } + + /// Replaces unused ArrayGet/ArraySet instructions with out of bounds checks. + /// Returns `true` if at least one check was inserted. + /// Because some ArrayGet might happen in groups (for composite types), if just + /// some of the instructions in a group are used but not all of them, no check + /// is inserted, so this method might return `false`. + fn replace_array_instructions_with_out_of_bounds_checks( + &mut self, + function: &mut Function, + block_id: BasicBlockId, + possible_index_out_of_bounds_indexes: &mut Vec, + ) -> bool { + let mut inserted_check = false; + + // Keep track of the current side effects condition + let mut side_effects_condition = None; + + // Keep track of the next index we need to handle + let mut next_out_of_bounds_index = possible_index_out_of_bounds_indexes.pop(); + + let instructions = function.dfg[block_id].take_instructions(); + for (index, instruction_id) in instructions.iter().enumerate() { + let instruction_id = *instruction_id; + let instruction = &function.dfg[instruction_id]; + + if let Instruction::EnableSideEffects { condition } = instruction { + side_effects_condition = Some(*condition); + + // We still need to keep the EnableSideEffects instruction + function.dfg[block_id].instructions_mut().push(instruction_id); + continue; + }; + + // If it's an ArrayGet we'll deal with groups of it in case the array type is a composite type, + // and adjust `next_out_of_bounds_index` and `possible_index_out_of_bounds_indexes` accordingly + if let Instruction::ArrayGet { array, .. } = instruction { + handle_array_get_group( + function, + array, + index, + &mut next_out_of_bounds_index, + possible_index_out_of_bounds_indexes, + ); + } + + let Some(out_of_bounds_index) = next_out_of_bounds_index else { + // No more out of bounds instructions to insert, just push the current instruction + function.dfg[block_id].instructions_mut().push(instruction_id); + continue; + }; + + if index != out_of_bounds_index { + // This instruction is not out of bounds: let's just push it + function.dfg[block_id].instructions_mut().push(instruction_id); + continue; + } + + // This is an instruction that might be out of bounds: let's add a constrain. + let (array, index) = match instruction { + Instruction::ArrayGet { array, index } + | Instruction::ArraySet { array, index, .. } => (array, index), + _ => panic!("Expected an ArrayGet or ArraySet instruction here"), + }; + + let call_stack = function.dfg.get_call_stack(instruction_id); + + let (lhs, rhs) = if function.dfg.get_numeric_constant(*index).is_some() { + // If we are here it means the index is known but out of bounds. That's always an error! + let false_const = function.dfg.make_constant(false.into(), Type::bool()); + let true_const = function.dfg.make_constant(true.into(), Type::bool()); + (false_const, true_const) + } else { + // `index` will be relative to the flattened array length, so we need to take that into account + let array_length = function.dfg.type_of_value(*array).flattened_size(); + + // If we are here it means the index is dynamic, so let's add a check that it's less than length + let index = function.dfg.insert_instruction_and_results( + Instruction::Cast(*index, Type::unsigned(SSA_WORD_SIZE)), + block_id, + None, + call_stack.clone(), + ); + let index = index.first(); + + let array_typ = Type::unsigned(SSA_WORD_SIZE); + let array_length = + function.dfg.make_constant((array_length as u128).into(), array_typ); + let is_index_out_of_bounds = function.dfg.insert_instruction_and_results( + Instruction::binary(BinaryOp::Lt, index, array_length), + block_id, + None, + call_stack.clone(), + ); + let is_index_out_of_bounds = is_index_out_of_bounds.first(); + let true_const = function.dfg.make_constant(true.into(), Type::bool()); + (is_index_out_of_bounds, true_const) + }; + + let (lhs, rhs) = apply_side_effects( + side_effects_condition, + lhs, + rhs, + function, + block_id, + call_stack.clone(), + ); + + let message = Some("Index out of bounds".to_owned().into()); + function.dfg.insert_instruction_and_results( + Instruction::Constrain(lhs, rhs, message), + block_id, + None, + call_stack, + ); + inserted_check = true; + + next_out_of_bounds_index = possible_index_out_of_bounds_indexes.pop(); + } + + inserted_check + } +} + +fn instruction_might_result_in_out_of_bounds( + function: &Function, + instruction: &Instruction, +) -> bool { + use Instruction::*; + match instruction { + ArrayGet { array, index } | ArraySet { array, index, .. } => { + if function.dfg.try_get_array_length(*array).is_some() { + if let Some(known_index) = function.dfg.get_numeric_constant(*index) { + // `index` will be relative to the flattened array length, so we need to take that into account + let typ = function.dfg.type_of_value(*array); + let array_length = typ.flattened_size(); + known_index >= array_length.into() + } else { + // A dynamic index might always be out of bounds + true + } + } else { + // Slice operations might be out of bounds, but there's no way we + // can insert a check because we don't know a slice's length + false + } + } + _ => false, + } +} + +fn handle_array_get_group( + function: &Function, + array: &ValueId, + index: usize, + next_out_of_bounds_index: &mut Option, + possible_index_out_of_bounds_indexes: &mut Vec, +) { + let Some(array_length) = function.dfg.try_get_array_length(*array) else { + // Nothing to do for slices + return; + }; + + let flattened_size = function.dfg.type_of_value(*array).flattened_size(); + let element_size = flattened_size / array_length; + if element_size <= 1 { + // Not a composite type + return; + }; + + // It's a composite type. + // When doing ArrayGet on a composite type, this **always** results in instructions like these + // (assuming element_size == 3): + // + // 1. v27 = array_get v1, index v26 + // 2. v28 = add v26, u32 1 + // 3. v29 = array_get v1, index v28 + // 4. v30 = add v26, u32 2 + // 5. v31 = array_get v1, index v30 + // + // That means that after this instructions, (element_size - 1) instructions will be + // part of this composite array get, and they'll be two instructions apart. + // + // Now three things can happen: + // a) none of the array_get instructions are unused: in this case they won't be in + // `possible_index_out_of_bounds_indexes` and they won't be removed, nothing to do here + // b) all of the array_get instructions are unused: in this case we can replace **all** + // of them with just one constrain: no need to do one per array_get + // c) some of the array_get instructions are unused, but not all: in this case + // we don't need to insert any constrain, because on a later stage array bound checks + // will be performed anyway. We'll let DIE remove the unused ones, without replacing + // them with bounds checks, and leave the used ones. + // + // To check in which scenario we are we can get from `possible_index_out_of_bounds_indexes` + // (starting from `next_out_of_bounds_index`) while we are in the group ranges + // (1..=5 in the example above) + + let Some(out_of_bounds_index) = *next_out_of_bounds_index else { + // No next unused instruction, so this is case a) and nothing needs to be done here + return; + }; + + if index != out_of_bounds_index { + // The next index is not the one for the current instructions, + // so we are in case a), and nothing needs to be done here + return; + } + + // What's the last instruction that's part of the group? (5 in the example above) + let last_instruction_index = index + 2 * (element_size - 1); + // How many unused instructions are in this group? + let mut unused_count = 1; + loop { + *next_out_of_bounds_index = possible_index_out_of_bounds_indexes.pop(); + if let Some(out_of_bounds_index) = *next_out_of_bounds_index { + if out_of_bounds_index <= last_instruction_index { + unused_count += 1; + if unused_count == element_size { + // We are in case b): we need to insert just one constrain. + // Since we popped all of the group indexes, and given that we + // are analyzing the first instruction in the group, we can + // set `next_out_of_bounds_index` to the current index: + // then a check will be inserted, and no other check will be + // inserted for the rest of the group. + *next_out_of_bounds_index = Some(index); + break; + } else { + continue; + } + } + } + + // We are in case c): some of the instructions are unused. + // We don't need to insert any checks, and given that we already popped + // all of the indexes in the group, there's nothing else to do here. + break; + } +} + +// Given `lhs` and `rhs` values, if there's a side effects condition this will +// return (`lhs * condition`, `rhs * condition`), otherwise just (`lhs`, `rhs`) +fn apply_side_effects( + side_effects_condition: Option, + lhs: ValueId, + rhs: ValueId, + function: &mut Function, + block_id: BasicBlockId, + call_stack: Vector, +) -> (ValueId, ValueId) { + // See if there's an active "enable side effects" condition + let Some(condition) = side_effects_condition else { + return (lhs, rhs); + }; + + let dfg = &mut function.dfg; + + // Condition needs to be cast to argument type in order to multiply them together. + // In our case, lhs is always a boolean. + let casted_condition = dfg.insert_instruction_and_results( + Instruction::Cast(condition, Type::bool()), + block_id, + None, + call_stack.clone(), + ); + let casted_condition = casted_condition.first(); + + let lhs = dfg.insert_instruction_and_results( + Instruction::binary(BinaryOp::Mul, lhs, casted_condition), + block_id, + None, + call_stack.clone(), + ); + let lhs = lhs.first(); + + let rhs = dfg.insert_instruction_and_results( + Instruction::binary(BinaryOp::Mul, rhs, casted_condition), + block_id, + None, + call_stack, + ); + let rhs = rhs.first(); + + (lhs, rhs) } #[cfg(test)] diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index ef7b9f2be55..12bc6fe2c62 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -23,7 +23,7 @@ use crate::{ hir::comptime::{errors::IResult, value::add_token_spans, InterpreterError, Value}, hir_def::function::FunctionBody, macros_api::{ModuleDefId, NodeInterner, Signedness}, - node_interner::DefinitionKind, + node_interner::{DefinitionKind, TraitImplKind}, parser::{self}, token::{SpannedToken, Token}, QuotedType, Shared, Type, @@ -93,6 +93,9 @@ impl<'local, 'context> Interpreter<'local, 'context> { "type_as_struct" => type_as_struct(arguments, return_type, location), "type_as_tuple" => type_as_tuple(arguments, return_type, location), "type_eq" => type_eq(arguments, location), + "type_get_trait_impl" => { + type_get_trait_impl(interner, arguments, return_type, location) + } "type_implements" => type_implements(interner, arguments, location), "type_is_bool" => type_is_bool(arguments, location), "type_is_field" => type_is_field(arguments, location), @@ -507,6 +510,26 @@ fn type_eq(arguments: Vec<(Value, Location)>, location: Location) -> IResult Option +fn type_get_trait_impl( + interner: &NodeInterner, + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + let (typ, constraint) = check_two_arguments(arguments, location)?; + + let typ = get_type(typ)?; + let (trait_id, generics) = get_trait_constraint(constraint)?; + + let option_value = match interner.try_lookup_trait_implementation(&typ, trait_id, &generics) { + Ok((TraitImplKind::Normal(trait_impl_id), _)) => Some(Value::TraitImpl(trait_impl_id)), + _ => None, + }; + + option(return_type, option_value) +} + // fn implements(self, constraint: TraitConstraint) -> bool fn type_implements( interner: &NodeInterner, diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/value.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/value.rs index d5408309e55..d65c2bb7dcc 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -9,12 +9,15 @@ use noirc_errors::{Location, Span}; use crate::{ ast::{ArrayLiteral, ConstructorExpression, Ident, IntegerBitSize, Signedness}, hir::def_map::ModuleId, - hir_def::expr::{HirArrayLiteral, HirConstructorExpression, HirIdent, HirLambda, ImplKind}, + hir_def::{ + expr::{HirArrayLiteral, HirConstructorExpression, HirIdent, HirLambda, ImplKind}, + traits::TraitConstraint, + }, macros_api::{ Expression, ExpressionKind, HirExpression, HirLiteral, Literal, NodeInterner, Path, StructId, }, - node_interner::{ExprId, FuncId, TraitId}, + node_interner::{ExprId, FuncId, TraitId, TraitImplId}, parser::{self, NoirParser, TopLevelStatement}, token::{SpannedToken, Token, Tokens}, QuotedType, Shared, Type, TypeBindings, @@ -53,6 +56,7 @@ pub enum Value { StructDefinition(StructId), TraitConstraint(TraitId, /* trait generics */ Vec), TraitDefinition(TraitId), + TraitImpl(TraitImplId), FunctionDefinition(FuncId), ModuleDefinition(ModuleId), Type(Type), @@ -100,6 +104,7 @@ impl Value { } Value::TraitConstraint { .. } => Type::Quoted(QuotedType::TraitConstraint), Value::TraitDefinition(_) => Type::Quoted(QuotedType::TraitDefinition), + Value::TraitImpl(_) => Type::Quoted(QuotedType::TraitImpl), Value::FunctionDefinition(_) => Type::Quoted(QuotedType::FunctionDefinition), Value::ModuleDefinition(_) => Type::Quoted(QuotedType::Module), Value::Type(_) => Type::Quoted(QuotedType::Type), @@ -230,6 +235,7 @@ impl Value { | Value::StructDefinition(_) | Value::TraitConstraint(..) | Value::TraitDefinition(_) + | Value::TraitImpl(_) | Value::FunctionDefinition(_) | Value::Zeroed(_) | Value::Type(_) @@ -353,6 +359,7 @@ impl Value { | Value::StructDefinition(_) | Value::TraitConstraint(..) | Value::TraitDefinition(_) + | Value::TraitImpl(_) | Value::FunctionDefinition(_) | Value::Zeroed(_) | Value::Type(_) @@ -516,18 +523,40 @@ impl<'value, 'interner> Display for ValuePrinter<'value, 'interner> { write!(f, "{}", def.name) } Value::TraitConstraint(trait_id, generics) => { - let trait_ = self.interner.get_trait(*trait_id); - let generic_string = vecmap(generics, ToString::to_string).join(", "); - if generics.is_empty() { - write!(f, "{}", trait_.name) - } else { - write!(f, "{}<{generic_string}>", trait_.name) - } + write!(f, "{}", display_trait_id_and_generics(self.interner, trait_id, generics)) } Value::TraitDefinition(trait_id) => { let trait_ = self.interner.get_trait(*trait_id); write!(f, "{}", trait_.name) } + Value::TraitImpl(trait_impl_id) => { + let trait_impl = self.interner.get_trait_implementation(*trait_impl_id); + let trait_impl = trait_impl.borrow(); + + let generic_string = + vecmap(&trait_impl.trait_generics, ToString::to_string).join(", "); + let generic_string = if generic_string.is_empty() { + generic_string + } else { + format!("<{}>", generic_string) + }; + + let where_clause = vecmap(&trait_impl.where_clause, |trait_constraint| { + display_trait_constraint(self.interner, trait_constraint) + }); + let where_clause = where_clause.join(", "); + let where_clause = if where_clause.is_empty() { + where_clause + } else { + format!(" where {}", where_clause) + }; + + write!( + f, + "impl {}{} for {}{}", + trait_impl.ident, generic_string, trait_impl.typ, where_clause + ) + } Value::FunctionDefinition(function_id) => { write!(f, "{}", self.interner.function_name(function_id)) } @@ -538,3 +567,26 @@ impl<'value, 'interner> Display for ValuePrinter<'value, 'interner> { } } } + +fn display_trait_id_and_generics( + interner: &NodeInterner, + trait_id: &TraitId, + generics: &Vec, +) -> String { + let trait_ = interner.get_trait(*trait_id); + let generic_string = vecmap(generics, ToString::to_string).join(", "); + if generics.is_empty() { + format!("{}", trait_.name) + } else { + format!("{}<{generic_string}>", trait_.name) + } +} + +fn display_trait_constraint(interner: &NodeInterner, trait_constraint: &TraitConstraint) -> String { + let trait_constraint_string = display_trait_id_and_generics( + interner, + &trait_constraint.trait_id, + &trait_constraint.trait_generics, + ); + format!("{}: {}", trait_constraint.typ, trait_constraint_string) +} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs index 177d23c74dd..c2d55284ef9 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs @@ -146,6 +146,7 @@ pub enum QuotedType { StructDefinition, TraitConstraint, TraitDefinition, + TraitImpl, FunctionDefinition, Module, } @@ -665,12 +666,12 @@ impl std::fmt::Display for Type { Type::Function(args, ret, env) => { let closure_env_text = match **env { Type::Unit => "".to_string(), - _ => format!(" with env {env}"), + _ => format!("[{env}]"), }; let args = vecmap(args.iter(), ToString::to_string); - write!(f, "fn({}) -> {ret}{closure_env_text}", args.join(", ")) + write!(f, "fn{closure_env_text}({}) -> {ret}", args.join(", ")) } Type::MutableReference(element) => { write!(f, "&mut {element}") @@ -727,6 +728,7 @@ impl std::fmt::Display for QuotedType { QuotedType::StructDefinition => write!(f, "StructDefinition"), QuotedType::TraitDefinition => write!(f, "TraitDefinition"), QuotedType::TraitConstraint => write!(f, "TraitConstraint"), + QuotedType::TraitImpl => write!(f, "TraitImpl"), QuotedType::FunctionDefinition => write!(f, "FunctionDefinition"), QuotedType::Module => write!(f, "Module"), } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs b/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs index 4222d2b585f..c4145c62791 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs @@ -925,6 +925,7 @@ pub enum Keyword { Trait, TraitConstraint, TraitDefinition, + TraitImpl, Type, TypeType, Unchecked, @@ -977,6 +978,7 @@ impl fmt::Display for Keyword { Keyword::Trait => write!(f, "trait"), Keyword::TraitConstraint => write!(f, "TraitConstraint"), Keyword::TraitDefinition => write!(f, "TraitDefinition"), + Keyword::TraitImpl => write!(f, "TraitImpl"), Keyword::Type => write!(f, "type"), Keyword::TypeType => write!(f, "Type"), Keyword::Unchecked => write!(f, "unchecked"), @@ -1031,6 +1033,7 @@ impl Keyword { "trait" => Keyword::Trait, "TraitConstraint" => Keyword::TraitConstraint, "TraitDefinition" => Keyword::TraitDefinition, + "TraitImpl" => Keyword::TraitImpl, "type" => Keyword::Type, "Type" => Keyword::TypeType, "StructDefinition" => Keyword::StructDefinition, diff --git a/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs b/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs index 43e742b940e..9b9bfd463b9 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs @@ -179,10 +179,10 @@ pub struct NodeInterner { /// may have both `impl Struct { fn foo(){} }` and `impl Struct { fn foo(){} }`. /// If this happens, the returned Vec will have 2 entries and we'll need to further /// disambiguate them by checking the type of each function. - struct_methods: HashMap<(StructId, String), Methods>, + struct_methods: HashMap>, /// Methods on primitive types defined in the stdlib. - primitive_methods: HashMap<(TypeMethodKey, String), Methods>, + primitive_methods: HashMap>, // For trait implementation functions, this is their self type and trait they belong to func_id_to_trait: HashMap, @@ -1131,22 +1131,27 @@ impl NodeInterner { self.structs[&id].clone() } - pub fn get_struct_methods(&self, id: StructId) -> Vec { - self.struct_methods - .keys() - .filter_map(|(key_id, name)| { - if key_id == &id { - Some( - self.struct_methods - .get(&(*key_id, name.clone())) - .expect("get_struct_methods given invalid StructId") - .clone(), - ) - } else { - None - } - }) - .collect() + pub fn get_struct_methods(&self, id: StructId) -> Option<&HashMap> { + self.struct_methods.get(&id) + } + + fn get_primitive_methods(&self, key: TypeMethodKey) -> Option<&HashMap> { + self.primitive_methods.get(&key) + } + + pub fn get_type_methods(&self, typ: &Type) -> Option<&HashMap> { + match typ { + Type::Struct(struct_type, _) => { + let struct_type = struct_type.borrow(); + self.get_struct_methods(struct_type.id) + } + Type::Alias(type_alias, generics) => { + let type_alias = type_alias.borrow(); + let typ = type_alias.get_type(generics); + self.get_type_methods(&typ) + } + _ => get_type_method_key(typ).and_then(|key| self.get_primitive_methods(key)), + } } pub fn get_trait(&self, id: TraitId) -> &Trait { @@ -1300,8 +1305,12 @@ impl NodeInterner { return Some(existing); } - let key = (id, method_name); - self.struct_methods.entry(key).or_default().add_method(method_id, is_trait_method); + self.struct_methods + .entry(id) + .or_default() + .entry(method_name) + .or_default() + .add_method(method_id, is_trait_method); None } Type::Error => None, @@ -1314,7 +1323,9 @@ impl NodeInterner { unreachable!("Cannot add a method to the unsupported type '{}'", other) }); self.primitive_methods - .entry((key, method_name)) + .entry(key) + .or_default() + .entry(method_name) .or_default() .add_method(method_id, is_trait_method); None @@ -1648,7 +1659,7 @@ impl NodeInterner { method_name: &str, force_type_check: bool, ) -> Option { - let methods = self.struct_methods.get(&(id, method_name.to_owned())); + let methods = self.struct_methods.get(&id).and_then(|h| h.get(method_name)); // If there is only one method, just return it immediately. // It will still be typechecked later. @@ -1673,8 +1684,8 @@ impl NodeInterner { } else { // Failed to find a match for the type in question, switch to looking at impls // for all types `T`, e.g. `impl Foo for T` - let key = &(TypeMethodKey::Generic, method_name.to_owned()); - let global_methods = self.primitive_methods.get(key)?; + let global_methods = + self.primitive_methods.get(&TypeMethodKey::Generic)?.get(method_name)?; global_methods.find_matching_method(typ, self) } } @@ -1682,7 +1693,7 @@ impl NodeInterner { /// Looks up a given method name on the given primitive type. pub fn lookup_primitive_method(&self, typ: &Type, method_name: &str) -> Option { let key = get_type_method_key(typ)?; - let methods = self.primitive_methods.get(&(key, method_name.to_owned()))?; + let methods = self.primitive_methods.get(&key)?.get(method_name)?; self.find_matching_method(typ, Some(methods), method_name) } @@ -1803,6 +1814,11 @@ impl NodeInterner { self.prefix_operator_traits.insert(operator, trait_id); } + pub fn is_operator_trait(&self, trait_id: TraitId) -> bool { + self.infix_operator_traits.values().any(|id| *id == trait_id) + || self.prefix_operator_traits.values().any(|id| *id == trait_id) + } + /// This function is needed when creating a NodeInterner for testing so that calls /// to `get_operator_trait` do not panic when the stdlib isn't present. #[cfg(test)] @@ -2017,7 +2033,7 @@ impl Methods { } /// Iterate through each method, starting with the direct methods - fn iter(&self) -> impl Iterator + '_ { + pub fn iter(&self) -> impl Iterator + '_ { self.direct.iter().copied().chain(self.trait_impl_methods.iter().copied()) } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/errors.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/errors.rs index 36d3ce5898c..b2de3b0794b 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/errors.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/errors.rs @@ -16,6 +16,8 @@ pub enum ParserErrorReason { ExpectedFieldName(Token), #[error("expected a pattern but found a type - {0}")] ExpectedPatternButFoundType(Token), + #[error("expected an identifier after .")] + ExpectedIdentifierAfterDot, #[error("expected an identifier after ::")] ExpectedIdentifierAfterColons, #[error("Expected a ; separating these two statements")] diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs index 5a97d66df9a..876fc454565 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs @@ -847,6 +847,9 @@ where ArrayIndex(Expression), Cast(UnresolvedType), MemberAccess(UnaryRhsMemberAccess), + /// This is to allow `foo.` (no identifier afterwards) to be parsed as `foo` + /// and produce an error, rather than just erroring (for LSP). + JustADot, } // `(arg1, ..., argN)` in `my_func(arg1, ..., argN)` @@ -890,7 +893,16 @@ where }) .labelled(ParsingRuleLabel::FieldAccess); - let rhs = choice((call_rhs, array_rhs, cast_rhs, member_rhs)); + let just_a_dot = + just(Token::Dot).map(|_| UnaryRhs::JustADot).validate(|value, span, emit_error| { + emit_error(ParserError::with_reason( + ParserErrorReason::ExpectedIdentifierAfterDot, + span, + )); + value + }); + + let rhs = choice((call_rhs, array_rhs, cast_rhs, member_rhs, just_a_dot)); foldl_with_span( atom(expr_parser, expr_no_constructors, statement, allow_constructors), @@ -904,6 +916,7 @@ where UnaryRhs::MemberAccess(field) => { Expression::member_access_or_method_call(lhs, field, span) } + UnaryRhs::JustADot => lhs, }, ) } @@ -1673,4 +1686,27 @@ mod test { let block_expr = block_expr.expect("Failed to parse module"); assert_eq!(block_expr.statements.len(), 2); } + + #[test] + fn test_parses_member_access_without_member_name() { + let src = "{ foo. }"; + + let (Some(block_expression), errors) = parse_recover(block(fresh_statement()), src) else { + panic!("Expected to be able to parse a block expression"); + }; + + assert_eq!(errors.len(), 1); + assert_eq!(errors[0].message, "expected an identifier after ."); + + let statement = &block_expression.statements[0]; + let StatementKind::Expression(expr) = &statement.kind else { + panic!("Expected an expression statement"); + }; + + let ExpressionKind::Variable(var) = &expr.kind else { + panic!("Expected a variable expression"); + }; + + assert_eq!(var.to_string(), "foo"); + } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/types.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/types.rs index 7c551ca96d1..7644c451dff 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/types.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/types.rs @@ -31,6 +31,7 @@ pub(super) fn parse_type_inner<'a>( struct_definition_type(), trait_constraint_type(), trait_definition_type(), + trait_impl_type(), function_definition_type(), module_type(), top_level_item_type(), @@ -107,6 +108,11 @@ pub(super) fn trait_definition_type() -> impl NoirParser { }) } +pub(super) fn trait_impl_type() -> impl NoirParser { + keyword(Keyword::TraitImpl) + .map_with_span(|_, span| UnresolvedTypeData::Quoted(QuotedType::TraitImpl).with_span(span)) +} + pub(super) fn function_definition_type() -> impl NoirParser { keyword(Keyword::FunctionDefinition).map_with_span(|_, span| { UnresolvedTypeData::Quoted(QuotedType::FunctionDefinition).with_span(span) diff --git a/noir/noir-repo/compiler/noirc_frontend/src/resolve_locations.rs b/noir/noir-repo/compiler/noirc_frontend/src/resolve_locations.rs index efb430b75eb..61ff6baf919 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/resolve_locations.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/resolve_locations.rs @@ -31,6 +31,12 @@ impl NodeInterner { location_candidate.map(|(index, _location)| *index) } + /// Returns the Type of the expression that exists at the given location. + pub fn type_at_location(&self, location: Location) -> Option { + let index = self.find_location_index(location)?; + Some(self.id_type(index)) + } + /// Returns the [Location] of the definition of the given Ident found at [Span] of the given [FileId]. /// Returns [None] when definition is not found. pub fn get_definition_location_from( diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.33.0/reference/debugger/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.33.0/reference/debugger/_category_.json index f0768339ea9..27869205ad3 100644 --- a/noir/noir-repo/docs/versioned_docs/version-v0.33.0/reference/debugger/_category_.json +++ b/noir/noir-repo/docs/versioned_docs/version-v0.33.0/reference/debugger/_category_.json @@ -3,4 +3,4 @@ "position": 1, "collapsible": true, "collapsed": true -} \ No newline at end of file +} diff --git a/noir/noir-repo/noir_stdlib/src/meta/typ.nr b/noir/noir-repo/noir_stdlib/src/meta/typ.nr index ad669e93c0a..67ad2a96739 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/typ.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/typ.nr @@ -20,6 +20,9 @@ impl Type { #[builtin(type_as_tuple)] fn as_tuple(self) -> Option<[Type]> {} + #[builtin(type_get_trait_impl)] + fn get_trait_impl(self, constraint: TraitConstraint) -> Option {} + #[builtin(type_implements)] fn implements(self, constraint: TraitConstraint) -> bool {} diff --git a/noir/noir-repo/scripts/install_bb.sh b/noir/noir-repo/scripts/install_bb.sh index 65a449be543..91b9180f138 100755 --- a/noir/noir-repo/scripts/install_bb.sh +++ b/noir/noir-repo/scripts/install_bb.sh @@ -1,6 +1,6 @@ #!/bin/bash -VERSION="0.47.1" +VERSION="0.48.0" BBUP_PATH=~/.bb/bbup diff --git a/noir/noir-repo/test_programs/compile_success_empty/comptime_type/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/comptime_type/src/main.nr index 170292b0e37..f0b53a392ed 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/comptime_type/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_empty/comptime_type/src/main.nr @@ -108,6 +108,8 @@ fn main() { let some_trait_field = quote { SomeTrait }.as_trait_constraint(); assert(!struct_implements_some_trait.implements(some_trait_field)); assert(!struct_does_not_implement_some_trait.implements(some_trait_field)); + + let _trait_impl = struct_implements_some_trait.get_trait_impl(some_trait_i32).unwrap(); } } @@ -117,5 +119,7 @@ fn function_with_where(_x: T) where T: SomeTrait { let t = quote { T }.as_type(); let some_trait_i32 = quote { SomeTrait }.as_trait_constraint(); assert(t.implements(some_trait_i32)); + + assert(t.get_trait_impl(some_trait_i32).is_none()); } } diff --git a/noir/noir-repo/test_programs/execution_failure/unused_array_get_known_index_out_of_bounds/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/unused_array_get_known_index_out_of_bounds/Nargo.toml new file mode 100644 index 00000000000..4123215e2b6 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_failure/unused_array_get_known_index_out_of_bounds/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "unused_array_get_known_index_out_of_bounds" +type = "bin" +authors = [""] +compiler_version = ">=0.31.0" + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_failure/unused_array_get_known_index_out_of_bounds/Prover.toml b/noir/noir-repo/test_programs/execution_failure/unused_array_get_known_index_out_of_bounds/Prover.toml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/test_programs/execution_failure/unused_array_get_known_index_out_of_bounds/src/main.nr b/noir/noir-repo/test_programs/execution_failure/unused_array_get_known_index_out_of_bounds/src/main.nr new file mode 100644 index 00000000000..bdc645ec483 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_failure/unused_array_get_known_index_out_of_bounds/src/main.nr @@ -0,0 +1,4 @@ +fn main() { + let array = [1, 2, 3]; + let _ = array[10]; // Index out of bounds +} diff --git a/noir/noir-repo/test_programs/execution_failure/unused_array_get_unknown_index_out_of_bounds/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/unused_array_get_unknown_index_out_of_bounds/Nargo.toml new file mode 100644 index 00000000000..04d9146b881 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_failure/unused_array_get_unknown_index_out_of_bounds/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "unused_array_get_unknown_index_out_of_bounds" +type = "bin" +authors = [""] +compiler_version = ">=0.31.0" + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_failure/unused_array_get_unknown_index_out_of_bounds/Prover.toml b/noir/noir-repo/test_programs/execution_failure/unused_array_get_unknown_index_out_of_bounds/Prover.toml new file mode 100644 index 00000000000..1ec81884d61 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_failure/unused_array_get_unknown_index_out_of_bounds/Prover.toml @@ -0,0 +1 @@ +x = "10" \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_failure/unused_array_get_unknown_index_out_of_bounds/src/main.nr b/noir/noir-repo/test_programs/execution_failure/unused_array_get_unknown_index_out_of_bounds/src/main.nr new file mode 100644 index 00000000000..15c2d1f1f23 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_failure/unused_array_get_unknown_index_out_of_bounds/src/main.nr @@ -0,0 +1,4 @@ +fn main(x: Field) { + let array = [1, 2, 3]; + let _ = array[x]; // Index out of bounds +} diff --git a/noir/noir-repo/test_programs/execution_failure/unused_array_set_known_index_out_of_bounds/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/unused_array_set_known_index_out_of_bounds/Nargo.toml new file mode 100644 index 00000000000..b8fe7e955a1 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_failure/unused_array_set_known_index_out_of_bounds/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "unused_array_set_known_index_out_of_bounds" +type = "bin" +authors = [""] +compiler_version = ">=0.31.0" + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_failure/unused_array_set_known_index_out_of_bounds/Prover.toml b/noir/noir-repo/test_programs/execution_failure/unused_array_set_known_index_out_of_bounds/Prover.toml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/test_programs/execution_failure/unused_array_set_known_index_out_of_bounds/src/main.nr b/noir/noir-repo/test_programs/execution_failure/unused_array_set_known_index_out_of_bounds/src/main.nr new file mode 100644 index 00000000000..9c447aee08f --- /dev/null +++ b/noir/noir-repo/test_programs/execution_failure/unused_array_set_known_index_out_of_bounds/src/main.nr @@ -0,0 +1,4 @@ +fn main() { + let mut array = [1, 2, 3]; + array[10] = 1; // Index out of bounds +} diff --git a/noir/noir-repo/test_programs/execution_failure/unused_array_set_unknown_index_out_of_bounds/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/unused_array_set_unknown_index_out_of_bounds/Nargo.toml new file mode 100644 index 00000000000..ccc00956e80 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_failure/unused_array_set_unknown_index_out_of_bounds/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "unused_array_set_unknown_index_out_of_bounds" +type = "bin" +authors = [""] +compiler_version = ">=0.31.0" + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_failure/unused_array_set_unknown_index_out_of_bounds/Prover.toml b/noir/noir-repo/test_programs/execution_failure/unused_array_set_unknown_index_out_of_bounds/Prover.toml new file mode 100644 index 00000000000..1ec81884d61 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_failure/unused_array_set_unknown_index_out_of_bounds/Prover.toml @@ -0,0 +1 @@ +x = "10" \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_failure/unused_array_set_unknown_index_out_of_bounds/src/main.nr b/noir/noir-repo/test_programs/execution_failure/unused_array_set_unknown_index_out_of_bounds/src/main.nr new file mode 100644 index 00000000000..dbde898f7a9 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_failure/unused_array_set_unknown_index_out_of_bounds/src/main.nr @@ -0,0 +1,4 @@ +fn main(x: Field) { + let mut array = [1, 2, 3]; + array[x] = 1; // Index out of bounds +} diff --git a/noir/noir-repo/test_programs/execution_failure/unused_slice_get_known_index_out_of_bounds/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/unused_slice_get_known_index_out_of_bounds/Nargo.toml new file mode 100644 index 00000000000..f2acfa4d4cf --- /dev/null +++ b/noir/noir-repo/test_programs/execution_failure/unused_slice_get_known_index_out_of_bounds/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "unused_slice_get_known_index_out_of_bounds" +type = "bin" +authors = [""] +compiler_version = ">=0.31.0" + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_failure/unused_slice_get_known_index_out_of_bounds/Prover.toml b/noir/noir-repo/test_programs/execution_failure/unused_slice_get_known_index_out_of_bounds/Prover.toml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/test_programs/execution_failure/unused_slice_get_known_index_out_of_bounds/src/main.nr b/noir/noir-repo/test_programs/execution_failure/unused_slice_get_known_index_out_of_bounds/src/main.nr new file mode 100644 index 00000000000..59e57664bbe --- /dev/null +++ b/noir/noir-repo/test_programs/execution_failure/unused_slice_get_known_index_out_of_bounds/src/main.nr @@ -0,0 +1,4 @@ +fn main() { + let slice = &[1, 2, 3]; + let _ = slice[10]; // Index out of bounds +} diff --git a/noir/noir-repo/test_programs/execution_failure/unused_slice_get_unknown_index_out_of_bounds/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/unused_slice_get_unknown_index_out_of_bounds/Nargo.toml new file mode 100644 index 00000000000..3c8ae8fe07a --- /dev/null +++ b/noir/noir-repo/test_programs/execution_failure/unused_slice_get_unknown_index_out_of_bounds/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "unused_slice_get_unknown_index_out_of_bounds" +type = "bin" +authors = [""] +compiler_version = ">=0.31.0" + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_failure/unused_slice_get_unknown_index_out_of_bounds/Prover.toml b/noir/noir-repo/test_programs/execution_failure/unused_slice_get_unknown_index_out_of_bounds/Prover.toml new file mode 100644 index 00000000000..1ec81884d61 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_failure/unused_slice_get_unknown_index_out_of_bounds/Prover.toml @@ -0,0 +1 @@ +x = "10" \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_failure/unused_slice_get_unknown_index_out_of_bounds/src/main.nr b/noir/noir-repo/test_programs/execution_failure/unused_slice_get_unknown_index_out_of_bounds/src/main.nr new file mode 100644 index 00000000000..5a62e0e9843 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_failure/unused_slice_get_unknown_index_out_of_bounds/src/main.nr @@ -0,0 +1,4 @@ +fn main(x: Field) { + let slice = &[1, 2, 3]; + let _ = slice[x]; // Index out of bounds +} diff --git a/noir/noir-repo/test_programs/execution_success/verify_honk_proof/Nargo.toml b/noir/noir-repo/test_programs/execution_success/verify_honk_proof/Nargo.toml deleted file mode 100644 index 8fce1bf44b6..00000000000 --- a/noir/noir-repo/test_programs/execution_success/verify_honk_proof/Nargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "verify_honk_proof" -type = "bin" -authors = [""] - -[dependencies] diff --git a/noir/noir-repo/test_programs/execution_success/verify_honk_proof/Prover.toml b/noir/noir-repo/test_programs/execution_success/verify_honk_proof/Prover.toml deleted file mode 100644 index f2e6bbed8ef..00000000000 --- a/noir/noir-repo/test_programs/execution_success/verify_honk_proof/Prover.toml +++ /dev/null @@ -1,537 +0,0 @@ -key_hash = "0x096129b1c6e108252fc5c829c4cc9b7e8f0d1fd9f29c2532b563d6396645e08f" -proof = [ - "0x0000000000000000000000000000000000000000000000000000000000000020", - "0x0000000000000000000000000000000000000000000000000000000000000011", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000042ab5d6d1986846cf", - "0x00000000000000000000000000000000000000000000000b75c020998797da78", - "0x0000000000000000000000000000000000000000000000005a107acb64952eca", - "0x000000000000000000000000000000000000000000000000000031e97a575e9d", - "0x00000000000000000000000000000000000000000000000b5666547acf8bd5a4", - "0x00000000000000000000000000000000000000000000000c410db10a01750aeb", - "0x00000000000000000000000000000000000000000000000d722669117f9758a4", - "0x000000000000000000000000000000000000000000000000000178cbf4206471", - "0x000000000000000000000000000000000000000000000000e91b8a11e7842c38", - "0x000000000000000000000000000000000000000000000007fd51009034b3357f", - "0x000000000000000000000000000000000000000000000009889939f81e9c7402", - "0x0000000000000000000000000000000000000000000000000000f94656a2ca48", - "0x000000000000000000000000000000000000000000000006fb128b46c1ddb67f", - "0x0000000000000000000000000000000000000000000000093fe27776f50224bd", - "0x000000000000000000000000000000000000000000000004a0c80c0da527a081", - "0x0000000000000000000000000000000000000000000000000001b52c2020d746", - "0x0000000000000000000000000000005a9bae947e1e91af9e4033d8d6aa6ed632", - "0x000000000000000000000000000000000025e485e013446d4ac7981c88ba6ecc", - "0x000000000000000000000000000000ff1e0496e30ab24a63b32b2d1120b76e62", - "0x00000000000000000000000000000000001afe0a8a685d7cd85d1010e55d9d7c", - "0x000000000000000000000000000000b0804efd6573805f991458295f510a2004", - "0x00000000000000000000000000000000000c81a178016e2fe18605022d5a8b0e", - "0x000000000000000000000000000000eba51e76eb1cfff60a53a0092a3c3dea47", - "0x000000000000000000000000000000000022e7466247b533282f5936ac4e6c15", - "0x00000000000000000000000000000071b1d76edf770edff98f00ff4deec264cd", - "0x00000000000000000000000000000000001e48128e68794d8861fcbb2986a383", - "0x000000000000000000000000000000d3a2af4915ae6d86b097adc377fafda2d4", - "0x000000000000000000000000000000000006359de9ca452dab3a4f1f8d9c9d98", - "0x0000000000000000000000000000000d9d719a8b9f020ad3642d60fe704e696f", - "0x00000000000000000000000000000000000ddfdbbdefc4ac1580ed38e12cfa49", - "0x0000000000000000000000000000008289fe9754ce48cd01b7be96a861b5e157", - "0x00000000000000000000000000000000000ff3e0896bdea021253b3d360fa678", - "0x0000000000000000000000000000000d9d719a8b9f020ad3642d60fe704e696f", - "0x00000000000000000000000000000000000ddfdbbdefc4ac1580ed38e12cfa49", - "0x0000000000000000000000000000008289fe9754ce48cd01b7be96a861b5e157", - "0x00000000000000000000000000000000000ff3e0896bdea021253b3d360fa678", - "0x000000000000000000000000000000f968b227a358a305607f3efc933823d288", - "0x00000000000000000000000000000000000eaf8adb390375a76d95e918b65e08", - "0x000000000000000000000000000000bb34b4b447aae56f5e24f81c3acd6d547f", - "0x00000000000000000000000000000000002175d012746260ebcfe339a91a81e1", - "0x0000000000000000000000000000005b739ed2075f2b046062b8fc6a2d1e9863", - "0x00000000000000000000000000000000001285cd1030d338c0e1603b4da2c838", - "0x00000000000000000000000000000027447d6c281eb38b2b937af4a516d60c04", - "0x000000000000000000000000000000000019bc3d980465fbb4a656a74296fc58", - "0x000000000000000000000000000000b484788ace8f7df86dd5e325d2e9b12599", - "0x00000000000000000000000000000000000a2ca0d10eb7b767114ae230b728d3", - "0x000000000000000000000000000000c6dfc7092f16f95795e437664498b88d53", - "0x0000000000000000000000000000000000131067b4e4d95a4f6f8cf5c9b5450a", - "0x0f413f22eec51f2a02800e0cafaeec1d92d744fbbaef213c687b9edabd6985f5", - "0x21230f4ff26c80ffb5d037a9d1d26c3f955ca34cbeca4f54db6656b932967a0c", - "0x0521f877fe35535767f99597cc50effbd283dcae6812ee0a7620d796ccbfd642", - "0x202b01350a9cc5c20ec0f3eaada338c0a3b793811bd539418ffa3cc4302615e2", - "0x2d1214d9b0d41058ad4a172d9c0aecc5bdabe95e687c3465050c6b5396509be4", - "0x1113b344a151b0af091cb28d728b752ebb4865da6cd7ee68471b961ca5cf69b9", - "0x2aa66d0954bb83e17bd5c9928d3aa7a7df75d741d409f7c15ba596804ba643fb", - "0x2e26bc7a530771ef7a95d5360d537e41cf94d8a0942764ff09881c107f91a106", - "0x0f14f32b921bb63ad1df00adab7c82af58ea8aa7f353f14b281208d8c5fab504", - "0x13429515c0c53b6502bbcdf545defb3cb69a986c9263e070fcbb397391aae1a3", - "0x1f21cac5e2f262afc1006a21454cc6bcb018c44e53ad8ab61cebbac99e539176", - "0x2a9886a6ddc8a61b097c668cd362fc8acdee8dde74f7b1af192c3e060bb2948f", - "0x2d718181e408ead2e9bcd30a84ad1fccbaf8d48ab6d1820bad4933d284b503c4", - "0x2634c1aafc902f14508f34d3d7e9d485f42d1a4c95b5a1ef73711ed0d3c68d77", - "0x092ede9777e6472ce5ffd8c963d466006189e960e2c591d338dc8d4af1a057fb", - "0x1cba45b17fd24f1cb1b4ab7b83eee741f6c77ba70a497dc4de259eceb7d5ea26", - "0x246e887c7bf2e17f919b2393b6e9b00b33e8822d862544a775aac05cb7bff710", - "0x04c3f539fe8689971948afcb437f1ecbd444a5bddaca1c8a450348dcd8480047", - "0x20c6a423ae4fd58e8951aa378d02d77baf90508ceb48856db2319d70938b186e", - "0x1bcf8786b554b3316d8ebdbc9d006a4e5d4865aad512ffd404b7f83550d3d030", - "0x09ab038260518f0970564afcd6bf22e2abf6b1fa5e12a327bbf195b6ca5edd78", - "0x1024e32554746f89c195286ba6ccfc9765e5d14bbe8064bc6fdf22d16ec6b495", - "0x17706656f8dbd7e47bb257a6428f0cb7278ea02fa9e6ce431d7bcc9133fba9c7", - "0x25a3e8a33c15ef2a4dd16313a6049bf1d468b4cdc141f238f2d51a1e8e1c22b3", - "0x1198863f08006edb27aee23164fb117a4ddec1bf1ed89807aa907e5cd24bf068", - "0x1862b4856b5b4d4a064f873e221703e4e2cd1ebfca1337dedca56485c38ed5a0", - "0x062214af1ea6dd6bf8895b92d394571c43970b6f967e1c794624d96071b25ad3", - "0x1e5be9428ddcf1f9b0cbafc28101e792ec5cf73852b0cd0b84fbff71b4490e09", - "0x2d4189bea5b1e30f63c64bd26df82f18bcaf885ec8887b54634b2557869ce87f", - "0x0f2e5d9a908850e9d44925e17d8b12d1adb1ed029799c9b5858598504242bbc0", - "0x3050dc85746a57931d99f3f35e77c2ba561fba0baa018b79ff1fd544026833ae", - "0x2a591a32437e5e0b875a137fd868bd1b6dbc003ff1b661f26e00627cc7c5cf47", - "0x27946841e1670ad9c65717016d0cedf524724217236e81b9fd0a264a36ebfb0e", - "0x0fc396e9d19d6e68e289602e292ee345542d0d28bf6de34fa62cc577cbdfb1df", - "0x08e7433a07a44c0c9c4dd4b273a2685bbd1a91fd5cf2b43409458fab42a23e1b", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x12bd9bfb029c3503a5c6deea87b0a0f11bb9f7ea584af2d48f3e48d7e09247ae", - "0x2ccc4810748c0a82dfc0f063d0b8c7999ffe9474653080e6ef92b3cb7a428784", - "0x08eb574d7fecadadb508c8bd35fdad06b99110609d679763c2e3645229b1b95a", - "0x0f1a65e747c8021ed7c454a4be1e89b1bce66ead9ed980fa98a7a050eafe98a1", - "0x1c8ff9e36684ec71614dee4c17859b06c742089f6029d3694a16e00dac9b57f1", - "0x0303101a8ba712aeca4da85b767ab8d3ecf489ec7d746f8ee20041717cc000e9", - "0x0aaf64c65e7088e5596108c9601467911fea809ca6540d79af77e6e66e36cd99", - "0x17caf164ce74ea7edfb1390e07763d2197797ec26661b92cde18a98d61d2fddc", - "0x18cb055c7ad6d01437725bb457681d81f3ecadc4f35d838a3c13daf25a44456a", - "0x2d78602b8bbcd32b36a99a6e2d248e7fe044ef1b50813133370412f9ef5299f0", - "0x2b139276ea86d426a115479e4154f72a6bd83a6253bf13e9670dc6b4664378f0", - "0x127c7837b384902c39a104036c09546728571c46c8166b1b9b13b3a615ebb781", - "0x05faa4816f83cf0189a482ad943c94b9ec6474002f2b327f8698763ad0ea0985", - "0x2f90359cc30ee693fb3aced96523cf7aebd152c22329eee56a398d9a4ac0628e", - "0x0a71beaf17a59c5a238f04c1f203848d87502c5057a78c13f0cfb0f9876e7714", - "0x2696c1e6d089556adaeb95c8a5e3065b00a393a38c2d69e9bd6ce8cdc49d87da", - "0x1f3d165a7dc6564a036e451eb9cb7f1e1cb1e6d29daa75e3f135ea3e58a79ccd", - "0x1473a660819bdd838d56122b72b32b267211e9f1103239480ec50fa85c9e1035", - "0x0a8ccaeb22451f391b3fc3467c8e6e900270a7afb7b510e8acf5a4f06f1c0888", - "0x03b3080afc0658cc87e307758cebc171921f43eca159b9dedf7f72aa8dd926bd", - "0x2dd7d6663fa0e1755dfafac352c361fcd64c7f4d53627e3646870ac169cc4a07", - "0x1ec54b883f5f35ccad0e75695af20790d9860104095bab34c9bf01628dd40cb9", - "0x193dff50f83c241f7a9e087a29ce72ecf3f6d8563593f786dcd04c32bcfd4ced", - "0x135122c0dae26cda8ca1c09de8225064ad86d10423ab0aaa53b481aa4626e1d6", - "0x08d5a56cbfab5aeed56d3cdd7fb6b30fc26b0c1a5b63fccd7fa44c53ba6fd35a", - "0x0d12f126dfa2daad3726d00ca339284cc22e36c6d81bb7a4b95c6f9598b60e7c", - "0x2e8b24bbdf2fd839d3c7cae1f0eeb96bfcfaeef30b27476f2fafcb17da78cd5e", - "0x2364acfe0cea39b7f749c5f303b99504977357925f810f684c60f35d16315211", - "0x06ca062eb70b8c51cfac35345e7b6b51f33a8ec9ebe204fb9b4911200bf508b7", - "0x266c0aa1ccb97186815bf69084f600d06ddd934e59a38dfe602ee5d6b9487f22", - "0x1d817537a49c6d0e3b4b65c6665334b91d7593142e60065048be9e55ceb5e7ab", - "0x05e9b7256a368df053c691952b59e9327a7c12ed322bbd6f72c669b9b9c26d49", - "0x05e9b7256a368df053c691952b59e9327a7c12ed322bbd6f72c669b9b9c26d49", - "0x25b77026673a1e613e50df0e88fb510973739d5f9064bd364079a9f884209632", - "0x25c9bc7a3f6aae3d43ff68b5614b34b5eaceff37157b37347995d231784ac1fd", - "0x085f69baef22680ae15f4801ef4361ebe9c7fc24a94b5bc2527dce8fb705439e", - "0x0d7c6b9ce31bfc32238a205455baf5ffe99cd30eb0f7bb5b504e1d4501e01382", - "0x1001a8cc4bc1221c814fba0eddcf3c40619b133373640c600de5bed0a0a05b10", - "0x20f5894be90e52977cb70f4f4cbd5101693db0360848939750db7e91109d54b6", - "0x22c09cb26db43f0599408b4daed0f4f496c66424e6affa41c14387d8e0af851b", - "0x24e5f41357798432426a9549d71e8cc681eaebacbe87f6e3bf38e85de5aa2f3d", - "0x06eb90100c736fbf2b87432d7821ecdc0b365024739bc36363d48b905973f5b9", - "0x000000000000000000000000000000ece6d09ed58e9f5661c01140b10558a8c2", - "0x000000000000000000000000000000000012b6e4f37adcb34b8e88ff8b6eebce", - "0x000000000000000000000000000000b226a2bb93593fa1fab19a44767828a3f5", - "0x00000000000000000000000000000000002b5b518342030543092e1428a7e33c", - "0x00000000000000000000000000000022ba33857034a0574c216eb3c1ddff3025", - "0x00000000000000000000000000000000001918e58df857985a7cf9eae7802165", - "0x00000000000000000000000000000045c2d840b96fb6106cc14dcad89dd5f675", - "0x00000000000000000000000000000000000afdfac1e3a1febdd0208867d44f98", - "0x00000000000000000000000000000042ebed6c5ec45d794f119aef24c192af0f", - "0x00000000000000000000000000000000002d05ef250900bbcc5751bbeb210d6a", - "0x00000000000000000000000000000060d604bdda48eecc90ed065bd9770e1323", - "0x00000000000000000000000000000000001fed91c63d0041660c1cbc84c2ffbb", - "0x00000000000000000000000000000054196b549cde36092e8184c7f4f7d878de", - "0x00000000000000000000000000000000000153f26a01294329922b492485cc31", - "0x00000000000000000000000000000056ebea579d10dbb440f0222931df2c0059", - "0x00000000000000000000000000000000000d2cbc61ce5b7cdd7fce398da4637b", - "0x000000000000000000000000000000e2b9512360b9797d96675d8a2fd2f7aa5d", - "0x000000000000000000000000000000000025742905f105ff895f74e7c3daa34a", - "0x000000000000000000000000000000a2dd7df55db59bd41b83518d4403fbc382", - "0x00000000000000000000000000000000002c1d9c3cbb9371d4cc4e9f900b9a46", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x000000000000000000000000000000bcf12ae40c9425c3e67654b84181f90502", - "0x00000000000000000000000000000000000b6d3faa8a71ff6ef1aa887b7307cf", - "0x0000000000000000000000000000001f6f719acc23b8f84808c0275d61cfb456", - "0x0000000000000000000000000000000000296030933ed0c134457ae71c393dfe", - "0x000000000000000000000000000000ebe1a57cdd7d3d763289b40ef5ed9a7ae0", - "0x000000000000000000000000000000000010f30483e7df51fca2316d3367603c", - "0x0000000000000000000000000000000149b7b283ab18060618c8e051864c03cd", - "0x00000000000000000000000000000000001ef7763235a3a25e241a5f06704dc3", -] -public_inputs = [ - "0x0000000000000000000000000000000000000000000000000000000000000003", -] -verification_key = [ - "0x0000000000000000000000000000000000000000000000000000000000000020", - "0x0000000000000000000000000000000000000000000000000000000000000011", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000003", - "0x0000000000000000000000000000000000000000000000000000000000000004", - "0x0000000000000000000000000000000000000000000000000000000000000005", - "0x0000000000000000000000000000000000000000000000000000000000000006", - "0x0000000000000000000000000000000000000000000000000000000000000007", - "0x0000000000000000000000000000000000000000000000000000000000000008", - "0x0000000000000000000000000000000000000000000000000000000000000009", - "0x000000000000000000000000000000000000000000000000000000000000000a", - "0x000000000000000000000000000000000000000000000000000000000000000b", - "0x000000000000000000000000000000000000000000000000000000000000000c", - "0x000000000000000000000000000000000000000000000000000000000000000d", - "0x000000000000000000000000000000000000000000000000000000000000000e", - "0x000000000000000000000000000000000000000000000000000000000000000f", - "0x0000000000000000000000000000000000000000000000000000000000000010", - "0x00000000000000000000000000000060e430ad1c23bfcf3514323aae3f206e84", - "0x00000000000000000000000000000000001b5c3ff4c2458d8f481b1c068f27ae", - "0x000000000000000000000000000000bb510ab2112def34980e4fc6998ad9dd16", - "0x00000000000000000000000000000000000576e7c105b43e061e13cb877fefe1", - "0x000000000000000000000000000000ced074785d11857b065d8199e6669a601c", - "0x00000000000000000000000000000000000053b48a4098c1c0ae268f273952f7", - "0x000000000000000000000000000000d1d4b26e941db8168cee8f6de548ae0fd8", - "0x00000000000000000000000000000000001a9adf5a6dadc3d948bb61dfd63f4c", - "0x0000000000000000000000000000009ce1faac6f8de6ebb18f1db17372c82ad5", - "0x00000000000000000000000000000000002002681bb417184b2df070a16a3858", - "0x000000000000000000000000000000161baa651a8092e0e84725594de5aba511", - "0x00000000000000000000000000000000000be0064399c2a1efff9eb0cdcb2223", - "0x0000000000000000000000000000008673be6fd1bdbe980a29d8c1ded54381e7", - "0x000000000000000000000000000000000008a5158a7d9648cf1d234524c9fa0c", - "0x0000000000000000000000000000002b4fce6e4b1c72062b296d49bca2aa4130", - "0x00000000000000000000000000000000002e45a9eff4b6769e55fb710cded44f", - "0x00000000000000000000000000000072b85bf733758b76bcf97333efb85a23e3", - "0x000000000000000000000000000000000017da0ea508994fc82862715e4b5592", - "0x00000000000000000000000000000094fa74695cf058dba8ff35aec95456c6c3", - "0x0000000000000000000000000000000000211acddb851061c24b8f159e832bd1", - "0x000000000000000000000000000000303b5e5c531384b9a792e11702ad3bcab0", - "0x00000000000000000000000000000000000d336dff51a60b8833d5d7f6d4314c", - "0x0000000000000000000000000000009f825dde88092070747180d581c342444a", - "0x0000000000000000000000000000000000237fbd6511a03cca8cac01b555fe01", - "0x0000000000000000000000000000007c313205159495df6d8de292079a4844ff", - "0x000000000000000000000000000000000018facdfc468530dd45e8f7a1d38ce9", - "0x0000000000000000000000000000000d1ce33446fc3dc4ab40ca38d92dac74e1", - "0x00000000000000000000000000000000000852d8e3e0e8f4435af3e94222688b", - "0x0000000000000000000000000000006c04ee19ec1dfec87ed47d6d04aa158de2", - "0x000000000000000000000000000000000013240f97a584b45184c8ec31319b5f", - "0x000000000000000000000000000000cefb5d240b07ceb4be26ea429b6dc9d9e0", - "0x00000000000000000000000000000000002dad22022121d689f57fb38ca21349", - "0x000000000000000000000000000000c9f189f2a91aeb664ce376d8b157ba98f8", - "0x00000000000000000000000000000000002531a51ad54f124d58094b219818d2", - "0x000000000000000000000000000000ef1e6db71809307f677677e62b4163f556", - "0x0000000000000000000000000000000000272da4396fb2a7ee0638b9140e523d", - "0x0000000000000000000000000000002e54c0244a7732c87bc4712a76dd8c83fb", - "0x000000000000000000000000000000000007db77b3e04b7eba9643da57cbbe4d", - "0x000000000000000000000000000000e0dfe1ddd7f74ae0d636c910c3e85830d8", - "0x00000000000000000000000000000000000466fa9b57ec4664abd1505b490862", - "0x0000000000000000000000000000009ee55ae8a32fe5384c79907067cc27192e", - "0x00000000000000000000000000000000000799d0e465cec07ecb5238c854e830", - "0x0000000000000000000000000000001d5910ad361e76e1c241247a823733c39f", - "0x00000000000000000000000000000000002b03f2ccf7507564da2e6678bef8fe", - "0x000000000000000000000000000000231147211b3c75e1f47d150e4bbd2fb22e", - "0x00000000000000000000000000000000000d19ee104a10d3c701cfd87473cbbe", - "0x0000000000000000000000000000006705f3f382637d00f698e2c5c94ed05ae9", - "0x00000000000000000000000000000000000b9c792da28bb60601dd7ce4b74e68", - "0x000000000000000000000000000000ac5acc8cc21e4ddb225c510670f80c80b3", - "0x00000000000000000000000000000000002da9d3fa57343e6998aba19429b9fa", - "0x0000000000000000000000000000004bacbf54b7c17a560df0af18b6d0d527be", - "0x00000000000000000000000000000000000faea33aeca2025b22c288964b21eb", - "0x000000000000000000000000000000492e756298d68d6e95de096055cc0336c3", - "0x00000000000000000000000000000000001a12a12f004859e5a3675c7315121b", - "0x000000000000000000000000000000893d521d512f30e6d32afbbc0cecd8ee00", - "0x00000000000000000000000000000000001674b3c1ef12c6da690631e0d86c04", - "0x000000000000000000000000000000aa6cb02a52e7a613873d4ac9b411349945", - "0x00000000000000000000000000000000001ecb1fe9c493add46751f9940f73e1", - "0x00000000000000000000000000000045b3d362ca82cba69fb2b9c733a5b8c351", - "0x000000000000000000000000000000000019a683586af466e331945b732d2f8c", - "0x000000000000000000000000000000fc79b052dfdfe67c0ecfc06b4267ffd694", - "0x00000000000000000000000000000000001336a70c396393038d5e9913744ac2", - "0x0000000000000000000000000000005450d29af1e9438e91cd33ddeb2548226e", - "0x000000000000000000000000000000000000993a602891cfd0e6f6ecf7404933", - "0x000000000000000000000000000000498efddab90a32e9b2db729ed6e9b40192", - "0x00000000000000000000000000000000002425efebe9628c63ca6fc28bdb5901", - "0x000000000000000000000000000000d8488157f875a21ab5f93f1c2b641f3de9", - "0x0000000000000000000000000000000000290f95ada3936604dc4b14df7504e3", - "0x0000000000000000000000000000005d6902187f3ed60dcce06fca211b40329a", - "0x00000000000000000000000000000000002b5870a6ba0b20aaa0178e5adfbc36", - "0x000000000000000000000000000000e5c2519171fa0e548fc3c4966ffc1ce570", - "0x00000000000000000000000000000000001cb8d8f4793b7debbdc429389dbf2d", - "0x000000000000000000000000000000a3ee22dd60456277b86c32a18982dcb185", - "0x00000000000000000000000000000000002493c99a3d068b03f8f2b8d28b57ce", - "0x000000000000000000000000000000f6c3731486320082c20ec71bbdc92196c1", - "0x00000000000000000000000000000000001ded39c4c8366469843cd63f09ecac", - "0x000000000000000000000000000000494997477ab161763e46601d95844837ef", - "0x00000000000000000000000000000000002e0cddbc5712d79b59cb3b41ebbcdd", - "0x000000000000000000000000000000426db4c64531d350750df62dbbc41a1bd9", - "0x0000000000000000000000000000000000303126892f664d8d505964d14315ec", - "0x00000000000000000000000000000076a6b2c6040c0c62bd59acfe3e3e125672", - "0x000000000000000000000000000000000000874a5ad262eecc6b565e0b085074", - "0x000000000000000000000000000000ef082fb517183c9c6841c2b8ef2ca1df04", - "0x0000000000000000000000000000000000127b2a745a1b74968c3edc18982b9b", - "0x000000000000000000000000000000c9efd4f8c3d56e1eb23d789a8f710d5be6", - "0x000000000000000000000000000000000015a18748490ff4c2b1871081954e86", - "0x000000000000000000000000000000a0011ef987dc016ab110eacd554a1d8bbf", - "0x00000000000000000000000000000000002097c84955059442a95df075833071", - "0x000000000000000000000000000000d38e9426ad3085b68b00a93c17897c2877", - "0x00000000000000000000000000000000002aecd48089890ea0798eb952c66824", - "0x00000000000000000000000000000078d8a9ce405ce559f441f2e71477ff3ddb", - "0x00000000000000000000000000000000001216bdb2f0d961bb8a7a23331d2150", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x000000000000000000000000000000ee40d90bea71fba7a412dd61fcf34e8ceb", - "0x0000000000000000000000000000000000140b0936c323fd2471155617b6af56", - "0x0000000000000000000000000000002b90071823185c5ff8e440fd3d73b6fefc", - "0x00000000000000000000000000000000002b6c10790a5f6631c87d652e059df4", -] diff --git a/noir/noir-repo/test_programs/execution_success/verify_honk_proof/src/main.nr b/noir/noir-repo/test_programs/execution_success/verify_honk_proof/src/main.nr deleted file mode 100644 index 17adc68c056..00000000000 --- a/noir/noir-repo/test_programs/execution_success/verify_honk_proof/src/main.nr +++ /dev/null @@ -1,16 +0,0 @@ - -// This circuit aggregates a single Honk proof from `assert_statement_recursive`. -global SIZE_OF_PROOF_IF_LOGN_IS_28 : u32 = 409; -fn main( - verification_key: [Field; 120], - // This is the proof without public inputs attached. - // - // This means: the size of this does not change with the number of public inputs. - proof: [Field; SIZE_OF_PROOF_IF_LOGN_IS_28], - public_inputs: pub [Field; 1], - // This is currently not public. It is fine given that the vk is a part of the circuit definition. - // I believe we want to eventually make it public too though. - key_hash: Field -) { - std::verify_proof(verification_key, proof, public_inputs, key_hash); -} diff --git a/noir/noir-repo/tooling/lsp/src/requests/completion.rs b/noir/noir-repo/tooling/lsp/src/requests/completion.rs index 48616c0f52d..028bbcd6b28 100644 --- a/noir/noir-repo/tooling/lsp/src/requests/completion.rs +++ b/noir/noir-repo/tooling/lsp/src/requests/completion.rs @@ -31,7 +31,7 @@ use noirc_frontend::{ node_interner::{FuncId, GlobalId, ReferenceId, TraitId, TypeAliasId}, parser::{Item, ItemKind}, token::Keyword, - ParsedModule, Type, + ParsedModule, StructType, Type, }; use strum::IntoEnumIterator; @@ -55,13 +55,22 @@ enum ModuleCompletionKind { /// When suggest a function as a result of completion, whether to autocomplete its name or its name and parameters. #[derive(Clone, Copy, PartialEq, Eq, Debug)] -enum FunctionCompleteKind { +enum FunctionCompletionKind { // Only complete a function's name. This is used in use statement. Name, // Complete a function's name and parameters (as a snippet). This is used in regular code. NameAndParameters, } +/// Is there a requirement for suggesting functions? +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +enum FunctionKind<'a> { + /// No requirement: any function is okay to suggest. + Any, + /// Only show functions that have the given self type. + SelfType(&'a Type), +} + /// When requesting completions, whether to list all items or just types. /// For example, when writing `let x: S` we only want to suggest types at this /// point (modules too, because they might include types too). @@ -173,7 +182,16 @@ impl<'a> NodeFinder<'a> { if self.completion_items.is_empty() { None } else { - Some(CompletionResponse::Array(std::mem::take(&mut self.completion_items))) + let mut items = std::mem::take(&mut self.completion_items); + + // Show items that start with underscore last in the list + for item in items.iter_mut() { + if item.label.starts_with('_') { + item.sort_text = Some(underscore_sort_text()); + } + } + + Some(CompletionResponse::Array(items)) } } @@ -459,6 +477,19 @@ impl<'a> NodeFinder<'a> { } fn find_in_expression(&mut self, expression: &Expression) { + // "foo." (no identifier afterwards) is parsed as the expression on the left hand-side of the dot. + // Here we check if there's a dot at the completion position, and if the expression + // ends right before the dot. If so, it means we want to complete the expression's type fields and methods. + if self.byte == Some(b'.') && expression.span.end() as usize == self.byte_index - 1 { + let location = Location::new(expression.span, self.file); + if let Some(typ) = self.interner.type_at_location(location) { + let typ = typ.follow_bindings(); + let prefix = ""; + self.complete_type_fields_and_methods(&typ, prefix); + return; + } + } + match &expression.kind { noirc_frontend::ast::ExpressionKind::Literal(literal) => self.find_in_literal(literal), noirc_frontend::ast::ExpressionKind::Block(block_expression) => { @@ -572,6 +603,19 @@ impl<'a> NodeFinder<'a> { &mut self, member_access_expression: &MemberAccessExpression, ) { + let ident = &member_access_expression.rhs; + + if self.byte_index == ident.span().end() as usize { + // Assuming member_access_expression is of the form `foo.bar`, we are right after `bar` + let location = Location::new(member_access_expression.lhs.span, self.file); + if let Some(typ) = self.interner.type_at_location(location) { + let typ = typ.follow_bindings(); + let prefix = ident.to_string(); + self.complete_type_fields_and_methods(&typ, &prefix); + return; + } + } + self.find_in_expression(&member_access_expression.lhs); } @@ -707,19 +751,50 @@ impl<'a> NodeFinder<'a> { } let is_single_segment = !after_colons && idents.is_empty() && path.kind == PathKind::Plain; + let module_id; - let module_id = - if idents.is_empty() { Some(self.module_id) } else { self.resolve_module(idents) }; - let Some(module_id) = module_id else { - return; - }; + if idents.is_empty() { + module_id = self.module_id; + } else { + let Some(module_def_id) = self.resolve_path(idents) else { + return; + }; + + match module_def_id { + ModuleDefId::ModuleId(id) => module_id = id, + ModuleDefId::TypeId(struct_id) => { + let struct_type = self.interner.get_struct(struct_id); + self.complete_type_methods( + &Type::Struct(struct_type, vec![]), + &prefix, + FunctionKind::Any, + ); + return; + } + ModuleDefId::FunctionId(_) => { + // There's nothing inside a function + return; + } + ModuleDefId::TypeAliasId(type_alias_id) => { + let type_alias = self.interner.get_type_alias(type_alias_id); + let type_alias = type_alias.borrow(); + self.complete_type_methods(&type_alias.typ, &prefix, FunctionKind::Any); + return; + } + ModuleDefId::TraitId(_) => { + // For now we don't suggest trait methods + return; + } + ModuleDefId::GlobalId(_) => return, + } + } let module_completion_kind = if after_colons { ModuleCompletionKind::DirectChildren } else { ModuleCompletionKind::AllVisibleItems }; - let function_completion_kind = FunctionCompleteKind::NameAndParameters; + let function_completion_kind = FunctionCompletionKind::NameAndParameters; self.complete_in_module( module_id, @@ -827,7 +902,7 @@ impl<'a> NodeFinder<'a> { } let module_completion_kind = ModuleCompletionKind::DirectChildren; - let function_completion_kind = FunctionCompleteKind::Name; + let function_completion_kind = FunctionCompletionKind::Name; let requested_items = RequestedItems::AnyItems; if after_colons { @@ -913,6 +988,78 @@ impl<'a> NodeFinder<'a> { }; } + fn complete_type_fields_and_methods(&mut self, typ: &Type, prefix: &str) { + match typ { + Type::Struct(struct_type, generics) => { + self.complete_struct_fields(&struct_type.borrow(), generics, prefix); + } + Type::MutableReference(typ) => { + return self.complete_type_fields_and_methods(typ, prefix); + } + Type::Alias(type_alias, _) => { + let type_alias = type_alias.borrow(); + return self.complete_type_fields_and_methods(&type_alias.typ, prefix); + } + Type::FieldElement + | Type::Array(_, _) + | Type::Slice(_) + | Type::Integer(_, _) + | Type::Bool + | Type::String(_) + | Type::FmtString(_, _) + | Type::Unit + | Type::Tuple(_) + | Type::TypeVariable(_, _) + | Type::TraitAsType(_, _, _) + | Type::NamedGeneric(_, _, _) + | Type::Function(_, _, _) + | Type::Forall(_, _) + | Type::Constant(_) + | Type::Quoted(_) + | Type::InfixExpr(_, _, _) + | Type::Error => (), + } + + self.complete_type_methods(typ, prefix, FunctionKind::SelfType(typ)); + } + + fn complete_type_methods(&mut self, typ: &Type, prefix: &str, function_kind: FunctionKind) { + let Some(methods_by_name) = self.interner.get_type_methods(typ) else { + return; + }; + + for (name, methods) in methods_by_name { + for func_id in methods.iter() { + if name_matches(name, prefix) { + if let Some(completion_item) = self.function_completion_item( + func_id, + FunctionCompletionKind::NameAndParameters, + function_kind, + ) { + self.completion_items.push(completion_item); + } + } + } + } + } + + fn complete_struct_fields( + &mut self, + struct_type: &StructType, + generics: &[Type], + prefix: &str, + ) { + for (name, typ) in struct_type.get_fields(generics) { + if name_matches(&name, prefix) { + self.completion_items.push(simple_completion_item( + name, + CompletionItemKind::FIELD, + Some(typ.to_string()), + )); + } + } + } + #[allow(clippy::too_many_arguments)] fn complete_in_module( &mut self, @@ -921,7 +1068,7 @@ impl<'a> NodeFinder<'a> { path_kind: PathKind, at_root: bool, module_completion_kind: ModuleCompletionKind, - function_completion_kind: FunctionCompleteKind, + function_completion_kind: FunctionCompletionKind, requested_items: RequestedItems, ) { let def_map = &self.def_maps[&module_id.krate]; @@ -951,6 +1098,8 @@ impl<'a> NodeFinder<'a> { } } + let function_kind = FunctionKind::Any; + let items = match module_completion_kind { ModuleCompletionKind::DirectChildren => module_data.definitions(), ModuleCompletionKind::AllVisibleItems => module_data.scope(), @@ -966,6 +1115,7 @@ impl<'a> NodeFinder<'a> { module_def_id, name.clone(), function_completion_kind, + function_kind, requested_items, ) { self.completion_items.push(completion_item); @@ -977,6 +1127,7 @@ impl<'a> NodeFinder<'a> { module_def_id, name.clone(), function_completion_kind, + function_kind, requested_items, ) { self.completion_items.push(completion_item); @@ -1015,7 +1166,8 @@ impl<'a> NodeFinder<'a> { &self, module_def_id: ModuleDefId, name: String, - function_completion_kind: FunctionCompleteKind, + function_completion_kind: FunctionCompletionKind, + function_kind: FunctionKind, requested_items: RequestedItems, ) -> Option { match requested_items { @@ -1029,64 +1181,142 @@ impl<'a> NodeFinder<'a> { RequestedItems::AnyItems => (), } - let completion_item = match module_def_id { - ModuleDefId::ModuleId(_) => module_completion_item(name), + match module_def_id { + ModuleDefId::ModuleId(_) => Some(module_completion_item(name)), ModuleDefId::FunctionId(func_id) => { - self.function_completion_item(func_id, function_completion_kind) + self.function_completion_item(func_id, function_completion_kind, function_kind) } - ModuleDefId::TypeId(struct_id) => self.struct_completion_item(struct_id), + ModuleDefId::TypeId(struct_id) => Some(self.struct_completion_item(struct_id)), ModuleDefId::TypeAliasId(type_alias_id) => { - self.type_alias_completion_item(type_alias_id) + Some(self.type_alias_completion_item(type_alias_id)) } - ModuleDefId::TraitId(trait_id) => self.trait_completion_item(trait_id), - ModuleDefId::GlobalId(global_id) => self.global_completion_item(global_id), - }; - Some(completion_item) + ModuleDefId::TraitId(trait_id) => Some(self.trait_completion_item(trait_id)), + ModuleDefId::GlobalId(global_id) => Some(self.global_completion_item(global_id)), + } } fn function_completion_item( &self, func_id: FuncId, - function_completion_kind: FunctionCompleteKind, - ) -> CompletionItem { + function_completion_kind: FunctionCompletionKind, + function_kind: FunctionKind, + ) -> Option { let func_meta = self.interner.function_meta(&func_id); - let name = self.interner.function_name(&func_id).to_string(); + let name = &self.interner.function_name(&func_id).to_string(); + + let func_self_type = if let Some((pattern, typ, _)) = func_meta.parameters.0.get(0) { + if self.hir_pattern_is_self_type(pattern) { + if let Type::MutableReference(mut_typ) = typ { + let typ: &Type = mut_typ; + Some(typ) + } else { + Some(typ) + } + } else { + None + } + } else { + None + }; - let mut typ = &func_meta.typ; - if let Type::Forall(_, typ_) = typ { - typ = typ_; + match function_kind { + FunctionKind::Any => (), + FunctionKind::SelfType(mut self_type) => { + if let Some(func_self_type) = func_self_type { + if matches!(self_type, Type::Integer(..)) + || matches!(self_type, Type::FieldElement) + { + // Check that the pattern type is the same as self type. + // We do this because some types (only Field and integer types) + // have their methods in the same HashMap. + + if let Type::MutableReference(mut_typ) = self_type { + self_type = mut_typ; + } + + if self_type != func_self_type { + return None; + } + } + } else { + return None; + } + } } - let description = typ.to_string(); - let description = description.strip_suffix(" -> ()").unwrap_or(&description).to_string(); - match function_completion_kind { - FunctionCompleteKind::Name => { + let is_operator = if let Some(trait_impl_id) = &func_meta.trait_impl { + let trait_impl = self.interner.get_trait_implementation(*trait_impl_id); + let trait_impl = trait_impl.borrow(); + self.interner.is_operator_trait(trait_impl.trait_id) + } else { + false + }; + let description = func_meta_type_to_string(func_meta, func_self_type.is_some()); + + let completion_item = match function_completion_kind { + FunctionCompletionKind::Name => { simple_completion_item(name, CompletionItemKind::FUNCTION, Some(description)) } - FunctionCompleteKind::NameAndParameters => { - let label = format!("{}(…)", name); + FunctionCompletionKind::NameAndParameters => { let kind = CompletionItemKind::FUNCTION; - let insert_text = self.compute_function_insert_text(func_meta, &name); + let insert_text = self.compute_function_insert_text(func_meta, name, function_kind); + let label = if insert_text.ends_with("()") { + format!("{}()", name) + } else { + format!("{}(…)", name) + }; snippet_completion_item(label, kind, insert_text, Some(description)) } - } + }; + + let completion_item = if is_operator { + completion_item_with_sort_text(completion_item, operator_sort_text()) + } else if function_kind == FunctionKind::Any && name == "new" { + completion_item_with_sort_text(completion_item, new_sort_text()) + } else if function_kind == FunctionKind::Any && func_self_type.is_some() { + completion_item_with_sort_text(completion_item, self_mismatch_sort_text()) + } else { + completion_item + }; + + Some(completion_item) } - fn compute_function_insert_text(&self, func_meta: &FuncMeta, name: &str) -> String { + fn compute_function_insert_text( + &self, + func_meta: &FuncMeta, + name: &str, + function_kind: FunctionKind, + ) -> String { let mut text = String::new(); text.push_str(name); text.push('('); - for (index, (pattern, _, _)) in func_meta.parameters.0.iter().enumerate() { - if index > 0 { + + let mut index = 1; + for (pattern, _, _) in &func_meta.parameters.0 { + if index == 1 { + match function_kind { + FunctionKind::SelfType(_) => { + if self.hir_pattern_is_self_type(pattern) { + continue; + } + } + FunctionKind::Any => (), + } + } + + if index > 1 { text.push_str(", "); } text.push_str("${"); - text.push_str(&(index + 1).to_string()); + text.push_str(&index.to_string()); text.push(':'); self.hir_pattern_to_argument(pattern, &mut text); text.push('}'); + + index += 1; } text.push(')'); text @@ -1102,6 +1332,17 @@ impl<'a> NodeFinder<'a> { } } + fn hir_pattern_is_self_type(&self, pattern: &HirPattern) -> bool { + match pattern { + HirPattern::Identifier(hir_ident) => { + let name = self.interner.definition_name(hir_ident.id); + name == "self" || name == "_self" + } + HirPattern::Mutable(pattern, _) => self.hir_pattern_is_self_type(pattern), + HirPattern::Tuple(_, _) | HirPattern::Struct(_, _, _) => false, + } + } + fn struct_completion_item(&self, struct_id: StructId) -> CompletionItem { let struct_type = self.interner.get_struct(struct_id); let struct_type = struct_type.borrow(); @@ -1145,14 +1386,25 @@ impl<'a> NodeFinder<'a> { } fn resolve_path(&self, segments: Vec) -> Option { + let last_segment = segments.last().unwrap().clone(); + let path_segments = segments.into_iter().map(PathSegment::from).collect(); let path = Path { segments: path_segments, kind: PathKind::Plain, span: Span::default() }; let path_resolver = StandardPathResolver::new(self.root_module_id); - match path_resolver.resolve(self.def_maps, path, &mut None) { - Ok(path_resolution) => Some(path_resolution.module_def_id), - Err(_) => None, + if let Ok(path_resolution) = path_resolver.resolve(self.def_maps, path, &mut None) { + return Some(path_resolution.module_def_id); } + + // If we can't resolve a path trough lookup, let's see if the last segment is bound to a type + let location = Location::new(last_segment.span(), self.file); + if let Some(reference_id) = self.interner.find_referenced(location) { + if let Some(id) = module_def_id_from_reference_id(reference_id) { + return Some(id); + } + } + + None } fn builtin_functions_completion(&mut self, prefix: &str) { @@ -1236,7 +1488,7 @@ fn simple_completion_item( documentation: None, deprecated: None, preselect: None, - sort_text: None, + sort_text: Some(default_sort_text()), filter_text: None, insert_text: None, insert_text_format: None, @@ -1266,7 +1518,7 @@ fn snippet_completion_item( documentation: None, deprecated: None, preselect: None, - sort_text: None, + sort_text: Some(default_sort_text()), filter_text: None, insert_text_mode: None, text_edit: None, @@ -1278,6 +1530,98 @@ fn snippet_completion_item( } } +fn completion_item_with_sort_text( + completion_item: CompletionItem, + sort_text: String, +) -> CompletionItem { + CompletionItem { sort_text: Some(sort_text), ..completion_item } +} + +fn module_def_id_from_reference_id(reference_id: ReferenceId) -> Option { + match reference_id { + ReferenceId::Module(module_id) => Some(ModuleDefId::ModuleId(module_id)), + ReferenceId::Struct(struct_id) => Some(ModuleDefId::TypeId(struct_id)), + ReferenceId::Trait(trait_id) => Some(ModuleDefId::TraitId(trait_id)), + ReferenceId::Function(func_id) => Some(ModuleDefId::FunctionId(func_id)), + ReferenceId::Alias(type_alias_id) => Some(ModuleDefId::TypeAliasId(type_alias_id)), + ReferenceId::StructMember(_, _) + | ReferenceId::Global(_) + | ReferenceId::Local(_) + | ReferenceId::Reference(_, _) => None, + } +} + +fn func_meta_type_to_string(func_meta: &FuncMeta, has_self_type: bool) -> String { + let mut typ = &func_meta.typ; + if let Type::Forall(_, typ_) = typ { + typ = typ_; + } + + if let Type::Function(args, ret, _env) = typ { + let mut string = String::new(); + string.push_str("fn("); + for (index, arg) in args.iter().enumerate() { + if index > 0 { + string.push_str(", "); + } + if index == 0 && has_self_type { + type_to_self_string(arg, &mut string); + } else { + string.push_str(&arg.to_string()); + } + } + string.push(')'); + + let ret: &Type = ret; + if let Type::Unit = ret { + // Nothing + } else { + string.push_str(" -> "); + string.push_str(&ret.to_string()); + } + string + } else { + typ.to_string() + } +} + +fn type_to_self_string(typ: &Type, string: &mut String) { + if let Type::MutableReference(..) = typ { + string.push_str("&mut self"); + } else { + string.push_str("self"); + } +} + +/// Sort text for "new" methods: we want these to show up before anything else, +/// if we are completing at something like `Foo::` +fn new_sort_text() -> String { + "3".to_string() +} + +/// This is the default sort text. +fn default_sort_text() -> String { + "5".to_string() +} + +/// When completing something like `Foo::`, we want to show methods that take +/// self after the other ones. +fn self_mismatch_sort_text() -> String { + "7".to_string() +} + +/// We want to show operator methods last. +fn operator_sort_text() -> String { + "8".to_string() +} + +/// If a name begins with underscore it's likely something that's meant to +/// be private (but visibility doesn't exist everywhere yet, so for now +/// we assume that) +fn underscore_sort_text() -> String { + "9".to_string() +} + #[cfg(test)] mod completion_tests { use crate::{notifications::on_did_open_text_document, test_utils}; @@ -1664,6 +2008,27 @@ mod completion_tests { .await; } + #[test] + async fn test_complete_function_without_arguments() { + let src = r#" + fn hello() { } + + fn main() { + h>|< + } + "#; + assert_completion( + src, + vec![snippet_completion_item( + "hello()", + CompletionItemKind::FUNCTION, + "hello()", + Some("fn()".to_string()), + )], + ) + .await; + } + #[test] async fn test_complete_function() { let src = r#" @@ -2201,4 +2566,315 @@ mod completion_tests { ) .await; } + + #[test] + async fn test_suggests_struct_field_after_dot_and_letter() { + let src = r#" + struct Some { + property: i32, + } + + fn foo(s: Some) { + s.p>|< + } + "#; + assert_completion( + src, + vec![simple_completion_item( + "property", + CompletionItemKind::FIELD, + Some("i32".to_string()), + )], + ) + .await; + } + + #[test] + async fn test_suggests_struct_field_after_dot_and_letter_for_generic_type() { + let src = r#" + struct Some { + property: T, + } + + fn foo(s: Some) { + s.p>|< + } + "#; + assert_completion( + src, + vec![simple_completion_item( + "property", + CompletionItemKind::FIELD, + Some("i32".to_string()), + )], + ) + .await; + } + + #[test] + async fn test_suggests_struct_field_after_dot_followed_by_brace() { + let src = r#" + struct Some { + property: i32, + } + + fn foo(s: Some) { + s.>|< + } + "#; + assert_completion( + src, + vec![simple_completion_item( + "property", + CompletionItemKind::FIELD, + Some("i32".to_string()), + )], + ) + .await; + } + + #[test] + async fn test_suggests_struct_field_after_dot_chain() { + let src = r#" + struct Some { + property: Other, + } + + struct Other { + bar: i32, + } + + fn foo(some: Some) { + some.property.>|< + } + "#; + assert_completion( + src, + vec![simple_completion_item("bar", CompletionItemKind::FIELD, Some("i32".to_string()))], + ) + .await; + } + + #[test] + async fn test_suggests_struct_impl_method() { + let src = r#" + struct Some { + } + + impl Some { + fn foobar(self, x: i32) {} + fn foobar2(&mut self, x: i32) {} + fn foobar3(y: i32) {} + } + + fn foo(some: Some) { + some.f>|< + } + "#; + assert_completion( + src, + vec![ + snippet_completion_item( + "foobar(…)", + CompletionItemKind::FUNCTION, + "foobar(${1:x})", + Some("fn(self, i32)".to_string()), + ), + snippet_completion_item( + "foobar2(…)", + CompletionItemKind::FUNCTION, + "foobar2(${1:x})", + Some("fn(&mut self, i32)".to_string()), + ), + ], + ) + .await; + } + + #[test] + async fn test_suggests_struct_trait_impl_method() { + let src = r#" + struct Some { + } + + trait SomeTrait { + fn foobar(self, x: i32); + fn foobar2(y: i32); + } + + impl SomeTrait for Some { + fn foobar(self, x: i32) {} + fn foobar2(y: i32) {} + } + + fn foo(some: Some) { + some.f>|< + } + "#; + assert_completion( + src, + vec![snippet_completion_item( + "foobar(…)", + CompletionItemKind::FUNCTION, + "foobar(${1:x})", + Some("fn(self, i32)".to_string()), + )], + ) + .await; + } + + #[test] + async fn test_suggests_primitive_trait_impl_method() { + let src = r#" + trait SomeTrait { + fn foobar(self, x: i32); + fn foobar2(y: i32); + } + + impl SomeTrait for Field { + fn foobar(self, x: i32) {} + fn foobar2(y: i32) {} + } + + fn foo(field: Field) { + field.f>|< + } + "#; + assert_completion( + src, + vec![snippet_completion_item( + "foobar(…)", + CompletionItemKind::FUNCTION, + "foobar(${1:x})", + Some("fn(self, i32)".to_string()), + )], + ) + .await; + } + + #[test] + async fn test_suggests_struct_methods_after_colons() { + let src = r#" + struct Some { + } + + impl Some { + fn foobar(self, x: i32) {} + fn foobar2(&mut self, x: i32) {} + fn foobar3(y: i32) {} + } + + fn foo() { + Some::>|< + } + "#; + assert_completion( + src, + vec![ + completion_item_with_sort_text( + snippet_completion_item( + "foobar(…)", + CompletionItemKind::FUNCTION, + "foobar(${1:self}, ${2:x})", + Some("fn(self, i32)".to_string()), + ), + self_mismatch_sort_text(), + ), + completion_item_with_sort_text( + snippet_completion_item( + "foobar2(…)", + CompletionItemKind::FUNCTION, + "foobar2(${1:self}, ${2:x})", + Some("fn(&mut self, i32)".to_string()), + ), + self_mismatch_sort_text(), + ), + snippet_completion_item( + "foobar3(…)", + CompletionItemKind::FUNCTION, + "foobar3(${1:y})", + Some("fn(i32)".to_string()), + ), + ], + ) + .await; + } + + #[test] + async fn test_suggests_struct_behind_alias_methods_after_dot() { + let src = r#" + struct Some { + } + + type Alias = Some; + + impl Some { + fn foobar(self, x: i32) {} + } + + fn foo(some: Alias) { + some.>|< + } + "#; + assert_completion( + src, + vec![snippet_completion_item( + "foobar(…)", + CompletionItemKind::FUNCTION, + "foobar(${1:x})", + Some("fn(self, i32)".to_string()), + )], + ) + .await; + } + + #[test] + async fn test_suggests_struct_behind_alias_methods_after_colons() { + let src = r#" + struct Some { + } + + type Alias = Some; + + impl Some { + fn foobar(self, x: i32) {} + fn foobar2(&mut self, x: i32) {} + fn foobar3(y: i32) {} + } + + fn foo() { + Alias::>|< + } + "#; + assert_completion( + src, + vec![ + completion_item_with_sort_text( + snippet_completion_item( + "foobar(…)", + CompletionItemKind::FUNCTION, + "foobar(${1:self}, ${2:x})", + Some("fn(self, i32)".to_string()), + ), + self_mismatch_sort_text(), + ), + completion_item_with_sort_text( + snippet_completion_item( + "foobar2(…)", + CompletionItemKind::FUNCTION, + "foobar2(${1:self}, ${2:x})", + Some("fn(&mut self, i32)".to_string()), + ), + self_mismatch_sort_text(), + ), + snippet_completion_item( + "foobar3(…)", + CompletionItemKind::FUNCTION, + "foobar3(${1:y})", + Some("fn(i32)".to_string()), + ), + ], + ) + .await; + } } diff --git a/noir/noir-repo/tooling/lsp/src/requests/completion/builtins.rs b/noir/noir-repo/tooling/lsp/src/requests/completion/builtins.rs index 070be109f13..00f7717046c 100644 --- a/noir/noir-repo/tooling/lsp/src/requests/completion/builtins.rs +++ b/noir/noir-repo/tooling/lsp/src/requests/completion/builtins.rs @@ -14,6 +14,7 @@ pub(super) fn keyword_builtin_type(keyword: &Keyword) -> Option<&'static str> { Keyword::StructDefinition => Some("StructDefinition"), Keyword::TraitConstraint => Some("TraitConstraint"), Keyword::TraitDefinition => Some("TraitDefinition"), + Keyword::TraitImpl => Some("TraitImpl"), Keyword::TypeType => Some("Type"), Keyword::As @@ -116,6 +117,7 @@ pub(super) fn keyword_builtin_function(keyword: &Keyword) -> Option